938 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			938 lines
		
	
	
		
			30 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
| // Protocol Buffers - Google's data interchange format
 | |
| // Copyright 2008 Google Inc.  All rights reserved.
 | |
| // https://developers.google.com/protocol-buffers/
 | |
| //
 | |
| // Redistribution and use in source and binary forms, with or without
 | |
| // modification, are permitted provided that the following conditions are
 | |
| // met:
 | |
| //
 | |
| //     * Redistributions of source code must retain the above copyright
 | |
| // notice, this list of conditions and the following disclaimer.
 | |
| //     * Redistributions in binary form must reproduce the above
 | |
| // copyright notice, this list of conditions and the following disclaimer
 | |
| // in the documentation and/or other materials provided with the
 | |
| // distribution.
 | |
| //     * Neither the name of Google Inc. nor the names of its
 | |
| // contributors may be used to endorse or promote products derived from
 | |
| // this software without specific prior written permission.
 | |
| //
 | |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 | |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 | |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 | |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 | |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 | |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 | |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 | |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
| 
 | |
| /**
 | |
|  * @fileoverview Test cases for jspb's binary protocol buffer reader.
 | |
|  *
 | |
|  * There are two particular magic numbers that need to be pointed out -
 | |
|  * 2^64-1025 is the largest number representable as both a double and an
 | |
|  * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
 | |
|  * both a double and a signed 64-bit integer.
 | |
|  *
 | |
|  * Test suite is written using Jasmine -- see http://jasmine.github.io/
 | |
|  *
 | |
|  * @author aappleby@google.com (Austin Appleby)
 | |
|  */
 | |
| 
 | |
| goog.require('goog.testing.asserts');
 | |
| goog.require('jspb.BinaryConstants');
 | |
| goog.require('jspb.BinaryDecoder');
 | |
| goog.require('jspb.BinaryReader');
 | |
| goog.require('jspb.BinaryWriter');
 | |
| 
 | |
| 
 | |
| 
 | |
| describe('binaryReaderTest', function() {
 | |
|   /**
 | |
|    * Tests the reader instance cache.
 | |
|    */
 | |
|   it('testInstanceCaches', /** @suppress {visibility} */ function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
|     writer.writeMessage(1, dummyMessage, goog.nullFunction);
 | |
|     writer.writeMessage(2, dummyMessage, goog.nullFunction);
 | |
| 
 | |
|     var buffer = writer.getResultBuffer();
 | |
| 
 | |
|     // Empty the instance caches.
 | |
|     jspb.BinaryReader.instanceCache_ = [];
 | |
| 
 | |
|     // Allocating and then freeing three decoders should leave us with three in
 | |
|     // the cache.
 | |
| 
 | |
|     var decoder1 = jspb.BinaryDecoder.alloc();
 | |
|     var decoder2 = jspb.BinaryDecoder.alloc();
 | |
|     var decoder3 = jspb.BinaryDecoder.alloc();
 | |
|     decoder1.free();
 | |
|     decoder2.free();
 | |
|     decoder3.free();
 | |
| 
 | |
|     assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
 | |
|     assertEquals(0, jspb.BinaryReader.instanceCache_.length);
 | |
| 
 | |
|     // Allocating and then freeing a reader should remove one decoder from its
 | |
|     // cache, but it should stay stuck to the reader afterwards since we can't
 | |
|     // have a reader without a decoder.
 | |
|     jspb.BinaryReader.alloc().free();
 | |
| 
 | |
|     assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
 | |
|     assertEquals(1, jspb.BinaryReader.instanceCache_.length);
 | |
| 
 | |
|     // Allocating a reader should remove a reader from the cache.
 | |
|     var reader = jspb.BinaryReader.alloc(buffer);
 | |
| 
 | |
|     assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
 | |
|     assertEquals(0, jspb.BinaryReader.instanceCache_.length);
 | |
| 
 | |
|     // Processing the message reuses the current reader.
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       assertEquals(0, jspb.BinaryReader.instanceCache_.length);
 | |
|     });
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       assertEquals(0, jspb.BinaryReader.instanceCache_.length);
 | |
|     });
 | |
