reader_test.js 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. /**
  31. * @fileoverview Test cases for jspb's binary protocol buffer reader.
  32. *
  33. * There are two particular magic numbers that need to be pointed out -
  34. * 2^64-1025 is the largest number representable as both a double and an
  35. * unsigned 64-bit integer, and 2^63-513 is the largest number representable as
  36. * both a double and a signed 64-bit integer.
  37. *
  38. * Test suite is written using Jasmine -- see http://jasmine.github.io/
  39. *
  40. * @author aappleby@google.com (Austin Appleby)
  41. */
  42. goog.require('goog.testing.asserts');
  43. // CommonJS-LoadFromFile: google_protobuf
  44. goog.require('jspb.BinaryConstants');
  45. goog.require('jspb.BinaryDecoder');
  46. goog.require('jspb.BinaryReader');
  47. goog.require('jspb.BinaryWriter');
  48. describe('binaryReaderTest', function() {
  49. /**
  50. * Tests the reader instance cache.
  51. * @suppress {visibility}
  52. */
  53. it('testInstanceCaches', function() {
  54. var writer = new jspb.BinaryWriter();
  55. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  56. writer.writeMessage(1, dummyMessage, goog.nullFunction);
  57. writer.writeMessage(2, dummyMessage, goog.nullFunction);
  58. var buffer = writer.getResultBuffer();
  59. // Empty the instance caches.
  60. jspb.BinaryReader.instanceCache_ = [];
  61. // Allocating and then freeing three decoders should leave us with three in
  62. // the cache.
  63. var decoder1 = jspb.BinaryDecoder.alloc();
  64. var decoder2 = jspb.BinaryDecoder.alloc();
  65. var decoder3 = jspb.BinaryDecoder.alloc();
  66. decoder1.free();
  67. decoder2.free();
  68. decoder3.free();
  69. assertEquals(3, jspb.BinaryDecoder.instanceCache_.length);
  70. assertEquals(0, jspb.BinaryReader.instanceCache_.length);
  71. // Allocating and then freeing a reader should remove one decoder from its
  72. // cache, but it should stay stuck to the reader afterwards since we can't
  73. // have a reader without a decoder.
  74. jspb.BinaryReader.alloc().free();
  75. assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
  76. assertEquals(1, jspb.BinaryReader.instanceCache_.length);
  77. // Allocating a reader should remove a reader from the cache.
  78. var reader = jspb.BinaryReader.alloc(buffer);
  79. assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
  80. assertEquals(0, jspb.BinaryReader.instanceCache_.length);
  81. // Processing the message reuses the current reader.
  82. reader.nextField();
  83. assertEquals(1, reader.getFieldNumber());
  84. reader.readMessage(dummyMessage, function() {
  85. assertEquals(0, jspb.BinaryReader.instanceCache_.length);
  86. });
  87. reader.nextField();
  88. assertEquals(2, reader.getFieldNumber());
  89. reader.readMessage(dummyMessage, function() {
  90. assertEquals(0, jspb.BinaryReader.instanceCache_.length);
  91. });
  92. assertEquals(false, reader.nextField());
  93. assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
  94. assertEquals(0, jspb.BinaryReader.instanceCache_.length);
  95. // Freeing the reader should put it back into the cache.
  96. reader.free();
  97. assertEquals(2, jspb.BinaryDecoder.instanceCache_.length);
  98. assertEquals(1, jspb.BinaryReader.instanceCache_.length);
  99. });
  100. /**
  101. * @param {number} x
  102. * @return {number}
  103. */
  104. function truncate(x) {
  105. var temp = new Float32Array(1);
  106. temp[0] = x;
  107. return temp[0];
  108. }
  109. /**
  110. * Verifies that misuse of the reader class triggers assertions.
  111. * @suppress {checkTypes|visibility}
  112. */
  113. it('testReadErrors', function() {
  114. // Calling readMessage on a non-delimited field should trigger an
  115. // assertion.
  116. var reader = jspb.BinaryReader.alloc([8, 1]);
  117. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  118. reader.nextField();
  119. assertThrows(function() {
  120. reader.readMessage(dummyMessage, goog.nullFunction);
  121. });
  122. // Reading past the end of the stream should trigger an assertion.
  123. reader = jspb.BinaryReader.alloc([9, 1]);
  124. reader.nextField();
  125. assertThrows(function() {reader.readFixed64()});
  126. // Reading past the end of a submessage should trigger an assertion.
  127. reader = jspb.BinaryReader.alloc([10, 4, 13, 1, 1, 1]);
  128. reader.nextField();
  129. reader.readMessage(dummyMessage, function() {
  130. reader.nextField();
  131. assertThrows(function() {reader.readFixed32()});
  132. });
  133. // Skipping an invalid field should trigger an assertion.
  134. reader = jspb.BinaryReader.alloc([12, 1]);
  135. reader.nextWireType_ = 1000;
  136. assertThrows(function() {reader.skipField()});
  137. // Reading fields with the wrong wire type should assert.
  138. reader = jspb.BinaryReader.alloc([9, 0, 0, 0, 0, 0, 0, 0, 0]);
  139. reader.nextField();
  140. assertThrows(function() {reader.readInt32()});
  141. assertThrows(function() {reader.readInt32String()});
  142. assertThrows(function() {reader.readInt64()});
  143. assertThrows(function() {reader.readInt64String()});
  144. assertThrows(function() {reader.readUint32()});
  145. assertThrows(function() {reader.readUint32String()});
  146. assertThrows(function() {reader.readUint64()});
  147. assertThrows(function() {reader.readUint64String()});
  148. assertThrows(function() {reader.readSint32()});
  149. assertThrows(function() {reader.readBool()});
  150. assertThrows(function() {reader.readEnum()});
  151. reader = jspb.BinaryReader.alloc([8, 1]);
  152. reader.nextField();
  153. assertThrows(function() {reader.readFixed32()});
  154. assertThrows(function() {reader.readFixed64()});
  155. assertThrows(function() {reader.readSfixed32()});
  156. assertThrows(function() {reader.readSfixed64()});
  157. assertThrows(function() {reader.readFloat()});
  158. assertThrows(function() {reader.readDouble()});
  159. assertThrows(function() {reader.readString()});
  160. assertThrows(function() {reader.readBytes()});
  161. });
  162. /**
  163. * Tests encoding and decoding of unsigned field types.
  164. * @param {Function} readField
  165. * @param {Function} writeField
  166. * @param {number} epsilon
  167. * @param {number} upperLimit
  168. * @param {Function} filter
  169. * @private
  170. * @suppress {missingProperties}
  171. */
  172. function doTestUnsignedField_(readField,
  173. writeField, epsilon, upperLimit, filter) {
  174. assertNotNull(readField);
  175. assertNotNull(writeField);
  176. var writer = new jspb.BinaryWriter();
  177. // Encode zero and limits.
  178. writeField.call(writer, 1, filter(0));
  179. writeField.call(writer, 2, filter(epsilon));
  180. writeField.call(writer, 3, filter(upperLimit));
  181. // Encode positive values.
  182. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
  183. writeField.call(writer, 4, filter(cursor));
  184. }
  185. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  186. // Check zero and limits.
  187. reader.nextField();
  188. assertEquals(1, reader.getFieldNumber());
  189. assertEquals(filter(0), readField.call(reader));
  190. reader.nextField();
  191. assertEquals(2, reader.getFieldNumber());
  192. assertEquals(filter(epsilon), readField.call(reader));
  193. reader.nextField();
  194. assertEquals(3, reader.getFieldNumber());
  195. assertEquals(filter(upperLimit), readField.call(reader));
  196. // Check positive values.
  197. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
  198. reader.nextField();
  199. if (4 != reader.getFieldNumber()) throw 'fail!';
  200. if (filter(cursor) != readField.call(reader)) throw 'fail!';
  201. }
  202. };
  203. /**
  204. * Tests encoding and decoding of signed field types.
  205. * @param {Function} readField
  206. * @param {Function} writeField
  207. * @param {number} epsilon
  208. * @param {number} lowerLimit
  209. * @param {number} upperLimit
  210. * @param {Function} filter
  211. * @private
  212. * @suppress {missingProperties}
  213. */
  214. function doTestSignedField_(readField,
  215. writeField, epsilon, lowerLimit, upperLimit, filter) {
  216. var writer = new jspb.BinaryWriter();
  217. // Encode zero and limits.
  218. writeField.call(writer, 1, filter(lowerLimit));
  219. writeField.call(writer, 2, filter(-epsilon));
  220. writeField.call(writer, 3, filter(0));
  221. writeField.call(writer, 4, filter(epsilon));
  222. writeField.call(writer, 5, filter(upperLimit));
  223. var inputValues = [];
  224. // Encode negative values.
  225. for (var cursor = lowerLimit; cursor < -epsilon; cursor /= 1.1) {
  226. var val = filter(cursor);
  227. writeField.call(writer, 6, val);
  228. inputValues.push({
  229. fieldNumber: 6,
  230. value: val
  231. });
  232. }
  233. // Encode positive values.
  234. for (var cursor = epsilon; cursor < upperLimit; cursor *= 1.1) {
  235. var val = filter(cursor);
  236. writeField.call(writer, 7, val);
  237. inputValues.push({
  238. fieldNumber: 7,
  239. value: val
  240. });
  241. }
  242. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  243. // Check zero and limits.
  244. reader.nextField();
  245. assertEquals(1, reader.getFieldNumber());
  246. assertEquals(filter(lowerLimit), readField.call(reader));
  247. reader.nextField();
  248. assertEquals(2, reader.getFieldNumber());
  249. assertEquals(filter(-epsilon), readField.call(reader));
  250. reader.nextField();
  251. assertEquals(3, reader.getFieldNumber());
  252. assertEquals(filter(0), readField.call(reader));
  253. reader.nextField();
  254. assertEquals(4, reader.getFieldNumber());
  255. assertEquals(filter(epsilon), readField.call(reader));
  256. reader.nextField();
  257. assertEquals(5, reader.getFieldNumber());
  258. assertEquals(filter(upperLimit), readField.call(reader));
  259. for (var i = 0; i < inputValues.length; i++) {
  260. var expected = inputValues[i];
  261. reader.nextField();
  262. assertEquals(expected.fieldNumber, reader.getFieldNumber());
  263. assertEquals(expected.value, readField.call(reader));
  264. }
  265. };
  266. /**
  267. * Tests fields that use varint encoding.
  268. */
  269. it('testVarintFields', function() {
  270. assertNotNull(jspb.BinaryReader.prototype.readUint32);
  271. assertNotNull(jspb.BinaryReader.prototype.writeUint32);
  272. assertNotNull(jspb.BinaryReader.prototype.readUint64);
  273. assertNotNull(jspb.BinaryReader.prototype.writeUint64);
  274. assertNotNull(jspb.BinaryReader.prototype.readBool);
  275. assertNotNull(jspb.BinaryReader.prototype.writeBool);
  276. doTestUnsignedField_(
  277. jspb.BinaryReader.prototype.readUint32,
  278. jspb.BinaryWriter.prototype.writeUint32,
  279. 1, Math.pow(2, 32) - 1, Math.round);
  280. doTestUnsignedField_(
  281. jspb.BinaryReader.prototype.readUint64,
  282. jspb.BinaryWriter.prototype.writeUint64,
  283. 1, Math.pow(2, 64) - 1025, Math.round);
  284. doTestSignedField_(
  285. jspb.BinaryReader.prototype.readInt32,
  286. jspb.BinaryWriter.prototype.writeInt32,
  287. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  288. doTestSignedField_(
  289. jspb.BinaryReader.prototype.readInt64,
  290. jspb.BinaryWriter.prototype.writeInt64,
  291. 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
  292. doTestSignedField_(
  293. jspb.BinaryReader.prototype.readEnum,
  294. jspb.BinaryWriter.prototype.writeEnum,
  295. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  296. doTestUnsignedField_(
  297. jspb.BinaryReader.prototype.readBool,
  298. jspb.BinaryWriter.prototype.writeBool,
  299. 1, 1, function(x) { return !!x; });
  300. });
  301. /**
  302. * Tests 64-bit fields that are handled as strings.
  303. */
  304. it('testStringInt64Fields', function() {
  305. var writer = new jspb.BinaryWriter();
  306. var testSignedData = [
  307. '2730538252207801776',
  308. '-2688470994844604560',
  309. '3398529779486536359',
  310. '3568577411627971000',
  311. '272477188847484900',
  312. '-6649058714086158188',
  313. '-7695254765712060806',
  314. '-4525541438037104029',
  315. '-4993706538836508568',
  316. '4990160321893729138'
  317. ];
  318. var testUnsignedData = [
  319. '7822732630241694882',
  320. '6753602971916687352',
  321. '2399935075244442116',
  322. '8724292567325338867',
  323. '16948784802625696584',
  324. '4136275908516066934',
  325. '3575388346793700364',
  326. '5167142028379259461',
  327. '1557573948689737699',
  328. '17100725280812548567'
  329. ];
  330. for (var i = 0; i < testSignedData.length; i++) {
  331. writer.writeInt64String(2 * i + 1, testSignedData[i]);
  332. writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
  333. }
  334. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  335. for (var i = 0; i < testSignedData.length; i++) {
  336. reader.nextField();
  337. assertEquals(2 * i + 1, reader.getFieldNumber());
  338. assertEquals(testSignedData[i], reader.readInt64String());
  339. reader.nextField();
  340. assertEquals(2 * i + 2, reader.getFieldNumber());
  341. assertEquals(testUnsignedData[i], reader.readUint64String());
  342. }
  343. });
  344. /**
  345. * Tests fields that use zigzag encoding.
  346. */
  347. it('testZigzagFields', function() {
  348. doTestSignedField_(
  349. jspb.BinaryReader.prototype.readSint32,
  350. jspb.BinaryWriter.prototype.writeSint32,
  351. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  352. doTestSignedField_(
  353. jspb.BinaryReader.prototype.readSint64,
  354. jspb.BinaryWriter.prototype.writeSint64,
  355. 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
  356. });
  357. /**
  358. * Tests fields that use fixed-length encoding.
  359. */
  360. it('testFixedFields', function() {
  361. doTestUnsignedField_(
  362. jspb.BinaryReader.prototype.readFixed32,
  363. jspb.BinaryWriter.prototype.writeFixed32,
  364. 1, Math.pow(2, 32) - 1, Math.round);
  365. doTestUnsignedField_(
  366. jspb.BinaryReader.prototype.readFixed64,
  367. jspb.BinaryWriter.prototype.writeFixed64,
  368. 1, Math.pow(2, 64) - 1025, Math.round);
  369. doTestSignedField_(
  370. jspb.BinaryReader.prototype.readSfixed32,
  371. jspb.BinaryWriter.prototype.writeSfixed32,
  372. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  373. doTestSignedField_(
  374. jspb.BinaryReader.prototype.readSfixed64,
  375. jspb.BinaryWriter.prototype.writeSfixed64,
  376. 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
  377. });
  378. /**
  379. * Tests floating point fields.
  380. */
  381. it('testFloatFields', function() {
  382. doTestSignedField_(
  383. jspb.BinaryReader.prototype.readFloat,
  384. jspb.BinaryWriter.prototype.writeFloat,
  385. jspb.BinaryConstants.FLOAT32_MIN,
  386. -jspb.BinaryConstants.FLOAT32_MAX,
  387. jspb.BinaryConstants.FLOAT32_MAX,
  388. truncate);
  389. doTestSignedField_(
  390. jspb.BinaryReader.prototype.readDouble,
  391. jspb.BinaryWriter.prototype.writeDouble,
  392. jspb.BinaryConstants.FLOAT64_EPS * 10,
  393. -jspb.BinaryConstants.FLOAT64_MIN,
  394. jspb.BinaryConstants.FLOAT64_MIN,
  395. function(x) { return x; });
  396. });
  397. /**
  398. * Tests length-delimited string fields.
  399. */
  400. it('testStringFields', function() {
  401. var s1 = 'The quick brown fox jumps over the lazy dog.';
  402. var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
  403. var writer = new jspb.BinaryWriter();
  404. writer.writeString(1, s1);
  405. writer.writeString(2, s2);
  406. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  407. reader.nextField();
  408. assertEquals(1, reader.getFieldNumber());
  409. assertEquals(s1, reader.readString());
  410. reader.nextField();
  411. assertEquals(2, reader.getFieldNumber());
  412. assertEquals(s2, reader.readString());
  413. });
  414. /**
  415. * Tests length-delimited byte fields.
  416. */
  417. it('testByteFields', function() {
  418. var message = [];
  419. var lowerLimit = 1;
  420. var upperLimit = 256;
  421. var scale = 1.1;
  422. var writer = new jspb.BinaryWriter();
  423. for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
  424. var len = Math.round(cursor);
  425. var bytes = [];
  426. for (var i = 0; i < len; i++) bytes.push(i % 256);
  427. writer.writeBytes(len, bytes);
  428. }
  429. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  430. for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
  431. var len = Math.round(cursor);
  432. if (len != reader.getFieldNumber()) throw 'fail!';
  433. var bytes = reader.readBytes();
  434. if (len != bytes.length) throw 'fail!';
  435. for (var i = 0; i < bytes.length; i++) {
  436. if (i % 256 != bytes[i]) throw 'fail!';
  437. }
  438. }
  439. });
  440. /**
  441. * Tests nested messages.
  442. */
  443. it('testNesting', function() {
  444. var writer = new jspb.BinaryWriter();
  445. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  446. writer.writeInt32(1, 100);
  447. // Add one message with 3 int fields.
  448. writer.writeMessage(2, dummyMessage, function() {
  449. writer.writeInt32(3, 300);
  450. writer.writeInt32(4, 400);
  451. writer.writeInt32(5, 500);
  452. });
  453. // Add one empty message.
  454. writer.writeMessage(6, dummyMessage, goog.nullFunction);
  455. writer.writeInt32(7, 700);
  456. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  457. // Validate outermost message.
  458. reader.nextField();
  459. assertEquals(1, reader.getFieldNumber());
  460. assertEquals(100, reader.readInt32());
  461. reader.nextField();
  462. assertEquals(2, reader.getFieldNumber());
  463. reader.readMessage(dummyMessage, function() {
  464. // Validate embedded message 1.
  465. reader.nextField();
  466. assertEquals(3, reader.getFieldNumber());
  467. assertEquals(300, reader.readInt32());
  468. reader.nextField();
  469. assertEquals(4, reader.getFieldNumber());
  470. assertEquals(400, reader.readInt32());
  471. reader.nextField();
  472. assertEquals(5, reader.getFieldNumber());
  473. assertEquals(500, reader.readInt32());
  474. assertEquals(false, reader.nextField());
  475. });
  476. reader.nextField();
  477. assertEquals(6, reader.getFieldNumber());
  478. reader.readMessage(dummyMessage, function() {
  479. // Validate embedded message 2.
  480. assertEquals(false, reader.nextField());
  481. });
  482. reader.nextField();
  483. assertEquals(7, reader.getFieldNumber());
  484. assertEquals(700, reader.readInt32());
  485. assertEquals(false, reader.nextField());
  486. });
  487. /**
  488. * Tests skipping fields of each type by interleaving them with sentinel
  489. * values and skipping everything that's not a sentinel.
  490. */
  491. it('testSkipField', function() {
  492. var writer = new jspb.BinaryWriter();
  493. var sentinel = 123456789;
  494. // Write varint fields of different sizes.
  495. writer.writeInt32(1, sentinel);
  496. writer.writeInt32(1, 1);
  497. writer.writeInt32(1, 1000);
  498. writer.writeInt32(1, 1000000);
  499. writer.writeInt32(1, 1000000000);
  500. // Write fixed 64-bit encoded fields.
  501. writer.writeInt32(2, sentinel);
  502. writer.writeDouble(2, 1);
  503. writer.writeFixed64(2, 1);
  504. writer.writeSfixed64(2, 1);
  505. // Write fixed 32-bit encoded fields.
  506. writer.writeInt32(3, sentinel);
  507. writer.writeFloat(3, 1);
  508. writer.writeFixed32(3, 1);
  509. writer.writeSfixed32(3, 1);
  510. // Write delimited fields.
  511. writer.writeInt32(4, sentinel);
  512. writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  513. writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
  514. // Write a group with a nested group inside. We use the internal
  515. // .rawWriteVarint() to ensure the tested wire data is what we want,
  516. // independently of any serialization logic.
  517. writer.writeInt32(5, sentinel);
  518. // Start group, field 5.
  519. writer.rawWriteVarint(
  520. (5 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
  521. // Varint, field 42.
  522. writer.rawWriteVarint(
  523. (42 << 3) + jspb.BinaryConstants.WireType.VARINT);
  524. // Varint data.
  525. writer.rawWriteVarint(42);
  526. // Start group, field 6.
  527. writer.rawWriteVarint(
  528. (6 << 3) + jspb.BinaryConstants.WireType.START_GROUP);
  529. // Varint, field 84.
  530. writer.rawWriteVarint(
  531. (84 << 3) + jspb.BinaryConstants.WireType.VARINT);
  532. writer.rawWriteVarint(42);
  533. // End group, field 6.
  534. writer.rawWriteVarint(
  535. (6 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
  536. // End group, field 5.
  537. writer.rawWriteVarint(
  538. (5 << 3) + jspb.BinaryConstants.WireType.END_GROUP);
  539. // Write final sentinel.
  540. writer.writeInt32(6, sentinel);
  541. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  542. function skip(field, count) {
  543. for (var i = 0; i < count; i++) {
  544. reader.nextField();
  545. if (field != reader.getFieldNumber()) throw 'fail!';
  546. reader.skipField();
  547. }
  548. }
  549. reader.nextField();
  550. assertEquals(1, reader.getFieldNumber());
  551. assertEquals(sentinel, reader.readInt32());
  552. skip(1, 4);
  553. reader.nextField();
  554. assertEquals(2, reader.getFieldNumber());
  555. assertEquals(sentinel, reader.readInt32());
  556. skip(2, 3);
  557. reader.nextField();
  558. assertEquals(3, reader.getFieldNumber());
  559. assertEquals(sentinel, reader.readInt32());
  560. skip(3, 3);
  561. reader.nextField();
  562. assertEquals(4, reader.getFieldNumber());
  563. assertEquals(sentinel, reader.readInt32());
  564. skip(4, 2);
  565. reader.nextField();
  566. assertEquals(5, reader.getFieldNumber());
  567. assertEquals(sentinel, reader.readInt32());
  568. skip(5, 1);
  569. reader.nextField();
  570. assertEquals(6, reader.getFieldNumber());
  571. assertEquals(sentinel, reader.readInt32());
  572. });
  573. /**
  574. * Tests packed fields.
  575. */
  576. it('testPackedFields', function() {
  577. var writer = new jspb.BinaryWriter();
  578. var sentinel = 123456789;
  579. var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  580. var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
  581. var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
  582. var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
  583. var boolData = [true, false, true, true, false, false, true, false];
  584. for (var i = 0; i < floatData.length; i++) {
  585. floatData[i] = truncate(floatData[i]);
  586. }
  587. writer.writeInt32(1, sentinel);
  588. writer.writePackedInt32(2, signedData);
  589. writer.writePackedInt64(2, signedData);
  590. writer.writePackedUint32(2, unsignedData);
  591. writer.writePackedUint64(2, unsignedData);
  592. writer.writePackedSint32(2, signedData);
  593. writer.writePackedSint64(2, signedData);
  594. writer.writePackedFixed32(2, unsignedData);
  595. writer.writePackedFixed64(2, unsignedData);
  596. writer.writePackedSfixed32(2, signedData);
  597. writer.writePackedSfixed64(2, signedData);
  598. writer.writePackedFloat(2, floatData);
  599. writer.writePackedDouble(2, doubleData);
  600. writer.writePackedBool(2, boolData);
  601. writer.writePackedEnum(2, unsignedData);
  602. writer.writeInt32(3, sentinel);
  603. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  604. reader.nextField();
  605. assertEquals(sentinel, reader.readInt32());
  606. reader.nextField();
  607. assertElementsEquals(reader.readPackedInt32(), signedData);
  608. reader.nextField();
  609. assertElementsEquals(reader.readPackedInt64(), signedData);
  610. reader.nextField();
  611. assertElementsEquals(reader.readPackedUint32(), unsignedData);
  612. reader.nextField();
  613. assertElementsEquals(reader.readPackedUint64(), unsignedData);
  614. reader.nextField();
  615. assertElementsEquals(reader.readPackedSint32(), signedData);
  616. reader.nextField();
  617. assertElementsEquals(reader.readPackedSint64(), signedData);
  618. reader.nextField();
  619. assertElementsEquals(reader.readPackedFixed32(), unsignedData);
  620. reader.nextField();
  621. assertElementsEquals(reader.readPackedFixed64(), unsignedData);
  622. reader.nextField();
  623. assertElementsEquals(reader.readPackedSfixed32(), signedData);
  624. reader.nextField();
  625. assertElementsEquals(reader.readPackedSfixed64(), signedData);
  626. reader.nextField();
  627. assertElementsEquals(reader.readPackedFloat(), floatData);
  628. reader.nextField();
  629. assertElementsEquals(reader.readPackedDouble(), doubleData);
  630. reader.nextField();
  631. assertElementsEquals(reader.readPackedBool(), boolData);
  632. reader.nextField();
  633. assertElementsEquals(reader.readPackedEnum(), unsignedData);
  634. reader.nextField();
  635. assertEquals(sentinel, reader.readInt32());
  636. });
  637. /**
  638. * Byte blobs inside nested messages should always have their byte offset set
  639. * relative to the start of the outermost blob, not the start of their parent
  640. * blob.
  641. */
  642. it('testNestedBlobs', function() {
  643. // Create a proto consisting of two nested messages, with the inner one
  644. // containing a blob of bytes.
  645. var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
  646. var blob = [1, 2, 3, 4, 5];
  647. var writer = new jspb.BinaryWriter();
  648. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  649. writer.writeMessage(1, dummyMessage, function() {
  650. writer.writeMessage(1, dummyMessage, function() {
  651. writer.writeBytes(1, blob);
  652. });
  653. });
  654. // Peel off the outer two message layers. Each layer should have two bytes
  655. // of overhead, one for the field tag and one for the length of the inner
  656. // blob.
  657. var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
  658. assertEquals(fieldTag, decoder1.readUnsignedVarint32());
  659. assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
  660. var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
  661. assertEquals(fieldTag, decoder2.readUnsignedVarint32());
  662. assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
  663. assertEquals(fieldTag, decoder2.readUnsignedVarint32());
  664. assertEquals(blob.length, decoder2.readUnsignedVarint32());
  665. var bytes = decoder2.readBytes(blob.length);
  666. assertElementsEquals(bytes, blob);
  667. });
  668. /**
  669. * Tests read callbacks.
  670. */
  671. it('testReadCallbacks', function() {
  672. var writer = new jspb.BinaryWriter();
  673. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  674. // Add an int, a submessage, and another int.
  675. writer.writeInt32(1, 100);
  676. writer.writeMessage(2, dummyMessage, function() {
  677. writer.writeInt32(3, 300);
  678. writer.writeInt32(4, 400);
  679. writer.writeInt32(5, 500);
  680. });
  681. writer.writeInt32(7, 700);
  682. // Create the reader and register a custom read callback.
  683. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  684. /**
  685. * @param {!jspb.BinaryReader} reader
  686. * @return {*}
  687. */
  688. function readCallback(reader) {
  689. reader.nextField();
  690. assertEquals(3, reader.getFieldNumber());
  691. assertEquals(300, reader.readInt32());
  692. reader.nextField();
  693. assertEquals(4, reader.getFieldNumber());
  694. assertEquals(400, reader.readInt32());
  695. reader.nextField();
  696. assertEquals(5, reader.getFieldNumber());
  697. assertEquals(500, reader.readInt32());
  698. assertEquals(false, reader.nextField());
  699. };
  700. reader.registerReadCallback('readCallback', readCallback);
  701. // Read the container message.
  702. reader.nextField();
  703. assertEquals(1, reader.getFieldNumber());
  704. assertEquals(100, reader.readInt32());
  705. reader.nextField();
  706. assertEquals(2, reader.getFieldNumber());
  707. reader.readMessage(dummyMessage, function() {
  708. // Decode the embedded message using the registered callback.
  709. reader.runReadCallback('readCallback');
  710. });
  711. reader.nextField();
  712. assertEquals(7, reader.getFieldNumber());
  713. assertEquals(700, reader.readInt32());
  714. assertEquals(false, reader.nextField());
  715. });
  716. });