1// Protocol Buffers - Google's data interchange format 2// Copyright 2008 Google Inc. All rights reserved. 3// https://developers.google.com/protocol-buffers/ 4// 5// Redistribution and use in source and binary forms, with or without 6// modification, are permitted provided that the following conditions are 7// met: 8// 9// * Redistributions of source code must retain the above copyright 10// notice, this list of conditions and the following disclaimer. 11// * Redistributions in binary form must reproduce the above 12// copyright notice, this list of conditions and the following disclaimer 13// in the documentation and/or other materials provided with the 14// distribution. 15// * Neither the name of Google Inc. nor the names of its 16// contributors may be used to endorse or promote products derived from 17// this software without specific prior written permission. 18// 19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 31/** 32 * @fileoverview Test cases for Int64-manipulation functions. 33 * 34 * Test suite is written using Jasmine -- see http://jasmine.github.io/ 35 * 36 * @author cfallin@google.com (Chris Fallin) 37 */ 38 39goog.require('jspb.arith.Int64'); 40goog.require('jspb.arith.UInt64'); 41 42 43describe('binaryArithTest', function() { 44 /** 45 * Tests comparison operations. 46 */ 47 it('testCompare', function() { 48 var a = new jspb.arith.UInt64(1234, 5678); 49 var b = new jspb.arith.UInt64(1234, 5678); 50 expect(a.cmp(b)).toEqual(0); 51 expect(b.cmp(a)).toEqual(0); 52 b.lo -= 1; 53 expect(a.cmp(b)).toEqual(1); 54 expect(b.cmp(a)).toEqual(-1); 55 b.lo += 2; 56 expect(a.cmp(b)).toEqual(-1); 57 expect(b.cmp(a)).toEqual(1); 58 b.lo = a.lo; 59 b.hi = a.hi - 1; 60 expect(a.cmp(b)).toEqual(1); 61 expect(b.cmp(a)).toEqual(-1); 62 63 expect(a.zero()).toEqual(false); 64 expect(a.msb()).toEqual(false); 65 expect(a.lsb()).toEqual(false); 66 a.hi = 0; 67 a.lo = 0; 68 expect(a.zero()).toEqual(true); 69 a.hi = 0x80000000; 70 expect(a.zero()).toEqual(false); 71 expect(a.msb()).toEqual(true); 72 a.lo = 0x00000001; 73 expect(a.lsb()).toEqual(true); 74 }); 75 76 77 /** 78 * Tests shifts. 79 */ 80 it('testShifts', function() { 81 var a = new jspb.arith.UInt64(1, 0); 82 expect(a.lo).toEqual(1); 83 expect(a.hi).toEqual(0); 84 var orig = a; 85 a = a.leftShift(); 86 expect(orig.lo).toEqual(1); // original unmodified. 87 expect(orig.hi).toEqual(0); 88 expect(a.lo).toEqual(2); 89 expect(a.hi).toEqual(0); 90 a = a.leftShift(); 91 expect(a.lo).toEqual(4); 92 expect(a.hi).toEqual(0); 93 for (var i = 0; i < 29; i++) { 94 a = a.leftShift(); 95 } 96 expect(a.lo).toEqual(0x80000000); 97 expect(a.hi).toEqual(0); 98 a = a.leftShift(); 99 expect(a.lo).toEqual(0); 100 expect(a.hi).toEqual(1); 101 a = a.leftShift(); 102 expect(a.lo).toEqual(0); 103 expect(a.hi).toEqual(2); 104 a = a.rightShift(); 105 a = a.rightShift(); 106 expect(a.lo).toEqual(0x80000000); 107 expect(a.hi).toEqual(0); 108 a = a.rightShift(); 109 expect(a.lo).toEqual(0x40000000); 110 expect(a.hi).toEqual(0); 111 }); 112 113 114 /** 115 * Tests additions. 116 */ 117 it('testAdd', function() { 118 var a = new jspb.arith.UInt64(/* lo = */ 0x89abcdef, 119 /* hi = */ 0x01234567); 120 var b = new jspb.arith.UInt64(/* lo = */ 0xff52ab91, 121 /* hi = */ 0x92fa2123); 122 // Addition with carry. 123 var c = a.add(b); 124 expect(a.lo).toEqual(0x89abcdef); // originals unmodified. 125 expect(a.hi).toEqual(0x01234567); 126 expect(b.lo).toEqual(0xff52ab91); 127 expect(b.hi).toEqual(0x92fa2123); 128 expect(c.lo).toEqual(0x88fe7980); 129 expect(c.hi).toEqual(0x941d668b); 130 131 // Simple addition without carry. 132 a.lo = 2; 133 a.hi = 0; 134 b.lo = 3; 135 b.hi = 0; 136 c = a.add(b); 137 expect(c.lo).toEqual(5); 138 expect(c.hi).toEqual(0); 139 }); 140 141 142 /** 143 * Test subtractions. 144 */ 145 it('testSub', function() { 146 var kLength = 10; 147 var hiValues = [0x1682ef32, 148 0x583902f7, 149 0xb62f5955, 150 0x6ea99bbf, 151 0x25a39c20, 152 0x0700a08b, 153 0x00f7304d, 154 0x91a5b5af, 155 0x89077fd2, 156 0xe09e347c]; 157 var loValues = [0xe1538b18, 158 0xbeacd556, 159 0x74100758, 160 0x96e3cb26, 161 0x56c37c3f, 162 0xe00b3f7d, 163 0x859f25d7, 164 0xc2ee614a, 165 0xe1d21cd7, 166 0x30aae6a4]; 167 for (var i = 0; i < kLength; i++) { 168 for (var j = 0; j < kLength; j++) { 169 var a = new jspb.arith.UInt64(loValues[i], hiValues[j]); 170 var b = new jspb.arith.UInt64(loValues[j], hiValues[i]); 171 var c = a.add(b).sub(b); 172 expect(c.hi).toEqual(a.hi); 173 expect(c.lo).toEqual(a.lo); 174 } 175 } 176 }); 177 178 179 /** 180 * Tests 32-by-32 multiplication. 181 */ 182 it('testMul32x32', function() { 183 var testData = [ 184 // a b low(a*b) high(a*b) 185 [0xc0abe2f8, 0x1607898a, 0x5de711b0, 0x109471b8], 186 [0x915eb3cb, 0x4fb66d0e, 0xbd0d441a, 0x2d43d0bc], 187 [0xfe4efe70, 0x80b48c37, 0xbcddea10, 0x7fdada0c], 188 [0xe222fd4a, 0xe43d524a, 0xd5e0eb64, 0xc99d549c], 189 [0xd171f469, 0xb94ebd01, 0x4be17969, 0x979bc4fa], 190 [0x829cc1df, 0xe2598b38, 0xf4157dc8, 0x737c12ad], 191 [0xf10c3767, 0x8382881e, 0x942b3612, 0x7bd428b8], 192 [0xb0f6dd24, 0x232597e1, 0x079c98a4, 0x184bbce7], 193 [0xfcdb05a7, 0x902f55bc, 0x636199a4, 0x8e69f412], 194 [0x0dd0bfa9, 0x916e27b1, 0x6e2542d9, 0x07d92e65] 195 ]; 196 197 for (var i = 0; i < testData.length; i++) { 198 var a = testData[i][0] >>> 0; 199 var b = testData[i][1] >>> 0; 200 var cLow = testData[i][2] >>> 0; 201 var cHigh = testData[i][3] >>> 0; 202 var c = jspb.arith.UInt64.mul32x32(a, b); 203 expect(c.lo).toEqual(cLow); 204 expect(c.hi).toEqual(cHigh); 205 } 206 }); 207 208 209 /** 210 * Tests 64-by-32 multiplication. 211 */ 212 it('testMul', function() { 213 // 64x32 bits produces 96 bits of product. The multiplication function under 214 // test truncates the top 32 bits, so we compare against a 64-bit expected 215 // product. 216 var testData = [ 217 // low(a) high(a) low(a*b) high(a*b) 218 [0xec10955b, 0x360eb168, 0x4b7f3f5b, 0xbfcb7c59, 0x9517da5f], 219 [0x42b000fc, 0x9d101642, 0x6fa1ab72, 0x2584c438, 0x6a9e6d2b], 220 [0xf42d4fb4, 0xae366403, 0xa65a1000, 0x92434000, 0x1ff978df], 221 [0x17e2f56b, 0x25487693, 0xf13f98c7, 0x73794e2d, 0xa96b0c6a], 222 [0x492f241f, 0x76c0eb67, 0x7377ac44, 0xd4336c3c, 0xfc4b1ebe], 223 [0xd6b92321, 0xe184fa48, 0xd6e76904, 0x93141584, 0xcbf44da1], 224 [0x4bf007ea, 0x968c0a9e, 0xf5e4026a, 0x4fdb1ae4, 0x61b9fb7d], 225 [0x10a83be7, 0x2d685ba6, 0xc9e5fb7f, 0x2ad43499, 0x3742473d], 226 [0x2f261829, 0x1aca681a, 0x3d3494e3, 0x8213205b, 0x283719f8], 227 [0xe4f2ce21, 0x2e74b7bd, 0xd801b38b, 0xbc17feeb, 0xc6c44e0f] 228 ]; 229 230 for (var i = 0; i < testData.length; i++) { 231 var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]); 232 var prod = a.mul(testData[i][2]); 233 expect(prod.lo).toEqual(testData[i][3]); 234 expect(prod.hi).toEqual(testData[i][4]); 235 } 236 }); 237 238 239 /** 240 * Tests 64-div-by-32 division. 241 */ 242 it('testDiv', function() { 243 // Compute a/b, yielding quot = a/b and rem = a%b. 244 var testData = [ 245 // --- divisors in (0, 2^32-1) to test full divisor range 246 // low(a) high(a) b low(quot) high(quot) rem 247 [0x712443f1, 0xe85cefcc, 0xc1a7050b, 0x332c79ad, 0x00000001, 0x92ffa882], 248 [0x11912915, 0xb2699eb5, 0x30467cbe, 0xb21b4be4, 0x00000003, 0x283465dd], 249 [0x0d917982, 0x201f2a6e, 0x3f35bf03, 0x8217c8e4, 0x00000000, 0x153402d6], 250 [0xa072c108, 0x74020c96, 0xc60568fd, 0x95f9613e, 0x00000000, 0x3f4676c2], 251 [0xd845d5d8, 0xcdd235c4, 0x20426475, 0x6154e78b, 0x00000006, 0x202fb751], 252 [0xa4dbf71f, 0x9e90465e, 0xf08e022f, 0xa8be947f, 0x00000000, 0xbe43b5ce], 253 [0x3dbe627f, 0xa791f4b9, 0x28a5bd89, 0x1f5dfe93, 0x00000004, 0x02bf9ed4], 254 [0x5c1c53ee, 0xccf5102e, 0x198576e7, 0x07e3ae31, 0x00000008, 0x02ea8fb7], 255 [0xfef1e581, 0x04714067, 0xca6540c1, 0x059e73ec, 0x00000000, 0x31658095], 256 [0x1e2dd90c, 0x13dd6667, 0x8b2184c3, 0x248d1a42, 0x00000000, 0x4ca6d0c6], 257 // --- divisors in (0, 2^16-1) to test larger quotient high-words 258 // low(a) high(a) b low(quot) high(quot) rem 259 [0x86722b47, 0x2cd57c9a, 0x00003123, 0x2ae41b7a, 0x0000e995, 0x00000f99], 260 [0x1dd7884c, 0xf5e839bc, 0x00009eeb, 0x5c886242, 0x00018c21, 0x000099b6], 261 [0x5c53d625, 0x899fc7e5, 0x000087d7, 0xd625007a, 0x0001035c, 0x000019af], 262 [0x6932d932, 0x9d0a5488, 0x000051fb, 0x9d976143, 0x0001ea63, 0x00004981], 263 [0x4d18bb85, 0x0c92fb31, 0x00001d9f, 0x03265ab4, 0x00006cac, 0x000001b9], 264 [0xbe756768, 0xdea67ccb, 0x00008a03, 0x58add442, 0x00019cff, 0x000056a2], 265 [0xe2466f9a, 0x2521f114, 0x0000c350, 0xa0c0860d, 0x000030ab, 0x0000a48a], 266 [0xf00ddad1, 0xe2f5446a, 0x00002cfc, 0x762697a6, 0x00050b96, 0x00000b69], 267 [0xa879152a, 0x0a70e0a5, 0x00007cdf, 0xb44151b3, 0x00001567, 0x0000363d], 268 [0x7179a74c, 0x46083fff, 0x0000253c, 0x4d39ba6e, 0x0001e17f, 0x00000f84] 269 ]; 270 271 for (var i = 0; i < testData.length; i++) { 272 var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]); 273 var result = a.div(testData[i][2]); 274 var quotient = result[0]; 275 var remainder = result[1]; 276 expect(quotient.lo).toEqual(testData[i][3]); 277 expect(quotient.hi).toEqual(testData[i][4]); 278 expect(remainder.lo).toEqual(testData[i][5]); 279 } 280 }); 281 282 283 /** 284 * Tests .toString() and .fromString(). 285 */ 286 it('testStrings', function() { 287 var testData = [ 288 [0x5e84c935, 0xcae33d0e, '14619595947299359029'], 289 [0x62b3b8b8, 0x93480544, '10612738313170434232'], 290 [0x319bfb13, 0xc01c4172, '13843011313344445203'], 291 [0x5b8a65fb, 0xa5885b31, '11927883880638080507'], 292 [0x6bdb80f1, 0xb0d1b16b, '12741159895737008369'], 293 [0x4b82b442, 0x2e0d8c97, '3318463081876730946'], 294 [0x780d5208, 0x7d76752c, '9040542135845999112'], 295 [0x2e46800f, 0x0993778d, '690026616168284175'], 296 [0xf00a7e32, 0xcd8e3931, '14811839111111540274'], 297 [0x1baeccd6, 0x923048c4, '10533999535534820566'], 298 [0x03669d29, 0xbff3ab72, '13831587386756603177'], 299 [0x2526073e, 0x01affc81, '121593346566522686'], 300 [0xc24244e0, 0xd7f40d0e, '15561076969511732448'], 301 [0xc56a341e, 0xa68b66a7, '12000798502816461854'], 302 [0x8738d64d, 0xbfe78604, '13828168534871037517'], 303 [0x5baff03b, 0xd7572aea, '15516918227177304123'], 304 [0x4a843d8a, 0x864e132b, '9677693725920476554'], 305 [0x25b4e94d, 0x22b54dc6, '2500990681505655117'], 306 [0x6bbe664b, 0x55a5cc0e, '6171563226690381387'], 307 [0xee916c81, 0xb00aabb3, '12685140089732426881'] 308 ]; 309 310 for (var i = 0; i < testData.length; i++) { 311 var a = new jspb.arith.UInt64(testData[i][0], testData[i][1]); 312 var roundtrip = jspb.arith.UInt64.fromString(a.toString()); 313 expect(roundtrip.lo).toEqual(a.lo); 314 expect(roundtrip.hi).toEqual(a.hi); 315 expect(a.toString()).toEqual(testData[i][2]); 316 } 317 }); 318 319 320 /** 321 * Tests signed Int64s. These are built on UInt64s, so we only need to test 322 * the explicit overrides: .toString() and .fromString(). 323 */ 324 it('testSignedInt64', function() { 325 var testStrings = [ 326 '-7847499644178593666', 327 '3771946501229139523', 328 '2872856549054995060', 329 '-5780049594274350904', 330 '3383785956695105201', 331 '2973055184857072610', 332 '-3879428459215627206', 333 '4589812431064156631', 334 '8484075557333689940', 335 '1075325817098092407', 336 '-4346697501012292314', 337 '2488620459718316637', 338 '6112655187423520672', 339 '-3655278273928612104', 340 '3439154019435803196', 341 '1004112478843763757', 342 '-6587790776614368413', 343 '664320065099714586', 344 '4760412909973292912', 345 '-7911903989602274672' 346 ]; 347 348 for (var i = 0; i < testStrings.length; i++) { 349 var roundtrip = 350 jspb.arith.Int64.fromString(testStrings[i]).toString(); 351 expect(roundtrip).toEqual(testStrings[i]); 352 } 353 }); 354}); 355