h1-mod/deps/protobuf/js/binary/reader_test.js
2024-03-07 00:54:32 -05:00

993 lines
31 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');
goog.require('jspb.utils');
goog.requireType('jspb.BinaryMessage');
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 reading 64-bit integers as split values.
*/
it('handles split 64 fields', function() {
var writer = new jspb.BinaryWriter();
writer.writeInt64String(1, '4294967296');
writer.writeSfixed64String(2, '4294967298');
writer.writeInt64String(3, '3'); // 3 is the zig-zag encoding of -2.
var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
function rejoin(lowBits, highBits) {
return highBits * 2 ** 32 + (lowBits >>> 0);
}
reader.nextField();
expect(reader.getFieldNumber()).toEqual(1);
expect(reader.readSplitVarint64(rejoin)).toEqual(0x100000000);
reader.nextField();
expect(reader.getFieldNumber()).toEqual(2);
expect(reader.readSplitFixed64(rejoin)).toEqual(0x100000002);
reader.nextField();
expect(reader.getFieldNumber()).toEqual(3);
expect(reader.readSplitZigzagVarint64(rejoin)).toEqual(-2);
});
/**
* 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);
doTestSignedField_(
jspb.BinaryReader.prototype.readSintHash64,
jspb.BinaryWriter.prototype.writeSintHash64, 1, -Math.pow(2, 63),
Math.pow(2, 63) - 513, jspb.utils.numberToHash64);
});
/**
* 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());
});
});