Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 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 | /** |
| 32 | * @fileoverview Test cases for jspb's binary protocol buffer writer. In |
| 33 | * practice BinaryWriter is used to drive the Decoder and Reader test cases, |
| 34 | * so only writer-specific tests are here. |
| 35 | * |
| 36 | * Test suite is written using Jasmine -- see http://jasmine.github.io/ |
| 37 | * |
| 38 | * @author aappleby@google.com (Austin Appleby) |
| 39 | */ |
| 40 | |
| 41 | goog.require('goog.crypt'); |
| 42 | goog.require('goog.testing.asserts'); |
Paul Yang | 763c358 | 2019-09-12 11:03:27 -0700 | [diff] [blame] | 43 | goog.require('jspb.BinaryConstants'); |
Paul Yang | 7bff839 | 2019-07-19 14:49:01 -0700 | [diff] [blame] | 44 | goog.require('jspb.BinaryReader'); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 45 | goog.require('jspb.BinaryWriter'); |
Rafi Kamal | 4f02f05 | 2019-08-22 16:14:22 -0700 | [diff] [blame] | 46 | goog.require('jspb.utils'); |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 47 | goog.require('goog.crypt.base64'); |
| 48 | goog.requireType('jspb.BinaryMessage'); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 49 | |
| 50 | /** |
| 51 | * @param {function()} func This function should throw an error when run. |
| 52 | */ |
| 53 | function assertFails(func) { |
Feng Xiao | d36c0c5 | 2017-03-29 14:32:48 -0700 | [diff] [blame] | 54 | assertThrows(func); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 55 | } |
| 56 | |
| 57 | |
| 58 | describe('binaryWriterTest', function() { |
| 59 | /** |
| 60 | * Verifies that misuse of the writer class triggers assertions. |
| 61 | */ |
| 62 | it('testWriteErrors', function() { |
| 63 | // Submessages with invalid field indices should assert. |
| 64 | var writer = new jspb.BinaryWriter(); |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 65 | var dummyMessage = /** @type {!jspb.BinaryMessage} */ ({}); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 66 | |
| 67 | assertFails(function() { |
| 68 | writer.writeMessage(-1, dummyMessage, goog.nullFunction); |
| 69 | }); |
| 70 | |
| 71 | // Writing invalid field indices should assert. |
| 72 | writer = new jspb.BinaryWriter(); |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 73 | assertFails(function() { |
| 74 | writer.writeUint64(-1, 1); |
| 75 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 76 | |
| 77 | // Writing out-of-range field values should assert. |
| 78 | writer = new jspb.BinaryWriter(); |
| 79 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 80 | assertFails(function() { |
| 81 | writer.writeInt32(1, -Infinity); |
| 82 | }); |
| 83 | assertFails(function() { |
| 84 | writer.writeInt32(1, Infinity); |
| 85 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 86 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 87 | assertFails(function() { |
| 88 | writer.writeInt64(1, -Infinity); |
| 89 | }); |
| 90 | assertFails(function() { |
| 91 | writer.writeInt64(1, Infinity); |
| 92 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 93 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 94 | assertFails(function() { |
| 95 | writer.writeUint32(1, -1); |
| 96 | }); |
| 97 | assertFails(function() { |
| 98 | writer.writeUint32(1, Infinity); |
| 99 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 100 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 101 | assertFails(function() { |
| 102 | writer.writeUint64(1, -1); |
| 103 | }); |
| 104 | assertFails(function() { |
| 105 | writer.writeUint64(1, Infinity); |
| 106 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 107 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 108 | assertFails(function() { |
| 109 | writer.writeSint32(1, -Infinity); |
| 110 | }); |
| 111 | assertFails(function() { |
| 112 | writer.writeSint32(1, Infinity); |
| 113 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 114 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 115 | assertFails(function() { |
| 116 | writer.writeSint64(1, -Infinity); |
| 117 | }); |
| 118 | assertFails(function() { |
| 119 | writer.writeSint64(1, Infinity); |
| 120 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 121 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 122 | assertFails(function() { |
| 123 | writer.writeFixed32(1, -1); |
| 124 | }); |
| 125 | assertFails(function() { |
| 126 | writer.writeFixed32(1, Infinity); |
| 127 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 128 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 129 | assertFails(function() { |
| 130 | writer.writeFixed64(1, -1); |
| 131 | }); |
| 132 | assertFails(function() { |
| 133 | writer.writeFixed64(1, Infinity); |
| 134 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 135 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 136 | assertFails(function() { |
| 137 | writer.writeSfixed32(1, -Infinity); |
| 138 | }); |
| 139 | assertFails(function() { |
| 140 | writer.writeSfixed32(1, Infinity); |
| 141 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 142 | |
Joshua Haberman | 51daaba | 2021-02-04 14:09:49 -0800 | [diff] [blame] | 143 | assertFails(function() { |
| 144 | writer.writeSfixed64(1, -Infinity); |
| 145 | }); |
| 146 | assertFails(function() { |
| 147 | writer.writeSfixed64(1, Infinity); |
| 148 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 149 | }); |
| 150 | |
| 151 | |
| 152 | /** |
| 153 | * Basic test of retrieving the result as a Uint8Array buffer |
| 154 | */ |
| 155 | it('testGetResultBuffer', function() { |
| 156 | var expected = '0864120b48656c6c6f20776f726c641a0301020320c801'; |
| 157 | |
| 158 | var writer = new jspb.BinaryWriter(); |
| 159 | writer.writeUint32(1, 100); |
| 160 | writer.writeString(2, 'Hello world'); |
| 161 | writer.writeBytes(3, new Uint8Array([1, 2, 3])); |
| 162 | writer.writeUint32(4, 200); |
| 163 | |
| 164 | var buffer = writer.getResultBuffer(); |
| 165 | assertEquals(expected, goog.crypt.byteArrayToHex(buffer)); |
| 166 | }); |
Adam Cozzette | 0400cca | 2018-03-13 16:37:29 -0700 | [diff] [blame] | 167 | |
| 168 | |
| 169 | /** |
| 170 | * Tests websafe encodings for base64 strings. |
| 171 | */ |
| 172 | it('testWebSafeOption', function() { |
| 173 | var writer = new jspb.BinaryWriter(); |
| 174 | writer.writeBytes(1, new Uint8Array([127])); |
| 175 | assertEquals('CgF/', writer.getResultBase64String()); |
Rafi Kamal | 4f02f05 | 2019-08-22 16:14:22 -0700 | [diff] [blame] | 176 | assertEquals( |
| 177 | 'CgF/', |
| 178 | writer.getResultBase64String(goog.crypt.base64.Alphabet.DEFAULT)); |
| 179 | assertEquals( |
| 180 | 'CgF_', |
| 181 | writer.getResultBase64String( |
| 182 | goog.crypt.base64.Alphabet.WEBSAFE_NO_PADDING)); |
Adam Cozzette | 0400cca | 2018-03-13 16:37:29 -0700 | [diff] [blame] | 183 | }); |
Paul Yang | 7bff839 | 2019-07-19 14:49:01 -0700 | [diff] [blame] | 184 | |
| 185 | it('writes split 64 fields', function() { |
| 186 | var writer = new jspb.BinaryWriter(); |
| 187 | writer.writeSplitVarint64(1, 0x1, 0x2); |
| 188 | writer.writeSplitVarint64(1, 0xFFFFFFFF, 0xFFFFFFFF); |
| 189 | writer.writeSplitFixed64(2, 0x1, 0x2); |
| 190 | writer.writeSplitFixed64(2, 0xFFFFFFF0, 0xFFFFFFFF); |
| 191 | function lo(i) { |
| 192 | return i + 1; |
| 193 | } |
| 194 | function hi(i) { |
| 195 | return i + 2; |
| 196 | } |
| 197 | writer.writeRepeatedSplitVarint64(3, [0, 1, 2], lo, hi); |
| 198 | writer.writeRepeatedSplitFixed64(4, [0, 1, 2], lo, hi); |
| 199 | writer.writePackedSplitVarint64(5, [0, 1, 2], lo, hi); |
| 200 | writer.writePackedSplitFixed64(6, [0, 1, 2], lo, hi); |
| 201 | |
| 202 | function bitsAsArray(lowBits, highBits) { |
| 203 | return [lowBits >>> 0, highBits >>> 0]; |
| 204 | } |
| 205 | var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); |
| 206 | reader.nextField(); |
| 207 | expect(reader.getFieldNumber()).toEqual(1); |
| 208 | expect(reader.readSplitVarint64(bitsAsArray)).toEqual([0x1, 0x2]); |
| 209 | |
| 210 | reader.nextField(); |
| 211 | expect(reader.getFieldNumber()).toEqual(1); |
| 212 | expect(reader.readSplitVarint64(bitsAsArray)).toEqual([ |
| 213 | 0xFFFFFFFF, 0xFFFFFFFF |
| 214 | ]); |
| 215 | |
| 216 | reader.nextField(); |
| 217 | expect(reader.getFieldNumber()).toEqual(2); |
| 218 | expect(reader.readSplitFixed64(bitsAsArray)).toEqual([0x1, 0x2]); |
| 219 | |
| 220 | reader.nextField(); |
| 221 | expect(reader.getFieldNumber()).toEqual(2); |
| 222 | expect(reader.readSplitFixed64(bitsAsArray)).toEqual([ |
| 223 | 0xFFFFFFF0, 0xFFFFFFFF |
| 224 | ]); |
| 225 | |
| 226 | for (let i = 0; i < 3; i++) { |
| 227 | reader.nextField(); |
| 228 | expect(reader.getFieldNumber()).toEqual(3); |
| 229 | expect(reader.readSplitVarint64(bitsAsArray)).toEqual([i + 1, i + 2]); |
| 230 | } |
| 231 | |
| 232 | for (let i = 0; i < 3; i++) { |
| 233 | reader.nextField(); |
| 234 | expect(reader.getFieldNumber()).toEqual(4); |
| 235 | expect(reader.readSplitFixed64(bitsAsArray)).toEqual([i + 1, i + 2]); |
| 236 | } |
| 237 | |
| 238 | reader.nextField(); |
| 239 | expect(reader.getFieldNumber()).toEqual(5); |
| 240 | expect(reader.readPackedInt64String()).toEqual([ |
| 241 | String(2 * 2 ** 32 + 1), |
| 242 | String(3 * 2 ** 32 + 2), |
| 243 | String(4 * 2 ** 32 + 3), |
| 244 | ]); |
| 245 | |
| 246 | reader.nextField(); |
| 247 | expect(reader.getFieldNumber()).toEqual(6); |
| 248 | expect(reader.readPackedFixed64String()).toEqual([ |
| 249 | String(2 * 2 ** 32 + 1), |
| 250 | String(3 * 2 ** 32 + 2), |
| 251 | String(4 * 2 ** 32 + 3), |
| 252 | ]); |
| 253 | }); |
Rafi Kamal | 4f02f05 | 2019-08-22 16:14:22 -0700 | [diff] [blame] | 254 | |
| 255 | it('writes zigzag 64 fields', function() { |
Brian Wignall | a104dff | 2020-01-08 13:18:20 -0500 | [diff] [blame] | 256 | // Test cases directly from the protobuf dev guide. |
Rafi Kamal | 4f02f05 | 2019-08-22 16:14:22 -0700 | [diff] [blame] | 257 | // https://engdoc.corp.google.com/eng/howto/protocolbuffers/developerguide/encoding.shtml?cl=head#types |
| 258 | var testCases = [ |
| 259 | {original: '0', zigzag: '0'}, |
| 260 | {original: '-1', zigzag: '1'}, |
| 261 | {original: '1', zigzag: '2'}, |
| 262 | {original: '-2', zigzag: '3'}, |
| 263 | {original: '2147483647', zigzag: '4294967294'}, |
| 264 | {original: '-2147483648', zigzag: '4294967295'}, |
| 265 | // 64-bit extremes, not in dev guide. |
| 266 | {original: '9223372036854775807', zigzag: '18446744073709551614'}, |
| 267 | {original: '-9223372036854775808', zigzag: '18446744073709551615'}, |
| 268 | ]; |
| 269 | function decimalToLowBits(v) { |
| 270 | jspb.utils.splitDecimalString(v); |
| 271 | return jspb.utils.split64Low >>> 0; |
| 272 | } |
| 273 | function decimalToHighBits(v) { |
| 274 | jspb.utils.splitDecimalString(v); |
| 275 | return jspb.utils.split64High >>> 0; |
| 276 | } |
| 277 | |
| 278 | var writer = new jspb.BinaryWriter(); |
| 279 | testCases.forEach(function(c) { |
| 280 | writer.writeSint64String(1, c.original); |
| 281 | writer.writeSintHash64(1, jspb.utils.decimalStringToHash64(c.original)); |
| 282 | jspb.utils.splitDecimalString(c.original); |
| 283 | writer.writeSplitZigzagVarint64( |
| 284 | 1, jspb.utils.split64Low, jspb.utils.split64High); |
| 285 | }); |
| 286 | |
| 287 | writer.writeRepeatedSint64String(2, testCases.map(function(c) { |
| 288 | return c.original; |
| 289 | })); |
| 290 | |
| 291 | writer.writeRepeatedSintHash64(3, testCases.map(function(c) { |
| 292 | return jspb.utils.decimalStringToHash64(c.original); |
| 293 | })); |
| 294 | |
| 295 | writer.writeRepeatedSplitZigzagVarint64( |
| 296 | 4, testCases.map(function(c) { |
| 297 | return c.original; |
| 298 | }), |
| 299 | decimalToLowBits, decimalToHighBits); |
| 300 | |
| 301 | writer.writePackedSint64String(5, testCases.map(function(c) { |
| 302 | return c.original; |
| 303 | })); |
| 304 | |
| 305 | writer.writePackedSintHash64(6, testCases.map(function(c) { |
| 306 | return jspb.utils.decimalStringToHash64(c.original); |
| 307 | })); |
| 308 | |
| 309 | writer.writePackedSplitZigzagVarint64( |
| 310 | 7, testCases.map(function(c) { |
| 311 | return c.original; |
| 312 | }), |
| 313 | decimalToLowBits, decimalToHighBits); |
| 314 | |
| 315 | // Verify by reading the stream as normal int64 fields and checking with |
| 316 | // the canonical zigzag encoding of each value. |
| 317 | var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); |
| 318 | testCases.forEach(function(c) { |
| 319 | reader.nextField(); |
| 320 | expect(reader.getFieldNumber()).toEqual(1); |
| 321 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 322 | reader.nextField(); |
| 323 | expect(reader.getFieldNumber()).toEqual(1); |
| 324 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 325 | reader.nextField(); |
| 326 | expect(reader.getFieldNumber()).toEqual(1); |
| 327 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 328 | }); |
| 329 | |
| 330 | testCases.forEach(function(c) { |
| 331 | reader.nextField(); |
| 332 | expect(reader.getFieldNumber()).toEqual(2); |
| 333 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 334 | }); |
| 335 | |
| 336 | testCases.forEach(function(c) { |
| 337 | reader.nextField(); |
| 338 | expect(reader.getFieldNumber()).toEqual(3); |
| 339 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 340 | }); |
| 341 | |
| 342 | testCases.forEach(function(c) { |
| 343 | reader.nextField(); |
| 344 | expect(reader.getFieldNumber()).toEqual(4); |
| 345 | expect(reader.readUint64String()).toEqual(c.zigzag); |
| 346 | }); |
| 347 | |
| 348 | reader.nextField(); |
| 349 | expect(reader.getFieldNumber()).toEqual(5); |
| 350 | expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) { |
| 351 | return c.zigzag; |
| 352 | })); |
| 353 | |
| 354 | reader.nextField(); |
| 355 | expect(reader.getFieldNumber()).toEqual(6); |
| 356 | expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) { |
| 357 | return c.zigzag; |
| 358 | })); |
| 359 | |
| 360 | reader.nextField(); |
| 361 | expect(reader.getFieldNumber()).toEqual(7); |
| 362 | expect(reader.readPackedUint64String()).toEqual(testCases.map(function(c) { |
| 363 | return c.zigzag; |
| 364 | })); |
| 365 | }); |
Paul Yang | 763c358 | 2019-09-12 11:03:27 -0700 | [diff] [blame] | 366 | |
| 367 | it('writes float32 fields', function() { |
| 368 | var testCases = [ |
| 369 | 0, 1, -1, jspb.BinaryConstants.FLOAT32_MIN, |
| 370 | -jspb.BinaryConstants.FLOAT32_MIN, jspb.BinaryConstants.FLOAT32_MAX, |
| 371 | -jspb.BinaryConstants.FLOAT32_MAX, 3.1415927410125732, Infinity, |
| 372 | -Infinity, NaN |
| 373 | ]; |
| 374 | var writer = new jspb.BinaryWriter(); |
| 375 | testCases.forEach(function(f) { |
| 376 | writer.writeFloat(1, f); |
| 377 | }); |
| 378 | var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); |
| 379 | testCases.forEach(function(f) { |
| 380 | reader.nextField(); |
| 381 | expect(reader.getFieldNumber()).toEqual(1); |
| 382 | if (isNaN(f)) { |
| 383 | expect(isNaN(reader.readFloat())).toEqual(true); |
| 384 | } else { |
| 385 | expect(reader.readFloat()).toEqual(f); |
| 386 | } |
| 387 | }); |
| 388 | }); |
| 389 | |
| 390 | it('writes double fields', function() { |
| 391 | var testCases = [ |
| 392 | 0, 1, -1, Number.MAX_SAFE_INTEGER, Number.MIN_SAFE_INTEGER, |
| 393 | Number.MAX_VALUE, Number.MIN_VALUE, jspb.BinaryConstants.FLOAT32_MIN, |
| 394 | -jspb.BinaryConstants.FLOAT32_MIN, jspb.BinaryConstants.FLOAT32_MAX, |
| 395 | -jspb.BinaryConstants.FLOAT32_MAX, Math.PI, Infinity, -Infinity, NaN |
| 396 | ]; |
| 397 | var writer = new jspb.BinaryWriter(); |
| 398 | testCases.forEach(function(f) { |
| 399 | writer.writeDouble(1, f); |
| 400 | }); |
| 401 | var reader = jspb.BinaryReader.alloc(writer.getResultBuffer()); |
| 402 | testCases.forEach(function(f) { |
| 403 | reader.nextField(); |
| 404 | expect(reader.getFieldNumber()).toEqual(1); |
| 405 | if (isNaN(f)) { |
| 406 | expect(isNaN(reader.readDouble())).toEqual(true); |
| 407 | } else { |
| 408 | expect(reader.readDouble()).toEqual(f); |
| 409 | } |
| 410 | }); |
| 411 | }); |
Feng Xiao | e841bac | 2015-12-11 17:09:20 -0800 | [diff] [blame] | 412 | }); |