blob: 957113859e5d2e765717d7cd8d2455d37a542537 [file] [log] [blame]
Feng Xiaoe841bac2015-12-11 17:09:20 -08001// 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 reader.
33 *
34 * There are two particular magic numbers that need to be pointed out -
35 * 2^64-1025 is the largest number representable as both a double and an
36 * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
37 * both a double and a signed 64-bit integer.
38 *
39 * Test suite is written using Jasmine -- see http://jasmine.github.io/
40 *
41 * @author aappleby@google.com (Austin Appleby)
42 */
43
44goog.require('goog.testing.asserts');
45goog.require('jspb.BinaryConstants');
46goog.require('jspb.BinaryDecoder');
47goog.require('jspb.BinaryReader');
48goog.require('jspb.BinaryWriter');
49
50
51
52describe('binaryReaderTest', function() {
53 /**
54 * Tests the reader instance cache.
Feng Xiaoe841bac2015-12-11 17:09:20 -080055 */
Adam Cozzetted64a2d92016-06-29 15:23:27 -070056 it('testInstanceCaches', /** @suppress {visibility} */ function() {
Feng Xiaoe841bac2015-12-11 17:09:20 -080057 var writer = new jspb.BinaryWriter();
58 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
59 writer.writeMessage(1, dummyMessage, goog.nullFunction);
60 writer.writeMessage(2, dummyMessage, goog.nullFunction);
61
62 var buffer = writer.getResultBuffer();
63
64 // Empty the instance caches.
65 jspb.BinaryReader.instanceCache_ = [];
66
67 // Allocating and then freeing three decoders should leave us with three in
68 // the cache.
69
70 var decoder1 = jspb.BinaryDecoder.alloc();
71 var decoder2 = jspb.BinaryDecoder.alloc();
72 var decoder3 = jspb.BinaryDecoder.alloc();
73 decoder1.free();
74 decoder2.free();
75 decoder3.free();
76
77 assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
78 assertEquals(0, jspb.BinaryReader.instanceCache_.length);
79
80 // Allocating and then freeing a reader should remove one decoder from its
81 // cache, but it should stay stuck to the reader afterwards since we can't
82 // have a reader without a decoder.
83 jspb.BinaryReader.alloc().free();
84
85 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
86 assertEquals(1, jspb.BinaryReader.instanceCache_.length);
87
88 // Allocating a reader should remove a reader from the cache.
89 var reader = jspb.BinaryReader.alloc(buffer);
90
91 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
92 assertEquals(0, jspb.BinaryReader.instanceCache_.length);
93
94 // Processing the message reuses the current reader.
95 reader.nextField();
96 assertEquals(1, reader.getFieldNumber());
97 reader.readMessage(dummyMessage, function() {
98 assertEquals(0, jspb.BinaryReader.instanceCache_.length);
99 });
100
101 reader.nextField();
102 assertEquals(2, reader.getFieldNumber());
103 reader.readMessage(dummyMessage, function() {
104 assertEquals(0, jspb.BinaryReader.instanceCache_.length);
105 });
106
107 assertEquals(false, reader.nextField());
108
109 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
110 assertEquals(0, jspb.BinaryReader.instanceCache_.length);
111
112 // Freeing the reader should put it back into the cache.
113 reader.free();
114
115 assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
116 assertEquals(1, jspb.BinaryReader.instanceCache_.length);
117 });
118
119
120 /**
121 * @param {number} x
122 * @return {number}
123 */
124 function truncate(x) {
125 var temp = new Float32Array(1);
126 temp[0] = x;
127 return temp[0];
128 }
129
130
131 /**
132 * Verifies that misuse of the reader class triggers assertions.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800133 */
Adam Cozzetted64a2d92016-06-29 15:23:27 -0700134 it('testReadErrors', /** @suppress {checkTypes|visibility} */ function() {
Feng Xiaoe841bac2015-12-11 17:09:20 -0800135 // Calling readMessage on a non-delimited field should trigger an
136 // assertion.
137 var reader = jspb.BinaryReader.alloc([8, 1]);
138 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
139 reader.nextField();
140 assertThrows(function() {
141 reader.readMessage(dummyMessage, goog.nullFunction);
142 });
143
144 // Reading past the end of the stream should trigger an assertion.
145 reader = jspb.BinaryReader.alloc([9, 1]);
146 reader.nextField();
147 assertThrows(function() {reader.readFixed64()});
148
149 // Reading past the end of a submessage should trigger an assertion.
150 reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
151 reader.nextField();
152 reader.readMessage(dummyMessage, function() {
153 reader.nextField();
154 assertThrows(function() {reader.readFixed32()});
155 });
156
157 // Skipping an invalid field should trigger an assertion.
158 reader = jspb.BinaryReader.alloc([12, 1]);
159 reader.nextWireType_ = 1000;
160 assertThrows(function() {reader.skipField()});
161
162 // Reading fields with the wrong wire type should assert.
163 reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
164 reader.nextField();
165 assertThrows(function() {reader.readInt32()});
166 assertThrows(function() {reader.readInt32String()});
167 assertThrows(function() {reader.readInt64()});
168 assertThrows(function() {reader.readInt64String()});
169 assertThrows(function() {reader.readUint32()});
170 assertThrows(function() {reader.readUint32String()});
171 assertThrows(function() {reader.readUint64()});
172 assertThrows(function() {reader.readUint64String()});
173 assertThrows(function() {reader.readSint32()});
174 assertThrows(function() {reader.readBool()});
175 assertThrows(function() {reader.readEnum()});
176
177 reader = jspb.BinaryReader.alloc([8, 1]);
178 reader.nextField();
179 assertThrows(function() {reader.readFixed32()});
180 assertThrows(function() {reader.readFixed64()});
181 assertThrows(function() {reader.readSfixed32()});
182 assertThrows(function() {reader.readSfixed64()});
183 assertThrows(function() {reader.readFloat()});
184 assertThrows(function() {reader.readDouble()});
185
186 assertThrows(function() {reader.readString()});
187 assertThrows(function() {reader.readBytes()});
188 });
189
190
191 /**
192 * Tests encoding and decoding of unsigned field types.
193 * @param {Function} readField
194 * @param {Function} writeField
195 * @param {number} epsilon
196 * @param {number} upperLimit
197 * @param {Function} filter
198 * @private
199 * @suppress {missingProperties}
200 */
Adam Cozzetted64a2d92016-06-29 15:23:27 -0700201 var doTestUnsignedField_ = function(readField,
Feng Xiaoe841bac2015-12-11 17:09:20 -0800202 writeField, epsilon, upperLimit, filter) {
203 assertNotNull(readField);
204 assertNotNull(writeField);
205
206 var writer = new jspb.BinaryWriter();
207
208 // Encode zero and limits.
209 writeField.call(writer, 1, filter(0));
210 writeField.call(writer, 2, filter(epsilon));
211 writeField.call(writer, 3, filter(upperLimit));
212
213 // Encode positive values.
214 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
215 writeField.call(writer, 4, filter(cursor));
216 }
217
218 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
219
220 // Check zero and limits.
221 reader.nextField();
222 assertEquals(1, reader.getFieldNumber());
223 assertEquals(filter(0), readField.call(reader));
224
225 reader.nextField();
226 assertEquals(2, reader.getFieldNumber());
227 assertEquals(filter(epsilon), readField.call(reader));
228
229 reader.nextField();
230 assertEquals(3, reader.getFieldNumber());
231 assertEquals(filter(upperLimit), readField.call(reader));
232
233 // Check positive values.
234 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
235 reader.nextField();
236 if (4 != reader.getFieldNumber()) throw 'fail!';
237 if (filter(cursor) != readField.call(reader)) throw 'fail!';
238 }
239 };
240
241
242 /**
243 * Tests encoding and decoding of signed field types.
244 * @param {Function} readField
245 * @param {Function} writeField
246 * @param {number} epsilon
247 * @param {number} lowerLimit
248 * @param {number} upperLimit
249 * @param {Function} filter
250 * @private
251 * @suppress {missingProperties}
252 */
Adam Cozzetted64a2d92016-06-29 15:23:27 -0700253 var doTestSignedField_ = function(readField,
Feng Xiaoe841bac2015-12-11 17:09:20 -0800254 writeField, epsilon, lowerLimit, upperLimit, filter) {
255 var writer = new jspb.BinaryWriter();
256
257 // Encode zero and limits.
258 writeField.call(writer, 1, filter(lowerLimit));
259 writeField.call(writer, 2, filter(-epsilon));
260 writeField.call(writer, 3, filter(0));
261 writeField.call(writer, 4, filter(epsilon));
262 writeField.call(writer, 5, filter(upperLimit));
263
264 var inputValues = [];
265
266 // Encode negative values.
267 for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
268 var val = filter(cursor);
269 writeField.call(writer, 6, val);
270 inputValues.push({
271 fieldNumber: 6,
272 value: val
273 });
274 }
275
276 // Encode positive values.
277 for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
278 var val = filter(cursor);
279 writeField.call(writer, 7, val);
280 inputValues.push({
281 fieldNumber: 7,
282 value: val
283 });
284 }
285
286 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
287
288 // Check zero and limits.
289 reader.nextField();
290 assertEquals(1, reader.getFieldNumber());
291 assertEquals(filter(lowerLimit), readField.call(reader));
292
293 reader.nextField();
294 assertEquals(2, reader.getFieldNumber());
295 assertEquals(filter(-epsilon), readField.call(reader));
296
297 reader.nextField();
298 assertEquals(3, reader.getFieldNumber());
299 assertEquals(filter(0), readField.call(reader));
300
301 reader.nextField();
302 assertEquals(4, reader.getFieldNumber());
303 assertEquals(filter(epsilon), readField.call(reader));
304
305 reader.nextField();
306 assertEquals(5, reader.getFieldNumber());
307 assertEquals(filter(upperLimit), readField.call(reader));
308
309 for (var i = 0; i < inputValues.length; i++) {
310 var expected = inputValues[i];
311 reader.nextField();
312 assertEquals(expected.fieldNumber, reader.getFieldNumber());
313 assertEquals(expected.value, readField.call(reader));
314 }
315 };
316
317
318 /**
319 * Tests fields that use varint encoding.
320 */
321 it('testVarintFields', function() {
Adam Cozzetted64a2d92016-06-29 15:23:27 -0700322 assertNotUndefined(jspb.BinaryReader.prototype.readUint32);
323 assertNotUndefined(jspb.BinaryWriter.prototype.writeUint32);
324 assertNotUndefined(jspb.BinaryReader.prototype.readUint64);
325 assertNotUndefined(jspb.BinaryWriter.prototype.writeUint64);
326 assertNotUndefined(jspb.BinaryReader.prototype.readBool);
327 assertNotUndefined(jspb.BinaryWriter.prototype.writeBool);
Feng Xiaoe841bac2015-12-11 17:09:20 -0800328 doTestUnsignedField_(
329 jspb.BinaryReader.prototype.readUint32,
330 jspb.BinaryWriter.prototype.writeUint32,
331 1, Math.pow(2, 32) - 1, Math.round);
332
333 doTestUnsignedField_(
334 jspb.BinaryReader.prototype.readUint64,
335 jspb.BinaryWriter.prototype.writeUint64,
336 1, Math.pow(2, 64) - 1025, Math.round);
337
338 doTestSignedField_(
339 jspb.BinaryReader.prototype.readInt32,
340 jspb.BinaryWriter.prototype.writeInt32,
341 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
342
343 doTestSignedField_(
344 jspb.BinaryReader.prototype.readInt64,
345 jspb.BinaryWriter.prototype.writeInt64,
346 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
347
348 doTestSignedField_(
349 jspb.BinaryReader.prototype.readEnum,
350 jspb.BinaryWriter.prototype.writeEnum,
351 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
352
353 doTestUnsignedField_(
354 jspb.BinaryReader.prototype.readBool,
355 jspb.BinaryWriter.prototype.writeBool,
356 1, 1, function(x) { return !!x; });
357 });
358
359
360 /**
Grigoriy Kraynov5d54a852016-05-12 14:11:20 +0100361 * Tests reading a field from hexadecimal string (format: '08 BE EF').
362 * @param {Function} readField
363 * @param {number} expected
364 * @param {string} hexString
365 */
366 function doTestHexStringVarint_(readField, expected, hexString) {
367 var bytesCount = (hexString.length + 1) / 3;
368 var bytes = new Uint8Array(bytesCount);
369 for (var i = 0; i < bytesCount; i++) {
Adam Cozzetted64a2d92016-06-29 15:23:27 -0700370 bytes[i] = parseInt(hexString.substring(i * 3, i * 3 + 2), 16);
Grigoriy Kraynov5d54a852016-05-12 14:11:20 +0100371 }
372 var reader = jspb.BinaryReader.alloc(bytes);
373 reader.nextField();
374 assertEquals(expected, readField.call(reader));
375 }
376
377
378 /**
379 * Tests non-canonical redundant varint decoding.
380 */
381 it('testRedundantVarintFields', function() {
382 assertNotNull(jspb.BinaryReader.prototype.readUint32);
383 assertNotNull(jspb.BinaryReader.prototype.readUint64);
384 assertNotNull(jspb.BinaryReader.prototype.readSint32);
385 assertNotNull(jspb.BinaryReader.prototype.readSint64);
386
387 // uint32 and sint32 take no more than 5 bytes
388 // 08 - field prefix (type = 0 means varint)
389 doTestHexStringVarint_(
390 jspb.BinaryReader.prototype.readUint32,
391 12, '08 8C 80 80 80 00');
392
393 // 11 stands for -6 in zigzag encoding
394 doTestHexStringVarint_(
395 jspb.BinaryReader.prototype.readSint32,
396 -6, '08 8B 80 80 80 00');
397
398 // uint64 and sint64 take no more than 10 bytes
399 // 08 - field prefix (type = 0 means varint)
400 doTestHexStringVarint_(
401 jspb.BinaryReader.prototype.readUint64,
402 12, '08 8C 80 80 80 80 80 80 80 80 00');
403
404 // 11 stands for -6 in zigzag encoding
405 doTestHexStringVarint_(
406 jspb.BinaryReader.prototype.readSint64,
407 -6, '08 8B 80 80 80 80 80 80 80 80 00');
408 });
409
410
411 /**
Feng Xiaoe841bac2015-12-11 17:09:20 -0800412 * Tests 64-bit fields that are handled as strings.
413 */
414 it('testStringInt64Fields', function() {
415 var writer = new jspb.BinaryWriter();
416
417 var testSignedData = [
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700418 '2730538252207801776',
419 '-2688470994844604560',
420 '3398529779486536359',
421 '3568577411627971000',
422 '272477188847484900',
423 '-6649058714086158188',
424 '-7695254765712060806',
425 '-4525541438037104029',
426 '-4993706538836508568',
427 '4990160321893729138'
Feng Xiaoe841bac2015-12-11 17:09:20 -0800428 ];
429 var testUnsignedData = [
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700430 '7822732630241694882',
431 '6753602971916687352',
432 '2399935075244442116',
433 '8724292567325338867',
434 '16948784802625696584',
435 '4136275908516066934',
436 '3575388346793700364',
437 '5167142028379259461',
438 '1557573948689737699',
439 '17100725280812548567'
Feng Xiaoe841bac2015-12-11 17:09:20 -0800440 ];
441
442 for (var i = 0; i < testSignedData.length; i++) {
443 writer.writeInt64String(2 * i + 1, testSignedData[i]);
444 writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
445 }
446
447 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
448
449 for (var i = 0; i < testSignedData.length; i++) {
450 reader.nextField();
451 assertEquals(2 * i + 1, reader.getFieldNumber());
452 assertEquals(testSignedData[i], reader.readInt64String());
453 reader.nextField();
454 assertEquals(2 * i + 2, reader.getFieldNumber());
455 assertEquals(testUnsignedData[i], reader.readUint64String());
456 }
457 });
458
459
460 /**
461 * Tests fields that use zigzag encoding.
462 */
463 it('testZigzagFields', function() {
464 doTestSignedField_(
465 jspb.BinaryReader.prototype.readSint32,
466 jspb.BinaryWriter.prototype.writeSint32,
467 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
468
469 doTestSignedField_(
470 jspb.BinaryReader.prototype.readSint64,
471 jspb.BinaryWriter.prototype.writeSint64,
472 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
473 });
474
475
476 /**
477 * Tests fields that use fixed-length encoding.
478 */
479 it('testFixedFields', function() {
480 doTestUnsignedField_(
481 jspb.BinaryReader.prototype.readFixed32,
482 jspb.BinaryWriter.prototype.writeFixed32,
483 1, Math.pow(2, 32) - 1, Math.round);
484
485 doTestUnsignedField_(
486 jspb.BinaryReader.prototype.readFixed64,
487 jspb.BinaryWriter.prototype.writeFixed64,
488 1, Math.pow(2, 64) - 1025, Math.round);
489
490 doTestSignedField_(
491 jspb.BinaryReader.prototype.readSfixed32,
492 jspb.BinaryWriter.prototype.writeSfixed32,
493 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
494
495 doTestSignedField_(
496 jspb.BinaryReader.prototype.readSfixed64,
497 jspb.BinaryWriter.prototype.writeSfixed64,
498 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
499 });
500
501
502 /**
503 * Tests floating point fields.
504 */
505 it('testFloatFields', function() {
506 doTestSignedField_(
507 jspb.BinaryReader.prototype.readFloat,
508 jspb.BinaryWriter.prototype.writeFloat,
509 jspb.BinaryConstants.FLOAT32_MIN,
510 -jspb.BinaryConstants.FLOAT32_MAX,
511 jspb.BinaryConstants.FLOAT32_MAX,
512 truncate);
513
514 doTestSignedField_(
515 jspb.BinaryReader.prototype.readDouble,
516 jspb.BinaryWriter.prototype.writeDouble,
517 jspb.BinaryConstants.FLOAT64_EPS * 10,
518 -jspb.BinaryConstants.FLOAT64_MIN,
519 jspb.BinaryConstants.FLOAT64_MIN,
520 function(x) { return x; });
521 });
522
523
524 /**
525 * Tests length-delimited string fields.
526 */
527 it('testStringFields', function() {
528 var s1 = 'The quick brown fox jumps over the lazy dog.';
529 var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
530
531 var writer = new jspb.BinaryWriter();
532
533 writer.writeString(1, s1);
534 writer.writeString(2, s2);
535
536 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
537
538 reader.nextField();
539 assertEquals(1, reader.getFieldNumber());
540 assertEquals(s1, reader.readString());
541
542 reader.nextField();
543 assertEquals(2, reader.getFieldNumber());
544 assertEquals(s2, reader.readString());
545 });
546
547
548 /**
549 * Tests length-delimited byte fields.
550 */
551 it('testByteFields', function() {
552 var message = [];
553 var lowerLimit = 1;
554 var upperLimit = 256;
555 var scale = 1.1;
556
557 var writer = new jspb.BinaryWriter();
558
559 for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
560 var len = Math.round(cursor);
561 var bytes = [];
562 for (var i = 0; i < len; i++) bytes.push(i % 256);
563
564 writer.writeBytes(len, bytes);
565 }
566
567 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
568
569 for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
570 var len = Math.round(cursor);
571 if (len != reader.getFieldNumber()) throw 'fail!';
572
573 var bytes = reader.readBytes();
574 if (len != bytes.length) throw 'fail!';
575 for (var i = 0; i < bytes.length; i++) {
576 if (i % 256 != bytes[i]) throw 'fail!';
577 }
578 }
579 });
580
581
582 /**
583 * Tests nested messages.
584 */
585 it('testNesting', function() {
586 var writer = new jspb.BinaryWriter();
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700587 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
Feng Xiaoe841bac2015-12-11 17:09:20 -0800588
589 writer.writeInt32(1, 100);
590
591 // Add one message with 3 int fields.
592 writer.writeMessage(2, dummyMessage, function() {
593 writer.writeInt32(3, 300);
594 writer.writeInt32(4, 400);
595 writer.writeInt32(5, 500);
596 });
597
598 // Add one empty message.
599 writer.writeMessage(6, dummyMessage, goog.nullFunction);
600
601 writer.writeInt32(7, 700);
602
603 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
604
605 // Validate outermost message.
606
607 reader.nextField();
608 assertEquals(1, reader.getFieldNumber());
609 assertEquals(100, reader.readInt32());
610
611 reader.nextField();
612 assertEquals(2, reader.getFieldNumber());
613 reader.readMessage(dummyMessage, function() {
614 // Validate embedded message 1.
615 reader.nextField();
616 assertEquals(3, reader.getFieldNumber());
617 assertEquals(300, reader.readInt32());
618
619 reader.nextField();
620 assertEquals(4, reader.getFieldNumber());
621 assertEquals(400, reader.readInt32());
622
623 reader.nextField();
624 assertEquals(5, reader.getFieldNumber());
625 assertEquals(500, reader.readInt32());
626
627 assertEquals(false, reader.nextField());
628 });
629
630 reader.nextField();
631 assertEquals(6, reader.getFieldNumber());
632 reader.readMessage(dummyMessage, function() {
633 // Validate embedded message 2.
634
635 assertEquals(false, reader.nextField());
636 });
637
638 reader.nextField();
639 assertEquals(7, reader.getFieldNumber());
640 assertEquals(700, reader.readInt32());
641
642 assertEquals(false, reader.nextField());
643 });
644
645 /**
646 * Tests skipping fields of each type by interleaving them with sentinel
647 * values and skipping everything that's not a sentinel.
648 */
649 it('testSkipField', function() {
650 var writer = new jspb.BinaryWriter();
651
652 var sentinel = 123456789;
653
654 // Write varint fields of different sizes.
655 writer.writeInt32(1, sentinel);
656 writer.writeInt32(1, 1);
657 writer.writeInt32(1, 1000);
658 writer.writeInt32(1, 1000000);
659 writer.writeInt32(1, 1000000000);
660
661 // Write fixed 64-bit encoded fields.
662 writer.writeInt32(2, sentinel);
663 writer.writeDouble(2, 1);
664 writer.writeFixed64(2, 1);
665 writer.writeSfixed64(2, 1);
666
667 // Write fixed 32-bit encoded fields.
668 writer.writeInt32(3, sentinel);
669 writer.writeFloat(3, 1);
670 writer.writeFixed32(3, 1);
671 writer.writeSfixed32(3, 1);
672
673 // Write delimited fields.
674 writer.writeInt32(4, sentinel);
675 writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
676 writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
677
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700678 // Write a group with a nested group inside.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800679 writer.writeInt32(5, sentinel);
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700680 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
681 writer.writeGroup(5, dummyMessage, function() {
682 writer.writeInt64(42, 42);
683 writer.writeGroup(6, dummyMessage, function() {
684 writer.writeInt64(84, 42);
685 });
686 });
Feng Xiaoe841bac2015-12-11 17:09:20 -0800687
688 // Write final sentinel.
689 writer.writeInt32(6, sentinel);
690
691 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
692
693 function skip(field, count) {
694 for (var i = 0; i < count; i++) {
695 reader.nextField();
696 if (field != reader.getFieldNumber()) throw 'fail!';
697 reader.skipField();
698 }
699 }
700
701 reader.nextField();
702 assertEquals(1, reader.getFieldNumber());
703 assertEquals(sentinel, reader.readInt32());
704 skip(1, 4);
705
706 reader.nextField();
707 assertEquals(2, reader.getFieldNumber());
708 assertEquals(sentinel, reader.readInt32());
709 skip(2, 3);
710
711 reader.nextField();
712 assertEquals(3, reader.getFieldNumber());
713 assertEquals(sentinel, reader.readInt32());
714 skip(3, 3);
715
716 reader.nextField();
717 assertEquals(4, reader.getFieldNumber());
718 assertEquals(sentinel, reader.readInt32());
719 skip(4, 2);
720
721 reader.nextField();
722 assertEquals(5, reader.getFieldNumber());
723 assertEquals(sentinel, reader.readInt32());
724 skip(5, 1);
725
726 reader.nextField();
727 assertEquals(6, reader.getFieldNumber());
728 assertEquals(sentinel, reader.readInt32());
729 });
730
731
732 /**
733 * Tests packed fields.
734 */
735 it('testPackedFields', function() {
736 var writer = new jspb.BinaryWriter();
737
738 var sentinel = 123456789;
739
740 var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
741 var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
742 var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
743 var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
744 var boolData = [true, false, true, true, false, false, true, false];
745
746 for (var i = 0; i < floatData.length; i++) {
747 floatData[i] = truncate(floatData[i]);
748 }
749
750 writer.writeInt32(1, sentinel);
751
752 writer.writePackedInt32(2, signedData);
753 writer.writePackedInt64(2, signedData);
754 writer.writePackedUint32(2, unsignedData);
755 writer.writePackedUint64(2, unsignedData);
756 writer.writePackedSint32(2, signedData);
757 writer.writePackedSint64(2, signedData);
758 writer.writePackedFixed32(2, unsignedData);
759 writer.writePackedFixed64(2, unsignedData);
760 writer.writePackedSfixed32(2, signedData);
761 writer.writePackedSfixed64(2, signedData);
762 writer.writePackedFloat(2, floatData);
763 writer.writePackedDouble(2, doubleData);
764 writer.writePackedBool(2, boolData);
765 writer.writePackedEnum(2, unsignedData);
766
767 writer.writeInt32(3, sentinel);
768
769 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
770
771 reader.nextField();
772 assertEquals(sentinel, reader.readInt32());
773
774 reader.nextField();
775 assertElementsEquals(reader.readPackedInt32(), signedData);
776
777 reader.nextField();
778 assertElementsEquals(reader.readPackedInt64(), signedData);
779
780 reader.nextField();
781 assertElementsEquals(reader.readPackedUint32(), unsignedData);
782
783 reader.nextField();
784 assertElementsEquals(reader.readPackedUint64(), unsignedData);
785
786 reader.nextField();
787 assertElementsEquals(reader.readPackedSint32(), signedData);
788
789 reader.nextField();
790 assertElementsEquals(reader.readPackedSint64(), signedData);
791
792 reader.nextField();
793 assertElementsEquals(reader.readPackedFixed32(), unsignedData);
794
795 reader.nextField();
796 assertElementsEquals(reader.readPackedFixed64(), unsignedData);
797
798 reader.nextField();
799 assertElementsEquals(reader.readPackedSfixed32(), signedData);
800
801 reader.nextField();
802 assertElementsEquals(reader.readPackedSfixed64(), signedData);
803
804 reader.nextField();
805 assertElementsEquals(reader.readPackedFloat(), floatData);
806
807 reader.nextField();
808 assertElementsEquals(reader.readPackedDouble(), doubleData);
809
810 reader.nextField();
811 assertElementsEquals(reader.readPackedBool(), boolData);
812
813 reader.nextField();
814 assertElementsEquals(reader.readPackedEnum(), unsignedData);
815
816 reader.nextField();
817 assertEquals(sentinel, reader.readInt32());
818 });
819
820
821 /**
822 * Byte blobs inside nested messages should always have their byte offset set
823 * relative to the start of the outermost blob, not the start of their parent
824 * blob.
825 */
826 it('testNestedBlobs', function() {
827 // Create a proto consisting of two nested messages, with the inner one
828 // containing a blob of bytes.
829
830 var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
831 var blob = [1, 2, 3, 4, 5];
832 var writer = new jspb.BinaryWriter();
833 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
834
835 writer.writeMessage(1, dummyMessage, function() {
836 writer.writeMessage(1, dummyMessage, function() {
837 writer.writeBytes(1, blob);
838 });
839 });
840
841 // Peel off the outer two message layers. Each layer should have two bytes
842 // of overhead, one for the field tag and one for the length of the inner
843 // blob.
844
845 var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
846 assertEquals(fieldTag, decoder1.readUnsignedVarint32());
847 assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
848
849 var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
850 assertEquals(fieldTag, decoder2.readUnsignedVarint32());
851 assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
852
853 assertEquals(fieldTag, decoder2.readUnsignedVarint32());
854 assertEquals(blob.length, decoder2.readUnsignedVarint32());
855 var bytes = decoder2.readBytes(blob.length);
856
857 assertElementsEquals(bytes, blob);
858 });
859
860
861 /**
862 * Tests read callbacks.
863 */
864 it('testReadCallbacks', function() {
865 var writer = new jspb.BinaryWriter();
866 var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
867
868 // Add an int, a submessage, and another int.
869 writer.writeInt32(1, 100);
870
871 writer.writeMessage(2, dummyMessage, function() {
872 writer.writeInt32(3, 300);
873 writer.writeInt32(4, 400);
874 writer.writeInt32(5, 500);
875 });
876
877 writer.writeInt32(7, 700);
878
879 // Create the reader and register a custom read callback.
880 var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
881
882 /**
883 * @param {!jspb.BinaryReader} reader
884 * @return {*}
885 */
886 function readCallback(reader) {
887 reader.nextField();
888 assertEquals(3, reader.getFieldNumber());
889 assertEquals(300, reader.readInt32());
890
891 reader.nextField();
892 assertEquals(4, reader.getFieldNumber());
893 assertEquals(400, reader.readInt32());
894
895 reader.nextField();
896 assertEquals(5, reader.getFieldNumber());
897 assertEquals(500, reader.readInt32());
898
899 assertEquals(false, reader.nextField());
900 };
901
902 reader.registerReadCallback('readCallback', readCallback);
903
904 // Read the container message.
905 reader.nextField();
906 assertEquals(1, reader.getFieldNumber());
907 assertEquals(100, reader.readInt32());
908
909 reader.nextField();
910 assertEquals(2, reader.getFieldNumber());
911 reader.readMessage(dummyMessage, function() {
912 // Decode the embedded message using the registered callback.
913 reader.runReadCallback('readCallback');
914 });
915
916 reader.nextField();
917 assertEquals(7, reader.getFieldNumber());
918 assertEquals(700, reader.readInt32());
919
920 assertEquals(false, reader.nextField());
921 });
922});