928 lines
30 KiB
JavaScript
928 lines
30 KiB
JavaScript
|
/**
|
||
|
* @fileoverview Tests for writer.js.
|
||
|
*/
|
||
|
goog.module('protobuf.binary.WriterTest');
|
||
|
|
||
|
goog.setTestOnly();
|
||
|
|
||
|
// Note to the reader:
|
||
|
// Since the writer behavior changes with the checking level some of the tests
|
||
|
// in this file have to know which checking level is enable to make correct
|
||
|
// assertions.
|
||
|
const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
|
||
|
const ByteString = goog.require('protobuf.ByteString');
|
||
|
const WireType = goog.require('protobuf.binary.WireType');
|
||
|
const Writer = goog.require('protobuf.binary.Writer');
|
||
|
const {CHECK_BOUNDS, CHECK_TYPE, MAX_FIELD_NUMBER} = goog.require('protobuf.internal.checks');
|
||
|
const {arrayBufferSlice} = goog.require('protobuf.binary.typedArrays');
|
||
|
const {getDoublePairs} = goog.require('protobuf.binary.doubleTestPairs');
|
||
|
const {getFixed32Pairs} = goog.require('protobuf.binary.fixed32TestPairs');
|
||
|
const {getFloatPairs} = goog.require('protobuf.binary.floatTestPairs');
|
||
|
const {getInt32Pairs} = goog.require('protobuf.binary.int32TestPairs');
|
||
|
const {getInt64Pairs} = goog.require('protobuf.binary.int64TestPairs');
|
||
|
const {getPackedBoolPairs} = goog.require('protobuf.binary.packedBoolTestPairs');
|
||
|
const {getPackedDoublePairs} = goog.require('protobuf.binary.packedDoubleTestPairs');
|
||
|
const {getPackedFixed32Pairs} = goog.require('protobuf.binary.packedFixed32TestPairs');
|
||
|
const {getPackedFloatPairs} = goog.require('protobuf.binary.packedFloatTestPairs');
|
||
|
const {getPackedInt32Pairs} = goog.require('protobuf.binary.packedInt32TestPairs');
|
||
|
const {getPackedInt64Pairs} = goog.require('protobuf.binary.packedInt64TestPairs');
|
||
|
const {getPackedSfixed32Pairs} = goog.require('protobuf.binary.packedSfixed32TestPairs');
|
||
|
const {getPackedSfixed64Pairs} = goog.require('protobuf.binary.packedSfixed64TestPairs');
|
||
|
const {getPackedSint32Pairs} = goog.require('protobuf.binary.packedSint32TestPairs');
|
||
|
const {getPackedSint64Pairs} = goog.require('protobuf.binary.packedSint64TestPairs');
|
||
|
const {getPackedUint32Pairs} = goog.require('protobuf.binary.packedUint32TestPairs');
|
||
|
const {getSfixed32Pairs} = goog.require('protobuf.binary.sfixed32TestPairs');
|
||
|
const {getSfixed64Pairs} = goog.require('protobuf.binary.sfixed64TestPairs');
|
||
|
const {getSint32Pairs} = goog.require('protobuf.binary.sint32TestPairs');
|
||
|
const {getSint64Pairs} = goog.require('protobuf.binary.sint64TestPairs');
|
||
|
const {getUint32Pairs} = goog.require('protobuf.binary.uint32TestPairs');
|
||
|
|
||
|
|
||
|
/**
|
||
|
* @param {...number} bytes
|
||
|
* @return {!ArrayBuffer}
|
||
|
*/
|
||
|
function createArrayBuffer(...bytes) {
|
||
|
return new Uint8Array(bytes).buffer;
|
||
|
}
|
||
|
|
||
|
/******************************************************************************
|
||
|
* OPTIONAL FUNCTIONS
|
||
|
******************************************************************************/
|
||
|
|
||
|
describe('Writer does', () => {
|
||
|
it('return an empty ArrayBuffer when nothing is encoded', () => {
|
||
|
const writer = new Writer();
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
it('encode tag', () => {
|
||
|
const writer = new Writer();
|
||
|
writer.writeTag(1, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0x08));
|
||
|
|
||
|
writer.writeTag(0x0FFFFFFF, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0x7));
|
||
|
|
||
|
writer.writeTag(0x10000000, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0x80, 0x80, 0x80, 0x80, 0x08));
|
||
|
|
||
|
writer.writeTag(0x1FFFFFFF, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0x0F));
|
||
|
});
|
||
|
|
||
|
it('reset after calling getAndResetResultBuffer', () => {
|
||
|
const writer = new Writer();
|
||
|
writer.writeTag(1, WireType.VARINT);
|
||
|
writer.getAndResetResultBuffer();
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
it('fail when field number is too large for writeTag', () => {
|
||
|
const writer = new Writer();
|
||
|
if (CHECK_TYPE) {
|
||
|
expect(() => writer.writeTag(MAX_FIELD_NUMBER + 1, WireType.VARINT))
|
||
|
.toThrowError('Field number is out of range: 536870912');
|
||
|
} else {
|
||
|
// Note in unchecked mode we produce invalid output for invalid inputs.
|
||
|
// This test just documents our behavior in those cases.
|
||
|
// These values might change at any point and are not considered
|
||
|
// what the implementation should be doing here.
|
||
|
writer.writeTag(MAX_FIELD_NUMBER + 1, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('fail when field number is negative for writeTag', () => {
|
||
|
const writer = new Writer();
|
||
|
if (CHECK_TYPE) {
|
||
|
expect(() => writer.writeTag(-1, WireType.VARINT))
|
||
|
.toThrowError('Field number is out of range: -1');
|
||
|
} else {
|
||
|
// Note in unchecked mode we produce invalid output for invalid inputs.
|
||
|
// This test just documents our behavior in those cases.
|
||
|
// These values might change at any point and are not considered
|
||
|
// what the implementation should be doing here.
|
||
|
writer.writeTag(-1, WireType.VARINT);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0xF));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('fail when wire type is invalid for writeTag', () => {
|
||
|
const writer = new Writer();
|
||
|
if (CHECK_TYPE) {
|
||
|
expect(() => writer.writeTag(1, /** @type {!WireType} */ (0x08)))
|
||
|
.toThrowError('Invalid wire type: 8');
|
||
|
} else {
|
||
|
// Note in unchecked mode we produce invalid output for invalid inputs.
|
||
|
// This test just documents our behavior in those cases.
|
||
|
// These values might change at any point and are not considered
|
||
|
// what the implementation should be doing here.
|
||
|
writer.writeTag(1, /** @type {!WireType} */ (0x08));
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0x08));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('encode singular boolean value', () => {
|
||
|
const writer = new Writer();
|
||
|
writer.writeBool(1, true);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0x08, 0x01));
|
||
|
});
|
||
|
|
||
|
it('encode length delimited', () => {
|
||
|
const writer = new Writer();
|
||
|
writer.writeDelimited(1, createArrayBuffer(0x01, 0x02));
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(0x0A, 0x02, 0x01, 0x02));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeBufferDecoder does', () => {
|
||
|
it('encode BufferDecoder containing a varint value', () => {
|
||
|
const writer = new Writer();
|
||
|
const expected = createArrayBuffer(
|
||
|
0x08, /* varint start= */ 0xFF, /* varint end= */ 0x01, 0x08, 0x01);
|
||
|
writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(expected), 1, WireType.VARINT, 1);
|
||
|
const result = writer.getAndResetResultBuffer();
|
||
|
expect(result).toEqual(arrayBufferSlice(expected, 1, 3));
|
||
|
});
|
||
|
|
||
|
it('encode BufferDecoder containing a fixed64 value', () => {
|
||
|
const writer = new Writer();
|
||
|
const expected = createArrayBuffer(
|
||
|
0x09, /* fixed64 start= */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||
|
/* fixed64 end= */ 0x08, 0x08, 0x01);
|
||
|
writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(expected), 1, WireType.FIXED64, 1);
|
||
|
const result = writer.getAndResetResultBuffer();
|
||
|
expect(result).toEqual(arrayBufferSlice(expected, 1, 9));
|
||
|
});
|
||
|
|
||
|
it('encode BufferDecoder containing a length delimited value', () => {
|
||
|
const writer = new Writer();
|
||
|
const expected = createArrayBuffer(
|
||
|
0xA, /* length= */ 0x03, /* data start= */ 0x01, 0x02,
|
||
|
/* data end= */ 0x03, 0x08, 0x01);
|
||
|
writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(expected), 1, WireType.DELIMITED, 1);
|
||
|
const result = writer.getAndResetResultBuffer();
|
||
|
expect(result).toEqual(arrayBufferSlice(expected, 1, 5));
|
||
|
});
|
||
|
|
||
|
it('encode BufferDecoder containing a group', () => {
|
||
|
const writer = new Writer();
|
||
|
const expected = createArrayBuffer(
|
||
|
0xB, /* group start= */ 0x08, 0x01, /* nested group start= */ 0x0B,
|
||
|
/* nested group end= */ 0x0C, /* group end= */ 0x0C, 0x08, 0x01);
|
||
|
writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(expected), 1, WireType.START_GROUP, 1);
|
||
|
const result = writer.getAndResetResultBuffer();
|
||
|
expect(result).toEqual(arrayBufferSlice(expected, 1, 6));
|
||
|
});
|
||
|
|
||
|
it('encode BufferDecoder containing a fixed32 value', () => {
|
||
|
const writer = new Writer();
|
||
|
const expected = createArrayBuffer(
|
||
|
0x09, /* fixed64 start= */ 0x01, 0x02, 0x03, /* fixed64 end= */ 0x04,
|
||
|
0x08, 0x01);
|
||
|
writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(expected), 1, WireType.FIXED32, 1);
|
||
|
const result = writer.getAndResetResultBuffer();
|
||
|
expect(result).toEqual(arrayBufferSlice(expected, 1, 5));
|
||
|
});
|
||
|
|
||
|
it('fail when encoding out of bound data', () => {
|
||
|
const writer = new Writer();
|
||
|
const buffer = createArrayBuffer(0x4, 0x0, 0x1, 0x2, 0x3);
|
||
|
const subBuffer = arrayBufferSlice(buffer, 0, 2);
|
||
|
expect(
|
||
|
() => writer.writeBufferDecoder(
|
||
|
BufferDecoder.fromArrayBuffer(subBuffer), 0, WireType.DELIMITED, 1))
|
||
|
.toThrow();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeBytes does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encodes empty ByteString', () => {
|
||
|
writer.writeBytes(1, ByteString.EMPTY);
|
||
|
const buffer = writer.getAndResetResultBuffer();
|
||
|
expect(buffer.byteLength).toBe(2);
|
||
|
});
|
||
|
|
||
|
it('encodes empty array', () => {
|
||
|
writer.writeBytes(1, ByteString.fromArrayBuffer(new ArrayBuffer(0)));
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
1 << 3 | 0x02, // tag (fieldnumber << 3 | (length delimited))
|
||
|
0, // length of the bytes
|
||
|
));
|
||
|
});
|
||
|
|
||
|
it('encodes ByteString', () => {
|
||
|
const array = createArrayBuffer(1, 2, 3);
|
||
|
writer.writeBytes(1, ByteString.fromArrayBuffer(array));
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
1 << 3 | 0x02, // tag (fieldnumber << 3 | (length delimited))
|
||
|
3, // length of the bytes
|
||
|
1,
|
||
|
2,
|
||
|
3,
|
||
|
));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeDouble does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getDoublePairs()) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeDouble(1, pair.doubleValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(9);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x09);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, 9))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* NaN may have different value in different browsers. Thus, we need to make
|
||
|
* the test lenient.
|
||
|
*/
|
||
|
it('encode NaN', () => {
|
||
|
writer.writeDouble(1, NaN);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(9);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x09);
|
||
|
// Encoded values are stored right after the tag
|
||
|
const float64 = new DataView(buffer.buffer);
|
||
|
expect(float64.getFloat64(1, true)).toBeNaN();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeFixed32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getFixed32Pairs()) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeFixed32(1, pair.intValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(5);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0D);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeFloat does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getFloatPairs()) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeFloat(1, pair.floatValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(5);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0D);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* NaN may have different value in different browsers. Thus, we need to make
|
||
|
* the test lenient.
|
||
|
*/
|
||
|
it('encode NaN', () => {
|
||
|
writer.writeFloat(1, NaN);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(5);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0D);
|
||
|
// Encoded values are stored right after the tag
|
||
|
const float32 = new DataView(buffer.buffer);
|
||
|
expect(float32.getFloat32(1, true)).toBeNaN();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeInt32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getInt32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeInt32(1, pair.intValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x08);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeSfixed32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedSfixed32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getSfixed32Pairs()) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeSfixed32(1, pair.intValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(5);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0D);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeSfixed64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSfixed64Pairs()) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeSfixed64(1, pair.longValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
expect(buffer.length).toBe(9);
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x09);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, 9)).toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeSint32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSint32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeSint32(1, pair.intValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x08);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeSint64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSint64Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeSint64(1, pair.longValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x08);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeInt64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getInt64Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeInt64(1, pair.longValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x08);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeUint32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
for (const pair of getUint32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writeUint32(1, pair.intValue);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x08);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeString does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty string', () => {
|
||
|
writer.writeString(1, '');
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
1 << 3 | 0x02, // tag (fieldnumber << 3 | (length delimited))
|
||
|
0, // length of the string
|
||
|
));
|
||
|
});
|
||
|
|
||
|
it('encode simple string', () => {
|
||
|
writer.writeString(1, 'hello');
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
1 << 3 | 0x02, // tag (fieldnumber << 3 | (length delimited))
|
||
|
5, // length of the string
|
||
|
'h'.charCodeAt(0),
|
||
|
'e'.charCodeAt(0),
|
||
|
'l'.charCodeAt(0),
|
||
|
'l'.charCodeAt(0),
|
||
|
'o'.charCodeAt(0),
|
||
|
));
|
||
|
});
|
||
|
|
||
|
it('throw for invalid fieldnumber', () => {
|
||
|
if (CHECK_BOUNDS) {
|
||
|
expect(() => writer.writeString(-1, 'a'))
|
||
|
.toThrowError('Field number is out of range: -1');
|
||
|
} else {
|
||
|
writer.writeString(-1, 'a');
|
||
|
expect(new Uint8Array(writer.getAndResetResultBuffer()))
|
||
|
.toEqual(new Uint8Array(createArrayBuffer(
|
||
|
-6, // invalid tag
|
||
|
0xff,
|
||
|
0xff,
|
||
|
0xff,
|
||
|
0x0f,
|
||
|
1, // string length
|
||
|
'a'.charCodeAt(0),
|
||
|
)));
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('throw for null string value', () => {
|
||
|
expect(
|
||
|
() => writer.writeString(
|
||
|
1, /** @type {string} */ (/** @type {*} */ (null))))
|
||
|
.toThrow();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
|
||
|
/******************************************************************************
|
||
|
* REPEATED FUNCTIONS
|
||
|
******************************************************************************/
|
||
|
|
||
|
describe('Writer.writePackedBool does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedBool(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedBoolPairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedBool(1, pair.boolValues);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeRepeatedBool does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writeRepeatedBool(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
it('encode repeated unpacked boolean values', () => {
|
||
|
const writer = new Writer();
|
||
|
writer.writeRepeatedBool(1, [true, false]);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
1 << 3 | 0x00, // tag (fieldnumber << 3 | (varint))
|
||
|
0x01, // value[0]
|
||
|
1 << 3 | 0x00, // tag (fieldnumber << 3 | (varint))
|
||
|
0x00, // value[1]
|
||
|
));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedDouble does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedDouble(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedDoublePairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedDouble(1, pair.doubleValues);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedFixed32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedFixed32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedFixed32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedFixed32(1, pair.fixed32Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedFloat does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedFloat(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedFloatPairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedFloat(1, pair.floatValues);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedInt32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedInt32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedInt32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedInt32(1, pair.int32Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedInt64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedInt64(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedInt64Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedInt64(1, pair.int64Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedSfixed32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedSfixed32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedSfixed32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedSfixed32(1, pair.sfixed32Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedSfixed64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedSfixed64(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedSfixed64Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedSfixed64(1, pair.sfixed64Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedSint32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedSint32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedSint32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedSint32(1, pair.sint32Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedSint64 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedSint64(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedSint64Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedSint64(1, pair.sint64Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writePackedUint32 does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writePackedUint32(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
for (const pair of getPackedUint32Pairs()) {
|
||
|
if (!pair.skip_writer) {
|
||
|
it(`encode ${pair.name}`, () => {
|
||
|
writer.writePackedUint32(1, pair.uint32Values);
|
||
|
const buffer = new Uint8Array(writer.getAndResetResultBuffer());
|
||
|
// ensure we have a correct tag
|
||
|
expect(buffer[0]).toEqual(0x0A);
|
||
|
// Encoded values are stored right after the tag
|
||
|
expect(buffer.subarray(1, buffer.length))
|
||
|
.toEqual(pair.bufferDecoder.asUint8Array());
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeRepeatedBytes does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writeRepeatedBytes(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
it('encode single value', () => {
|
||
|
const value = createArrayBuffer(0x61);
|
||
|
writer.writeRepeatedBytes(1, [ByteString.fromArrayBuffer(value)]);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x61, // a
|
||
|
));
|
||
|
});
|
||
|
|
||
|
it('encode multiple values', () => {
|
||
|
const value1 = createArrayBuffer(0x61);
|
||
|
const value2 = createArrayBuffer(0x62);
|
||
|
writer.writeRepeatedBytes(1, [
|
||
|
ByteString.fromArrayBuffer(value1),
|
||
|
ByteString.fromArrayBuffer(value2),
|
||
|
]);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x61, // a
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x62, // b
|
||
|
));
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('Writer.writeRepeatedString does', () => {
|
||
|
let writer;
|
||
|
beforeEach(() => {
|
||
|
writer = new Writer();
|
||
|
});
|
||
|
|
||
|
it('encode empty array', () => {
|
||
|
writer.writeRepeatedString(1, []);
|
||
|
expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
|
||
|
});
|
||
|
|
||
|
it('encode single value', () => {
|
||
|
writer.writeRepeatedString(1, ['a']);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x61, // a
|
||
|
));
|
||
|
});
|
||
|
|
||
|
it('encode multiple values', () => {
|
||
|
writer.writeRepeatedString(1, ['a', 'b']);
|
||
|
expect(writer.getAndResetResultBuffer())
|
||
|
.toEqual(createArrayBuffer(
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x61, // a
|
||
|
0x0A,
|
||
|
0x01,
|
||
|
0x62, // b
|
||
|
));
|
||
|
});
|
||
|
});
|