| 
 | |
|     assertEquals(false, reader.nextField());
 | |
| 
 | |
|     assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
 | |
|     assertEquals(0, jspb.BinaryReader.instanceCache_.length);
 | |
| 
 | |
|     // Freeing the reader should put it back into the cache.
 | |
|     reader.free();
 | |
| 
 | |
|     assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
 | |
|     assertEquals(1, jspb.BinaryReader.instanceCache_.length);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * @param {number} x
 | |
|    * @return {number}
 | |
|    */
 | |
|   function truncate(x) {
 | |
|     var temp = new Float32Array(1);
 | |
|     temp[0] = x;
 | |
|     return temp[0];
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Verifies that misuse of the reader class triggers assertions.
 | |
|    */
 | |
|   it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() {
 | |
|     // Calling readMessage on a non-delimited field should trigger an
 | |
|     // assertion.
 | |
|     var reader = jspb.BinaryReader.alloc([8, 1]);
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
|     reader.nextField();
 | |
|     assertThrows(function() {
 | |
|       reader.readMessage(dummyMessage, goog.nullFunction);
 | |
|     });
 | |
| 
 | |
|     // Reading past the end of the stream should trigger an assertion.
 | |
|     reader = jspb.BinaryReader.alloc([9, 1]);
 | |
|     reader.nextField();
 | |
|     assertThrows(function() {reader.readFixed64()});
 | |
| 
 | |
|     // Reading past the end of a submessage should trigger an assertion.
 | |
|     reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
 | |
|     reader.nextField();
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       reader.nextField();
 | |
|       assertThrows(function() {reader.readFixed32()});
 | |
|     });
 | |
| 
 | |
|     // Skipping an invalid field should trigger an assertion.
 | |
|     reader = jspb.BinaryReader.alloc([12, 1]);
 | |
|     reader.nextWireType_ = 1000;
 | |
|     assertThrows(function() {reader.skipField()});
 | |
| 
 | |
|     // Reading fields with the wrong wire type should assert.
 | |
|     reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
 | |
|     reader.nextField();
 | |
|     assertThrows(function() {reader.readInt32()});
 | |
|     assertThrows(function() {reader.readInt32String()});
 | |
|     assertThrows(function() {reader.readInt64()});
 | |
|     assertThrows(function() {reader.readInt64String()});
 | |
|     assertThrows(function() {reader.readUint32()});
 | |
|     assertThrows(function() {reader.readUint32String()});
 | |
|     assertThrows(function() {reader.readUint64()});
 | |
|     assertThrows(function() {reader.readUint64String()});
 | |
|     assertThrows(function() {reader.readSint32()});
 | |
|     assertThrows(function() {reader.readBool()});
 | |
|     assertThrows(function() {reader.readEnum()});
 | |
| 
 | |
|     reader = jspb.BinaryReader.alloc([8, 1]);
 | |
|     reader.nextField();
 | |
|     assertThrows(function() {reader.readFixed32()});
 | |
|     assertThrows(function() {reader.readFixed64()});
 | |
|     assertThrows(function() {reader.readSfixed32()});
 | |
|     assertThrows(function() {reader.readSfixed64()});
 | |
|     assertThrows(function() {reader.readFloat()});
 | |
|     assertThrows(function() {reader.readDouble()});
 | |
| 
 | |
|     assertThrows(function() {reader.readString()});
 | |
|     assertThrows(function() {reader.readBytes()});
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests encoding and decoding of unsigned field types.
 | |
|    * @param {Function} readField
 | |
|    * @param {Function} writeField
 | |
|    * @param {number} epsilon
 | |
|    * @param {number} upperLimit
 | |
|    * @param {Function} filter
 | |
|    * @private
 | |
|    * @suppress {missingProperties}
 | |
|    */
 | |
