reader_test.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922
  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 64-bit fields that are handled as strings.
  343. */
  344. it('testStringInt64Fields', function() {
  345. var writer = new jspb.BinaryWriter();
  346. var testSignedData = [
  347. '2730538252207801776',
  348. '-2688470994844604560',
  349. '3398529779486536359',
  350. '3568577411627971000',
  351. '272477188847484900',
  352. '-6649058714086158188',
  353. '-7695254765712060806',
  354. '-4525541438037104029',
  355. '-4993706538836508568',
  356. '4990160321893729138'
  357. ];
  358. var testUnsignedData = [
  359. '7822732630241694882',
  360. '6753602971916687352',
  361. '2399935075244442116',
  362. '8724292567325338867',
  363. '16948784802625696584',
  364. '4136275908516066934',
  365. '3575388346793700364',
  366. '5167142028379259461',
  367. '1557573948689737699',
  368. '17100725280812548567'
  369. ];
  370. for (var i = 0; i < testSignedData.length; i++) {
  371. writer.writeInt64String(2 * i + 1, testSignedData[i]);
  372. writer.writeUint64String(2 * i + 2, testUnsignedData[i]);
  373. }
  374. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  375. for (var i = 0; i < testSignedData.length; i++) {
  376. reader.nextField();
  377. assertEquals(2 * i + 1, reader.getFieldNumber());
  378. assertEquals(testSignedData[i], reader.readInt64String());
  379. reader.nextField();
  380. assertEquals(2 * i + 2, reader.getFieldNumber());
  381. assertEquals(testUnsignedData[i], reader.readUint64String());
  382. }
  383. });
  384. /**
  385. * Tests fields that use zigzag encoding.
  386. */
  387. it('testZigzagFields', function() {
  388. doTestSignedField_(
  389. jspb.BinaryReader.prototype.readSint32,
  390. jspb.BinaryWriter.prototype.writeSint32,
  391. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  392. doTestSignedField_(
  393. jspb.BinaryReader.prototype.readSint64,
  394. jspb.BinaryWriter.prototype.writeSint64,
  395. 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
  396. });
  397. /**
  398. * Tests fields that use fixed-length encoding.
  399. */
  400. it('testFixedFields', function() {
  401. doTestUnsignedField_(
  402. jspb.BinaryReader.prototype.readFixed32,
  403. jspb.BinaryWriter.prototype.writeFixed32,
  404. 1, Math.pow(2, 32) - 1, Math.round);
  405. doTestUnsignedField_(
  406. jspb.BinaryReader.prototype.readFixed64,
  407. jspb.BinaryWriter.prototype.writeFixed64,
  408. 1, Math.pow(2, 64) - 1025, Math.round);
  409. doTestSignedField_(
  410. jspb.BinaryReader.prototype.readSfixed32,
  411. jspb.BinaryWriter.prototype.writeSfixed32,
  412. 1, -Math.pow(2, 31), Math.pow(2, 31) - 1, Math.round);
  413. doTestSignedField_(
  414. jspb.BinaryReader.prototype.readSfixed64,
  415. jspb.BinaryWriter.prototype.writeSfixed64,
  416. 1, -Math.pow(2, 63), Math.pow(2, 63) - 513, Math.round);
  417. });
  418. /**
  419. * Tests floating point fields.
  420. */
  421. it('testFloatFields', function() {
  422. doTestSignedField_(
  423. jspb.BinaryReader.prototype.readFloat,
  424. jspb.BinaryWriter.prototype.writeFloat,
  425. jspb.BinaryConstants.FLOAT32_MIN,
  426. -jspb.BinaryConstants.FLOAT32_MAX,
  427. jspb.BinaryConstants.FLOAT32_MAX,
  428. truncate);
  429. doTestSignedField_(
  430. jspb.BinaryReader.prototype.readDouble,
  431. jspb.BinaryWriter.prototype.writeDouble,
  432. jspb.BinaryConstants.FLOAT64_EPS * 10,
  433. -jspb.BinaryConstants.FLOAT64_MIN,
  434. jspb.BinaryConstants.FLOAT64_MIN,
  435. function(x) { return x; });
  436. });
  437. /**
  438. * Tests length-delimited string fields.
  439. */
  440. it('testStringFields', function() {
  441. var s1 = 'The quick brown fox jumps over the lazy dog.';
  442. var s2 = '人人生而自由,在尊嚴和權利上一律平等。';
  443. var writer = new jspb.BinaryWriter();
  444. writer.writeString(1, s1);
  445. writer.writeString(2, s2);
  446. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  447. reader.nextField();
  448. assertEquals(1, reader.getFieldNumber());
  449. assertEquals(s1, reader.readString());
  450. reader.nextField();
  451. assertEquals(2, reader.getFieldNumber());
  452. assertEquals(s2, reader.readString());
  453. });
  454. /**
  455. * Tests length-delimited byte fields.
  456. */
  457. it('testByteFields', function() {
  458. var message = [];
  459. var lowerLimit = 1;
  460. var upperLimit = 256;
  461. var scale = 1.1;
  462. var writer = new jspb.BinaryWriter();
  463. for (var cursor = lowerLimit; cursor < upperLimit; cursor *= 1.1) {
  464. var len = Math.round(cursor);
  465. var bytes = [];
  466. for (var i = 0; i < len; i++) bytes.push(i % 256);
  467. writer.writeBytes(len, bytes);
  468. }
  469. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  470. for (var cursor = lowerLimit; reader.nextField(); cursor *= 1.1) {
  471. var len = Math.round(cursor);
  472. if (len != reader.getFieldNumber()) throw 'fail!';
  473. var bytes = reader.readBytes();
  474. if (len != bytes.length) throw 'fail!';
  475. for (var i = 0; i < bytes.length; i++) {
  476. if (i % 256 != bytes[i]) throw 'fail!';
  477. }
  478. }
  479. });
  480. /**
  481. * Tests nested messages.
  482. */
  483. it('testNesting', function() {
  484. var writer = new jspb.BinaryWriter();
  485. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  486. writer.writeInt32(1, 100);
  487. // Add one message with 3 int fields.
  488. writer.writeMessage(2, dummyMessage, function() {
  489. writer.writeInt32(3, 300);
  490. writer.writeInt32(4, 400);
  491. writer.writeInt32(5, 500);
  492. });
  493. // Add one empty message.
  494. writer.writeMessage(6, dummyMessage, goog.nullFunction);
  495. writer.writeInt32(7, 700);
  496. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  497. // Validate outermost message.
  498. reader.nextField();
  499. assertEquals(1, reader.getFieldNumber());
  500. assertEquals(100, reader.readInt32());
  501. reader.nextField();
  502. assertEquals(2, reader.getFieldNumber());
  503. reader.readMessage(dummyMessage, function() {
  504. // Validate embedded message 1.
  505. reader.nextField();
  506. assertEquals(3, reader.getFieldNumber());
  507. assertEquals(300, reader.readInt32());
  508. reader.nextField();
  509. assertEquals(4, reader.getFieldNumber());
  510. assertEquals(400, reader.readInt32());
  511. reader.nextField();
  512. assertEquals(5, reader.getFieldNumber());
  513. assertEquals(500, reader.readInt32());
  514. assertEquals(false, reader.nextField());
  515. });
  516. reader.nextField();
  517. assertEquals(6, reader.getFieldNumber());
  518. reader.readMessage(dummyMessage, function() {
  519. // Validate embedded message 2.
  520. assertEquals(false, reader.nextField());
  521. });
  522. reader.nextField();
  523. assertEquals(7, reader.getFieldNumber());
  524. assertEquals(700, reader.readInt32());
  525. assertEquals(false, reader.nextField());
  526. });
  527. /**
  528. * Tests skipping fields of each type by interleaving them with sentinel
  529. * values and skipping everything that's not a sentinel.
  530. */
  531. it('testSkipField', function() {
  532. var writer = new jspb.BinaryWriter();
  533. var sentinel = 123456789;
  534. // Write varint fields of different sizes.
  535. writer.writeInt32(1, sentinel);
  536. writer.writeInt32(1, 1);
  537. writer.writeInt32(1, 1000);
  538. writer.writeInt32(1, 1000000);
  539. writer.writeInt32(1, 1000000000);
  540. // Write fixed 64-bit encoded fields.
  541. writer.writeInt32(2, sentinel);
  542. writer.writeDouble(2, 1);
  543. writer.writeFixed64(2, 1);
  544. writer.writeSfixed64(2, 1);
  545. // Write fixed 32-bit encoded fields.
  546. writer.writeInt32(3, sentinel);
  547. writer.writeFloat(3, 1);
  548. writer.writeFixed32(3, 1);
  549. writer.writeSfixed32(3, 1);
  550. // Write delimited fields.
  551. writer.writeInt32(4, sentinel);
  552. writer.writeBytes(4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
  553. writer.writeString(4, 'The quick brown fox jumps over the lazy dog');
  554. // Write a group with a nested group inside.
  555. writer.writeInt32(5, sentinel);
  556. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  557. writer.writeGroup(5, dummyMessage, function() {
  558. writer.writeInt64(42, 42);
  559. writer.writeGroup(6, dummyMessage, function() {
  560. writer.writeInt64(84, 42);
  561. });
  562. });
  563. // Write final sentinel.
  564. writer.writeInt32(6, sentinel);
  565. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  566. function skip(field, count) {
  567. for (var i = 0; i < count; i++) {
  568. reader.nextField();
  569. if (field != reader.getFieldNumber()) throw 'fail!';
  570. reader.skipField();
  571. }
  572. }
  573. reader.nextField();
  574. assertEquals(1, reader.getFieldNumber());
  575. assertEquals(sentinel, reader.readInt32());
  576. skip(1, 4);
  577. reader.nextField();
  578. assertEquals(2, reader.getFieldNumber());
  579. assertEquals(sentinel, reader.readInt32());
  580. skip(2, 3);
  581. reader.nextField();
  582. assertEquals(3, reader.getFieldNumber());
  583. assertEquals(sentinel, reader.readInt32());
  584. skip(3, 3);
  585. reader.nextField();
  586. assertEquals(4, reader.getFieldNumber());
  587. assertEquals(sentinel, reader.readInt32());
  588. skip(4, 2);
  589. reader.nextField();
  590. assertEquals(5, reader.getFieldNumber());
  591. assertEquals(sentinel, reader.readInt32());
  592. skip(5, 1);
  593. reader.nextField();
  594. assertEquals(6, reader.getFieldNumber());
  595. assertEquals(sentinel, reader.readInt32());
  596. });
  597. /**
  598. * Tests packed fields.
  599. */
  600. it('testPackedFields', function() {
  601. var writer = new jspb.BinaryWriter();
  602. var sentinel = 123456789;
  603. var unsignedData = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  604. var signedData = [-1, 2, -3, 4, -5, 6, -7, 8, -9, 10];
  605. var floatData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
  606. var doubleData = [1.1, 2.2, 3.3, 4.4, 5.5, 6.6, 7.7, 8.8, 9.9, 10.10];
  607. var boolData = [true, false, true, true, false, false, true, false];
  608. for (var i = 0; i < floatData.length; i++) {
  609. floatData[i] = truncate(floatData[i]);
  610. }
  611. writer.writeInt32(1, sentinel);
  612. writer.writePackedInt32(2, signedData);
  613. writer.writePackedInt64(2, signedData);
  614. writer.writePackedUint32(2, unsignedData);
  615. writer.writePackedUint64(2, unsignedData);
  616. writer.writePackedSint32(2, signedData);
  617. writer.writePackedSint64(2, signedData);
  618. writer.writePackedFixed32(2, unsignedData);
  619. writer.writePackedFixed64(2, unsignedData);
  620. writer.writePackedSfixed32(2, signedData);
  621. writer.writePackedSfixed64(2, signedData);
  622. writer.writePackedFloat(2, floatData);
  623. writer.writePackedDouble(2, doubleData);
  624. writer.writePackedBool(2, boolData);
  625. writer.writePackedEnum(2, unsignedData);
  626. writer.writeInt32(3, sentinel);
  627. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  628. reader.nextField();
  629. assertEquals(sentinel, reader.readInt32());
  630. reader.nextField();
  631. assertElementsEquals(reader.readPackedInt32(), signedData);
  632. reader.nextField();
  633. assertElementsEquals(reader.readPackedInt64(), signedData);
  634. reader.nextField();
  635. assertElementsEquals(reader.readPackedUint32(), unsignedData);
  636. reader.nextField();
  637. assertElementsEquals(reader.readPackedUint64(), unsignedData);
  638. reader.nextField();
  639. assertElementsEquals(reader.readPackedSint32(), signedData);
  640. reader.nextField();
  641. assertElementsEquals(reader.readPackedSint64(), signedData);
  642. reader.nextField();
  643. assertElementsEquals(reader.readPackedFixed32(), unsignedData);
  644. reader.nextField();
  645. assertElementsEquals(reader.readPackedFixed64(), unsignedData);
  646. reader.nextField();
  647. assertElementsEquals(reader.readPackedSfixed32(), signedData);
  648. reader.nextField();
  649. assertElementsEquals(reader.readPackedSfixed64(), signedData);
  650. reader.nextField();
  651. assertElementsEquals(reader.readPackedFloat(), floatData);
  652. reader.nextField();
  653. assertElementsEquals(reader.readPackedDouble(), doubleData);
  654. reader.nextField();
  655. assertElementsEquals(reader.readPackedBool(), boolData);
  656. reader.nextField();
  657. assertElementsEquals(reader.readPackedEnum(), unsignedData);
  658. reader.nextField();
  659. assertEquals(sentinel, reader.readInt32());
  660. });
  661. /**
  662. * Byte blobs inside nested messages should always have their byte offset set
  663. * relative to the start of the outermost blob, not the start of their parent
  664. * blob.
  665. */
  666. it('testNestedBlobs', function() {
  667. // Create a proto consisting of two nested messages, with the inner one
  668. // containing a blob of bytes.
  669. var fieldTag = (1 << 3) | jspb.BinaryConstants.WireType.DELIMITED;
  670. var blob = [1, 2, 3, 4, 5];
  671. var writer = new jspb.BinaryWriter();
  672. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  673. writer.writeMessage(1, dummyMessage, function() {
  674. writer.writeMessage(1, dummyMessage, function() {
  675. writer.writeBytes(1, blob);
  676. });
  677. });
  678. // Peel off the outer two message layers. Each layer should have two bytes
  679. // of overhead, one for the field tag and one for the length of the inner
  680. // blob.
  681. var decoder1 = new jspb.BinaryDecoder(writer.getResultBuffer());
  682. assertEquals(fieldTag, decoder1.readUnsignedVarint32());
  683. assertEquals(blob.length + 4, decoder1.readUnsignedVarint32());
  684. var decoder2 = new jspb.BinaryDecoder(decoder1.readBytes(blob.length + 4));
  685. assertEquals(fieldTag, decoder2.readUnsignedVarint32());
  686. assertEquals(blob.length + 2, decoder2.readUnsignedVarint32());
  687. assertEquals(fieldTag, decoder2.readUnsignedVarint32());
  688. assertEquals(blob.length, decoder2.readUnsignedVarint32());
  689. var bytes = decoder2.readBytes(blob.length);
  690. assertElementsEquals(bytes, blob);
  691. });
  692. /**
  693. * Tests read callbacks.
  694. */
  695. it('testReadCallbacks', function() {
  696. var writer = new jspb.BinaryWriter();
  697. var dummyMessage = /** @type {!jspb.BinaryMessage} */({});
  698. // Add an int, a submessage, and another int.
  699. writer.writeInt32(1, 100);
  700. writer.writeMessage(2, dummyMessage, function() {
  701. writer.writeInt32(3, 300);
  702. writer.writeInt32(4, 400);
  703. writer.writeInt32(5, 500);
  704. });
  705. writer.writeInt32(7, 700);
  706. // Create the reader and register a custom read callback.
  707. var reader = jspb.BinaryReader.alloc(writer.getResultBuffer());
  708. /**
  709. * @param {!jspb.BinaryReader} reader
  710. * @return {*}
  711. */
  712. function readCallback(reader) {
  713. reader.nextField();
  714. assertEquals(3, reader.getFieldNumber());
  715. assertEquals(300, reader.readInt32());
  716. reader.nextField();
  717. assertEquals(4, reader.getFieldNumber());
  718. assertEquals(400, reader.readInt32());
  719. reader.nextField();
  720. assertEquals(5, reader.getFieldNumber());
  721. assertEquals(500, reader.readInt32());
  722. assertEquals(false, reader.nextField());
  723. };
  724. reader.registerReadCallback('readCallback', readCallback);
  725. // Read the container message.
  726. reader.nextField();
  727. assertEquals(1, reader.getFieldNumber());
  728. assertEquals(100, reader.readInt32());
  729. reader.nextField();
  730. assertEquals(2, reader.getFieldNumber());
  731. reader.readMessage(dummyMessage, function() {
  732. // Decode the embedded message using the registered callback.
  733. reader.runReadCallback('readCallback');
  734. });
  735. reader.nextField();
  736. assertEquals(7, reader.getFieldNumber());
  737. assertEquals(700, reader.readInt32());
  738. assertEquals(false, reader.nextField());
  739. });
  740. });