• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31/**
32 * @fileoverview Test cases for jspb's binary protocol buffer writer. In
33 * practice BinaryWriter is used to drive the Decoder and Reader test cases,
34 * so only writer-specific tests are here.
35 *
36 * Test suite is written using Jasmine -- see http://jasmine.github.io/
37 *
38 * @author aappleby@google.com (Austin Appleby)
39 */
40
41goog.require('goog.crypt');
42goog.require('goog.testing.asserts');
43goog.require('jspb.BinaryConstants');
44goog.require('jspb.BinaryReader');
45goog.require('jspb.BinaryWriter');
46goog.require('jspb.utils');
47
48
49/**
50 * @param {function()} func This function should throw an error when run.
51 */
52function assertFails(func) {
53  assertThrows(func);
54}
55
56
57describe('binaryWriterTest', function() {
58  /**
59   * Verifies that misuse of the writer class triggers assertions.
60   */
61  it('testWriteErrors', function() {
62    // Submessages with invalid field indices should assert.
63    var writer = new jspb.BinaryWriter();
64    var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
65
66    assertFails(function() {
67      writer.writeMessage(-1, dummyMessage, goog.nullFunction);
68    });
69
70    // Writing invalid field indices should assert.
71    writer = new jspb.BinaryWriter();
72    assertFails(function() {writer.writeUint64(-1, 1);});
73
74    // Writing out-of-range field values should assert.
75    writer = new jspb.BinaryWriter();
76
77    assertFails(function() {writer.writeInt32(1, -Infinity);});
78    assertFails(function() {writer.writeInt32(1, Infinity);});
79
80    assertFails(function() {writer.writeInt64(1, -Infinity);});
81    assertFails(function() {writer.writeInt64(1, Infinity);});
82
83    assertFails(function() {writer.writeUint32(1, -1);});
84    assertFails(function() {writer.writeUint32(1, Infinity);});
85
86    assertFails(function() {writer.writeUint64(1, -1);});
87    assertFails(function() {writer.writeUint64(1, Infinity);});
88
89    assertFails(function() {writer.writeSint32(1, -Infinity);});
90    assertFails(function() {writer.writeSint32(1, Infinity);});
91
92    assertFails(function() {writer.writeSint64(1, -Infinity);});
93    assertFails(function() {writer.writeSint64(1, Infinity);});
94
95    assertFails(function() {writer.writeFixed32(1, -1);});
96    assertFails(function() {writer.writeFixed32(1, Infinity);});
97
98    assertFails(function() {writer.writeFixed64(1, -1);});
99    assertFails(function() {writer.writeFixed64(1, Infinity);});
100
101    assertFails(function() {writer.writeSfixed32(1, -Infinity);});
102    assertFails(function() {writer.writeSfixed32(1, Infinity);});
103
104    assertFails(function() {writer.writeSfixed64(1, -Infinity);});
105    assertFails(function() {writer.writeSfixed64(1, Infinity);});
106  });
107
108
109  /**
110   * Basic test of retrieving the result as a Uint8Array buffer
111   */
112  it('testGetResultBuffer', function() {
113    var expected = '0864120b48656c6c6f20776f726c641a0301020320c801';
114
115    var writer = new jspb.BinaryWriter();
116    writer.writeUint32(1, 100);
117    writer.writeString(2, 'Hello world');
118    writer.writeBytes(3, new Uint8Array([1, 2, 3]));
119    writer.writeUint32(4, 200);
120
121    var buffer = writer.getResultBuffer();
122    assertEquals(expected, goog.crypt.byteArrayToHex(buffer));
123  });
124
125
126  /**
127   * Tests websafe encodings for base64 strings.
128   */
129  it('testWebSafeOption', function() {
130    var writer = new jspb.BinaryWriter();
131    writer.writeBytes(1, new Uint8Array([127]));
132    assertEquals('CgF/', writer.getResultBase64String());
133    assertEquals(
134        'CgF/',
135        writer.getResultBase64String(goog.crypt.base64.Alphabet.DEFAULT));
136    assertEquals(
137        'CgF_',
138        writer.getResultBase64String(
139            goog.crypt.base64.Alphabet.WEBSAFE_NO_PADDING));
140  });
141
142  it('writes split 64 fields', function() {
143    var writer = new jspb.BinaryWriter();
144    writer.writeSplitVarint64(1, 0x1, 0x2);
145    writer.writeSplitVarint64(1, 0xFFFFFFFF, 0xFFFFFFFF);
146    writer.writeSplitFixed64(2, 0x1, 0x2);
147    writer.writeSplitFixed64(2, 0xFFFFFFF0, 0xFFFFFFFF);
148    function lo(i) {
149      return i + 1;
150    }
151    function hi(i) {
152      return i + 2;
153    }
154    writer.writeRepeatedSplitVarint64(3, [0, 1, 2], lo, hi);
155    writer.writeRepeatedSplitFixed64(4, [0, 1, 2], lo, hi);
156    writer.writePackedSplitVarint64(5, [0, 1, 2], lo, hi);
157    writer.writePackedSplitFixed64(6, [0, 1, 2], lo, hi);
158
159    function bitsAsArray(lowBits, highBits) {
160      return [lowBits >>> 0, highBits >>> 0];
161    }
162    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
163    reader.nextField();
164    expect(reader.getFieldNumber()).toEqual(1);
165    expect(reader.readSplitVarint64(bitsAsArray)).toEqual([0x1, 0x2]);
166
167    reader.nextField();
168    expect(reader.getFieldNumber()).toEqual(1);
169    expect(reader.readSplitVarint64(bitsAsArray)).toEqual([
170      0xFFFFFFFF, 0xFFFFFFFF
171    ]);
172
173    reader.nextField();
174    expect(reader.getFieldNumber()).toEqual(2);
175    expect(reader.readSplitFixed64(bitsAsArray)).toEqual([0x1, 0x2]);
176
177    reader.nextField();
178    expect(reader.getFieldNumber()).toEqual(2);
179    expect(reader.readSplitFixed64(bitsAsArray)).toEqual([
180      0xFFFFFFF0, 0xFFFFFFFF
181    ]);
182
183    for (let i = 0; i < 3; i++) {
184      reader.nextField();
185      expect(reader.getFieldNumber()).toEqual(3);
186      expect(reader.readSplitVarint64(bitsAsArray)).toEqual([i + 1, i + 2]);
187    }
188
189    for (let i = 0; i < 3; i++) {
190      reader.nextField();
191      expect(reader.getFieldNumber()).toEqual(4);
192      expect(reader.readSplitFixed64(bitsAsArray)).toEqual([i + 1, i + 2]);
193    }
194
195    reader.nextField();
196    expect(reader.getFieldNumber()).toEqual(5);
197    expect(reader.readPackedInt64String()).toEqual([
198      String(2 * 2 ** 32 + 1),
199      String(3 * 2 ** 32 + 2),
200      String(4 * 2 ** 32 + 3),
201    ]);
202
203    reader.nextField();
204    expect(reader.getFieldNumber()).toEqual(6);
205    expect(reader.readPackedFixed64String()).toEqual([
206      String(2 * 2 ** 32 + 1),
207      String(3 * 2 ** 32 + 2),
208      String(4 * 2 ** 32 + 3),
209    ]);
210  });
211
212  it('writes zigzag 64 fields', function() {
213    // Test cases directly from the protobuf dev guide.
214    // https://engdoc.corp.google.com/eng/howto/protocolbuffers/developerguide/encoding.shtml?cl=head#types
215    var testCases = [
216      {original: '0', zigzag: '0'},
217      {original: '-1', zigzag: '1'},
218      {original: '1', zigzag: '2'},
219      {original: '-2', zigzag: '3'},
220      {original: '2147483647', zigzag: '4294967294'},
221      {original: '-2147483648', zigzag: '4294967295'},
222      // 64-bit extremes, not in dev guide.
223      {original: '9223372036854775807', zigzag: '18446744073709551614'},
224      {original: '-9223372036854775808', zigzag: '18446744073709551615'},
225    ];
226    function decimalToLowBits(v) {
227      jspb.utils.splitDecimalString(v);
228      return jspb.utils.split64Low >>> 0;
229    }
230    function decimalToHighBits(v) {
231      jspb.utils.splitDecimalString(v);
232      return jspb.utils.split64High >>> 0;
233    }
234
235    var writer = new jspb.BinaryWriter();
236    testCases.forEach(function(c) {
237      writer.writeSint64String(1, c.original);
238      writer.writeSintHash64(1, jspb.utils.decimalStringToHash64(c.original));
239      jspb.utils.splitDecimalString(c.original);
240      writer.writeSplitZigzagVarint64(
241          1, jspb.utils.split64Low, jspb.utils.split64High);
242    });
243
244    writer.writeRepeatedSint64String(2, testCases.map(function(c) {
245      return c.original;
246    }));
247
248    writer.writeRepeatedSintHash64(3, testCases.map(function(c) {
249      return jspb.utils.decimalStringToHash64(c.original);
250    }));
251
252    writer.writeRepeatedSplitZigzagVarint64(
253        4, testCases.map(function(c) {
254          return c.original;
255        }),
256        decimalToLowBits, decimalToHighBits);
257
258    writer.writePackedSint64String(5, testCases.map(function(c) {
259      return c.original;
260    }));
261
262    writer.writePackedSintHash64(6, testCases.map(function(c) {
263      return jspb.utils.decimalStringToHash64(c.original);
264    }));
265
266    writer.writePackedSplitZigzagVarint64(
267        7, testCases.map(function(c) {
268          return c.original;
269        }),
270        decimalToLowBits, decimalToHighBits);
271
272    // Verify by reading the stream as normal int64 fields and checking with
273    // the canonical zigzag encoding of each value.
274    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
275    testCases.forEach(function(c) {
276      reader.nextField();
277      expect(reader.getFieldNumber()).toEqual(1);
278      expect(reader.readUint64String()).toEqual(c.zigzag);
279      reader.nextField();
280      expect(reader.getFieldNumber()).toEqual(1);
281      expect(reader.readUint64String()).toEqual(c.zigzag);
282      reader.nextField();
283      expect(reader.getFieldNumber()).toEqual(1);
284      expect(reader.readUint64String()).toEqual(c.zigzag);
285    });
286
287    testCases.forEach(function(c) {
288      reader.nextField();
289      expect(reader.getFieldNumber()).toEqual(2);
290      expect(reader.readUint64String()).toEqual(c.zigzag);
291    });
292
293    testCases.forEach(function(c) {
294      reader.nextField();
295      expect(reader.getFieldNumber()).toEqual(3);
296      expect(reader.readUint64String()).toEqual(c.zigzag);
297    });
298
299    testCases.forEach(function(c) {
300      reader.nextField();
301      expect(reader.getFieldNumber()).toEqual(4);
302      expect(reader.readUint64String()).toEqual(c.zigzag);
303    });
304
305    reader.nextField();
306    expect(reader.getFieldNumber()).toEqual(5);
307    expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) {
308      return c.zigzag;
309    }));
310
311    reader.nextField();
312    expect(reader.getFieldNumber()).toEqual(6);
313    expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) {
314      return c.zigzag;
315    }));
316
317    reader.nextField();
318    expect(reader.getFieldNumber()).toEqual(7);
319    expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) {
320      return c.zigzag;
321    }));
322  });
323
324  it('writes float32 fields', function() {
325    var testCases = [
326      0, 1, -1, jspb.BinaryConstants.FLOAT32_MIN,
327      -jspb.BinaryConstants.FLOAT32_MIN, jspb.BinaryConstants.FLOAT32_MAX,
328      -jspb.BinaryConstants.FLOAT32_MAX, 3.1415927410125732, Infinity,
329      -Infinity, NaN
330    ];
331    var writer = new jspb.BinaryWriter();
332    testCases.forEach(function(f) {
333      writer.writeFloat(1, f);
334    });
335    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
336    testCases.forEach(function(f) {
337      reader.nextField();
338      expect(reader.getFieldNumber()).toEqual(1);
339      if (isNaN(f)) {
340        expect(isNaN(reader.readFloat())).toEqual(true);
341      } else {
342        expect(reader.readFloat()).toEqual(f);
343      }
344    });
345  });
346
347  it('writes double fields', function() {
348    var testCases = [
349      0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER,
350      Number.MAX_VALUE, Number.MIN_VALUE, jspb.BinaryConstants.FLOAT32_MIN,
351      -jspb.BinaryConstants.FLOAT32_MIN, jspb.BinaryConstants.FLOAT32_MAX,
352      -jspb.BinaryConstants.FLOAT32_MAX, Math.PI, Infinity, -Infinity, NaN
353    ];
354    var writer = new jspb.BinaryWriter();
355    testCases.forEach(function(f) {
356      writer.writeDouble(1, f);
357    });
358    var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
359    testCases.forEach(function(f) {
360      reader.nextField();
361      expect(reader.getFieldNumber()).toEqual(1);
362      if (isNaN(f)) {
363        expect(isNaN(reader.readDouble())).toEqual(true);
364      } else {
365        expect(reader.readDouble()).toEqual(f);
366      }
367    });
368  });
369});
370