|   var doTestUnsignedField_ = function(readField,
 | |
|       writeField, epsilon, upperLimit, filter) {
 | |
|     assertNotNull(readField);
 | |
|     assertNotNull(writeField);
 | |
| 
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     // Encode zero and limits.
 | |
|     writeField.call(writer, 1, filter(0));
 | |
|     writeField.call(writer, 2, filter(epsilon));
 | |
|     writeField.call(writer, 3, filter(upperLimit));
 | |
| 
 | |
|     // Encode positive values.
 | |
|     for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
 | |
|       writeField.call(writer, 4, filter(cursor));
 | |
|     }
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     // Check zero and limits.
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(filter(0), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     assertEquals(filter(epsilon), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(3, reader.getFieldNumber());
 | |
|     assertEquals(filter(upperLimit), readField.call(reader));
 | |
| 
 | |
|     // Check positive values.
 | |
|     for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
 | |
|       reader.nextField();
 | |
|       if (4 != reader.getFieldNumber()) throw 'fail!';
 | |
|       if (filter(cursor) != readField.call(reader)) throw 'fail!';
 | |
|     }
 | |
|   };
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests encoding and decoding of signed field types.
 | |
|    * @param {Function} readField
 | |
|    * @param {Function} writeField
 | |
|    * @param {number} epsilon
 | |
|    * @param {number} lowerLimit
 | |
|    * @param {number} upperLimit
 | |
|    * @param {Function} filter
 | |
|    * @private
 | |
|    * @suppress {missingProperties}
 | |
|    */
 | |
