reader_test.js 29 KB

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