426 lines
14 KiB
JavaScript
426 lines
14 KiB
JavaScript
|
/**
|
||
|
* @fileoverview Tests for reader.js.
|
||
|
*/
|
||
|
goog.module('protobuf.binary.ReaderTest');
|
||
|
|
||
|
goog.setTestOnly();
|
||
|
|
||
|
// Note to the reader:
|
||
|
// Since the reader 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 reader = goog.require('protobuf.binary.reader');
|
||
|
const {CHECK_CRITICAL_STATE} = goog.require('protobuf.internal.checks');
|
||
|
const {createBufferDecoder} = goog.require('protobuf.binary.bufferDecoderHelper');
|
||
|
const {encode} = goog.require('protobuf.binary.textencoding');
|
||
|
const {getBoolPairs} = goog.require('protobuf.binary.boolTestPairs');
|
||
|
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');
|
||
|
|
||
|
/******************************************************************************
|
||
|
* Optional FUNCTIONS
|
||
|
******************************************************************************/
|
||
|
|
||
|
describe('Read bool does', () => {
|
||
|
for (const pair of getBoolPairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readBool(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readBool(
|
||
|
pair.bufferDecoder, pair.bufferDecoder.startIndex());
|
||
|
expect(d).toEqual(pair.boolValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readBytes does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder();
|
||
|
expect(() => reader.readBytes(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
it('read bytes by index', () => {
|
||
|
const bufferDecoder = createBufferDecoder(3, 1, 2, 3);
|
||
|
const byteString = reader.readBytes(bufferDecoder, 0);
|
||
|
expect(ByteString.fromArrayBuffer(new Uint8Array([1, 2, 3]).buffer))
|
||
|
.toEqual(byteString);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('readDouble does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder();
|
||
|
expect(() => reader.readDouble(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getDoublePairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readDouble(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.doubleValue);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readFixed32 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder();
|
||
|
expect(() => reader.readFixed32(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getFixed32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readFixed32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.intValue);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readFloat does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder();
|
||
|
expect(() => reader.readFloat(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getFloatPairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readFloat(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(Math.fround(pair.floatValue));
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readInt32 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readInt32(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getInt32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readInt32(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readInt32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.intValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readSfixed32 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readSfixed32(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSfixed32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readSfixed32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.intValue);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readSfixed64 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readSfixed64(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSfixed64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readSfixed64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.longValue);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readSint32 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readSint32(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSint32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readSint32(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readSint32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.intValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readInt64 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readInt64(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getInt64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readInt64(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readInt64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.longValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readSint64 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readSint64(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getSint64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readSint64(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readSint64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.longValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readUint32 does', () => {
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const bufferDecoder = createBufferDecoder(0x80);
|
||
|
expect(() => reader.readUint32(bufferDecoder, 0)).toThrow();
|
||
|
});
|
||
|
|
||
|
for (const pair of getUint32Pairs()) {
|
||
|
if (!pair.skip_reader) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
if (pair.error && CHECK_CRITICAL_STATE) {
|
||
|
expect(() => reader.readUint32(pair.bufferDecoder, 0)).toThrow();
|
||
|
} else {
|
||
|
const d = reader.readUint32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.intValue);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
});
|
||
|
|
||
|
/**
|
||
|
*
|
||
|
* @param {string} s
|
||
|
* @return {!Uint8Array}
|
||
|
*/
|
||
|
function encodeString(s) {
|
||
|
if (typeof TextEncoder !== 'undefined') {
|
||
|
const textEncoder = new TextEncoder('utf-8');
|
||
|
return textEncoder.encode(s);
|
||
|
} else {
|
||
|
return encode(s);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/** @param {string} s */
|
||
|
function expectEncodedStringToMatch(s) {
|
||
|
const array = encodeString(s);
|
||
|
const length = array.length;
|
||
|
if (length > 127) {
|
||
|
throw new Error('Test only works for strings shorter than 128');
|
||
|
}
|
||
|
const encodedArray = new Uint8Array(length + 1);
|
||
|
encodedArray[0] = length;
|
||
|
encodedArray.set(array, 1);
|
||
|
const bufferDecoder = BufferDecoder.fromArrayBuffer(encodedArray.buffer);
|
||
|
expect(reader.readString(bufferDecoder, 0)).toEqual(s);
|
||
|
}
|
||
|
|
||
|
describe('readString does', () => {
|
||
|
it('return empty string for zero length string', () => {
|
||
|
const s = reader.readString(createBufferDecoder(0x00), 0);
|
||
|
expect(s).toEqual('');
|
||
|
});
|
||
|
|
||
|
it('decode random strings', () => {
|
||
|
// 1 byte strings
|
||
|
expectEncodedStringToMatch('hello');
|
||
|
expectEncodedStringToMatch('HELLO1!');
|
||
|
|
||
|
// 2 byte String
|
||
|
expectEncodedStringToMatch('©');
|
||
|
|
||
|
// 3 byte string
|
||
|
expectEncodedStringToMatch('❄');
|
||
|
|
||
|
// 4 byte string
|
||
|
expectEncodedStringToMatch('😁');
|
||
|
});
|
||
|
|
||
|
it('decode 1 byte strings', () => {
|
||
|
for (let i = 0; i < 0x80; i++) {
|
||
|
const s = String.fromCharCode(i);
|
||
|
expectEncodedStringToMatch(s);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('decode 2 byte strings', () => {
|
||
|
for (let i = 0xC0; i < 0x7FF; i++) {
|
||
|
const s = String.fromCharCode(i);
|
||
|
expectEncodedStringToMatch(s);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('decode 3 byte strings', () => {
|
||
|
for (let i = 0x7FF; i < 0x8FFF; i++) {
|
||
|
const s = String.fromCharCode(i);
|
||
|
expectEncodedStringToMatch(s);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('throw exception on invalid bytes', () => {
|
||
|
// This test will only succeed with the native TextDecoder since
|
||
|
// our polyfill does not do any validation. IE10 and IE11 don't support
|
||
|
// TextDecoder.
|
||
|
// TODO: Remove this check once we no longer need to support IE
|
||
|
if (typeof TextDecoder !== 'undefined') {
|
||
|
expect(
|
||
|
() => reader.readString(
|
||
|
createBufferDecoder(0x01, /* invalid utf data point*/ 0xFF), 0))
|
||
|
.toThrow();
|
||
|
}
|
||
|
});
|
||
|
|
||
|
it('throw exception if data is too short', () => {
|
||
|
const array = createBufferDecoder(0x02, '?'.charCodeAt(0));
|
||
|
expect(() => reader.readString(array, 0)).toThrow();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
/******************************************************************************
|
||
|
* REPEATED FUNCTIONS
|
||
|
******************************************************************************/
|
||
|
|
||
|
describe('readPackedBool does', () => {
|
||
|
for (const pair of getPackedBoolPairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedBool(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.boolValues);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedDouble does', () => {
|
||
|
for (const pair of getPackedDoublePairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedDouble(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.doubleValues);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedFixed32 does', () => {
|
||
|
for (const pair of getPackedFixed32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedFixed32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.fixed32Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedFloat does', () => {
|
||
|
for (const pair of getPackedFloatPairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedFloat(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.floatValues);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedInt32 does', () => {
|
||
|
for (const pair of getPackedInt32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedInt32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.int32Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedInt64 does', () => {
|
||
|
for (const pair of getPackedInt64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedInt64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.int64Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedSfixed32 does', () => {
|
||
|
for (const pair of getPackedSfixed32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedSfixed32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.sfixed32Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedSfixed64 does', () => {
|
||
|
for (const pair of getPackedSfixed64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedSfixed64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.sfixed64Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedSint32 does', () => {
|
||
|
for (const pair of getPackedSint32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedSint32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.sint32Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedSint64 does', () => {
|
||
|
for (const pair of getPackedSint64Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedSint64(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.sint64Values);
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
|
||
|
describe('readPackedUint32 does', () => {
|
||
|
for (const pair of getPackedUint32Pairs()) {
|
||
|
it(`decode ${pair.name}`, () => {
|
||
|
const d = reader.readPackedUint32(pair.bufferDecoder, 0);
|
||
|
expect(d).toEqual(pair.uint32Values);
|
||
|
});
|
||
|
}
|
||
|
});
|