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'); 49 50 51 52describe('binaryReaderTest', function() { 53 /** 54 * Tests the reader instance cache. 55 * @suppress {visibility} 56 */ 57 it('testInstanceCaches', 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 * @suppress {checkTypes|visibility} 135 */ 136 it('testReadErrors', function() { 137 // Calling readMessage on a non-delimited field should trigger an 138 // assertion. 139 var reader = jspb.BinaryReader.alloc([8, 1]); 140 var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); 141 reader.nextField(); 142 assertThrows(function() { 143 reader.readMessage(dummyMessage, goog.nullFunction); 144 }); 145 146 // Reading past the end of the stream should trigger an assertion. 147 reader = jspb.BinaryReader.alloc([9, 1]); 148 reader.nextField(); 149 assertThrows(function() {reader.readFixed64()}); 150 151 // Reading past the end of a submessage should trigger an assertion. 152 reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]); 153 reader.nextField(); 154 reader.readMessage(dummyMessage, function() { 155 reader.nextField(); 156 assertThrows(function() {reader.readFixed32()}); 157 }); 158 159 // Skipping an invalid field should trigger an assertion. 160 reader = jspb.BinaryReader.alloc([12, 1]); 161 reader.nextWireType_ = 1000; 162 assertThrows(function() {reader.skipField()}); 163 164 // Reading fields with the wrong wire type should assert. 165 reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]); 166 reader.nextField(); 167 assertThrows(function() {reader.readInt32()}); 168 assertThrows(function() {reader.readInt32String()}); 169 assertThrows(function() {reader.readInt64()}); 170 assertThrows(function() {reader.readInt64String()}); 171 assertThrows(function() {reader.readUint32()}); 172 assertThrows(function() {reader.readUint32String()}); 173 assertThrows(function() {reader.readUint64()}); 174 assertThrows(function() {reader.readUint64String()}); 175 assertThrows(function() {reader.readSint32()}); 176 assertThrows(function() {reader.readBool()}); 177 assertThrows(function() {reader.readEnum()}); 178 179 reader = jspb.BinaryReader.alloc([8, 1]); 180 reader.nextField(); 181 assertThrows(function() {reader.readFixed32()}); 182 assertThrows(function() {reader.readFixed64()}); 183 assertThrows(function() {reader.readSfixed32()}); 184 assertThrows(function() {reader.readSfixed64()}); 185 assertThrows(function() {reader.readFloat()}); 186 assertThrows(function() {reader.readDouble()}); 187 188 assertThrows(function() {reader.readString()}); 189 assertThrows(function() {reader.readBytes()}); 190 }); 191 192 193 /** 194 * Tests encoding and decoding of unsigned field types. 195 * @param {Function} readField 196 * @param {Function} writeField 197 * @param {number} epsilon 198 * @param {number} upperLimit 199 * @param {Function} filter 200 * @private 201 * @suppress {missingProperties} 202 */ 203 function doTestUnsignedField_(readField, 204 writeField, epsilon, upperLimit, filter) { 205 assertNotNull(readField); 206 assertNotNull(writeField); 207 208 var writer = new jspb.BinaryWriter(); 209 210 // Encode zero and limits. 211 writeField.call(writer, 1, filter(0)); 212 writeField.call(writer, 2, filter(epsilon)); 213 writeField.call(writer, 3, filter(upperLimit)); 214 215 // Encode positive values. 216 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 217 writeField.call(writer, 4, filter(cursor)); 218 } 219 220 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 221 222 // Check zero and limits. 223 reader.nextField(); 224 assertEquals(1, reader.getFieldNumber()); 225 assertEquals(filter(0), readField.call(reader)); 226 227 reader.nextField(); 228 assertEquals(2, reader.getFieldNumber()); 229 assertEquals(filter(epsilon), readField.call(reader)); 230 231 reader.nextField(); 232 assertEquals(3, reader.getFieldNumber()); 233 assertEquals(filter(upperLimit), readField.call(reader)); 234 235 // Check positive values. 236 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 237 reader.nextField(); 238 if (4 != reader.getFieldNumber()) throw 'fail!'; 239 if (filter(cursor) != readField.call(reader)) throw 'fail!'; 240 } 241 }; 242 243 244 /** 245 * Tests encoding and decoding of signed field types. 246 * @param {Function} readField 247 * @param {Function} writeField 248 * @param {number} epsilon 249 * @param {number} lowerLimit 250 * @param {number} upperLimit 251 * @param {Function} filter 252 * @private 253 * @suppress {missingProperties} 254 */ 255 function doTestSignedField_(readField, 256 writeField, epsilon, lowerLimit, upperLimit, filter) { 257 var writer = new jspb.BinaryWriter(); 258 259 // Encode zero and limits. 260 writeField.call(writer, 1, filter(lowerLimit)); 261 writeField.call(writer, 2, filter(-epsilon)); 262 writeField.call(writer, 3, filter(0)); 263 writeField.call(writer, 4, filter(epsilon)); 264 writeField.call(writer, 5, filter(upperLimit)); 265 266 var inputValues = []; 267 268 // Encode negative values. 269 for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) { 270 var val = filter(cursor); 271 writeField.call(writer, 6, val); 272 inputValues.push({ 273 fieldNumber: 6, 274 value: val 275 }); 276 } 277 278 // Encode positive values. 279 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) { 280 var val = filter(cursor); 281 writeField.call(writer, 7, val); 282 inputValues.push({ 283 fieldNumber: 7, 284 value: val 285 }); 286 } 287 288 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 289 290 // Check zero and limits. 291 reader.nextField(); 292 assertEquals(1, reader.getFieldNumber()); 293 assertEquals(filter(lowerLimit), readField.call(reader)); 294 295 reader.nextField(); 296 assertEquals(2, reader.getFieldNumber()); 297 assertEquals(filter(-epsilon), readField.call(reader)); 298 299 reader.nextField(); 300 assertEquals(3, reader.getFieldNumber()); 301 assertEquals(filter(0), readField.call(reader)); 302 303 reader.nextField(); 304 assertEquals(4, reader.getFieldNumber()); 305 assertEquals(filter(epsilon), readField.call(reader)); 306 307 reader.nextField(); 308 assertEquals(5, reader.getFieldNumber()); 309 assertEquals(filter(upperLimit), readField.call(reader)); 310 311 for (var i = 0; i < inputValues.length; i++) { 312 var expected = inputValues[i]; 313 reader.nextField(); 314 assertEquals(expected.fieldNumber, reader.getFieldNumber()); 315 assertEquals(expected.value, readField.call(reader)); 316 } 317 }; 318 319 320 /** 321 * Tests fields that use varint encoding. 322 */ 323 it('testVarintFields', function() { 324 assertNotNull(jspb.BinaryReader.prototype.readUint32); 325 assertNotNull(jspb.BinaryReader.prototype.writeUint32); 326 assertNotNull(jspb.BinaryReader.prototype.readUint64); 327 assertNotNull(jspb.BinaryReader.prototype.writeUint64); 328 assertNotNull(jspb.BinaryReader.prototype.readBool); 329 assertNotNull(jspb.BinaryReader.prototype.writeBool); 330 doTestUnsignedField_( 331 jspb.BinaryReader.prototype.readUint32, 332 jspb.BinaryWriter.prototype.writeUint32, 333 1, Math.pow(2, 32) - 1, Math.round); 334 335 doTestUnsignedField_( 336 jspb.BinaryReader.prototype.readUint64, 337 jspb.BinaryWriter.prototype.writeUint64, 338 1, Math.pow(2, 64) - 1025, Math.round); 339 340 doTestSignedField_( 341 jspb.BinaryReader.prototype.readInt32, 342 jspb.BinaryWriter.prototype.writeInt32, 343 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round); 344 345 doTestSignedField_( 346 jspb.BinaryReader.prototype.readInt64, 347 jspb.BinaryWriter.prototype.writeInt64, 348 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round); 349 350 doTestSignedField_( 351 jspb.BinaryReader.prototype.readEnum, 352 jspb.BinaryWriter.prototype.writeEnum, 353 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round); 354 355 doTestUnsignedField_( 356 jspb.BinaryReader.prototype.readBool, 357 jspb.BinaryWriter.prototype.writeBool, 358 1, 1, function(x) { return !!x; }); 359 }); 360 361 362 /** 363 * Tests 64-bit fields that are handled as strings. 364 */ 365 it('testStringInt64Fields', function() { 366 var writer = new jspb.BinaryWriter(); 367 368 var testSignedData = [ 369 '2730538252207801776', 370 '-2688470994844604560', 371 '3398529779486536359', 372 '3568577411627971000', 373 '272477188847484900', 374 '-6649058714086158188', 375 '-7695254765712060806', 376 '-4525541438037104029', 377 '-4993706538836508568', 378 '4990160321893729138' 379 ]; 380 var testUnsignedData = [ 381 '7822732630241694882', 382 '6753602971916687352', 383 '2399935075244442116', 384 '8724292567325338867', 385 '16948784802625696584', 386 '4136275908516066934', 387 '3575388346793700364', 388 '5167142028379259461', 389 '1557573948689737699', 390 '17100725280812548567' 391 ]; 392 393 for (var i = 0; i < testSignedData.length; i++) { 394 writer.writeInt64String(2 * i + 1, testSignedData[i]); 395 writer.writeUint64String(2 * i + 2, testUnsignedData[i]); 396 } 397 398 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 399 400 for (var i = 0; i < testSignedData.length; i++) { 401 reader.nextField(); 402 assertEquals(2 * i + 1, reader.getFieldNumber()); 403 assertEquals(testSignedData[i], reader.readInt64String()); 404 reader.nextField(); 405 assertEquals(2 * i + 2, reader.getFieldNumber()); 406 assertEquals(testUnsignedData[i], reader.readUint64String()); 407 } 408 }); 409 410 411 /** 412 * Tests fields that use zigzag encoding. 413 */ 414 it('testZigzagFields', function() { 415 doTestSignedField_( 416 jspb.BinaryReader.prototype.readSint32, 417 jspb.BinaryWriter.prototype.writeSint32, 418 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round); 419 420 doTestSignedField_( 421 jspb.BinaryReader.prototype.readSint64, 422 jspb.BinaryWriter.prototype.writeSint64, 423 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round); 424 }); 425 426 427 /** 428 * Tests fields that use fixed-length encoding. 429 */ 430 it('testFixedFields', function() { 431 doTestUnsignedField_( 432 jspb.BinaryReader.prototype.readFixed32, 433 jspb.BinaryWriter.prototype.writeFixed32, 434 1, Math.pow(2, 32) - 1, Math.round); 435 436 doTestUnsignedField_( 437 jspb.BinaryReader.prototype.readFixed64, 438 jspb.BinaryWriter.prototype.writeFixed64, 439 1, Math.pow(2, 64) - 1025, Math.round); 440 441 doTestSignedField_( 442 jspb.BinaryReader.prototype.readSfixed32, 443 jspb.BinaryWriter.prototype.writeSfixed32, 444 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round); 445 446 doTestSignedField_( 447 jspb.BinaryReader.prototype.readSfixed64, 448 jspb.BinaryWriter.prototype.writeSfixed64, 449 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round); 450 }); 451 452 453 /** 454 * Tests floating point fields. 455 */ 456 it('testFloatFields', function() { 457 doTestSignedField_( 458 jspb.BinaryReader.prototype.readFloat, 459 jspb.BinaryWriter.prototype.writeFloat, 460 jspb.BinaryConstants.FLOAT32_MIN, 461 -jspb.BinaryConstants.FLOAT32_MAX, 462 jspb.BinaryConstants.FLOAT32_MAX, 463 truncate); 464 465 doTestSignedField_( 466 jspb.BinaryReader.prototype.readDouble, 467 jspb.BinaryWriter.prototype.writeDouble, 468 jspb.BinaryConstants.FLOAT64_EPS * 10, 469 -jspb.BinaryConstants.FLOAT64_MIN, 470 jspb.BinaryConstants.FLOAT64_MIN, 471 function(x) { return x; }); 472 }); 473 474 475 /** 476 * Tests length-delimited string fields. 477 */ 478 it('testStringFields', function() { 479 var s1 = 'The quick brown fox jumps over the lazy dog.'; 480 var s2 = '人人生而自由,在尊嚴和權利上一律平等。'; 481 482 var writer = new jspb.BinaryWriter(); 483 484 writer.writeString(1, s1); 485 writer.writeString(2, s2); 486 487 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 488 489 reader.nextField(); 490 assertEquals(1, reader.getFieldNumber()); 491 assertEquals(s1, reader.readString()); 492 493 reader.nextField(); 494 assertEquals(2, reader.getFieldNumber()); 495 assertEquals(s2, reader.readString()); 496 }); 497 498 499 /** 500 * Tests length-delimited byte fields. 501 */ 502 it('testByteFields', function() { 503 var message = []; 504 var lowerLimit = 1; 505 var upperLimit = 256; 506 var scale = 1.1; 507 508 var writer = new jspb.BinaryWriter(); 509 510 for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) { 511 var len = Math.round(cursor); 512 var bytes = []; 513 for (var i = 0; i < len; i++) bytes.push(i % 256); 514 515 writer.writeBytes(len, bytes); 516 } 517 518 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 519 520 for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) { 521 var len = Math.round(cursor); 522 if (len != reader.getFieldNumber()) throw 'fail!'; 523 524 var bytes = reader.readBytes(); 525 if (len != bytes.length) throw 'fail!'; 526 for (var i = 0; i < bytes.length; i++) { 527 if (i % 256 != bytes[i]) throw 'fail!'; 528 } 529 } 530 }); 531 532 533 /** 534 * Tests nested messages. 535 */ 536 it('testNesting', function() { 537 var writer = new jspb.BinaryWriter(); 538 var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); 539 540 writer.writeInt32(1, 100); 541 542 // Add one message with 3 int fields. 543 writer.writeMessage(2, dummyMessage, function() { 544 writer.writeInt32(3, 300); 545 writer.writeInt32(4, 400); 546 writer.writeInt32(5, 500); 547 }); 548 549 // Add one empty message. 550 writer.writeMessage(6, dummyMessage, goog.nullFunction); 551 552 writer.writeInt32(7, 700); 553 554 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 555 556 // Validate outermost message. 557 558 reader.nextField(); 559 assertEquals(1, reader.getFieldNumber()); 560 assertEquals(100, reader.readInt32()); 561 562 reader.nextField(); 563 assertEquals(2, reader.getFieldNumber()); 564 reader.readMessage(dummyMessage, function() { 565 // Validate embedded message 1. 566 reader.nextField(); 567 assertEquals(3, reader.getFieldNumber()); 568 assertEquals(300, reader.readInt32()); 569 570 reader.nextField(); 571 assertEquals(4, reader.getFieldNumber()); 572 assertEquals(400, reader.readInt32()); 573 574 reader.nextField(); 575 assertEquals(5, reader.getFieldNumber()); 576 assertEquals(500, reader.readInt32()); 577 578 assertEquals(false, reader.nextField()); 579 }); 580 581 reader.nextField(); 582 assertEquals(6, reader.getFieldNumber()); 583 reader.readMessage(dummyMessage, function() { 584 // Validate embedded message 2. 585 586 assertEquals(false, reader.nextField()); 587 }); 588 589 reader.nextField(); 590 assertEquals(7, reader.getFieldNumber()); 591 assertEquals(700, reader.readInt32()); 592 593 assertEquals(false, reader.nextField()); 594 }); 595 596 /** 597 * Tests skipping fields of each type by interleaving them with sentinel 598 * values and skipping everything that's not a sentinel. 599 */ 600 it('testSkipField', function() { 601 var writer = new jspb.BinaryWriter(); 602 603 var sentinel = 123456789; 604 605 // Write varint fields of different sizes. 606 writer.writeInt32(1, sentinel); 607 writer.writeInt32(1, 1); 608 writer.writeInt32(1, 1000); 609 writer.writeInt32(1, 1000000); 610 writer.writeInt32(1, 1000000000); 611 612 // Write fixed 64-bit encoded fields. 613 writer.writeInt32(2, sentinel); 614 writer.writeDouble(2, 1); 615 writer.writeFixed64(2, 1); 616 writer.writeSfixed64(2, 1); 617 618 // Write fixed 32-bit encoded fields. 619 writer.writeInt32(3, sentinel); 620 writer.writeFloat(3, 1); 621 writer.writeFixed32(3, 1); 622 writer.writeSfixed32(3, 1); 623 624 // Write delimited fields. 625 writer.writeInt32(4, sentinel); 626 writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 627 writer.writeString(4, 'The quick brown fox jumps over the lazy dog'); 628 629 // Write a group with a nested group inside. 630 writer.writeInt32(5, sentinel); 631 var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); 632 writer.writeGroup(5, dummyMessage, function() { 633 writer.writeInt64(42, 42); 634 writer.writeGroup(6, dummyMessage, function() { 635 writer.writeInt64(84, 42); 636 }); 637 }); 638 639 // Write final sentinel. 640 writer.writeInt32(6, sentinel); 641 642 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 643 644 function skip(field, count) { 645 for (var i = 0; i < count; i++) { 646 reader.nextField(); 647 if (field != reader.getFieldNumber()) throw 'fail!'; 648 reader.skipField(); 649 } 650 } 651 652 reader.nextField(); 653 assertEquals(1, reader.getFieldNumber()); 654 assertEquals(sentinel, reader.readInt32()); 655 skip(1, 4); 656 657 reader.nextField(); 658 assertEquals(2, reader.getFieldNumber()); 659 assertEquals(sentinel, reader.readInt32()); 660 skip(2, 3); 661 662 reader.nextField(); 663 assertEquals(3, reader.getFieldNumber()); 664 assertEquals(sentinel, reader.readInt32()); 665 skip(3, 3); 666 667 reader.nextField(); 668 assertEquals(4, reader.getFieldNumber()); 669 assertEquals(sentinel, reader.readInt32()); 670 skip(4, 2); 671 672 reader.nextField(); 673 assertEquals(5, reader.getFieldNumber()); 674 assertEquals(sentinel, reader.readInt32()); 675 skip(5, 1); 676 677 reader.nextField(); 678 assertEquals(6, reader.getFieldNumber()); 679 assertEquals(sentinel, reader.readInt32()); 680 }); 681 682 683 /** 684 * Tests packed fields. 685 */ 686 it('testPackedFields', function() { 687 var writer = new jspb.BinaryWriter(); 688 689 var sentinel = 123456789; 690 691 var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 692 var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10]; 693 var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10]; 694 var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10]; 695 var boolData = [true, false, true, true, false, false, true, false]; 696 697 for (var i = 0; i < floatData.length; i++) { 698 floatData[i] = truncate(floatData[i]); 699 } 700 701 writer.writeInt32(1, sentinel); 702 703 writer.writePackedInt32(2, signedData); 704 writer.writePackedInt64(2, signedData); 705 writer.writePackedUint32(2, unsignedData); 706 writer.writePackedUint64(2, unsignedData); 707 writer.writePackedSint32(2, signedData); 708 writer.writePackedSint64(2, signedData); 709 writer.writePackedFixed32(2, unsignedData); 710 writer.writePackedFixed64(2, unsignedData); 711 writer.writePackedSfixed32(2, signedData); 712 writer.writePackedSfixed64(2, signedData); 713 writer.writePackedFloat(2, floatData); 714 writer.writePackedDouble(2, doubleData); 715 writer.writePackedBool(2, boolData); 716 writer.writePackedEnum(2, unsignedData); 717 718 writer.writeInt32(3, sentinel); 719 720 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 721 722 reader.nextField(); 723 assertEquals(sentinel, reader.readInt32()); 724 725 reader.nextField(); 726 assertElementsEquals(reader.readPackedInt32(), signedData); 727 728 reader.nextField(); 729 assertElementsEquals(reader.readPackedInt64(), signedData); 730 731 reader.nextField(); 732 assertElementsEquals(reader.readPackedUint32(), unsignedData); 733 734 reader.nextField(); 735 assertElementsEquals(reader.readPackedUint64(), unsignedData); 736 737 reader.nextField(); 738 assertElementsEquals(reader.readPackedSint32(), signedData); 739 740 reader.nextField(); 741 assertElementsEquals(reader.readPackedSint64(), signedData); 742 743 reader.nextField(); 744 assertElementsEquals(reader.readPackedFixed32(), unsignedData); 745 746 reader.nextField(); 747 assertElementsEquals(reader.readPackedFixed64(), unsignedData); 748 749 reader.nextField(); 750 assertElementsEquals(reader.readPackedSfixed32(), signedData); 751 752 reader.nextField(); 753 assertElementsEquals(reader.readPackedSfixed64(), signedData); 754 755 reader.nextField(); 756 assertElementsEquals(reader.readPackedFloat(), floatData); 757 758 reader.nextField(); 759 assertElementsEquals(reader.readPackedDouble(), doubleData); 760 761 reader.nextField(); 762 assertElementsEquals(reader.readPackedBool(), boolData); 763 764 reader.nextField(); 765 assertElementsEquals(reader.readPackedEnum(), unsignedData); 766 767 reader.nextField(); 768 assertEquals(sentinel, reader.readInt32()); 769 }); 770 771 772 /** 773 * Byte blobs inside nested messages should always have their byte offset set 774 * relative to the start of the outermost blob, not the start of their parent 775 * blob. 776 */ 777 it('testNestedBlobs', function() { 778 // Create a proto consisting of two nested messages, with the inner one 779 // containing a blob of bytes. 780 781 var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED; 782 var blob = [1, 2, 3, 4, 5]; 783 var writer = new jspb.BinaryWriter(); 784 var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); 785 786 writer.writeMessage(1, dummyMessage, function() { 787 writer.writeMessage(1, dummyMessage, function() { 788 writer.writeBytes(1, blob); 789 }); 790 }); 791 792 // Peel off the outer two message layers. Each layer should have two bytes 793 // of overhead, one for the field tag and one for the length of the inner 794 // blob. 795 796 var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer()); 797 assertEquals(fieldTag, decoder1.readUnsignedVarint32()); 798 assertEquals(blob.length + 4, decoder1.readUnsignedVarint32()); 799 800 var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4)); 801 assertEquals(fieldTag, decoder2.readUnsignedVarint32()); 802 assertEquals(blob.length + 2, decoder2.readUnsignedVarint32()); 803 804 assertEquals(fieldTag, decoder2.readUnsignedVarint32()); 805 assertEquals(blob.length, decoder2.readUnsignedVarint32()); 806 var bytes = decoder2.readBytes(blob.length); 807 808 assertElementsEquals(bytes, blob); 809 }); 810 811 812 /** 813 * Tests read callbacks. 814 */ 815 it('testReadCallbacks', function() { 816 var writer = new jspb.BinaryWriter(); 817 var dummyMessage = /** @type {!jspb.BinaryMessage} */({}); 818 819 // Add an int, a submessage, and another int. 820 writer.writeInt32(1, 100); 821 822 writer.writeMessage(2, dummyMessage, function() { 823 writer.writeInt32(3, 300); 824 writer.writeInt32(4, 400); 825 writer.writeInt32(5, 500); 826 }); 827 828 writer.writeInt32(7, 700); 829 830 // Create the reader and register a custom read callback. 831 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); 832 833 /** 834 * @param {!jspb.BinaryReader} reader 835 * @return {*} 836 */ 837 function readCallback(reader) { 838 reader.nextField(); 839 assertEquals(3, reader.getFieldNumber()); 840 assertEquals(300, reader.readInt32()); 841 842 reader.nextField(); 843 assertEquals(4, reader.getFieldNumber()); 844 assertEquals(400, reader.readInt32()); 845 846 reader.nextField(); 847 assertEquals(5, reader.getFieldNumber()); 848 assertEquals(500, reader.readInt32()); 849 850 assertEquals(false, reader.nextField()); 851 }; 852 853 reader.registerReadCallback('readCallback', readCallback); 854 855 // Read the container message. 856 reader.nextField(); 857 assertEquals(1, reader.getFieldNumber()); 858 assertEquals(100, reader.readInt32()); 859 860 reader.nextField(); 861 assertEquals(2, reader.getFieldNumber()); 862 reader.readMessage(dummyMessage, function() { 863 // Decode the embedded message using the registered callback. 864 reader.runReadCallback('readCallback'); 865 }); 866 867 reader.nextField(); 868 assertEquals(7, reader.getFieldNumber()); 869 assertEquals(700, reader.readInt32()); 870 871 assertEquals(false, reader.nextField()); 872 }); 873}); 874