• 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
31goog.require('goog.crypt.base64');
32goog.require('goog.testing.asserts');
33// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test
34goog.require('proto.jspb.test.ForeignMessage');
35// CommonJS-LoadFromFile: proto3_test_pb proto.jspb.test
36goog.require('proto.jspb.test.Proto3Enum');
37goog.require('proto.jspb.test.TestProto3');
38// CommonJS-LoadFromFile: google/protobuf/any_pb proto.google.protobuf
39goog.require('proto.google.protobuf.Any');
40// CommonJS-LoadFromFile: google/protobuf/timestamp_pb proto.google.protobuf
41goog.require('proto.google.protobuf.Timestamp');
42// CommonJS-LoadFromFile: google/protobuf/struct_pb proto.google.protobuf
43goog.require('proto.google.protobuf.Struct');
44goog.require('jspb.Message');
45
46var BYTES = new Uint8Array([1, 2, 8, 9]);
47var BYTES_B64 = goog.crypt.base64.encodeByteArray(BYTES);
48
49
50/**
51 * Helper: compare a bytes field to an expected value
52 * @param {Uint8Array|string} arr
53 * @param {Uint8Array} expected
54 * @return {boolean}
55 */
56function bytesCompare(arr, expected) {
57  if (typeof arr === 'string') {
58    arr = goog.crypt.base64.decodeStringToUint8Array(arr);
59  }
60  if (arr.length != expected.length) {
61    return false;
62  }
63  for (var i = 0; i < arr.length; i++) {
64    if (arr[i] != expected[i]) {
65      return false;
66    }
67  }
68  return true;
69}
70
71
72describe('proto3Test', function() {
73  /**
74   * Test default values don't affect equality test.
75   */
76  it('testEqualsProto3', function() {
77    var msg1 = new proto.jspb.test.TestProto3();
78    var msg2 = new proto.jspb.test.TestProto3();
79    msg2.setSingularString('');
80
81    assertTrue(jspb.Message.equals(msg1, msg2));
82  });
83
84
85  /**
86   * Test setting when a field has default semantics.
87   */
88  it('testSetProto3ToValueAndBackToDefault', function() {
89    var msg = new proto.jspb.test.TestProto3();
90
91    // Setting should work normally.
92    msg.setSingularString('optionalString');
93    assertEquals(msg.getSingularString(), 'optionalString');
94
95    // Clearing should work too ...
96    msg.setSingularString('');
97    assertEquals(msg.getSingularString(), '');
98
99    // ... and shouldn't affect the equality with a brand new message.
100    assertTrue(jspb.Message.equals(msg, new proto.jspb.test.TestProto3()));
101  });
102
103  /**
104   * Test defaults for proto3 message fields.
105   */
106  it('testProto3FieldDefaults', function() {
107    var msg = new proto.jspb.test.TestProto3();
108
109    assertEquals(msg.getSingularInt32(), 0);
110    assertEquals(msg.getSingularInt64(), 0);
111    assertEquals(msg.getSingularUint32(), 0);
112    assertEquals(msg.getSingularUint64(), 0);
113    assertEquals(msg.getSingularSint32(), 0);
114    assertEquals(msg.getSingularSint64(), 0);
115    assertEquals(msg.getSingularFixed32(), 0);
116    assertEquals(msg.getSingularFixed64(), 0);
117    assertEquals(msg.getSingularSfixed32(), 0);
118    assertEquals(msg.getSingularSfixed64(), 0);
119    assertEquals(msg.getSingularFloat(), 0);
120    assertEquals(msg.getSingularDouble(), 0);
121    assertEquals(msg.getSingularString(), '');
122
123    // TODO(b/26173701): when we change bytes fields default getter to return
124    // Uint8Array, we'll want to switch this assertion to match the u8 case.
125    assertEquals(typeof msg.getSingularBytes(), 'string');
126    assertEquals(msg.getSingularBytes_asU8() instanceof Uint8Array, true);
127    assertEquals(typeof msg.getSingularBytes_asB64(), 'string');
128    assertEquals(msg.getSingularBytes().length, 0);
129    assertEquals(msg.getSingularBytes_asU8().length, 0);
130    assertEquals(msg.getSingularBytes_asB64(), '');
131
132    assertEquals(
133        msg.getSingularForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_FOO);
134    assertEquals(msg.getSingularForeignMessage(), undefined);
135    assertEquals(msg.getSingularForeignMessage(), undefined);
136
137    assertEquals(msg.getRepeatedInt32List().length, 0);
138    assertEquals(msg.getRepeatedInt64List().length, 0);
139    assertEquals(msg.getRepeatedUint32List().length, 0);
140    assertEquals(msg.getRepeatedUint64List().length, 0);
141    assertEquals(msg.getRepeatedSint32List().length, 0);
142    assertEquals(msg.getRepeatedSint64List().length, 0);
143    assertEquals(msg.getRepeatedFixed32List().length, 0);
144    assertEquals(msg.getRepeatedFixed64List().length, 0);
145    assertEquals(msg.getRepeatedSfixed32List().length, 0);
146    assertEquals(msg.getRepeatedSfixed64List().length, 0);
147    assertEquals(msg.getRepeatedFloatList().length, 0);
148    assertEquals(msg.getRepeatedDoubleList().length, 0);
149    assertEquals(msg.getRepeatedStringList().length, 0);
150    assertEquals(msg.getRepeatedBytesList().length, 0);
151    assertEquals(msg.getRepeatedForeignEnumList().length, 0);
152    assertEquals(msg.getRepeatedForeignMessageList().length, 0);
153  });
154
155  /**
156   * Test presence for proto3 optional fields.
157   */
158  it('testProto3Optional', function() {
159    var msg = new proto.jspb.test.TestProto3();
160
161    assertEquals(msg.getOptionalInt32(), 0);
162    assertEquals(msg.getOptionalInt64(), 0);
163    assertEquals(msg.getOptionalUint32(), 0);
164    assertEquals(msg.getOptionalUint64(), 0);
165    assertEquals(msg.getOptionalSint32(), 0);
166    assertEquals(msg.getOptionalSint64(), 0);
167    assertEquals(msg.getOptionalFixed32(), 0);
168    assertEquals(msg.getOptionalFixed64(), 0);
169    assertEquals(msg.getOptionalSfixed32(), 0);
170    assertEquals(msg.getOptionalSfixed64(), 0);
171    assertEquals(msg.getOptionalFloat(), 0);
172    assertEquals(msg.getOptionalDouble(), 0);
173    assertEquals(msg.getOptionalString(), '');
174
175    // TODO(b/26173701): when we change bytes fields default getter to return
176    // Uint8Array, we'll want to switch this assertion to match the u8 case.
177    assertEquals(typeof msg.getOptionalBytes(), 'string');
178    assertEquals(msg.getOptionalBytes_asU8() instanceof Uint8Array, true);
179    assertEquals(typeof msg.getOptionalBytes_asB64(), 'string');
180    assertEquals(msg.getOptionalBytes().length, 0);
181    assertEquals(msg.getOptionalBytes_asU8().length, 0);
182    assertEquals(msg.getOptionalBytes_asB64(), '');
183
184    assertEquals(
185        msg.getOptionalForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_FOO);
186    assertEquals(msg.getOptionalForeignMessage(), undefined);
187    assertEquals(msg.getOptionalForeignMessage(), undefined);
188
189    // Serializing an empty proto yields the empty string.
190    assertEquals(msg.serializeBinary().length, 0);
191
192    // Values start as unset, but can be explicitly set even to default values
193    // like 0.
194    assertFalse(msg.hasOptionalInt32());
195    msg.setOptionalInt32(0);
196    assertTrue(msg.hasOptionalInt32());
197
198    assertFalse(msg.hasOptionalInt64());
199    msg.setOptionalInt64(0);
200    assertTrue(msg.hasOptionalInt64());
201
202    assertFalse(msg.hasOptionalString());
203    msg.setOptionalString('');
204    assertTrue(msg.hasOptionalString());
205
206    // Now the proto will have a non-zero size, even though its values are 0.
207    var serialized = msg.serializeBinary();
208    assertNotEquals(serialized.length, 0);
209
210    var msg2 = proto.jspb.test.TestProto3.deserializeBinary(serialized);
211    assertTrue(msg2.hasOptionalInt32());
212    assertTrue(msg2.hasOptionalInt64());
213    assertTrue(msg2.hasOptionalString());
214
215    // We can clear fields to go back to empty.
216    msg2.clearOptionalInt32();
217    assertFalse(msg2.hasOptionalInt32());
218
219    msg2.clearOptionalString();
220    assertFalse(msg2.hasOptionalString());
221  });
222
223  /**
224   * Test that all fields can be set ,and read via a serialization roundtrip.
225   */
226  it('testProto3FieldSetGet', function() {
227    var msg = new proto.jspb.test.TestProto3();
228
229    msg.setSingularInt32(-42);
230    msg.setSingularInt64(-0x7fffffff00000000);
231    msg.setSingularUint32(0x80000000);
232    msg.setSingularUint64(0xf000000000000000);
233    msg.setSingularSint32(-100);
234    msg.setSingularSint64(-0x8000000000000000);
235    msg.setSingularFixed32(1234);
236    msg.setSingularFixed64(0x1234567800000000);
237    msg.setSingularSfixed32(-1234);
238    msg.setSingularSfixed64(-0x1234567800000000);
239    msg.setSingularFloat(1.5);
240    msg.setSingularDouble(-1.5);
241    msg.setSingularBool(true);
242    msg.setSingularString('hello world');
243    msg.setSingularBytes(BYTES);
244    var submsg = new proto.jspb.test.ForeignMessage();
245    submsg.setC(16);
246    msg.setSingularForeignMessage(submsg);
247    msg.setSingularForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
248
249    msg.setRepeatedInt32List([-42]);
250    msg.setRepeatedInt64List([-0x7fffffff00000000]);
251    msg.setRepeatedUint32List([0x80000000]);
252    msg.setRepeatedUint64List([0xf000000000000000]);
253    msg.setRepeatedSint32List([-100]);
254    msg.setRepeatedSint64List([-0x8000000000000000]);
255    msg.setRepeatedFixed32List([1234]);
256    msg.setRepeatedFixed64List([0x1234567800000000]);
257    msg.setRepeatedSfixed32List([-1234]);
258    msg.setRepeatedSfixed64List([-0x1234567800000000]);
259    msg.setRepeatedFloatList([1.5]);
260    msg.setRepeatedDoubleList([-1.5]);
261    msg.setRepeatedBoolList([true]);
262    msg.setRepeatedStringList(['hello world']);
263    msg.setRepeatedBytesList([BYTES]);
264    submsg = new proto.jspb.test.ForeignMessage();
265    submsg.setC(1000);
266    msg.setRepeatedForeignMessageList([submsg]);
267    msg.setRepeatedForeignEnumList([proto.jspb.test.Proto3Enum.PROTO3_BAR]);
268
269    msg.setOneofString('asdf');
270
271    var serialized = msg.serializeBinary();
272    msg = proto.jspb.test.TestProto3.deserializeBinary(serialized);
273
274    assertEquals(msg.getSingularInt32(), -42);
275    assertEquals(msg.getSingularInt64(), -0x7fffffff00000000);
276    assertEquals(msg.getSingularUint32(), 0x80000000);
277    assertEquals(msg.getSingularUint64(), 0xf000000000000000);
278    assertEquals(msg.getSingularSint32(), -100);
279    assertEquals(msg.getSingularSint64(), -0x8000000000000000);
280    assertEquals(msg.getSingularFixed32(), 1234);
281    assertEquals(msg.getSingularFixed64(), 0x1234567800000000);
282    assertEquals(msg.getSingularSfixed32(), -1234);
283    assertEquals(msg.getSingularSfixed64(), -0x1234567800000000);
284    assertEquals(msg.getSingularFloat(), 1.5);
285    assertEquals(msg.getSingularDouble(), -1.5);
286    assertEquals(msg.getSingularBool(), true);
287    assertEquals(msg.getSingularString(), 'hello world');
288    assertEquals(true, bytesCompare(msg.getSingularBytes(), BYTES));
289    assertEquals(msg.getSingularForeignMessage().getC(), 16);
290    assertEquals(
291        msg.getSingularForeignEnum(), proto.jspb.test.Proto3Enum.PROTO3_BAR);
292
293    assertElementsEquals(msg.getRepeatedInt32List(), [-42]);
294    assertElementsEquals(msg.getRepeatedInt64List(), [-0x7fffffff00000000]);
295    assertElementsEquals(msg.getRepeatedUint32List(), [0x80000000]);
296    assertElementsEquals(msg.getRepeatedUint64List(), [0xf000000000000000]);
297    assertElementsEquals(msg.getRepeatedSint32List(), [-100]);
298    assertElementsEquals(msg.getRepeatedSint64List(), [-0x8000000000000000]);
299    assertElementsEquals(msg.getRepeatedFixed32List(), [1234]);
300    assertElementsEquals(msg.getRepeatedFixed64List(), [0x1234567800000000]);
301    assertElementsEquals(msg.getRepeatedSfixed32List(), [-1234]);
302    assertElementsEquals(msg.getRepeatedSfixed64List(), [-0x1234567800000000]);
303    assertElementsEquals(msg.getRepeatedFloatList(), [1.5]);
304    assertElementsEquals(msg.getRepeatedDoubleList(), [-1.5]);
305    assertElementsEquals(msg.getRepeatedBoolList(), [true]);
306    assertElementsEquals(msg.getRepeatedStringList(), ['hello world']);
307    assertEquals(msg.getRepeatedBytesList().length, 1);
308    assertEquals(true, bytesCompare(msg.getRepeatedBytesList()[0], BYTES));
309    assertEquals(msg.getRepeatedForeignMessageList().length, 1);
310    assertEquals(msg.getRepeatedForeignMessageList()[0].getC(), 1000);
311    assertElementsEquals(
312        msg.getRepeatedForeignEnumList(),
313        [proto.jspb.test.Proto3Enum.PROTO3_BAR]);
314
315    assertEquals(msg.getOneofString(), 'asdf');
316  });
317
318
319  /**
320   * Test that oneofs continue to have a notion of field presence.
321   */
322  it('testOneofs', function() {
323    // Default instance.
324    var msg = new proto.jspb.test.TestProto3();
325    assertEquals(msg.getOneofUint32(), 0);
326    assertEquals(msg.getOneofForeignMessage(), undefined);
327    assertEquals(msg.getOneofString(), '');
328    assertEquals(msg.getOneofBytes(), '');
329
330    assertFalse(msg.hasOneofUint32());
331    assertFalse(msg.hasOneofForeignMessage());
332    assertFalse(msg.hasOneofString());
333    assertFalse(msg.hasOneofBytes());
334
335    // Integer field.
336    msg.setOneofUint32(42);
337    assertEquals(msg.getOneofUint32(), 42);
338    assertEquals(msg.getOneofForeignMessage(), undefined);
339    assertEquals(msg.getOneofString(), '');
340    assertEquals(msg.getOneofBytes(), '');
341
342    assertTrue(msg.hasOneofUint32());
343    assertFalse(msg.hasOneofForeignMessage());
344    assertFalse(msg.hasOneofString());
345    assertFalse(msg.hasOneofBytes());
346
347    // Sub-message field.
348    var submsg = new proto.jspb.test.ForeignMessage();
349    msg.setOneofForeignMessage(submsg);
350    assertEquals(msg.getOneofUint32(), 0);
351    assertEquals(msg.getOneofForeignMessage(), submsg);
352    assertEquals(msg.getOneofString(), '');
353    assertEquals(msg.getOneofBytes(), '');
354
355    assertFalse(msg.hasOneofUint32());
356    assertTrue(msg.hasOneofForeignMessage());
357    assertFalse(msg.hasOneofString());
358    assertFalse(msg.hasOneofBytes());
359
360    // String field.
361    msg.setOneofString('hello');
362    assertEquals(msg.getOneofUint32(), 0);
363    assertEquals(msg.getOneofForeignMessage(), undefined);
364    assertEquals(msg.getOneofString(), 'hello');
365    assertEquals(msg.getOneofBytes(), '');
366
367    assertFalse(msg.hasOneofUint32());
368    assertFalse(msg.hasOneofForeignMessage());
369    assertTrue(msg.hasOneofString());
370    assertFalse(msg.hasOneofBytes());
371
372    // Bytes field.
373    msg.setOneofBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
374    assertEquals(msg.getOneofUint32(), 0);
375    assertEquals(msg.getOneofForeignMessage(), undefined);
376    assertEquals(msg.getOneofString(), '');
377    assertEquals(
378        msg.getOneofBytes_asB64(),
379        goog.crypt.base64.encodeString('\u00FF\u00FF'));
380
381    assertFalse(msg.hasOneofUint32());
382    assertFalse(msg.hasOneofForeignMessage());
383    assertFalse(msg.hasOneofString());
384    assertTrue(msg.hasOneofBytes());
385  });
386
387
388  /**
389   * Test that "default"-valued primitive fields are not emitted on the wire.
390   */
391  it('testNoSerializeDefaults', function() {
392    var msg = new proto.jspb.test.TestProto3();
393
394    // Set each primitive to a non-default value, then back to its default, to
395    // ensure that the serialization is actually checking the value and not just
396    // whether it has ever been set.
397    msg.setSingularInt32(42);
398    msg.setSingularInt32(0);
399    msg.setSingularDouble(3.14);
400    msg.setSingularDouble(0.0);
401    msg.setSingularBool(true);
402    msg.setSingularBool(false);
403    msg.setSingularString('hello world');
404    msg.setSingularString('');
405    msg.setSingularBytes(goog.crypt.base64.encodeString('\u00FF\u00FF'));
406    msg.setSingularBytes('');
407    msg.setSingularForeignMessage(new proto.jspb.test.ForeignMessage());
408    msg.setSingularForeignMessage(null);
409    msg.setSingularForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR);
410    msg.setSingularForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO);
411    msg.setOneofUint32(32);
412    msg.clearOneofUint32();
413
414
415    var serialized = msg.serializeBinary();
416    assertEquals(0, serialized.length);
417  });
418
419  /**
420   * Test that base64 string and Uint8Array are interchangeable in bytes fields.
421   */
422  it('testBytesFieldsInterop', function() {
423    var msg = new proto.jspb.test.TestProto3();
424    // Set as a base64 string and check all the getters work.
425    msg.setSingularBytes(BYTES_B64);
426    assertTrue(bytesCompare(msg.getSingularBytes_asU8(), BYTES));
427    assertTrue(bytesCompare(msg.getSingularBytes_asB64(), BYTES));
428    assertTrue(bytesCompare(msg.getSingularBytes(), BYTES));
429
430    // Test binary serialize round trip doesn't break it.
431    msg = proto.jspb.test.TestProto3.deserializeBinary(msg.serializeBinary());
432    assertTrue(bytesCompare(msg.getSingularBytes_asU8(), BYTES));
433    assertTrue(bytesCompare(msg.getSingularBytes_asB64(), BYTES));
434    assertTrue(bytesCompare(msg.getSingularBytes(), BYTES));
435
436    msg = new proto.jspb.test.TestProto3();
437    // Set as a Uint8Array and check all the getters work.
438    msg.setSingularBytes(BYTES);
439    assertTrue(bytesCompare(msg.getSingularBytes_asU8(), BYTES));
440    assertTrue(bytesCompare(msg.getSingularBytes_asB64(), BYTES));
441    assertTrue(bytesCompare(msg.getSingularBytes(), BYTES));
442  });
443
444  it('testTimestampWellKnownType', function() {
445    var msg = new proto.google.protobuf.Timestamp();
446    msg.fromDate(new Date(123456789));
447    assertEquals(123456, msg.getSeconds());
448    assertEquals(789000000, msg.getNanos());
449    var date = msg.toDate();
450    assertEquals(123456789, date.getTime());
451    var anotherMsg = proto.google.protobuf.Timestamp.fromDate(date);
452    assertEquals(msg.getSeconds(), anotherMsg.getSeconds());
453    assertEquals(msg.getNanos(), anotherMsg.getNanos());
454  });
455
456  it('testStructWellKnownType', function() {
457    var jsObj = {
458      abc: 'def',
459      number: 12345.678,
460      nullKey: null,
461      boolKey: true,
462      listKey: [1, null, true, false, 'abc'],
463      structKey: {foo: 'bar', somenum: 123},
464      complicatedKey: [{xyz: {abc: [3, 4, null, false]}}, 'zzz']
465    };
466
467    var struct = proto.google.protobuf.Struct.fromJavaScript(jsObj);
468    var jsObj2 = struct.toJavaScript();
469
470    assertEquals('def', jsObj2.abc);
471    assertEquals(12345.678, jsObj2.number);
472    assertEquals(null, jsObj2.nullKey);
473    assertEquals(true, jsObj2.boolKey);
474    assertEquals('abc', jsObj2.listKey[4]);
475    assertEquals('bar', jsObj2.structKey.foo);
476    assertEquals(4, jsObj2.complicatedKey[0].xyz.abc[1]);
477  });
478});
479