diff options
Diffstat (limited to 'js')
-rw-r--r-- | js/binary/decoder.js | 4 | ||||
-rw-r--r-- | js/binary/decoder_test.js | 10 | ||||
-rw-r--r-- | js/binary/encoder.js | 4 | ||||
-rw-r--r-- | js/binary/message_test.js | 60 | ||||
-rw-r--r-- | js/map.js | 58 | ||||
-rwxr-xr-x | js/maps_test.js | 44 | ||||
-rw-r--r-- | js/message.js | 34 | ||||
-rw-r--r-- | js/message_test.js | 19 | ||||
-rw-r--r-- | js/package.json | 2 |
9 files changed, 181 insertions, 54 deletions
diff --git a/js/binary/decoder.js b/js/binary/decoder.js index 36828a73..26bf3594 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -942,7 +942,7 @@ jspb.BinaryDecoder.prototype.readEnum = function() { /** * Reads and parses a UTF-8 encoded unicode string from the stream. * The code is inspired by maps.vectortown.parse.StreamedDataViewReader. - * Supports codepoints from U+0000 up to U+10FFFF. + * Supports codepoints from U+0000 up to U+10FFFF. * (http://en.wikipedia.org/wiki/UTF-8). * @param {number} length The length of the string to read. * @return {string} The decoded string. @@ -984,7 +984,7 @@ jspb.BinaryDecoder.prototype.readString = function(length) { // 4. Add 0xDC00 to the low value to form the low surrogate: var low = (codepoint & 1023) + 0xDC00; var high = ((codepoint >> 10) & 1023) + 0xD800; - codeUnits.push(high, low) + codeUnits.push(high, low); } } // String.fromCharCode.apply is faster than manually appending characters on diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js index 9f947b99..cb8aff96 100644 --- a/js/binary/decoder_test.js +++ b/js/binary/decoder_test.js @@ -209,25 +209,25 @@ describe('binaryDecoderTest', function() { assertEquals(hashC, decoder.readFixedHash64()); assertEquals(hashD, decoder.readFixedHash64()); }); - + /** * Test encoding and decoding utf-8. */ it('testUtf8', function() { var encoder = new jspb.BinaryEncoder(); - var ascii = "ASCII should work in 3, 2, 1..." + var ascii = "ASCII should work in 3, 2, 1..."; var utf8_two_bytes = "©"; var utf8_three_bytes = "❄"; var utf8_four_bytes = "😁"; - + encoder.writeString(ascii); encoder.writeString(utf8_two_bytes); encoder.writeString(utf8_three_bytes); encoder.writeString(utf8_four_bytes); - + var decoder = jspb.BinaryDecoder.alloc(encoder.end()); - + assertEquals(ascii, decoder.readString(ascii.length)); assertEquals(utf8_two_bytes, decoder.readString(utf8_two_bytes.length)); assertEquals(utf8_three_bytes, decoder.readString(utf8_three_bytes.length)); diff --git a/js/binary/encoder.js b/js/binary/encoder.js index 1663bbd4..aee33e7e 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -452,9 +452,9 @@ jspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) { */ jspb.BinaryEncoder.prototype.writeString = function(value) { var oldLength = this.buffer_.length; - + for (var i = 0; i < value.length; i++) { - + var c = value.charCodeAt(i); if (c < 128) { diff --git a/js/binary/message_test.js b/js/binary/message_test.js new file mode 100644 index 00000000..4edc666b --- /dev/null +++ b/js/binary/message_test.js @@ -0,0 +1,60 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Test suite is written using Jasmine -- see http://jasmine.github.io/ + +goog.setTestOnly(); + +goog.require('goog.testing.asserts'); + +// CommonJS-LoadFromFile: test_pb proto.jspb.test +goog.require('proto.jspb.test.Deeply.Nested.Message'); + +// CommonJS-LoadFromFile: test2_pb proto.jspb.test +goog.require('proto.jspb.test.ForeignNestedFieldMessage'); + +describe('Message test suite', function() { + // Verify that we can successfully use a field referring to a nested message + // from a different .proto file. + it('testForeignNestedMessage', function() { + var msg = new proto.jspb.test.ForeignNestedFieldMessage(); + var nested = new proto.jspb.test.Deeply.Nested.Message(); + nested.setCount(5); + msg.setDeeplyNestedMessage(nested); + assertEquals(5, msg.getDeeplyNestedMessage().getCount()); + + // After a serialization-deserialization round trip we should get back the + // same data we started with. + var serialized = msg.serializeBinary(); + var deserialized = + proto.jspb.test.ForeignNestedFieldMessage.deserializeBinary(serialized); + assertEquals(5, deserialized.getDeeplyNestedMessage().getCount()); + }); +}); @@ -183,26 +183,39 @@ jspb.Map.fromObject = function(entries, valueCtor, valueFromObject) { /** - * Helper: return an iterator over an array. + * Helper: an IteratorIterable over an array. * @template T * @param {!Array<T>} arr the array - * @return {!Iterator<T>} an iterator + * @implements {IteratorIterable<T>} + * @constructor @struct * @private */ -jspb.Map.arrayIterator_ = function(arr) { - var idx = 0; - return /** @type {!Iterator} */ ({ - next: function() { - if (idx < arr.length) { - return { done: false, value: arr[idx++] }; - } else { - return { done: true }; - } - } - }); +jspb.Map.ArrayIteratorIterable_ = function(arr) { + /** @type {number} @private */ + this.idx_ = 0; + + /** @const @private */ + this.arr_ = arr; }; +/** @override @final */ +jspb.Map.ArrayIteratorIterable_.prototype.next = function() { + if (this.idx_ < this.arr_.length) { + return {done: false, value: this.arr_[this.idx_++]}; + } else { + return {done: true, value: undefined}; + } +}; + +if (typeof(Symbol) != 'undefined') { + /** @override */ + jspb.Map.ArrayIteratorIterable_.prototype[Symbol.iterator] = function() { + return this; + }; +} + + /** * Returns the map's length (number of key/value pairs). * @return {number} @@ -260,10 +273,9 @@ jspb.Map.prototype.getEntryList = function() { /** - * Returns an iterator over [key, value] pairs in the map. + * Returns an iterator-iterable over [key, value] pairs in the map. * Closure compiler sadly doesn't support tuples, ie. Iterator<[K,V]>. - * @return {!Iterator<!Array<K|V>>} - * The iterator + * @return {!IteratorIterable<!Array<K|V>>} The iterator-iterable. */ jspb.Map.prototype.entries = function() { var entries = []; @@ -273,13 +285,13 @@ jspb.Map.prototype.entries = function() { var entry = this.map_[strKeys[i]]; entries.push([entry.key, this.wrapEntry_(entry)]); } - return jspb.Map.arrayIterator_(entries); + return new jspb.Map.ArrayIteratorIterable_(entries); }; /** - * Returns an iterator over keys in the map. - * @return {!Iterator<K>} The iterator + * Returns an iterator-iterable over keys in the map. + * @return {!IteratorIterable<K>} The iterator-iterable. */ jspb.Map.prototype.keys = function() { var keys = []; @@ -289,13 +301,13 @@ jspb.Map.prototype.keys = function() { var entry = this.map_[strKeys[i]]; keys.push(entry.key); } - return jspb.Map.arrayIterator_(keys); + return new jspb.Map.ArrayIteratorIterable_(keys); }; /** - * Returns an iterator over values in the map. - * @return {!Iterator<V>} The iterator + * Returns an iterator-iterable over values in the map. + * @return {!IteratorIterable<V>} The iterator-iterable. */ jspb.Map.prototype.values = function() { var values = []; @@ -305,7 +317,7 @@ jspb.Map.prototype.values = function() { var entry = this.map_[strKeys[i]]; values.push(this.wrapEntry_(entry)); } - return jspb.Map.arrayIterator_(values); + return new jspb.Map.ArrayIteratorIterable_(values); }; diff --git a/js/maps_test.js b/js/maps_test.js index 6e6ddc29..e8dd2f21 100755 --- a/js/maps_test.js +++ b/js/maps_test.js @@ -288,6 +288,50 @@ function makeTests(msgInfo, submessageCtor, suffix) { var a = msg.toArray(); assertEquals(a[0], entries); // retains original reference }); + + /** + * Returns IteratorIterables for entries(), keys() and values(). + */ + it('testIteratorIterables' + suffix, function() { + var msg = new msgInfo.constructor(); + var m = msg.getMapStringStringMap(); + m.set('key1', 'value1'); + m.set('key2', 'value2'); + var entryIterator = m.entries(); + assertElementsEquals(entryIterator.next().value, ['key1', 'value1']); + assertElementsEquals(entryIterator.next().value, ['key2', 'value2']); + assertEquals(entryIterator.next().done, true); + + if (typeof(Symbol) != 'undefined') { + var entryIterable = m.entries()[Symbol.iterator](); + assertElementsEquals(entryIterable.next().value, ['key1', 'value1']); + assertElementsEquals(entryIterable.next().value, ['key2', 'value2']); + assertEquals(entryIterable.next().done, true); + } + + var keyIterator = m.keys(); + assertEquals(keyIterator.next().value, 'key1'); + assertEquals(keyIterator.next().value, 'key2'); + assertEquals(keyIterator.next().done, true); + + if (typeof(Symbol) != 'undefined') { + var keyIterable = m.keys()[Symbol.iterator](); + assertEquals(keyIterable.next().value, 'key1'); + assertEquals(keyIterable.next().value, 'key2'); + assertEquals(keyIterable.next().done, true); + } + var valueIterator = m.values(); + assertEquals(valueIterator.next().value, 'value1'); + assertEquals(valueIterator.next().value, 'value2'); + assertEquals(valueIterator.next().done, true); + + if (typeof(Symbol) != 'undefined') { + var valueIterable = m.values()[Symbol.iterator](); + assertEquals(valueIterable.next().value, 'value1'); + assertEquals(valueIterable.next().value, 'value2'); + assertEquals(valueIterable.next().done, true); + } + }); } describe('mapsTest', function() { diff --git a/js/message.js b/js/message.js index 1eb88aef..05d34e9d 100644 --- a/js/message.js +++ b/js/message.js @@ -175,6 +175,22 @@ goog.define('jspb.Message.GENERATE_FROM_OBJECT', !goog.DISALLOW_TEST_ONLY_CODE); /** + * @define {boolean} Whether to generate toString methods for objects. Turn + * this off if you do use toString in your project and want to trim it from + * compiled JS. + */ +goog.define('jspb.Message.GENERATE_TO_STRING', true); + + +/** + * @define {boolean} Whether arrays passed to initialize() can be assumed to be + * local (e.g. not from another iframe) and thus safely classified with + * instanceof Array. + */ +goog.define('jspb.Message.ASSUME_LOCAL_ARRAYS', false); + + +/** * @define {boolean} Turning on this flag does NOT change the behavior of JSPB * and only affects private internal state. It may, however, break some * tests that use naive deeply-equals algorithms, because using a proto @@ -364,6 +380,18 @@ jspb.Message.EMPTY_LIST_SENTINEL_ = goog.DEBUG && Object.freeze ? /** + * Returns true if the provided argument is an array. + * @param {*} o The object to classify as array or not. + * @return {boolean} True if the provided object is an array. + * @private + */ +jspb.Message.isArray_ = function(o) { + return jspb.Message.ASSUME_LOCAL_ARRAYS ? o instanceof Array : + goog.isArray(o); +}; + + +/** * Ensures that the array contains an extension object if necessary. * If the array contains an extension object in its last position, then the * object is kept in place and its position is used as the pivot. If not, then @@ -383,8 +411,8 @@ jspb.Message.materializeExtensionObject_ = function(msg, suggestedPivot) { // the object is not an array, since arrays are valid field values. // NOTE(lukestebbing): We avoid looking at .length to avoid a JIT bug // in Safari on iOS 8. See the description of CL/86511464 for details. - if (obj && typeof obj == 'object' && !goog.isArray(obj) && - !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) { + if (obj && typeof obj == 'object' && !jspb.Message.isArray_(obj) && + !(jspb.Message.SUPPORTS_UINT8ARRAY_ && obj instanceof Uint8Array)) { msg.pivot_ = foundIndex - msg.arrayIndexOffset_; msg.extensionObject_ = obj; return; @@ -1140,6 +1168,7 @@ jspb.Message.prototype.toArray = function() { +if (jspb.Message.GENERATE_TO_STRING) { /** * Creates a string representation of the internal data array of this proto. @@ -1152,6 +1181,7 @@ jspb.Message.prototype.toString = function() { return this.array.toString(); }; +} /** * Gets the value of the extension field from the extended object. diff --git a/js/message_test.js b/js/message_test.js index 6d7cdd21..a2c5763d 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -76,12 +76,10 @@ goog.require('proto.jspb.test.TestGroup1'); goog.require('proto.jspb.test.TestMessageWithOneof'); goog.require('proto.jspb.test.TestReservedNames'); goog.require('proto.jspb.test.TestReservedNamesExtension'); -goog.require('proto.jspb.test.Deeply.Nested.Message'); // CommonJS-LoadFromFile: test2_pb proto.jspb.test goog.require('proto.jspb.test.ExtensionMessage'); goog.require('proto.jspb.test.TestExtensionsMessage'); -goog.require('proto.jspb.test.ForeignNestedFieldMessage'); @@ -1053,21 +1051,4 @@ describe('Message test suite', function() { assertNan(message.getDefaultDoubleField()); }); - // Verify that we can successfully use a field referring to a nested message - // from a different .proto file. - it('testForeignNestedMessage', function() { - var msg = new proto.jspb.test.ForeignNestedFieldMessage(); - var nested = new proto.jspb.test.Deeply.Nested.Message(); - nested.setCount(5); - msg.setDeeplyNestedMessage(nested); - assertEquals(5, msg.getDeeplyNestedMessage().getCount()); - - // After a serialization-deserialization round trip we should get back the - // same data we started with. - var serialized = msg.serializeBinary(); - var deserialized = - proto.jspb.test.ForeignNestedFieldMessage.deserializeBinary(serialized); - assertEquals(5, deserialized.getDeeplyNestedMessage().getCount()); - }); - }); diff --git a/js/package.json b/js/package.json index d3c77eb6..dd6373de 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.1.0", + "version": "3.2.0", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ |