reader_test.js 30 KB

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