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