reader_test.js 31 KB

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