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