• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * @fileoverview Tests for reader.js.
3 */
4goog.module('protobuf.binary.ReaderTest');
5
6goog.setTestOnly();
7
8// Note to the reader:
9// Since the reader behavior changes with the checking level some of the
10// tests in this file have to know which checking level is enable to make
11// correct assertions.
12const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
13const ByteString = goog.require('protobuf.ByteString');
14const reader = goog.require('protobuf.binary.reader');
15const {CHECK_CRITICAL_STATE} = goog.require('protobuf.internal.checks');
16const {createBufferDecoder} = goog.require('protobuf.binary.bufferDecoderHelper');
17const {encode} = goog.require('protobuf.binary.textencoding');
18const {getBoolPairs} = goog.require('protobuf.binary.boolTestPairs');
19const {getDoublePairs} = goog.require('protobuf.binary.doubleTestPairs');
20const {getFixed32Pairs} = goog.require('protobuf.binary.fixed32TestPairs');
21const {getFloatPairs} = goog.require('protobuf.binary.floatTestPairs');
22const {getInt32Pairs} = goog.require('protobuf.binary.int32TestPairs');
23const {getInt64Pairs} = goog.require('protobuf.binary.int64TestPairs');
24const {getPackedBoolPairs} = goog.require('protobuf.binary.packedBoolTestPairs');
25const {getPackedDoublePairs} = goog.require('protobuf.binary.packedDoubleTestPairs');
26const {getPackedFixed32Pairs} = goog.require('protobuf.binary.packedFixed32TestPairs');
27const {getPackedFloatPairs} = goog.require('protobuf.binary.packedFloatTestPairs');
28const {getPackedInt32Pairs} = goog.require('protobuf.binary.packedInt32TestPairs');
29const {getPackedInt64Pairs} = goog.require('protobuf.binary.packedInt64TestPairs');
30const {getPackedSfixed32Pairs} = goog.require('protobuf.binary.packedSfixed32TestPairs');
31const {getPackedSfixed64Pairs} = goog.require('protobuf.binary.packedSfixed64TestPairs');
32const {getPackedSint32Pairs} = goog.require('protobuf.binary.packedSint32TestPairs');
33const {getPackedSint64Pairs} = goog.require('protobuf.binary.packedSint64TestPairs');
34const {getPackedUint32Pairs} = goog.require('protobuf.binary.packedUint32TestPairs');
35const {getSfixed32Pairs} = goog.require('protobuf.binary.sfixed32TestPairs');
36const {getSfixed64Pairs} = goog.require('protobuf.binary.sfixed64TestPairs');
37const {getSint32Pairs} = goog.require('protobuf.binary.sint32TestPairs');
38const {getSint64Pairs} = goog.require('protobuf.binary.sint64TestPairs');
39const {getUint32Pairs} = goog.require('protobuf.binary.uint32TestPairs');
40
41/******************************************************************************
42 *                        Optional FUNCTIONS
43 ******************************************************************************/
44
45describe('Read bool does', () => {
46  for (const pair of getBoolPairs()) {
47    it(`decode ${pair.name}`, () => {
48      if (pair.error && CHECK_CRITICAL_STATE) {
49        expect(() => reader.readBool(pair.bufferDecoder, 0)).toThrow();
50      } else {
51        const d = reader.readBool(
52            pair.bufferDecoder, pair.bufferDecoder.startIndex());
53        expect(d).toEqual(pair.boolValue);
54      }
55    });
56  }
57});
58
59describe('readBytes does', () => {
60  it('throw exception if data is too short', () => {
61    const bufferDecoder = createBufferDecoder();
62    expect(() => reader.readBytes(bufferDecoder, 0)).toThrow();
63  });
64
65  it('read bytes by index', () => {
66    const bufferDecoder = createBufferDecoder(3, 1, 2, 3);
67    const byteString = reader.readBytes(bufferDecoder, 0);
68    expect(ByteString.fromArrayBuffer(new Uint8Array([1, 2, 3]).buffer))
69        .toEqual(byteString);
70  });
71});
72
73describe('readDouble does', () => {
74  it('throw exception if data is too short', () => {
75    const bufferDecoder = createBufferDecoder();
76    expect(() => reader.readDouble(bufferDecoder, 0)).toThrow();
77  });
78
79  for (const pair of getDoublePairs()) {
80    it(`decode ${pair.name}`, () => {
81      const d = reader.readDouble(pair.bufferDecoder, 0);
82      expect(d).toEqual(pair.doubleValue);
83    });
84  }
85});
86
87describe('readFixed32 does', () => {
88  it('throw exception if data is too short', () => {
89    const bufferDecoder = createBufferDecoder();
90    expect(() => reader.readFixed32(bufferDecoder, 0)).toThrow();
91  });
92
93  for (const pair of getFixed32Pairs()) {
94    it(`decode ${pair.name}`, () => {
95      const d = reader.readFixed32(pair.bufferDecoder, 0);
96      expect(d).toEqual(pair.intValue);
97    });
98  }
99});
100
101describe('readFloat does', () => {
102  it('throw exception if data is too short', () => {
103    const bufferDecoder = createBufferDecoder();
104    expect(() => reader.readFloat(bufferDecoder, 0)).toThrow();
105  });
106
107  for (const pair of getFloatPairs()) {
108    it(`decode ${pair.name}`, () => {
109      const d = reader.readFloat(pair.bufferDecoder, 0);
110      expect(d).toEqual(Math.fround(pair.floatValue));
111    });
112  }
113});
114
115describe('readInt32 does', () => {
116  it('throw exception if data is too short', () => {
117    const bufferDecoder = createBufferDecoder(0x80);
118    expect(() => reader.readInt32(bufferDecoder, 0)).toThrow();
119  });
120
121  for (const pair of getInt32Pairs()) {
122    it(`decode ${pair.name}`, () => {
123      if (pair.error && CHECK_CRITICAL_STATE) {
124        expect(() => reader.readInt32(pair.bufferDecoder, 0)).toThrow();
125      } else {
126        const d = reader.readInt32(pair.bufferDecoder, 0);
127        expect(d).toEqual(pair.intValue);
128      }
129    });
130  }
131});
132
133describe('readSfixed32 does', () => {
134  it('throw exception if data is too short', () => {
135    const bufferDecoder = createBufferDecoder(0x80);
136    expect(() => reader.readSfixed32(bufferDecoder, 0)).toThrow();
137  });
138
139  for (const pair of getSfixed32Pairs()) {
140    it(`decode ${pair.name}`, () => {
141      const d = reader.readSfixed32(pair.bufferDecoder, 0);
142      expect(d).toEqual(pair.intValue);
143    });
144  }
145});
146
147describe('readSfixed64 does', () => {
148  it('throw exception if data is too short', () => {
149    const bufferDecoder = createBufferDecoder(0x80);
150    expect(() => reader.readSfixed64(bufferDecoder, 0)).toThrow();
151  });
152
153  for (const pair of getSfixed64Pairs()) {
154    it(`decode ${pair.name}`, () => {
155      const d = reader.readSfixed64(pair.bufferDecoder, 0);
156      expect(d).toEqual(pair.longValue);
157    });
158  }
159});
160
161describe('readSint32 does', () => {
162  it('throw exception if data is too short', () => {
163    const bufferDecoder = createBufferDecoder(0x80);
164    expect(() => reader.readSint32(bufferDecoder, 0)).toThrow();
165  });
166
167  for (const pair of getSint32Pairs()) {
168    it(`decode ${pair.name}`, () => {
169      if (pair.error && CHECK_CRITICAL_STATE) {
170        expect(() => reader.readSint32(pair.bufferDecoder, 0)).toThrow();
171      } else {
172        const d = reader.readSint32(pair.bufferDecoder, 0);
173        expect(d).toEqual(pair.intValue);
174      }
175    });
176  }
177});
178
179describe('readInt64 does', () => {
180  it('throw exception if data is too short', () => {
181    const bufferDecoder = createBufferDecoder(0x80);
182    expect(() => reader.readInt64(bufferDecoder, 0)).toThrow();
183  });
184
185  for (const pair of getInt64Pairs()) {
186    it(`decode ${pair.name}`, () => {
187      if (pair.error && CHECK_CRITICAL_STATE) {
188        expect(() => reader.readInt64(pair.bufferDecoder, 0)).toThrow();
189      } else {
190        const d = reader.readInt64(pair.bufferDecoder, 0);
191        expect(d).toEqual(pair.longValue);
192      }
193    });
194  }
195});
196
197describe('readSint64 does', () => {
198  it('throw exception if data is too short', () => {
199    const bufferDecoder = createBufferDecoder(0x80);
200    expect(() => reader.readSint64(bufferDecoder, 0)).toThrow();
201  });
202
203  for (const pair of getSint64Pairs()) {
204    it(`decode ${pair.name}`, () => {
205      if (pair.error && CHECK_CRITICAL_STATE) {
206        expect(() => reader.readSint64(pair.bufferDecoder, 0)).toThrow();
207      } else {
208        const d = reader.readSint64(pair.bufferDecoder, 0);
209        expect(d).toEqual(pair.longValue);
210      }
211    });
212  }
213});
214
215describe('readUint32 does', () => {
216  it('throw exception if data is too short', () => {
217    const bufferDecoder = createBufferDecoder(0x80);
218    expect(() => reader.readUint32(bufferDecoder, 0)).toThrow();
219  });
220
221  for (const pair of getUint32Pairs()) {
222    if (!pair.skip_reader) {
223      it(`decode ${pair.name}`, () => {
224        if (pair.error && CHECK_CRITICAL_STATE) {
225          expect(() => reader.readUint32(pair.bufferDecoder, 0)).toThrow();
226        } else {
227          const d = reader.readUint32(pair.bufferDecoder, 0);
228          expect(d).toEqual(pair.intValue);
229        }
230      });
231    }
232  }
233});
234
235/**
236 *
237 * @param {string} s
238 * @return {!Uint8Array}
239 */
240function encodeString(s) {
241  if (typeof TextEncoder !== 'undefined') {
242    const textEncoder = new TextEncoder('utf-8');
243    return textEncoder.encode(s);
244  } else {
245    return encode(s);
246  }
247}
248
249/** @param {string} s */
250function expectEncodedStringToMatch(s) {
251  const array = encodeString(s);
252  const length = array.length;
253  if (length > 127) {
254    throw new Error('Test only works for strings shorter than 128');
255  }
256  const encodedArray = new Uint8Array(length + 1);
257  encodedArray[0] = length;
258  encodedArray.set(array, 1);
259  const bufferDecoder = BufferDecoder.fromArrayBuffer(encodedArray.buffer);
260  expect(reader.readString(bufferDecoder, 0)).toEqual(s);
261}
262
263describe('readString does', () => {
264  it('return empty string for zero length string', () => {
265    const s = reader.readString(createBufferDecoder(0x00), 0);
266    expect(s).toEqual('');
267  });
268
269  it('decode random strings', () => {
270    // 1 byte strings
271    expectEncodedStringToMatch('hello');
272    expectEncodedStringToMatch('HELLO1!');
273
274    // 2 byte String
275    expectEncodedStringToMatch('©');
276
277    // 3 byte string
278    expectEncodedStringToMatch('❄');
279
280    // 4 byte string
281    expectEncodedStringToMatch('��');
282  });
283
284  it('decode 1 byte strings', () => {
285    for (let i = 0; i < 0x80; i++) {
286      const s = String.fromCharCode(i);
287      expectEncodedStringToMatch(s);
288    }
289  });
290
291  it('decode 2 byte strings', () => {
292    for (let i = 0xC0; i < 0x7FF; i++) {
293      const s = String.fromCharCode(i);
294      expectEncodedStringToMatch(s);
295    }
296  });
297
298  it('decode 3 byte strings', () => {
299    for (let i = 0x7FF; i < 0x8FFF; i++) {
300      const s = String.fromCharCode(i);
301      expectEncodedStringToMatch(s);
302    }
303  });
304
305  it('throw exception on invalid bytes', () => {
306    // This test will only succeed with the native TextDecoder since
307    // our polyfill does not do any validation. IE10 and IE11 don't support
308    // TextDecoder.
309    // TODO: Remove this check once we no longer need to support IE
310    if (typeof TextDecoder !== 'undefined') {
311      expect(
312          () => reader.readString(
313              createBufferDecoder(0x01, /* invalid utf data point*/ 0xFF), 0))
314          .toThrow();
315    }
316  });
317
318  it('throw exception if data is too short', () => {
319    const array = createBufferDecoder(0x02, '?'.charCodeAt(0));
320    expect(() => reader.readString(array, 0)).toThrow();
321  });
322});
323
324/******************************************************************************
325 *                        REPEATED FUNCTIONS
326 ******************************************************************************/
327
328describe('readPackedBool does', () => {
329  for (const pair of getPackedBoolPairs()) {
330    it(`decode ${pair.name}`, () => {
331      const d = reader.readPackedBool(pair.bufferDecoder, 0);
332      expect(d).toEqual(pair.boolValues);
333    });
334  }
335});
336
337describe('readPackedDouble does', () => {
338  for (const pair of getPackedDoublePairs()) {
339    it(`decode ${pair.name}`, () => {
340      const d = reader.readPackedDouble(pair.bufferDecoder, 0);
341      expect(d).toEqual(pair.doubleValues);
342    });
343  }
344});
345
346describe('readPackedFixed32 does', () => {
347  for (const pair of getPackedFixed32Pairs()) {
348    it(`decode ${pair.name}`, () => {
349      const d = reader.readPackedFixed32(pair.bufferDecoder, 0);
350      expect(d).toEqual(pair.fixed32Values);
351    });
352  }
353});
354
355describe('readPackedFloat does', () => {
356  for (const pair of getPackedFloatPairs()) {
357    it(`decode ${pair.name}`, () => {
358      const d = reader.readPackedFloat(pair.bufferDecoder, 0);
359      expect(d).toEqual(pair.floatValues);
360    });
361  }
362});
363
364describe('readPackedInt32 does', () => {
365  for (const pair of getPackedInt32Pairs()) {
366    it(`decode ${pair.name}`, () => {
367      const d = reader.readPackedInt32(pair.bufferDecoder, 0);
368      expect(d).toEqual(pair.int32Values);
369    });
370  }
371});
372
373describe('readPackedInt64 does', () => {
374  for (const pair of getPackedInt64Pairs()) {
375    it(`decode ${pair.name}`, () => {
376      const d = reader.readPackedInt64(pair.bufferDecoder, 0);
377      expect(d).toEqual(pair.int64Values);
378    });
379  }
380});
381
382describe('readPackedSfixed32 does', () => {
383  for (const pair of getPackedSfixed32Pairs()) {
384    it(`decode ${pair.name}`, () => {
385      const d = reader.readPackedSfixed32(pair.bufferDecoder, 0);
386      expect(d).toEqual(pair.sfixed32Values);
387    });
388  }
389});
390
391describe('readPackedSfixed64 does', () => {
392  for (const pair of getPackedSfixed64Pairs()) {
393    it(`decode ${pair.name}`, () => {
394      const d = reader.readPackedSfixed64(pair.bufferDecoder, 0);
395      expect(d).toEqual(pair.sfixed64Values);
396    });
397  }
398});
399
400describe('readPackedSint32 does', () => {
401  for (const pair of getPackedSint32Pairs()) {
402    it(`decode ${pair.name}`, () => {
403      const d = reader.readPackedSint32(pair.bufferDecoder, 0);
404      expect(d).toEqual(pair.sint32Values);
405    });
406  }
407});
408
409describe('readPackedSint64 does', () => {
410  for (const pair of getPackedSint64Pairs()) {
411    it(`decode ${pair.name}`, () => {
412      const d = reader.readPackedSint64(pair.bufferDecoder, 0);
413      expect(d).toEqual(pair.sint64Values);
414    });
415  }
416});
417
418describe('readPackedUint32 does', () => {
419  for (const pair of getPackedUint32Pairs()) {
420    it(`decode ${pair.name}`, () => {
421      const d = reader.readPackedUint32(pair.bufferDecoder, 0);
422      expect(d).toEqual(pair.uint32Values);
423    });
424  }
425});
426