reader_test.js 29 KB

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