• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/**
2 * @fileoverview Tests for writer.js.
3 */
4goog.module('protobuf.binary.WriterTest');
5
6goog.setTestOnly();
7
8// Note to the reader:
9// Since the writer behavior changes with the checking level some of the tests
10// in this file have to know which checking level is enable to make correct
11// assertions.
12const BufferDecoder = goog.require('protobuf.binary.BufferDecoder');
13const ByteString = goog.require('protobuf.ByteString');
14const WireType = goog.require('protobuf.binary.WireType');
15const Writer = goog.require('protobuf.binary.Writer');
16const {CHECK_BOUNDS, CHECK_TYPE, MAX_FIELD_NUMBER} = goog.require('protobuf.internal.checks');
17const {arrayBufferSlice} = goog.require('protobuf.binary.typedArrays');
18const {getDoublePairs} = goog.require('protobuf.binary.doubleTestPairs');
19const {getFixed32Pairs} = goog.require('protobuf.binary.fixed32TestPairs');
20const {getFloatPairs} = goog.require('protobuf.binary.floatTestPairs');
21const {getInt32Pairs} = goog.require('protobuf.binary.int32TestPairs');
22const {getInt64Pairs} = goog.require('protobuf.binary.int64TestPairs');
23const {getPackedBoolPairs} = goog.require('protobuf.binary.packedBoolTestPairs');
24const {getPackedDoublePairs} = goog.require('protobuf.binary.packedDoubleTestPairs');
25const {getPackedFixed32Pairs} = goog.require('protobuf.binary.packedFixed32TestPairs');
26const {getPackedFloatPairs} = goog.require('protobuf.binary.packedFloatTestPairs');
27const {getPackedInt32Pairs} = goog.require('protobuf.binary.packedInt32TestPairs');
28const {getPackedInt64Pairs} = goog.require('protobuf.binary.packedInt64TestPairs');
29const {getPackedSfixed32Pairs} = goog.require('protobuf.binary.packedSfixed32TestPairs');
30const {getPackedSfixed64Pairs} = goog.require('protobuf.binary.packedSfixed64TestPairs');
31const {getPackedSint32Pairs} = goog.require('protobuf.binary.packedSint32TestPairs');
32const {getPackedSint64Pairs} = goog.require('protobuf.binary.packedSint64TestPairs');
33const {getPackedUint32Pairs} = goog.require('protobuf.binary.packedUint32TestPairs');
34const {getSfixed32Pairs} = goog.require('protobuf.binary.sfixed32TestPairs');
35const {getSfixed64Pairs} = goog.require('protobuf.binary.sfixed64TestPairs');
36const {getSint32Pairs} = goog.require('protobuf.binary.sint32TestPairs');
37const {getSint64Pairs} = goog.require('protobuf.binary.sint64TestPairs');
38const {getUint32Pairs} = goog.require('protobuf.binary.uint32TestPairs');
39
40
41/**
42 * @param {...number} bytes
43 * @return {!ArrayBuffer}
44 */
45function createArrayBuffer(...bytes) {
46  return new Uint8Array(bytes).buffer;
47}
48
49/******************************************************************************
50 *                        OPTIONAL FUNCTIONS
51 ******************************************************************************/
52
53describe('Writer does', () => {
54  it('return an empty ArrayBuffer when nothing is encoded', () => {
55    const writer = new Writer();
56    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
57  });
58
59  it('encode tag', () => {
60    const writer = new Writer();
61    writer.writeTag(1, WireType.VARINT);
62    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0x08));
63
64    writer.writeTag(0x0FFFFFFF, WireType.VARINT);
65    expect(writer.getAndResetResultBuffer())
66        .toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0x7));
67
68    writer.writeTag(0x10000000, WireType.VARINT);
69    expect(writer.getAndResetResultBuffer())
70        .toEqual(createArrayBuffer(0x80, 0x80, 0x80, 0x80, 0x08));
71
72    writer.writeTag(0x1FFFFFFF, WireType.VARINT);
73    expect(writer.getAndResetResultBuffer())
74        .toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0x0F));
75  });
76
77  it('reset after calling getAndResetResultBuffer', () => {
78    const writer = new Writer();
79    writer.writeTag(1, WireType.VARINT);
80    writer.getAndResetResultBuffer();
81    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
82  });
83
84  it('fail when field number is too large for writeTag', () => {
85    const writer = new Writer();
86    if (CHECK_TYPE) {
87      expect(() => writer.writeTag(MAX_FIELD_NUMBER + 1, WireType.VARINT))
88          .toThrowError('Field number is out of range: 536870912');
89    } else {
90      // Note in unchecked mode we produce invalid output for invalid inputs.
91      // This test just documents our behavior in those cases.
92      // These values might change at any point and are not considered
93      // what the implementation should be doing here.
94      writer.writeTag(MAX_FIELD_NUMBER + 1, WireType.VARINT);
95      expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0));
96    }
97  });
98
99  it('fail when field number is negative for writeTag', () => {
100    const writer = new Writer();
101    if (CHECK_TYPE) {
102      expect(() => writer.writeTag(-1, WireType.VARINT))
103          .toThrowError('Field number is out of range: -1');
104    } else {
105      // Note in unchecked mode we produce invalid output for invalid inputs.
106      // This test just documents our behavior in those cases.
107      // These values might change at any point and are not considered
108      // what the implementation should be doing here.
109      writer.writeTag(-1, WireType.VARINT);
110      expect(writer.getAndResetResultBuffer())
111          .toEqual(createArrayBuffer(0xF8, 0xFF, 0xFF, 0xFF, 0xF));
112    }
113  });
114
115  it('fail when wire type is invalid for writeTag', () => {
116    const writer = new Writer();
117    if (CHECK_TYPE) {
118      expect(() => writer.writeTag(1, /** @type {!WireType} */ (0x08)))
119          .toThrowError('Invalid wire type: 8');
120    } else {
121      // Note in unchecked mode we produce invalid output for invalid inputs.
122      // This test just documents our behavior in those cases.
123      // These values might change at any point and are not considered
124      // what the implementation should be doing here.
125      writer.writeTag(1, /** @type {!WireType} */ (0x08));
126      expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer(0x08));
127    }
128  });
129
130  it('encode singular boolean value', () => {
131    const writer = new Writer();
132    writer.writeBool(1, true);
133    expect(writer.getAndResetResultBuffer())
134        .toEqual(createArrayBuffer(0x08, 0x01));
135  });
136
137  it('encode length delimited', () => {
138    const writer = new Writer();
139    writer.writeDelimited(1, createArrayBuffer(0x01, 0x02));
140    expect(writer.getAndResetResultBuffer())
141        .toEqual(createArrayBuffer(0x0A, 0x02, 0x01, 0x02));
142  });
143});
144
145describe('Writer.writeBufferDecoder does', () => {
146  it('encode BufferDecoder containing a varint value', () => {
147    const writer = new Writer();
148    const expected = createArrayBuffer(
149        0x08, /* varint start= */ 0xFF, /* varint end= */ 0x01, 0x08, 0x01);
150    writer.writeBufferDecoder(
151        BufferDecoder.fromArrayBuffer(expected), 1, WireType.VARINT, 1);
152    const result = writer.getAndResetResultBuffer();
153    expect(result).toEqual(arrayBufferSlice(expected, 1, 3));
154  });
155
156  it('encode BufferDecoder containing a fixed64 value', () => {
157    const writer = new Writer();
158    const expected = createArrayBuffer(
159        0x09, /* fixed64 start= */ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
160        /* fixed64 end= */ 0x08, 0x08, 0x01);
161    writer.writeBufferDecoder(
162        BufferDecoder.fromArrayBuffer(expected), 1, WireType.FIXED64, 1);
163    const result = writer.getAndResetResultBuffer();
164    expect(result).toEqual(arrayBufferSlice(expected, 1, 9));
165  });
166
167  it('encode BufferDecoder containing a length delimited value', () => {
168    const writer = new Writer();
169    const expected = createArrayBuffer(
170        0xA, /* length= */ 0x03, /* data start= */ 0x01, 0x02,
171        /* data end= */ 0x03, 0x08, 0x01);
172    writer.writeBufferDecoder(
173        BufferDecoder.fromArrayBuffer(expected), 1, WireType.DELIMITED, 1);
174    const result = writer.getAndResetResultBuffer();
175    expect(result).toEqual(arrayBufferSlice(expected, 1, 5));
176  });
177
178  it('encode BufferDecoder containing a group', () => {
179    const writer = new Writer();
180    const expected = createArrayBuffer(
181        0xB, /* group start= */ 0x08, 0x01, /* nested group start= */ 0x0B,
182        /* nested group end= */ 0x0C, /* group end= */ 0x0C, 0x08, 0x01);
183    writer.writeBufferDecoder(
184        BufferDecoder.fromArrayBuffer(expected), 1, WireType.START_GROUP, 1);
185    const result = writer.getAndResetResultBuffer();
186    expect(result).toEqual(arrayBufferSlice(expected, 1, 6));
187  });
188
189  it('encode BufferDecoder containing a fixed32 value', () => {
190    const writer = new Writer();
191    const expected = createArrayBuffer(
192        0x09, /* fixed64 start= */ 0x01, 0x02, 0x03, /* fixed64 end= */ 0x04,
193        0x08, 0x01);
194    writer.writeBufferDecoder(
195        BufferDecoder.fromArrayBuffer(expected), 1, WireType.FIXED32, 1);
196    const result = writer.getAndResetResultBuffer();
197    expect(result).toEqual(arrayBufferSlice(expected, 1, 5));
198  });
199
200  it('fail when encoding out of bound data', () => {
201    const writer = new Writer();
202    const buffer = createArrayBuffer(0x4, 0x0, 0x1, 0x2, 0x3);
203    const subBuffer = arrayBufferSlice(buffer, 0, 2);
204    expect(
205        () => writer.writeBufferDecoder(
206            BufferDecoder.fromArrayBuffer(subBuffer), 0, WireType.DELIMITED, 1))
207        .toThrow();
208  });
209});
210
211describe('Writer.writeBytes does', () => {
212  let writer;
213  beforeEach(() => {
214    writer = new Writer();
215  });
216
217  it('encodes empty ByteString', () => {
218    writer.writeBytes(1, ByteString.EMPTY);
219    const buffer = writer.getAndResetResultBuffer();
220    expect(buffer.byteLength).toBe(2);
221  });
222
223  it('encodes empty array', () => {
224    writer.writeBytes(1, ByteString.fromArrayBuffer(new ArrayBuffer(0)));
225    expect(writer.getAndResetResultBuffer())
226        .toEqual(createArrayBuffer(
227            1 << 3 | 0x02,  // tag (fieldnumber << 3 | (length delimited))
228            0,              // length of the bytes
229            ));
230  });
231
232  it('encodes ByteString', () => {
233    const array = createArrayBuffer(1, 2, 3);
234    writer.writeBytes(1, ByteString.fromArrayBuffer(array));
235    expect(writer.getAndResetResultBuffer())
236        .toEqual(createArrayBuffer(
237            1 << 3 | 0x02,  // tag (fieldnumber << 3 | (length delimited))
238            3,              // length of the bytes
239            1,
240            2,
241            3,
242            ));
243  });
244});
245
246describe('Writer.writeDouble does', () => {
247  let writer;
248  beforeEach(() => {
249    writer = new Writer();
250  });
251
252  for (const pair of getDoublePairs()) {
253    it(`encode ${pair.name}`, () => {
254        writer.writeDouble(1, pair.doubleValue);
255        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
256        expect(buffer.length).toBe(9);
257        // ensure we have a correct tag
258        expect(buffer[0]).toEqual(0x09);
259        // Encoded values are stored right after the tag
260        expect(buffer.subarray(1, 9))
261            .toEqual(pair.bufferDecoder.asUint8Array());
262    });
263  }
264
265  /**
266   * NaN may have different value in different browsers. Thus, we need to make
267   * the test lenient.
268   */
269  it('encode NaN', () => {
270    writer.writeDouble(1, NaN);
271    const buffer = new Uint8Array(writer.getAndResetResultBuffer());
272    expect(buffer.length).toBe(9);
273    // ensure we have a correct tag
274    expect(buffer[0]).toEqual(0x09);
275    // Encoded values are stored right after the tag
276    const float64 = new DataView(buffer.buffer);
277    expect(float64.getFloat64(1, true)).toBeNaN();
278  });
279});
280
281describe('Writer.writeFixed32 does', () => {
282  let writer;
283  beforeEach(() => {
284    writer = new Writer();
285  });
286
287  for (const pair of getFixed32Pairs()) {
288    it(`encode ${pair.name}`, () => {
289      writer.writeFixed32(1, pair.intValue);
290      const buffer = new Uint8Array(writer.getAndResetResultBuffer());
291      expect(buffer.length).toBe(5);
292      // ensure we have a correct tag
293      expect(buffer[0]).toEqual(0x0D);
294      // Encoded values are stored right after the tag
295      expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
296    });
297  }
298});
299
300describe('Writer.writeFloat does', () => {
301  let writer;
302  beforeEach(() => {
303    writer = new Writer();
304  });
305
306  for (const pair of getFloatPairs()) {
307    it(`encode ${pair.name}`, () => {
308      writer.writeFloat(1, pair.floatValue);
309      const buffer = new Uint8Array(writer.getAndResetResultBuffer());
310      expect(buffer.length).toBe(5);
311      // ensure we have a correct tag
312      expect(buffer[0]).toEqual(0x0D);
313      // Encoded values are stored right after the tag
314      expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
315    });
316  }
317
318  /**
319   * NaN may have different value in different browsers. Thus, we need to make
320   * the test lenient.
321   */
322  it('encode NaN', () => {
323    writer.writeFloat(1, NaN);
324    const buffer = new Uint8Array(writer.getAndResetResultBuffer());
325    expect(buffer.length).toBe(5);
326    // ensure we have a correct tag
327    expect(buffer[0]).toEqual(0x0D);
328    // Encoded values are stored right after the tag
329    const float32 = new DataView(buffer.buffer);
330    expect(float32.getFloat32(1, true)).toBeNaN();
331  });
332});
333
334describe('Writer.writeInt32 does', () => {
335  let writer;
336  beforeEach(() => {
337    writer = new Writer();
338  });
339
340  for (const pair of getInt32Pairs()) {
341    if (!pair.skip_writer) {
342      it(`encode ${pair.name}`, () => {
343        writer.writeInt32(1, pair.intValue);
344        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
345        // ensure we have a correct tag
346        expect(buffer[0]).toEqual(0x08);
347        // Encoded values are stored right after the tag
348        expect(buffer.subarray(1, buffer.length))
349            .toEqual(pair.bufferDecoder.asUint8Array());
350      });
351    }
352  }
353});
354
355describe('Writer.writeSfixed32 does', () => {
356  let writer;
357  beforeEach(() => {
358    writer = new Writer();
359  });
360
361  it('encode empty array', () => {
362    writer.writePackedSfixed32(1, []);
363    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
364  });
365
366  for (const pair of getSfixed32Pairs()) {
367    it(`encode ${pair.name}`, () => {
368      writer.writeSfixed32(1, pair.intValue);
369      const buffer = new Uint8Array(writer.getAndResetResultBuffer());
370      expect(buffer.length).toBe(5);
371      // ensure we have a correct tag
372      expect(buffer[0]).toEqual(0x0D);
373      // Encoded values are stored right after the tag
374      expect(buffer.subarray(1, 5)).toEqual(pair.bufferDecoder.asUint8Array());
375    });
376  }
377});
378
379describe('Writer.writeSfixed64 does', () => {
380  let writer;
381  beforeEach(() => {
382    writer = new Writer();
383  });
384
385  for (const pair of getSfixed64Pairs()) {
386    it(`encode ${pair.name}`, () => {
387      writer.writeSfixed64(1, pair.longValue);
388      const buffer = new Uint8Array(writer.getAndResetResultBuffer());
389      expect(buffer.length).toBe(9);
390      // ensure we have a correct tag
391      expect(buffer[0]).toEqual(0x09);
392      // Encoded values are stored right after the tag
393      expect(buffer.subarray(1, 9)).toEqual(pair.bufferDecoder.asUint8Array());
394    });
395  }
396});
397
398describe('Writer.writeSint32 does', () => {
399  let writer;
400  beforeEach(() => {
401    writer = new Writer();
402  });
403
404  for (const pair of getSint32Pairs()) {
405    if (!pair.skip_writer) {
406      it(`encode ${pair.name}`, () => {
407        writer.writeSint32(1, pair.intValue);
408        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
409        // ensure we have a correct tag
410        expect(buffer[0]).toEqual(0x08);
411        // Encoded values are stored right after the tag
412        expect(buffer.subarray(1, buffer.length))
413            .toEqual(pair.bufferDecoder.asUint8Array());
414      });
415    }
416  }
417});
418
419describe('Writer.writeSint64 does', () => {
420  let writer;
421  beforeEach(() => {
422    writer = new Writer();
423  });
424
425  for (const pair of getSint64Pairs()) {
426    if (!pair.skip_writer) {
427      it(`encode ${pair.name}`, () => {
428        writer.writeSint64(1, pair.longValue);
429        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
430        // ensure we have a correct tag
431        expect(buffer[0]).toEqual(0x08);
432        // Encoded values are stored right after the tag
433        expect(buffer.subarray(1, buffer.length))
434            .toEqual(pair.bufferDecoder.asUint8Array());
435      });
436    }
437  }
438});
439
440describe('Writer.writeInt64 does', () => {
441  let writer;
442  beforeEach(() => {
443    writer = new Writer();
444  });
445
446  for (const pair of getInt64Pairs()) {
447    if (!pair.skip_writer) {
448      it(`encode ${pair.name}`, () => {
449        writer.writeInt64(1, pair.longValue);
450        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
451        // ensure we have a correct tag
452        expect(buffer[0]).toEqual(0x08);
453        // Encoded values are stored right after the tag
454        expect(buffer.subarray(1, buffer.length))
455            .toEqual(pair.bufferDecoder.asUint8Array());
456      });
457    }
458  }
459});
460
461describe('Writer.writeUint32 does', () => {
462  let writer;
463  beforeEach(() => {
464    writer = new Writer();
465  });
466
467  for (const pair of getUint32Pairs()) {
468    if (!pair.skip_writer) {
469      it(`encode ${pair.name}`, () => {
470        writer.writeUint32(1, pair.intValue);
471        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
472        // ensure we have a correct tag
473        expect(buffer[0]).toEqual(0x08);
474        // Encoded values are stored right after the tag
475        expect(buffer.subarray(1, buffer.length))
476            .toEqual(pair.bufferDecoder.asUint8Array());
477      });
478    }
479  }
480});
481
482describe('Writer.writeString does', () => {
483  let writer;
484  beforeEach(() => {
485    writer = new Writer();
486  });
487
488  it('encode empty string', () => {
489    writer.writeString(1, '');
490    expect(writer.getAndResetResultBuffer())
491        .toEqual(createArrayBuffer(
492            1 << 3 | 0x02,  // tag (fieldnumber << 3 | (length delimited))
493            0,              // length of the string
494            ));
495  });
496
497  it('encode simple string', () => {
498    writer.writeString(1, 'hello');
499    expect(writer.getAndResetResultBuffer())
500        .toEqual(createArrayBuffer(
501            1 << 3 | 0x02,  // tag (fieldnumber << 3 | (length delimited))
502            5,              // length of the string
503            'h'.charCodeAt(0),
504            'e'.charCodeAt(0),
505            'l'.charCodeAt(0),
506            'l'.charCodeAt(0),
507            'o'.charCodeAt(0),
508            ));
509  });
510
511  it('throw for invalid fieldnumber', () => {
512    if (CHECK_BOUNDS) {
513      expect(() => writer.writeString(-1, 'a'))
514          .toThrowError('Field number is out of range: -1');
515    } else {
516      writer.writeString(-1, 'a');
517      expect(new Uint8Array(writer.getAndResetResultBuffer()))
518          .toEqual(new Uint8Array(createArrayBuffer(
519              -6,  // invalid tag
520              0xff,
521              0xff,
522              0xff,
523              0x0f,
524              1,  // string length
525              'a'.charCodeAt(0),
526              )));
527    }
528  });
529
530  it('throw for null string value', () => {
531    expect(
532        () => writer.writeString(
533            1, /** @type {string} */ (/** @type {*} */ (null))))
534        .toThrow();
535  });
536});
537
538
539/******************************************************************************
540 *                        REPEATED FUNCTIONS
541 ******************************************************************************/
542
543describe('Writer.writePackedBool does', () => {
544  let writer;
545  beforeEach(() => {
546    writer = new Writer();
547  });
548
549  it('encode empty array', () => {
550    writer.writePackedBool(1, []);
551    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
552  });
553
554  for (const pair of getPackedBoolPairs()) {
555    if (!pair.skip_writer) {
556      it(`encode ${pair.name}`, () => {
557        writer.writePackedBool(1, pair.boolValues);
558        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
559        // ensure we have a correct tag
560        expect(buffer[0]).toEqual(0x0A);
561        // Encoded values are stored right after the tag
562        expect(buffer.subarray(1, buffer.length))
563            .toEqual(pair.bufferDecoder.asUint8Array());
564      });
565    }
566  }
567});
568
569describe('Writer.writeRepeatedBool does', () => {
570  let writer;
571  beforeEach(() => {
572    writer = new Writer();
573  });
574
575  it('encode empty array', () => {
576    writer.writeRepeatedBool(1, []);
577    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
578  });
579
580  it('encode repeated unpacked boolean values', () => {
581    const writer = new Writer();
582    writer.writeRepeatedBool(1, [true, false]);
583    expect(writer.getAndResetResultBuffer())
584        .toEqual(createArrayBuffer(
585            1 << 3 | 0x00,  // tag (fieldnumber << 3 | (varint))
586            0x01,           // value[0]
587            1 << 3 | 0x00,  // tag (fieldnumber << 3 | (varint))
588            0x00,           // value[1]
589            ));
590  });
591});
592
593describe('Writer.writePackedDouble does', () => {
594  let writer;
595  beforeEach(() => {
596    writer = new Writer();
597  });
598
599  it('encode empty array', () => {
600    writer.writePackedDouble(1, []);
601    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
602  });
603
604  for (const pair of getPackedDoublePairs()) {
605    if (!pair.skip_writer) {
606      it(`encode ${pair.name}`, () => {
607        writer.writePackedDouble(1, pair.doubleValues);
608        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
609        // ensure we have a correct tag
610        expect(buffer[0]).toEqual(0x0A);
611        // Encoded values are stored right after the tag
612        expect(buffer.subarray(1, buffer.length))
613            .toEqual(pair.bufferDecoder.asUint8Array());
614      });
615    }
616  }
617});
618
619describe('Writer.writePackedFixed32 does', () => {
620  let writer;
621  beforeEach(() => {
622    writer = new Writer();
623  });
624
625  it('encode empty array', () => {
626    writer.writePackedFixed32(1, []);
627    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
628  });
629
630  for (const pair of getPackedFixed32Pairs()) {
631    if (!pair.skip_writer) {
632      it(`encode ${pair.name}`, () => {
633        writer.writePackedFixed32(1, pair.fixed32Values);
634        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
635        // ensure we have a correct tag
636        expect(buffer[0]).toEqual(0x0A);
637        // Encoded values are stored right after the tag
638        expect(buffer.subarray(1, buffer.length))
639            .toEqual(pair.bufferDecoder.asUint8Array());
640      });
641    }
642  }
643});
644
645describe('Writer.writePackedFloat does', () => {
646  let writer;
647  beforeEach(() => {
648    writer = new Writer();
649  });
650
651  it('encode empty array', () => {
652    writer.writePackedFloat(1, []);
653    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
654  });
655
656  for (const pair of getPackedFloatPairs()) {
657    if (!pair.skip_writer) {
658      it(`encode ${pair.name}`, () => {
659        writer.writePackedFloat(1, pair.floatValues);
660        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
661        // ensure we have a correct tag
662        expect(buffer[0]).toEqual(0x0A);
663        // Encoded values are stored right after the tag
664        expect(buffer.subarray(1, buffer.length))
665            .toEqual(pair.bufferDecoder.asUint8Array());
666      });
667    }
668  }
669});
670
671describe('Writer.writePackedInt32 does', () => {
672  let writer;
673  beforeEach(() => {
674    writer = new Writer();
675  });
676
677  it('encode empty array', () => {
678    writer.writePackedInt32(1, []);
679    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
680  });
681
682  for (const pair of getPackedInt32Pairs()) {
683    if (!pair.skip_writer) {
684      it(`encode ${pair.name}`, () => {
685        writer.writePackedInt32(1, pair.int32Values);
686        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
687        // ensure we have a correct tag
688        expect(buffer[0]).toEqual(0x0A);
689        // Encoded values are stored right after the tag
690        expect(buffer.subarray(1, buffer.length))
691            .toEqual(pair.bufferDecoder.asUint8Array());
692      });
693    }
694  }
695});
696
697describe('Writer.writePackedInt64 does', () => {
698  let writer;
699  beforeEach(() => {
700    writer = new Writer();
701  });
702
703  it('encode empty array', () => {
704    writer.writePackedInt64(1, []);
705    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
706  });
707
708  for (const pair of getPackedInt64Pairs()) {
709    if (!pair.skip_writer) {
710      it(`encode ${pair.name}`, () => {
711        writer.writePackedInt64(1, pair.int64Values);
712        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
713        // ensure we have a correct tag
714        expect(buffer[0]).toEqual(0x0A);
715        // Encoded values are stored right after the tag
716        expect(buffer.subarray(1, buffer.length))
717            .toEqual(pair.bufferDecoder.asUint8Array());
718      });
719    }
720  }
721});
722
723describe('Writer.writePackedSfixed32 does', () => {
724  let writer;
725  beforeEach(() => {
726    writer = new Writer();
727  });
728
729  it('encode empty array', () => {
730    writer.writePackedSfixed32(1, []);
731    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
732  });
733
734  for (const pair of getPackedSfixed32Pairs()) {
735    if (!pair.skip_writer) {
736      it(`encode ${pair.name}`, () => {
737        writer.writePackedSfixed32(1, pair.sfixed32Values);
738        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
739        // ensure we have a correct tag
740        expect(buffer[0]).toEqual(0x0A);
741        // Encoded values are stored right after the tag
742        expect(buffer.subarray(1, buffer.length))
743            .toEqual(pair.bufferDecoder.asUint8Array());
744      });
745    }
746  }
747});
748
749describe('Writer.writePackedSfixed64 does', () => {
750  let writer;
751  beforeEach(() => {
752    writer = new Writer();
753  });
754
755  it('encode empty array', () => {
756    writer.writePackedSfixed64(1, []);
757    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
758  });
759
760  for (const pair of getPackedSfixed64Pairs()) {
761    if (!pair.skip_writer) {
762      it(`encode ${pair.name}`, () => {
763        writer.writePackedSfixed64(1, pair.sfixed64Values);
764        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
765        // ensure we have a correct tag
766        expect(buffer[0]).toEqual(0x0A);
767        // Encoded values are stored right after the tag
768        expect(buffer.subarray(1, buffer.length))
769            .toEqual(pair.bufferDecoder.asUint8Array());
770      });
771    }
772  }
773});
774
775describe('Writer.writePackedSint32 does', () => {
776  let writer;
777  beforeEach(() => {
778    writer = new Writer();
779  });
780
781  it('encode empty array', () => {
782    writer.writePackedSint32(1, []);
783    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
784  });
785
786  for (const pair of getPackedSint32Pairs()) {
787    if (!pair.skip_writer) {
788      it(`encode ${pair.name}`, () => {
789        writer.writePackedSint32(1, pair.sint32Values);
790        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
791        // ensure we have a correct tag
792        expect(buffer[0]).toEqual(0x0A);
793        // Encoded values are stored right after the tag
794        expect(buffer.subarray(1, buffer.length))
795            .toEqual(pair.bufferDecoder.asUint8Array());
796      });
797    }
798  }
799});
800
801describe('Writer.writePackedSint64 does', () => {
802  let writer;
803  beforeEach(() => {
804    writer = new Writer();
805  });
806
807  it('encode empty array', () => {
808    writer.writePackedSint64(1, []);
809    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
810  });
811
812  for (const pair of getPackedSint64Pairs()) {
813    if (!pair.skip_writer) {
814      it(`encode ${pair.name}`, () => {
815        writer.writePackedSint64(1, pair.sint64Values);
816        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
817        // ensure we have a correct tag
818        expect(buffer[0]).toEqual(0x0A);
819        // Encoded values are stored right after the tag
820        expect(buffer.subarray(1, buffer.length))
821            .toEqual(pair.bufferDecoder.asUint8Array());
822      });
823    }
824  }
825});
826
827describe('Writer.writePackedUint32 does', () => {
828  let writer;
829  beforeEach(() => {
830    writer = new Writer();
831  });
832
833  it('encode empty array', () => {
834    writer.writePackedUint32(1, []);
835    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
836  });
837
838  for (const pair of getPackedUint32Pairs()) {
839    if (!pair.skip_writer) {
840      it(`encode ${pair.name}`, () => {
841        writer.writePackedUint32(1, pair.uint32Values);
842        const buffer = new Uint8Array(writer.getAndResetResultBuffer());
843        // ensure we have a correct tag
844        expect(buffer[0]).toEqual(0x0A);
845        // Encoded values are stored right after the tag
846        expect(buffer.subarray(1, buffer.length))
847            .toEqual(pair.bufferDecoder.asUint8Array());
848      });
849    }
850  }
851});
852
853describe('Writer.writeRepeatedBytes does', () => {
854  let writer;
855  beforeEach(() => {
856    writer = new Writer();
857  });
858
859  it('encode empty array', () => {
860    writer.writeRepeatedBytes(1, []);
861    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
862  });
863
864  it('encode single value', () => {
865    const value = createArrayBuffer(0x61);
866    writer.writeRepeatedBytes(1, [ByteString.fromArrayBuffer(value)]);
867    expect(writer.getAndResetResultBuffer())
868        .toEqual(createArrayBuffer(
869            0x0A,
870            0x01,
871            0x61,  // a
872            ));
873  });
874
875  it('encode multiple values', () => {
876    const value1 = createArrayBuffer(0x61);
877    const value2 = createArrayBuffer(0x62);
878    writer.writeRepeatedBytes(1, [
879      ByteString.fromArrayBuffer(value1),
880      ByteString.fromArrayBuffer(value2),
881    ]);
882    expect(writer.getAndResetResultBuffer())
883        .toEqual(createArrayBuffer(
884            0x0A,
885            0x01,
886            0x61,  // a
887            0x0A,
888            0x01,
889            0x62,  // b
890            ));
891  });
892});
893
894describe('Writer.writeRepeatedString does', () => {
895  let writer;
896  beforeEach(() => {
897    writer = new Writer();
898  });
899
900  it('encode empty array', () => {
901    writer.writeRepeatedString(1, []);
902    expect(writer.getAndResetResultBuffer()).toEqual(createArrayBuffer());
903  });
904
905  it('encode single value', () => {
906    writer.writeRepeatedString(1, ['a']);
907    expect(writer.getAndResetResultBuffer())
908        .toEqual(createArrayBuffer(
909            0x0A,
910            0x01,
911            0x61,  // a
912            ));
913  });
914
915  it('encode multiple values', () => {
916    writer.writeRepeatedString(1, ['a', 'b']);
917    expect(writer.getAndResetResultBuffer())
918        .toEqual(createArrayBuffer(
919            0x0A,
920            0x01,
921            0x61,  // a
922            0x0A,
923            0x01,
924            0x62,  // b
925            ));
926  });
927});
928