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 jspb's binary protocol buffer reader. 33 * 34 * There are two particular magic numbers that need to be pointed out - 35 * 2^64-1025 is the largest number representable as both a double and an 36 * unsigned 64-bit integer, and 2^63-513 is the largest number representable as 37 * both a double and a signed 64-bit integer. 38 * 39 * Test suite is written using Jasmine -- see http://jasmine.github.io/ 40 * 41 * @author aappleby@google.com (Austin Appleby) 42 */ 43 44goog.require('goog.testing.asserts'); 45goog.require('jspb.BinaryConstants'); 46goog.require('jspb.BinaryDecoder'); 47goog.require('jspb.BinaryReader'); 48goog.require('jspb.BinaryWriter'); 49goog.require('jspb.utils'); 50goog.requireType('jspb.BinaryMessage'); 51 52 53describe('binaryReaderTest', function() { 54 /** 55 * Tests the reader instance cache. 56 */ 57 it('testInstanceCaches', /** @suppress {visibility} */ function() { 58 var writer = new jspb.BinaryWriter(); 59 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 60 writer.writeMessage(1, dummyMessage, goog.nullFunction); 61 writer.writeMessage(2, dummyMessage, goog.nullFunction); 62 63 var buffer = writer.getResultBuffer(); 64 65 // Empty the instance caches. 66 jspb.BinaryReader.instanceCache_ = []; 67 68 // Allocating and then freeing three decoders should leave us with three in 69 // the cache. 70 71 var decoder1 = jspb.BinaryDecoder.alloc(); 72 var decoder2 = jspb.BinaryDecoder.alloc(); 73 var decoder3 = jspb.BinaryDecoder.alloc(); 74 decoder1.free(); 75 decoder2.free(); 76 decoder3.free(); 77 78 assertEquals(3, jspb.BinaryDecoder.instanceCache_.length); 79 assertEquals(0, jspb.BinaryReader.instanceCache_.length); 80 81 // Allocating and then freeing a reader should remove one decoder from its 82 // cache, but it should stay stuck to the reader afterwards since we can't 83 // have a reader without a decoder. 84 jspb.BinaryReader.alloc().free(); 85 86 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length); 87 assertEquals(1, jspb.BinaryReader.instanceCache_.length); 88 89 // Allocating a reader should remove a reader from the cache. 90 var reader = jspb.BinaryReader.alloc(buffer); 91 92 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length); 93 assertEquals(0, jspb.BinaryReader.instanceCache_.length); 94 95 // Processing the message reuses the current reader. 96 reader.nextField(); 97 assertEquals(1, reader.getFieldNumber()); 98 reader.readMessage(dummyMessage, function() { 99 assertEquals(0, jspb.BinaryReader.instanceCache_.length); 100 }); 101 102 reader.nextField(); 103 assertEquals(2, reader.getFieldNumber()); 104 reader.readMessage(dummyMessage, function() { 105 assertEquals(0, jspb.BinaryReader.instanceCache_.length); 106 }); 107 108 assertEquals(false, reader.nextField()); 109 110 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length); 111 assertEquals(0, jspb.BinaryReader.instanceCache_.length); 112 113 // Freeing the reader should put it back into the cache. 114 reader.free(); 115 116 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length); 117 assertEquals(1, jspb.BinaryReader.instanceCache_.length); 118 }); 119 120 121 /** 122 * @param {number} x 123 * @return {number} 124 */ 125 function truncate(x) { 126 var temp = new Float32Array(1); 127 temp[0] = x; 128 return temp[0]; 129 } 130 131 132 /** 133 * Verifies that misuse of the reader class triggers assertions. 134 */ 135 it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() { 136 // Calling readMessage on a non-delimited field should trigger an 137 // assertion. 138 var reader = jspb.BinaryReader.alloc([8, 1]); 139 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 140 reader.nextField(); 141 assertThrows(function() { 142 reader.readMessage(dummyMessage, goog.nullFunction); 143 }); 144 145 // Reading past the end of the stream should trigger an assertion. 146 reader = jspb.BinaryReader.alloc([9, 1]); 147 reader.nextField(); 148 assertThrows(function() { 149 reader.readFixed64() 150 }); 151 152 // Reading past the end of a submessage should trigger an assertion. 153 reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]); 154 reader.nextField(); 155 reader.readMessage(dummyMessage, function() { 156 reader.nextField(); 157 assertThrows(function() { 158 reader.readFixed32() 159 }); 160 }); 161 162 // Skipping an invalid field should trigger an assertion. 163 reader = jspb.BinaryReader.alloc([12, 1]); 164 reader.nextWireType_ = 1000; 165 assertThrows(function() { 166 reader.skipField() 167 }); 168 169 // Reading fields with the wrong wire type should assert. 170 reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]); 171 reader.nextField(); 172 assertThrows(function() { 173 reader.readInt32() 174 }); 175 assertThrows(function() { 176 reader.readInt32String() 177 }); 178 assertThrows(function() { 179 reader.readInt64() 180 }); 181 assertThrows(function() { 182 reader.readInt64String() 183 }); 184 assertThrows(function() { 185 reader.readUint32() 186 }); 187 assertThrows(function() { 188 reader.readUint32String() 189 }); 190 assertThrows(function() { 191 reader.readUint64() 192 }); 193 assertThrows(function() { 194 reader.readUint64String() 195 }); 196 assertThrows(function() { 197 reader.readSint32() 198 }); 199 assertThrows(function() { 200 reader.readBool() 201 }); 202 assertThrows(function() { 203 reader.readEnum() 204 }); 205 206 reader = jspb.BinaryReader.alloc([8, 1]); 207 reader.nextField(); 208 assertThrows(function() { 209 reader.readFixed32() 210 }); 211 assertThrows(function() { 212 reader.readFixed64() 213 }); 214 assertThrows(function() { 215 reader.readSfixed32() 216 }); 217 assertThrows(function() { 218 reader.readSfixed64() 219 }); 220 assertThrows(function() { 221 reader.readFloat() 222 }); 223 assertThrows(function() { 224 reader.readDouble() 225 }); 226 227 assertThrows(function() { 228 reader.readString() 229 }); 230 assertThrows(function() { 231 reader.readBytes() 232 }); 233 }); 234 235 236 /** 237 * Tests encoding and decoding of unsigned field types. 238 * @param {Function} readField 239 * @param {Function} writeField 240 * @param {number} epsilon 241 * @param {number} upperLimit 242 * @param {Function} filter 243 * @private 244 * @suppress {missingProperties} 245 */ 246 var doTestUnsignedField_ = function( 247 readField, writeField, epsilon, upperLimit, filter) { 248 assertNotNull(readField); 249 assertNotNull(writeField); 250 251 var writer = new jspb.BinaryWriter(); 252 253 // Encode zero and limits. 254 writeField.call(writer, 1, filter(0)); 255 writeField.call(writer, 2, filter(epsilon)); 256 writeField.call(writer, 3, filter(upperLimit)); 257 258 // Encode positive values. 259 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 260 writeField.call(writer, 4, filter(cursor)); 261 } 262 263 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 264 265 // Check zero and limits. 266 reader.nextField(); 267 assertEquals(1, reader.getFieldNumber()); 268 assertEquals(filter(0), readField.call(reader)); 269 270 reader.nextField(); 271 assertEquals(2, reader.getFieldNumber()); 272 assertEquals(filter(epsilon), readField.call(reader)); 273 274 reader.nextField(); 275 assertEquals(3, reader.getFieldNumber()); 276 assertEquals(filter(upperLimit), readField.call(reader)); 277 278 // Check positive values. 279 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 280 reader.nextField(); 281 if (4 != reader.getFieldNumber()) throw 'fail!'; 282 if (filter(cursor) != readField.call(reader)) throw 'fail!'; 283 } 284 }; 285 286 287 /** 288 * Tests encoding and decoding of signed field types. 289 * @param {Function} readField 290 * @param {Function} writeField 291 * @param {number} epsilon 292 * @param {number} lowerLimit 293 * @param {number} upperLimit 294 * @param {Function} filter 295 * @private 296 * @suppress {missingProperties} 297 */ 298 var doTestSignedField_ = function( 299 readField, writeField, epsilon, lowerLimit, upperLimit, filter) { 300 var writer = new jspb.BinaryWriter(); 301 302 // Encode zero and limits. 303 writeField.call(writer, 1, filter(lowerLimit)); 304 writeField.call(writer, 2, filter(-epsilon)); 305 writeField.call(writer, 3, filter(0)); 306 writeField.call(writer, 4, filter(epsilon)); 307 writeField.call(writer, 5, filter(upperLimit)); 308 309 var inputValues = []; 310 311 // Encode negative values. 312 for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) { 313 var val = filter(cursor); 314 writeField.call(writer, 6, val); 315 inputValues.push({fieldNumber: 6, value: val}); 316 } 317 318 // Encode positive values. 319 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 320 var val = filter(cursor); 321 writeField.call(writer, 7, val); 322 inputValues.push({fieldNumber: 7, value: val}); 323 } 324 325 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 326 327 // Check zero and limits. 328 reader.nextField(); 329 assertEquals(1, reader.getFieldNumber()); 330 assertEquals(filter(lowerLimit), readField.call(reader)); 331 332 reader.nextField(); 333 assertEquals(2, reader.getFieldNumber()); 334 assertEquals(filter(-epsilon), readField.call(reader)); 335 336 reader.nextField(); 337 assertEquals(3, reader.getFieldNumber()); 338 assertEquals(filter(0), readField.call(reader)); 339 340 reader.nextField(); 341 assertEquals(4, reader.getFieldNumber()); 342 assertEquals(filter(epsilon), readField.call(reader)); 343 344 reader.nextField(); 345 assertEquals(5, reader.getFieldNumber()); 346 assertEquals(filter(upperLimit), readField.call(reader)); 347 348 for (var i = 0; i < inputValues.length; i++) { 349 var expected = inputValues[i]; 350 reader.nextField(); 351 assertEquals(expected.fieldNumber, reader.getFieldNumber()); 352 assertEquals(expected.value, readField.call(reader)); 353 } 354 }; 355 356 357 /** 358 * Tests fields that use varint encoding. 359 */ 360 it('testVarintFields', function() { 361 assertNotUndefined(jspb.BinaryReader.prototype.readUint32); 362 assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32); 363 assertNotUndefined(jspb.BinaryReader.prototype.readUint64); 364 assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64); 365 assertNotUndefined(jspb.BinaryReader.prototype.readBool); 366 assertNotUndefined(jspb.BinaryWriter.prototype.writeBool); 367 doTestUnsignedField_( 368 jspb.BinaryReader.prototype.readUint32, 369 jspb.BinaryWriter.prototype.writeUint32, 1, Math.pow(2, 32) - 1, 370 Math.round); 371 372 doTestUnsignedField_( 373 jspb.BinaryReader.prototype.readUint64, 374 jspb.BinaryWriter.prototype.writeUint64, 1, Math.pow(2, 64) - 1025, 375 Math.round); 376 377 doTestSignedField_( 378 jspb.BinaryReader.prototype.readInt32, 379 jspb.BinaryWriter.prototype.writeInt32, 1, -Math.pow(2, 31), 380 Math.pow(2, 31) - 1, Math.round); 381 382 doTestSignedField_( 383 jspb.BinaryReader.prototype.readInt64, 384 jspb.BinaryWriter.prototype.writeInt64, 1, -Math.pow(2, 63), 385 Math.pow(2, 63) - 513, Math.round); 386 387 doTestSignedField_( 388 jspb.BinaryReader.prototype.readEnum, 389 jspb.BinaryWriter.prototype.writeEnum, 1, -Math.pow(2, 31), 390 Math.pow(2, 31) - 1, Math.round); 391 392 doTestUnsignedField_( 393 jspb.BinaryReader.prototype.readBool, 394 jspb.BinaryWriter.prototype.writeBool, 1, 1, function(x) { 395 return !!x; 396 }); 397 }); 398 399 400 /** 401 * Tests reading a field from hexadecimal string (format: '08 BE EF'). 402 * @param {Function} readField 403 * @param {number} expected 404 * @param {string} hexString 405 */ 406 function doTestHexStringVarint_(readField, expected, hexString) { 407 var bytesCount = (hexString.length + 1) / 3; 408 var bytes = new Uint8Array(bytesCount); 409 for (var i = 0; i < bytesCount; i++) { 410 bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16); 411 } 412 var reader = jspb.BinaryReader.alloc(bytes); 413 reader.nextField(); 414 assertEquals(expected, readField.call(reader)); 415 } 416 417 418 /** 419 * Tests non-canonical redundant varint decoding. 420 */ 421 it('testRedundantVarintFields', function() { 422 assertNotNull(jspb.BinaryReader.prototype.readUint32); 423 assertNotNull(jspb.BinaryReader.prototype.readUint64); 424 assertNotNull(jspb.BinaryReader.prototype.readSint32); 425 assertNotNull(jspb.BinaryReader.prototype.readSint64); 426 427 // uint32 and sint32 take no more than 5 bytes 428 // 08 - field prefix (type = 0 means varint) 429 doTestHexStringVarint_( 430 jspb.BinaryReader.prototype.readUint32, 12, '08 8C 80 80 80 00'); 431 432 // 11 stands for -6 in zigzag encoding 433 doTestHexStringVarint_( 434 jspb.BinaryReader.prototype.readSint32, -6, '08 8B 80 80 80 00'); 435 436 // uint64 and sint64 take no more than 10 bytes 437 // 08 - field prefix (type = 0 means varint) 438 doTestHexStringVarint_( 439 jspb.BinaryReader.prototype.readUint64, 12, 440 '08 8C 80 80 80 80 80 80 80 80 00'); 441 442 // 11 stands for -6 in zigzag encoding 443 doTestHexStringVarint_( 444 jspb.BinaryReader.prototype.readSint64, -6, 445 '08 8B 80 80 80 80 80 80 80 80 00'); 446 }); 447 448 /** 449 * Tests reading 64-bit integers as split values. 450 */ 451 it('handles split 64 fields', function() { 452 var writer = new jspb.BinaryWriter(); 453 writer.writeInt64String(1, '4294967296'); 454 writer.writeSfixed64String(2, '4294967298'); 455 writer.writeInt64String(3, '3'); // 3 is the zig-zag encoding of -2. 456 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 457 458 function rejoin(lowBits, highBits) { 459 return highBits * 2 ** 32 + (lowBits >>> 0); 460 } 461 reader.nextField(); 462 expect(reader.getFieldNumber()).toEqual(1); 463 expect(reader.readSplitVarint64(rejoin)).toEqual(0x100000000); 464 465 reader.nextField(); 466 expect(reader.getFieldNumber()).toEqual(2); 467 expect(reader.readSplitFixed64(rejoin)).toEqual(0x100000002); 468 469 reader.nextField(); 470 expect(reader.getFieldNumber()).toEqual(3); 471 expect(reader.readSplitZigzagVarint64(rejoin)).toEqual(-2); 472 }); 473 474 /** 475 * Tests 64-bit fields that are handled as strings. 476 */ 477 it('testStringInt64Fields', function() { 478 var writer = new jspb.BinaryWriter(); 479 480 var testSignedData = [ 481 '2730538252207801776', '-2688470994844604560', '3398529779486536359', 482 '3568577411627971000', '272477188847484900', '-6649058714086158188', 483 '-7695254765712060806', '-4525541438037104029', '-4993706538836508568', 484 '4990160321893729138' 485 ]; 486 var testUnsignedData = [ 487 '7822732630241694882', '6753602971916687352', '2399935075244442116', 488 '8724292567325338867', '16948784802625696584', '4136275908516066934', 489 '3575388346793700364', '5167142028379259461', '1557573948689737699', 490 '17100725280812548567' 491 ]; 492 493 for (var i = 0; i < testSignedData.length; i++) { 494 writer.writeInt64String(2 * i + 1, testSignedData[i]); 495 writer.writeUint64String(2 * i + 2, testUnsignedData[i]); 496 } 497 498 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 499 500 for (var i = 0; i < testSignedData.length; i++) { 501 reader.nextField(); 502 assertEquals(2 * i + 1, reader.getFieldNumber()); 503 assertEquals(testSignedData[i], reader.readInt64String()); 504 reader.nextField(); 505 assertEquals(2 * i + 2, reader.getFieldNumber()); 506 assertEquals(testUnsignedData[i], reader.readUint64String()); 507 } 508 }); 509 510 511 /** 512 * Tests fields that use zigzag encoding. 513 */ 514 it('testZigzagFields', function() { 515 doTestSignedField_( 516 jspb.BinaryReader.prototype.readSint32, 517 jspb.BinaryWriter.prototype.writeSint32, 1, -Math.pow(2, 31), 518 Math.pow(2, 31) - 1, Math.round); 519 520 doTestSignedField_( 521 jspb.BinaryReader.prototype.readSint64, 522 jspb.BinaryWriter.prototype.writeSint64, 1, -Math.pow(2, 63), 523 Math.pow(2, 63) - 513, Math.round); 524 525 doTestSignedField_( 526 jspb.BinaryReader.prototype.readSintHash64, 527 jspb.BinaryWriter.prototype.writeSintHash64, 1, -Math.pow(2, 63), 528 Math.pow(2, 63) - 513, jspb.utils.numberToHash64); 529 }); 530 531 532 /** 533 * Tests fields that use fixed-length encoding. 534 */ 535 it('testFixedFields', function() { 536 doTestUnsignedField_( 537 jspb.BinaryReader.prototype.readFixed32, 538 jspb.BinaryWriter.prototype.writeFixed32, 1, Math.pow(2, 32) - 1, 539 Math.round); 540 541 doTestUnsignedField_( 542 jspb.BinaryReader.prototype.readFixed64, 543 jspb.BinaryWriter.prototype.writeFixed64, 1, Math.pow(2, 64) - 1025, 544 Math.round); 545 546 doTestSignedField_( 547 jspb.BinaryReader.prototype.readSfixed32, 548 jspb.BinaryWriter.prototype.writeSfixed32, 1, -Math.pow(2, 31), 549 Math.pow(2, 31) - 1, Math.round); 550 551 doTestSignedField_( 552 jspb.BinaryReader.prototype.readSfixed64, 553 jspb.BinaryWriter.prototype.writeSfixed64, 1, -Math.pow(2, 63), 554 Math.pow(2, 63) - 513, Math.round); 555 }); 556 557 558 /** 559 * Tests floating point fields. 560 */ 561 it('testFloatFields', function() { 562 doTestSignedField_( 563 jspb.BinaryReader.prototype.readFloat, 564 jspb.BinaryWriter.prototype.writeFloat, 565 jspb.BinaryConstants.FLOAT32_MIN, -jspb.BinaryConstants.FLOAT32_MAX, 566 jspb.BinaryConstants.FLOAT32_MAX, truncate); 567 568 doTestSignedField_( 569 jspb.BinaryReader.prototype.readDouble, 570 jspb.BinaryWriter.prototype.writeDouble, 571 jspb.BinaryConstants.FLOAT64_EPS * 10, 572 -jspb.BinaryConstants.FLOAT64_MIN, jspb.BinaryConstants.FLOAT64_MIN, 573 function(x) { 574 return x; 575 }); 576 }); 577 578 579 /** 580 * Tests length-delimited string fields. 581 */ 582 it('testStringFields', function() { 583 var s1 = 'The quick brown fox jumps over the lazy dog.'; 584 var s2 = '人人生而自由,在尊嚴和權利上一律平等。'; 585 586 var writer = new jspb.BinaryWriter(); 587 588 writer.writeString(1, s1); 589 writer.writeString(2, s2); 590 591 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 592 593 reader.nextField(); 594 assertEquals(1, reader.getFieldNumber()); 595 assertEquals(s1, reader.readString()); 596 597 reader.nextField(); 598 assertEquals(2, reader.getFieldNumber()); 599 assertEquals(s2, reader.readString()); 600 }); 601 602 603 /** 604 * Tests length-delimited byte fields. 605 */ 606 it('testByteFields', function() { 607 var message = []; 608 var lowerLimit = 1; 609 var upperLimit = 256; 610 var scale = 1.1; 611 612 var writer = new jspb.BinaryWriter(); 613 614 for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) { 615 var len = Math.round(cursor); 616 var bytes = []; 617 for (var i = 0; i < len; i++) bytes.push(i % 256); 618 619 writer.writeBytes(len, bytes); 620 } 621 622 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 623 624 for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) { 625 var len = Math.round(cursor); 626 if (len != reader.getFieldNumber()) throw 'fail!'; 627 628 var bytes = reader.readBytes(); 629 if (len != bytes.length) throw 'fail!'; 630 for (var i = 0; i < bytes.length; i++) { 631 if (i % 256 != bytes[i]) throw 'fail!'; 632 } 633 } 634 }); 635 636 637 /** 638 * Tests nested messages. 639 */ 640 it('testNesting', function() { 641 var writer = new jspb.BinaryWriter(); 642 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 643 644 writer.writeInt32(1, 100); 645 646 // Add one message with 3 int fields. 647 writer.writeMessage(2, dummyMessage, function() { 648 writer.writeInt32(3, 300); 649 writer.writeInt32(4, 400); 650 writer.writeInt32(5, 500); 651 }); 652 653 // Add one empty message. 654 writer.writeMessage(6, dummyMessage, goog.nullFunction); 655 656 writer.writeInt32(7, 700); 657 658 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 659 660 // Validate outermost message. 661 662 reader.nextField(); 663 assertEquals(1, reader.getFieldNumber()); 664 assertEquals(100, reader.readInt32()); 665 666 reader.nextField(); 667 assertEquals(2, reader.getFieldNumber()); 668 reader.readMessage(dummyMessage, function() { 669 // Validate embedded message 1. 670 reader.nextField(); 671 assertEquals(3, reader.getFieldNumber()); 672 assertEquals(300, reader.readInt32()); 673 674 reader.nextField(); 675 assertEquals(4, reader.getFieldNumber()); 676 assertEquals(400, reader.readInt32()); 677 678 reader.nextField(); 679 assertEquals(5, reader.getFieldNumber()); 680 assertEquals(500, reader.readInt32()); 681 682 assertEquals(false, reader.nextField()); 683 }); 684 685 reader.nextField(); 686 assertEquals(6, reader.getFieldNumber()); 687 reader.readMessage(dummyMessage, function() { 688 // Validate embedded message 2. 689 690 assertEquals(false, reader.nextField()); 691 }); 692 693 reader.nextField(); 694 assertEquals(7, reader.getFieldNumber()); 695 assertEquals(700, reader.readInt32()); 696 697 assertEquals(false, reader.nextField()); 698 }); 699 700 /** 701 * Tests skipping fields of each type by interleaving them with sentinel 702 * values and skipping everything that's not a sentinel. 703 */ 704 it('testSkipField', function() { 705 var writer = new jspb.BinaryWriter(); 706 707 var sentinel = 123456789; 708 709 // Write varint fields of different sizes. 710 writer.writeInt32(1, sentinel); 711 writer.writeInt32(1, 1); 712 writer.writeInt32(1, 1000); 713 writer.writeInt32(1, 1000000); 714 writer.writeInt32(1, 1000000000); 715 716 // Write fixed 64-bit encoded fields. 717 writer.writeInt32(2, sentinel); 718 writer.writeDouble(2, 1); 719 writer.writeFixed64(2, 1); 720 writer.writeSfixed64(2, 1); 721 722 // Write fixed 32-bit encoded fields. 723 writer.writeInt32(3, sentinel); 724 writer.writeFloat(3, 1); 725 writer.writeFixed32(3, 1); 726 writer.writeSfixed32(3, 1); 727 728 // Write delimited fields. 729 writer.writeInt32(4, sentinel); 730 writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 731 writer.writeString(4, 'The quick brown fox jumps over the lazy dog'); 732 733 // Write a group with a nested group inside. 734 writer.writeInt32(5, sentinel); 735 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 736 writer.writeGroup(5, dummyMessage, function() { 737 // Previously the skipGroup implementation was wrong, which only consume 738 // the decoder by nextField. This case is for making the previous 739 // implementation failed in skipGroup by an early end group tag. 740 // The reason is 44 = 5 * 8 + 4, this will be translated in to a field 741 // with number 5 and with type 4 (end group) 742 writer.writeInt64(44, 44); 743 // This will make previous implementation failed by invalid tag (7). 744 writer.writeInt64(42, 47); 745 writer.writeInt64(42, 42); 746 // This is for making the previous implementation failed by an invalid 747 // varint. The bytes have at least 9 consecutive minus byte, which will 748 // fail in this.nextField for previous implementation. 749 writer.writeBytes(43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]); 750 writer.writeGroup(6, dummyMessage, function() { 751 writer.writeInt64(84, 42); 752 writer.writeInt64(84, 44); 753 writer.writeBytes( 754 43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]); 755 }); 756 }); 757 758 // Write final sentinel. 759 writer.writeInt32(6, sentinel); 760 761 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 762 763 function skip(field, count) { 764 for (var i = 0; i < count; i++) { 765 reader.nextField(); 766 if (field != reader.getFieldNumber()) throw 'fail!'; 767 reader.skipField(); 768 } 769 } 770 771 reader.nextField(); 772 assertEquals(1, reader.getFieldNumber()); 773 assertEquals(sentinel, reader.readInt32()); 774 skip(1, 4); 775 776 reader.nextField(); 777 assertEquals(2, reader.getFieldNumber()); 778 assertEquals(sentinel, reader.readInt32()); 779 skip(2, 3); 780 781 reader.nextField(); 782 assertEquals(3, reader.getFieldNumber()); 783 assertEquals(sentinel, reader.readInt32()); 784 skip(3, 3); 785 786 reader.nextField(); 787 assertEquals(4, reader.getFieldNumber()); 788 assertEquals(sentinel, reader.readInt32()); 789 skip(4, 2); 790 791 reader.nextField(); 792 assertEquals(5, reader.getFieldNumber()); 793 assertEquals(sentinel, reader.readInt32()); 794 skip(5, 1); 795 796 reader.nextField(); 797 assertEquals(6, reader.getFieldNumber()); 798 assertEquals(sentinel, reader.readInt32()); 799 }); 800 801 802 /** 803 * Tests packed fields. 804 */ 805 it('testPackedFields', function() { 806 var writer = new jspb.BinaryWriter(); 807 808 var sentinel = 123456789; 809 810 var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 811 var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]; 812 var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10]; 813 var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10]; 814 var boolData = [true, false, true, true, false, false, true, false]; 815 816 for (var i = 0; i < floatData.length; i++) { 817 floatData[i] = truncate(floatData[i]); 818 } 819 820 writer.writeInt32(1, sentinel); 821 822 writer.writePackedInt32(2, signedData); 823 writer.writePackedInt64(2, signedData); 824 writer.writePackedUint32(2, unsignedData); 825 writer.writePackedUint64(2, unsignedData); 826 writer.writePackedSint32(2, signedData); 827 writer.writePackedSint64(2, signedData); 828 writer.writePackedFixed32(2, unsignedData); 829 writer.writePackedFixed64(2, unsignedData); 830 writer.writePackedSfixed32(2, signedData); 831 writer.writePackedSfixed64(2, signedData); 832 writer.writePackedFloat(2, floatData); 833 writer.writePackedDouble(2, doubleData); 834 writer.writePackedBool(2, boolData); 835 writer.writePackedEnum(2, unsignedData); 836 837 writer.writeInt32(3, sentinel); 838 839 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 840 841 reader.nextField(); 842 assertEquals(sentinel, reader.readInt32()); 843 844 reader.nextField(); 845 assertElementsEquals(reader.readPackedInt32(), signedData); 846 847 reader.nextField(); 848 assertElementsEquals(reader.readPackedInt64(), signedData); 849 850 reader.nextField(); 851 assertElementsEquals(reader.readPackedUint32(), unsignedData); 852 853 reader.nextField(); 854 assertElementsEquals(reader.readPackedUint64(), unsignedData); 855 856 reader.nextField(); 857 assertElementsEquals(reader.readPackedSint32(), signedData); 858 859 reader.nextField(); 860 assertElementsEquals(reader.readPackedSint64(), signedData); 861 862 reader.nextField(); 863 assertElementsEquals(reader.readPackedFixed32(), unsignedData); 864 865 reader.nextField(); 866 assertElementsEquals(reader.readPackedFixed64(), unsignedData); 867 868 reader.nextField(); 869 assertElementsEquals(reader.readPackedSfixed32(), signedData); 870 871 reader.nextField(); 872 assertElementsEquals(reader.readPackedSfixed64(), signedData); 873 874 reader.nextField(); 875 assertElementsEquals(reader.readPackedFloat(), floatData); 876 877 reader.nextField(); 878 assertElementsEquals(reader.readPackedDouble(), doubleData); 879 880 reader.nextField(); 881 assertElementsEquals(reader.readPackedBool(), boolData); 882 883 reader.nextField(); 884 assertElementsEquals(reader.readPackedEnum(), unsignedData); 885 886 reader.nextField(); 887 assertEquals(sentinel, reader.readInt32()); 888 }); 889 890 891 /** 892 * Byte blobs inside nested messages should always have their byte offset set 893 * relative to the start of the outermost blob, not the start of their parent 894 * blob. 895 */ 896 it('testNestedBlobs', function() { 897 // Create a proto consisting of two nested messages, with the inner one 898 // containing a blob of bytes. 899 900 var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED; 901 var blob = [1, 2, 3, 4, 5]; 902 var writer = new jspb.BinaryWriter(); 903 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 904 905 writer.writeMessage(1, dummyMessage, function() { 906 writer.writeMessage(1, dummyMessage, function() { 907 writer.writeBytes(1, blob); 908 }); 909 }); 910 911 // Peel off the outer two message layers. Each layer should have two bytes 912 // of overhead, one for the field tag and one for the length of the inner 913 // blob. 914 915 var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer()); 916 assertEquals(fieldTag, decoder1.readUnsignedVarint32()); 917 assertEquals(blob.length + 4, decoder1.readUnsignedVarint32()); 918 919 var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4)); 920 assertEquals(fieldTag, decoder2.readUnsignedVarint32()); 921 assertEquals(blob.length + 2, decoder2.readUnsignedVarint32()); 922 923 assertEquals(fieldTag, decoder2.readUnsignedVarint32()); 924 assertEquals(blob.length, decoder2.readUnsignedVarint32()); 925 var bytes = decoder2.readBytes(blob.length); 926 927 assertElementsEquals(bytes, blob); 928 }); 929 930 931 /** 932 * Tests read callbacks. 933 */ 934 it('testReadCallbacks', function() { 935 var writer = new jspb.BinaryWriter(); 936 var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); 937 938 // Add an int, a submessage, and another int. 939 writer.writeInt32(1, 100); 940 941 writer.writeMessage(2, dummyMessage, function() { 942 writer.writeInt32(3, 300); 943 writer.writeInt32(4, 400); 944 writer.writeInt32(5, 500); 945 }); 946 947 writer.writeInt32(7, 700); 948 949 // Create the reader and register a custom read callback. 950 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 951 952 /** 953 * @param {!jspb.BinaryReader} reader 954 * @return {*} 955 */ 956 function readCallback(reader) { 957 reader.nextField(); 958 assertEquals(3, reader.getFieldNumber()); 959 assertEquals(300, reader.readInt32()); 960 961 reader.nextField(); 962 assertEquals(4, reader.getFieldNumber()); 963 assertEquals(400, reader.readInt32()); 964 965 reader.nextField(); 966 assertEquals(5, reader.getFieldNumber()); 967 assertEquals(500, reader.readInt32()); 968 969 assertEquals(false, reader.nextField()); 970 }; 971 972 reader.registerReadCallback('readCallback', readCallback); 973 974 // Read the container message. 975 reader.nextField(); 976 assertEquals(1, reader.getFieldNumber()); 977 assertEquals(100, reader.readInt32()); 978 979 reader.nextField(); 980 assertEquals(2, reader.getFieldNumber()); 981 reader.readMessage(dummyMessage, function() { 982 // Decode the embedded message using the registered callback. 983 reader.runReadCallback('readCallback'); 984 }); 985 986 reader.nextField(); 987 assertEquals(7, reader.getFieldNumber()); 988 assertEquals(700, reader.readInt32()); 989 990 assertEquals(false, reader.nextField()); 991 }); 992}); 993