|   var doTestSignedField_ = function(readField,
 | |
|       writeField, epsilon, lowerLimit, upperLimit, filter) {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     // Encode zero and limits.
 | |
|     writeField.call(writer, 1, filter(lowerLimit));
 | |
|     writeField.call(writer, 2, filter(-epsilon));
 | |
|     writeField.call(writer, 3, filter(0));
 | |
|     writeField.call(writer, 4, filter(epsilon));
 | |
|     writeField.call(writer, 5, filter(upperLimit));
 | |
| 
 | |
|     var inputValues = [];
 | |
| 
 | |
|     // Encode negative values.
 | |
|     for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
 | |
|       var val = filter(cursor);
 | |
|       writeField.call(writer, 6, val);
 | |
|       inputValues.push({
 | |
|         fieldNumber: 6,
 | |
|         value: val
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     // Encode positive values.
 | |
|     for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
 | |
|       var val = filter(cursor);
 | |
|       writeField.call(writer, 7, val);
 | |
|       inputValues.push({
 | |
|         fieldNumber: 7,
 | |
|         value: val
 | |
|       });
 | |
|     }
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     // Check zero and limits.
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(filter(lowerLimit), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     assertEquals(filter(-epsilon), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(3, reader.getFieldNumber());
 | |
|     assertEquals(filter(0), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(4, reader.getFieldNumber());
 | |
|     assertEquals(filter(epsilon), readField.call(reader));
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(5, reader.getFieldNumber());
 | |
|     assertEquals(filter(upperLimit), readField.call(reader));
 | |
| 
 | |
|     for (var i = 0; i < inputValues.length; i++) {
 | |
|       var expected = inputValues[i];
 | |
|       reader.nextField();
 | |
|       assertEquals(expected.fieldNumber, reader.getFieldNumber());
 | |
|       assertEquals(expected.value, readField.call(reader));
 | |
|     }
 | |
|   };
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests fields that use varint encoding.
 | |
|    */
 | |
|   it('testVarintFields', function() {
 | |
|     assertNotUndefined(jspb.BinaryReader.prototype.readUint32);
 | |
|     assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32);
 | |
|     assertNotUndefined(jspb.BinaryReader.prototype.readUint64);
 | |
|     assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64);
 | |
|     assertNotUndefined(jspb.BinaryReader.prototype.readBool);
 | |
|     assertNotUndefined(jspb.BinaryWriter.prototype.writeBool);
 | |
|     doTestUnsignedField_(
 | |
|         jspb.BinaryReader.prototype.readUint32,
 | |
|         jspb.BinaryWriter.prototype.writeUint32,
 | |
|         1, Math.pow(2, 32) - 1, Math.round);
 | |
| 
 | |
|     doTestUnsignedField_(
 | |
|         jspb.BinaryReader.prototype.readUint64,
 | |
|         jspb.BinaryWriter.prototype.writeUint64,
 | |
|         1, Math.pow(2, 64) - 1025, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readInt32,
 | |
|         jspb.BinaryWriter.prototype.writeInt32,
 | |
|         1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readInt64,
 | |
|         jspb.BinaryWriter.prototype.writeInt64,
 | |
|         1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readEnum,
 | |
|         jspb.BinaryWriter.prototype.writeEnum,
 | |
|         1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
 | |
| 
 | |
|     doTestUnsignedField_(
 | |
|         jspb.BinaryReader.prototype.readBool,
 | |
|         jspb.BinaryWriter.prototype.writeBool,
 | |
|         1, 1, function(x) { return !!x; });
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests reading a field from hexadecimal string (format: '08 BE EF').
 | |
|    * @param {Function} readField
 | |
|    * @param {number} expected
 | |
|    * @param {string} hexString
 | |
|    */
 | |
|   function doTestHexStringVarint_(readField, expected, hexString) {
 | |
|     var bytesCount = (hexString.length + 1) / 3;
 | |
|     var bytes = new Uint8Array(bytesCount);
 | |
|     for (var i = 0; i < bytesCount; i++) {
 | |
|       bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
 | |
|     }
 | |
|     var reader = jspb.BinaryReader.alloc(bytes);
 | |
|     reader.nextField();
 | |
|     assertEquals(expected, readField.call(reader));
 | |
|   }
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests non-canonical redundant varint decoding.
 | |
|    */
 | |
|   it('testRedundantVarintFields', function() {
 | |
|     assertNotNull(jspb.BinaryReader.prototype.readUint32);
 | |
|     assertNotNull(jspb.BinaryReader.prototype.readUint64);
 | |
|     assertNotNull(jspb.BinaryReader.prototype.readSint32);
 | |
|     assertNotNull(jspb.BinaryReader.prototype.readSint64);
 | |
| 
 | |
|     // uint32 and sint32 take no more than 5 bytes
 | |
|     // 08 - field prefix (type = 0 means varint)
 | |
|     doTestHexStringVarint_(
 | |
|       jspb.BinaryReader.prototype.readUint32,
 | |
|       12, '08 8C 80 80 80 00');
 | |
| 
 | |
|     // 11 stands for -6 in zigzag encoding
 | |
|     doTestHexStringVarint_(
 | |
|       jspb.BinaryReader.prototype.readSint32,
 | |
|       -6, '08 8B 80 80 80 00');
 | |
| 
 | |
|     // uint64 and sint64 take no more than 10 bytes
 | |
|     // 08 - field prefix (type = 0 means varint)
 | |
|     doTestHexStringVarint_(
 | |
|       jspb.BinaryReader.prototype.readUint64,
 | |
|       12, '08 8C 80 80 80 80 80 80 80 80 00');
 | |
| 
 | |
|     // 11 stands for -6 in zigzag encoding
 | |
|     doTestHexStringVarint_(
 | |
|       jspb.BinaryReader.prototype.readSint64,
 | |
|       -6, '08 8B 80 80 80 80 80 80 80 80 00');
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests 64-bit fields that are handled as strings.
 | |
|    */
 | |
|   it('testStringInt64Fields', function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     var testSignedData = [
 | |
|       '2730538252207801776',
 | |
|       '-2688470994844604560',
 | |
|       '3398529779486536359',
 | |
|       '3568577411627971000',
 | |
|       '272477188847484900',
 | |
|       '-6649058714086158188',
 | |
|       '-7695254765712060806',
 | |
|       '-4525541438037104029',
 | |
|       '-4993706538836508568',
 | |
|       '4990160321893729138'
 | |
|     ];
 | |
|     var testUnsignedData = [
 | |
|       '7822732630241694882',
 | |
|       '6753602971916687352',
 | |
|       '2399935075244442116',
 | |
|       '8724292567325338867',
 | |
|       '16948784802625696584',
 | |
|       '4136275908516066934',
 | |
|       '3575388346793700364',
 | |
|       '5167142028379259461',
 | |
|       '1557573948689737699',
 | |
|       '17100725280812548567'
 | |
|     ];
 | |
| 
 | |
|     for (var i = 0; i < testSignedData.length; i++) {
 | |
|       writer.writeInt64String(2 * i + 1, testSignedData[i]);
 | |
|       writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
 | |
|     }
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     for (var i = 0; i < testSignedData.length; i++) {
 | |
|       reader.nextField();
 | |
|       assertEquals(2 * i + 1, reader.getFieldNumber());
 | |
|       assertEquals(testSignedData[i], reader.readInt64String());
 | |
|       reader.nextField();
 | |
|       assertEquals(2 * i + 2, reader.getFieldNumber());
 | |
|       assertEquals(testUnsignedData[i], reader.readUint64String());
 | |
|     }
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests fields that use zigzag encoding.
 | |
|    */
 | |
|   it('testZigzagFields', function() {
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readSint32,
 | |
|         jspb.BinaryWriter.prototype.writeSint32,
 | |
|         1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readSint64,
 | |
|         jspb.BinaryWriter.prototype.writeSint64,
 | |
|         1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests fields that use fixed-length encoding.
 | |
|    */
 | |
|   it('testFixedFields', function() {
 | |
|     doTestUnsignedField_(
 | |
|         jspb.BinaryReader.prototype.readFixed32,
 | |
|         jspb.BinaryWriter.prototype.writeFixed32,
 | |
|         1, Math.pow(2, 32) - 1, Math.round);
 | |
| 
 | |
|     doTestUnsignedField_(
 | |
|         jspb.BinaryReader.prototype.readFixed64,
 | |
|         jspb.BinaryWriter.prototype.writeFixed64,
 | |
|         1, Math.pow(2, 64) - 1025, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readSfixed32,
 | |
|         jspb.BinaryWriter.prototype.writeSfixed32,
 | |
|         1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readSfixed64,
 | |
|         jspb.BinaryWriter.prototype.writeSfixed64,
 | |
|         1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests floating point fields.
 | |
|    */
 | |
|   it('testFloatFields', function() {
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readFloat,
 | |
|         jspb.BinaryWriter.prototype.writeFloat,
 | |
|         jspb.BinaryConstants.FLOAT32_MIN,
 | |
|         -jspb.BinaryConstants.FLOAT32_MAX,
 | |
|         jspb.BinaryConstants.FLOAT32_MAX,
 | |
|         truncate);
 | |
| 
 | |
|     doTestSignedField_(
 | |
|         jspb.BinaryReader.prototype.readDouble,
 | |
|         jspb.BinaryWriter.prototype.writeDouble,
 | |
|         jspb.BinaryConstants.FLOAT64_EPS * 10,
 | |
|         -jspb.BinaryConstants.FLOAT64_MIN,
 | |
|         jspb.BinaryConstants.FLOAT64_MIN,
 | |
|         function(x) { return x; });
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests length-delimited string fields.
 | |
|    */
 | |
|   it('testStringFields', function() {
 | |
|     var s1 = 'The quick brown fox jumps over the lazy dog.';
 | |
|     var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
 | |
| 
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     writer.writeString(1, s1);
 | |
|     writer.writeString(2, s2);
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(s1, reader.readString());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     assertEquals(s2, reader.readString());
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests length-delimited byte fields.
 | |
|    */
 | |
|   it('testByteFields', function() {
 | |
|     var message = [];
 | |
|     var lowerLimit = 1;
 | |
|     var upperLimit = 256;
 | |
|     var scale = 1.1;
 | |
| 
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
 | |
|       var len = Math.round(cursor);
 | |
|       var bytes = [];
 | |
|       for (var i = 0; i < len; i++) bytes.push(i % 256);
 | |
| 
 | |
|       writer.writeBytes(len, bytes);
 | |
|     }
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
 | |
|       var len = Math.round(cursor);
 | |
|       if (len != reader.getFieldNumber()) throw 'fail!';
 | |
| 
 | |
|       var bytes = reader.readBytes();
 | |
|       if (len != bytes.length) throw 'fail!';
 | |
|       for (var i = 0; i < bytes.length; i++) {
 | |
|         if (i % 256 != bytes[i]) throw 'fail!';
 | |
|       }
 | |
|     }
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests nested messages.
 | |
|    */
 | |
|   it('testNesting', function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
| 
 | |
|     writer.writeInt32(1, 100);
 | |
| 
 | |
|     // Add one message with 3 int fields.
 | |
|     writer.writeMessage(2, dummyMessage, function() {
 | |
|       writer.writeInt32(3, 300);
 | |
|       writer.writeInt32(4, 400);
 | |
|       writer.writeInt32(5, 500);
 | |
|     });
 | |
| 
 | |
|     // Add one empty message.
 | |
|     writer.writeMessage(6, dummyMessage, goog.nullFunction);
 | |
| 
 | |
|     writer.writeInt32(7, 700);
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     // Validate outermost message.
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(100, reader.readInt32());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       // Validate embedded message 1.
 | |
|       reader.nextField();
 | |
|       assertEquals(3, reader.getFieldNumber());
 | |
|       assertEquals(300, reader.readInt32());
 | |
| 
 | |
|       reader.nextField();
 | |
|       assertEquals(4, reader.getFieldNumber());
 | |
|       assertEquals(400, reader.readInt32());
 | |
| 
 | |
|       reader.nextField();
 | |
|       assertEquals(5, reader.getFieldNumber());
 | |
|       assertEquals(500, reader.readInt32());
 | |
| 
 | |
|       assertEquals(false, reader.nextField());
 | |
|     });
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(6, reader.getFieldNumber());
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       // Validate embedded message 2.
 | |
| 
 | |
|       assertEquals(false, reader.nextField());
 | |
|     });
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(7, reader.getFieldNumber());
 | |
|     assertEquals(700, reader.readInt32());
 | |
| 
 | |
|     assertEquals(false, reader.nextField());
 | |
|   });
 | |
| 
 | |
|   /**
 | |
|    * Tests skipping fields of each type by interleaving them with sentinel
 | |
|    * values and skipping everything that's not a sentinel.
 | |
|    */
 | |
|   it('testSkipField', function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     var sentinel = 123456789;
 | |
| 
 | |
|     // Write varint fields of different sizes.
 | |
|     writer.writeInt32(1, sentinel);
 | |
|     writer.writeInt32(1, 1);
 | |
|     writer.writeInt32(1, 1000);
 | |
|     writer.writeInt32(1, 1000000);
 | |
|     writer.writeInt32(1, 1000000000);
 | |
| 
 | |
|     // Write fixed 64-bit encoded fields.
 | |
|     writer.writeInt32(2, sentinel);
 | |
|     writer.writeDouble(2, 1);
 | |
|     writer.writeFixed64(2, 1);
 | |
|     writer.writeSfixed64(2, 1);
 | |
| 
 | |
|     // Write fixed 32-bit encoded fields.
 | |
|     writer.writeInt32(3, sentinel);
 | |
|     writer.writeFloat(3, 1);
 | |
|     writer.writeFixed32(3, 1);
 | |
|     writer.writeSfixed32(3, 1);
 | |
| 
 | |
|     // Write delimited fields.
 | |
|     writer.writeInt32(4, sentinel);
 | |
|     writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
 | |
|     writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
 | |
| 
 | |
|     // Write a group with a nested group inside.
 | |
|     writer.writeInt32(5, sentinel);
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
|     writer.writeGroup(5, dummyMessage, function() {
 | |
|       // Previously the skipGroup implementation was wrong, which only consume
 | |
|       // the decoder by nextField. This case is for making the previous
 | |
|       // implementation failed in skipGroup by an early end group tag.
 | |
|       // The reason is 44 = 5 * 8 + 4, this will be translated in to a field
 | |
|       // with number 5 and with type 4 (end group)
 | |
|       writer.writeInt64(44, 44);
 | |
|       // This will make previous implementation failed by invalid tag (7).
 | |
|       writer.writeInt64(42, 47);
 | |
|       writer.writeInt64(42, 42);
 | |
|       // This is for making the previous implementation failed by an invalid
 | |
|       // varint. The bytes have at least 9 consecutive minus byte, which will
 | |
|       // fail in this.nextField for previous implementation.
 | |
|       writer.writeBytes(43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
 | |
|       writer.writeGroup(6, dummyMessage, function() {
 | |
|         writer.writeInt64(84, 42);
 | |
|         writer.writeInt64(84, 44);
 | |
|         writer.writeBytes(
 | |
|           43, [255, 255, 255, 255, 255, 255, 255, 255, 255, 255]);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     // Write final sentinel.
 | |
|     writer.writeInt32(6, sentinel);
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     function skip(field, count) {
 | |
|       for (var i = 0; i < count; i++) {
 | |
|         reader.nextField();
 | |
|         if (field != reader.getFieldNumber()) throw 'fail!';
 | |
|         reader.skipField();
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|     skip(1, 4);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|     skip(2, 3);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(3, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|     skip(3, 3);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(4, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|     skip(4, 2);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(5, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|     skip(5, 1);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(6, reader.getFieldNumber());
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests packed fields.
 | |
|    */
 | |
|   it('testPackedFields', function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
| 
 | |
|     var sentinel = 123456789;
 | |
| 
 | |
|     var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
 | |
|     var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
 | |
|     var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
 | |
|     var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
 | |
|     var boolData = [true, false, true, true, false, false, true, false];
 | |
| 
 | |
|     for (var i = 0; i < floatData.length; i++) {
 | |
|       floatData[i] = truncate(floatData[i]);
 | |
|     }
 | |
| 
 | |
|     writer.writeInt32(1, sentinel);
 | |
| 
 | |
|     writer.writePackedInt32(2, signedData);
 | |
|     writer.writePackedInt64(2, signedData);
 | |
|     writer.writePackedUint32(2, unsignedData);
 | |
|     writer.writePackedUint64(2, unsignedData);
 | |
|     writer.writePackedSint32(2, signedData);
 | |
|     writer.writePackedSint64(2, signedData);
 | |
|     writer.writePackedFixed32(2, unsignedData);
 | |
|     writer.writePackedFixed64(2, unsignedData);
 | |
|     writer.writePackedSfixed32(2, signedData);
 | |
|     writer.writePackedSfixed64(2, signedData);
 | |
|     writer.writePackedFloat(2, floatData);
 | |
|     writer.writePackedDouble(2, doubleData);
 | |
|     writer.writePackedBool(2, boolData);
 | |
|     writer.writePackedEnum(2, unsignedData);
 | |
| 
 | |
|     writer.writeInt32(3, sentinel);
 | |
| 
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedInt32(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedInt64(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedUint32(), unsignedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedUint64(), unsignedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedSint32(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedSint64(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedFixed32(), unsignedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedFixed64(), unsignedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedSfixed32(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedSfixed64(), signedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedFloat(), floatData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedDouble(), doubleData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedBool(), boolData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertElementsEquals(reader.readPackedEnum(), unsignedData);
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(sentinel, reader.readInt32());
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Byte blobs inside nested messages should always have their byte offset set
 | |
|    * relative to the start of the outermost blob, not the start of their parent
 | |
|    * blob.
 | |
|    */
 | |
|   it('testNestedBlobs', function() {
 | |
|     // Create a proto consisting of two nested messages, with the inner one
 | |
|     // containing a blob of bytes.
 | |
| 
 | |
|     var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
 | |
|     var blob = [1, 2, 3, 4, 5];
 | |
|     var writer = new jspb.BinaryWriter();
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
| 
 | |
|     writer.writeMessage(1, dummyMessage, function() {
 | |
|       writer.writeMessage(1, dummyMessage, function() {
 | |
|         writer.writeBytes(1, blob);
 | |
|       });
 | |
|     });
 | |
| 
 | |
|     // Peel off the outer two message layers. Each layer should have two bytes
 | |
|     // of overhead, one for the field tag and one for the length of the inner
 | |
|     // blob.
 | |
| 
 | |
|     var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
 | |
|     assertEquals(fieldTag, decoder1.readUnsignedVarint32());
 | |
|     assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
 | |
| 
 | |
|     var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
 | |
|     assertEquals(fieldTag, decoder2.readUnsignedVarint32());
 | |
|     assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
 | |
| 
 | |
|     assertEquals(fieldTag, decoder2.readUnsignedVarint32());
 | |
|     assertEquals(blob.length, decoder2.readUnsignedVarint32());
 | |
|     var bytes = decoder2.readBytes(blob.length);
 | |
| 
 | |
|     assertElementsEquals(bytes, blob);
 | |
|   });
 | |
| 
 | |
| 
 | |
|   /**
 | |
|    * Tests read callbacks.
 | |
|    */
 | |
|   it('testReadCallbacks', function() {
 | |
|     var writer = new jspb.BinaryWriter();
 | |
|     var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
 | |
| 
 | |
|     // Add an int, a submessage, and another int.
 | |
|     writer.writeInt32(1, 100);
 | |
| 
 | |
|     writer.writeMessage(2, dummyMessage, function() {
 | |
|       writer.writeInt32(3, 300);
 | |
|       writer.writeInt32(4, 400);
 | |
|       writer.writeInt32(5, 500);
 | |
|     });
 | |
| 
 | |
|     writer.writeInt32(7, 700);
 | |
| 
 | |
|     // Create the reader and register a custom read callback.
 | |
|     var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
 | |
| 
 | |
|     /**
 | |
|      * @param {!jspb.BinaryReader} reader
 | |
|      * @return {*}
 | |
|      */
 | |
|     function readCallback(reader) {
 | |
|       reader.nextField();
 | |
|       assertEquals(3, reader.getFieldNumber());
 | |
|       assertEquals(300, reader.readInt32());
 | |
| 
 | |
|       reader.nextField();
 | |
|       assertEquals(4, reader.getFieldNumber());
 | |
|       assertEquals(400, reader.readInt32());
 | |
| 
 | |
|       reader.nextField();
 | |
|       assertEquals(5, reader.getFieldNumber());
 | |
|       assertEquals(500, reader.readInt32());
 | |
| 
 | |
|       assertEquals(false, reader.nextField());
 | |
|     };
 | |
| 
 | |
|     reader.registerReadCallback('readCallback', readCallback);
 | |
| 
 | |
|     // Read the container message.
 | |
|     reader.nextField();
 | |
|     assertEquals(1, reader.getFieldNumber());
 | |
|     assertEquals(100, reader.readInt32());
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(2, reader.getFieldNumber());
 | |
|     reader.readMessage(dummyMessage, function() {
 | |
|       // Decode the embedded message using the registered callback.
 | |
|       reader.runReadCallback('readCallback');
 | |
|     });
 | |
| 
 | |
|     reader.nextField();
 | |
|     assertEquals(7, reader.getFieldNumber());
 | |
|     assertEquals(700, reader.readInt32());
 | |
| 
 | |
|     assertEquals(false, reader.nextField());
 | |
|   });
 | |
| });
 |