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