From 98835fb8f8a8f144f2a1eac0b833ff83f4a05f54 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Mon, 19 Sep 2016 13:45:07 -0700 Subject: Integrate internal changes --- js/binary/proto_test.js | 2 +- js/debug.js | 3 +- js/debug_test.js | 2 +- js/map.js | 22 +-- js/maps_test.js | 359 ++++++++++++++++++++++++++++++++++++++++++++++++ js/message.js | 154 +++++++++++++++++---- js/message_test.js | 55 ++------ js/proto3_test.js | 2 +- 8 files changed, 514 insertions(+), 85 deletions(-) create mode 100755 js/maps_test.js (limited to 'js') diff --git a/js/binary/proto_test.js b/js/binary/proto_test.js index 14d0f42e..26e1d30f 100644 --- a/js/binary/proto_test.js +++ b/js/binary/proto_test.js @@ -496,7 +496,7 @@ describe('protoBinaryTest', function() { msg.setRepeatedBytesList([BYTES_B64, BYTES_B64]); assertGetters(); - msg.setRepeatedBytesList(null); + msg.setRepeatedBytesList([]); assertEquals(0, msg.getRepeatedBytesList().length); assertEquals(0, msg.getRepeatedBytesList_asB64().length); assertEquals(0, msg.getRepeatedBytesList_asU8().length); diff --git a/js/debug.js b/js/debug.js index 3c1ada02..46b24853 100644 --- a/js/debug.js +++ b/js/debug.js @@ -95,8 +95,7 @@ jspb.debug.dump_ = function(thing) { if (match && name != 'getExtension' && name != 'getJsPbMessageId') { var has = 'has' + match[1]; - if (!thing[has] || thing[has]()) - { + if (!thing[has] || thing[has]()) { var val = thing[name](); object[jspb.debug.formatFieldName_(match[1])] = jspb.debug.dump_(val); } diff --git a/js/debug_test.js b/js/debug_test.js index 01cbf891..702cc76e 100644 --- a/js/debug_test.js +++ b/js/debug_test.js @@ -65,7 +65,7 @@ describe('debugTest', function() { 'aBoolean': true }, jspb.debug.dump(message)); - message.setAString(undefined); + message.clearAString(); assertObjectEquals({ $name: 'proto.jspb.test.Simple1', diff --git a/js/map.js b/js/map.js index e6406a60..0f8401c4 100644 --- a/js/map.js +++ b/js/map.js @@ -103,7 +103,10 @@ jspb.Map.prototype.toArray = function() { var m = this.map_; for (var p in m) { if (Object.prototype.hasOwnProperty.call(m, p)) { - m[p].valueWrapper.toArray(); + var valueWrapper = /** @type {?jspb.Message} */ (m[p].valueWrapper); + if (valueWrapper) { + valueWrapper.toArray(); + } } } } @@ -343,13 +346,13 @@ jspb.Map.prototype.has = function(key) { * number. * @param {number} fieldNumber * @param {!jspb.BinaryWriter} writer - * @param {function(this:jspb.BinaryWriter,number,K)=} keyWriterFn + * @param {!function(this:jspb.BinaryWriter,number,K)} keyWriterFn * The method on BinaryWriter that writes type K to the stream. - * @param {function(this:jspb.BinaryWriter,number,V)| - * function(this:jspb.BinaryReader,V,?)=} valueWriterFn + * @param {!function(this:jspb.BinaryWriter,number,V)| + * function(this:jspb.BinaryReader,V,?)} valueWriterFn * The method on BinaryWriter that writes type V to the stream. May be * writeMessage, in which case the second callback arg form is used. - * @param {?function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback + * @param {function(V,!jspb.BinaryWriter)=} opt_valueWriterCallback * The BinaryWriter serialization callback for type V, if V is a message * type. */ @@ -376,14 +379,15 @@ jspb.Map.prototype.serializeBinary = function( * Read one key/value message from the given BinaryReader. Compatible as the * `reader` callback parameter to jspb.BinaryReader.readMessage, to be called * when a key/value pair submessage is encountered. + * @template K, V * @param {!jspb.Map} map * @param {!jspb.BinaryReader} reader - * @param {function(this:jspb.BinaryReader):K=} keyReaderFn + * @param {!function(this:jspb.BinaryReader):K} keyReaderFn * The method on BinaryReader that reads type K from the stream. * - * @param {function(this:jspb.BinaryReader):V| - * function(this:jspb.BinaryReader,V, - * function(V,!jspb.BinaryReader))=} valueReaderFn + * @param {!function(this:jspb.BinaryReader):V| + * function(this:jspb.BinaryReader,V, + * function(V,!jspb.BinaryReader))} valueReaderFn * The method on BinaryReader that reads type V from the stream. May be * readMessage, in which case the second callback arg form is used. * diff --git a/js/maps_test.js b/js/maps_test.js new file mode 100755 index 00000000..3ffb510b --- /dev/null +++ b/js/maps_test.js @@ -0,0 +1,359 @@ +// 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. + +goog.require('goog.testing.asserts'); +goog.require('goog.userAgent'); +goog.require('proto.jspb.test.MapValueEnum'); +goog.require('proto.jspb.test.MapValueMessage'); +goog.require('proto.jspb.test.MapValueMessageNoBinary'); +goog.require('proto.jspb.test.TestMapFields'); +goog.require('proto.jspb.test.TestMapFieldsNoBinary'); + +/** + * Helper: check that the given map has exactly this set of (sorted) entries. + * @param {!jspb.Map} map + * @param {!Array>} entries + */ +function checkMapEquals(map, entries) { + var arr = map.toArray(); + assertEquals(arr.length, entries.length); + for (var i = 0; i < arr.length; i++) { + assertElementsEquals(arr[i], entries[i]); + } +} + +/** + * Converts an ES6 iterator to an array. + * @template T + * @param {!Iterator} iter an iterator + * @return {!Array} + */ +function toArray(iter) { + var arr = []; + while (true) { + var val = iter.next(); + if (val.done) { + break; + } + arr.push(val.value); + } + return arr; +} + + +/** + * Helper: generate test methods for this TestMapFields class. + * @param {?} msgInfo + * @param {?} submessageCtor + * @param {!string} suffix + */ +function makeTests(msgInfo, submessageCtor, suffix) { + /** + * Helper: fill all maps on a TestMapFields. + * @param {?} msg + */ + var fillMapFields = function(msg) { + msg.getMapStringStringMap().set('asdf', 'jkl;').set('key 2', 'hello world'); + msg.getMapStringInt32Map().set('a', 1).set('b', -2); + msg.getMapStringInt64Map().set('c', 0x100000000).set('d', 0x200000000); + msg.getMapStringBoolMap().set('e', true).set('f', false); + msg.getMapStringDoubleMap().set('g', 3.14159).set('h', 2.71828); + msg.getMapStringEnumMap() + .set('i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR) + .set('j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ); + msg.getMapStringMsgMap() + .set('k', new submessageCtor()) + .set('l', new submessageCtor()); + msg.getMapStringMsgMap().get('k').setFoo(42); + msg.getMapStringMsgMap().get('l').setFoo(84); + msg.getMapInt32StringMap().set(-1, 'a').set(42, 'b'); + msg.getMapInt64StringMap().set(0x123456789abc, 'c').set(0xcba987654321, 'd'); + msg.getMapBoolStringMap().set(false, 'e').set(true, 'f'); + }; + + /** + * Helper: check all maps on a TestMapFields. + * @param {?} msg + */ + var checkMapFields = function(msg) { + checkMapEquals(msg.getMapStringStringMap(), [ + ['asdf', 'jkl;'], + ['key 2', 'hello world'] + ]); + checkMapEquals(msg.getMapStringInt32Map(), [ + ['a', 1], + ['b', -2] + ]); + checkMapEquals(msg.getMapStringInt64Map(), [ + ['c', 0x100000000], + ['d', 0x200000000] + ]); + checkMapEquals(msg.getMapStringBoolMap(), [ + ['e', true], + ['f', false] + ]); + checkMapEquals(msg.getMapStringDoubleMap(), [ + ['g', 3.14159], + ['h', 2.71828] + ]); + checkMapEquals(msg.getMapStringEnumMap(), [ + ['i', proto.jspb.test.MapValueEnum.MAP_VALUE_BAR], + ['j', proto.jspb.test.MapValueEnum.MAP_VALUE_BAZ] + ]); + checkMapEquals(msg.getMapInt32StringMap(), [ + [-1, 'a'], + [42, 'b'] + ]); + checkMapEquals(msg.getMapInt64StringMap(), [ + [0x123456789abc, 'c'], + [0xcba987654321, 'd'] + ]); + checkMapEquals(msg.getMapBoolStringMap(), [ + [false, 'e'], + [true, 'f'] + ]); + + assertEquals(msg.getMapStringMsgMap().getLength(), 2); + assertEquals(msg.getMapStringMsgMap().get('k').getFoo(), 42); + assertEquals(msg.getMapStringMsgMap().get('l').getFoo(), 84); + + var entries = toArray(msg.getMapStringMsgMap().entries()); + assertEquals(entries.length, 2); + entries.forEach(function(entry) { + var key = entry[0]; + var val = entry[1]; + assert(val === msg.getMapStringMsgMap().get(key)); + }); + + msg.getMapStringMsgMap().forEach(function(val, key) { + assert(val === msg.getMapStringMsgMap().get(key)); + }); + }; + + it('testMapStringStringField' + suffix, function() { + var msg = new msgInfo.constructor(); + assertEquals(msg.getMapStringStringMap().getLength(), 0); + assertEquals(msg.getMapStringInt32Map().getLength(), 0); + assertEquals(msg.getMapStringInt64Map().getLength(), 0); + assertEquals(msg.getMapStringBoolMap().getLength(), 0); + assertEquals(msg.getMapStringDoubleMap().getLength(), 0); + assertEquals(msg.getMapStringEnumMap().getLength(), 0); + assertEquals(msg.getMapStringMsgMap().getLength(), 0); + + // Re-create to clear out any internally-cached wrappers, etc. + msg = new msgInfo.constructor(); + var m = msg.getMapStringStringMap(); + assertEquals(m.has('asdf'), false); + assertEquals(m.get('asdf'), undefined); + m.set('asdf', 'hello world'); + assertEquals(m.has('asdf'), true); + assertEquals(m.get('asdf'), 'hello world'); + m.set('jkl;', 'key 2'); + assertEquals(m.has('jkl;'), true); + assertEquals(m.get('jkl;'), 'key 2'); + assertEquals(m.getLength(), 2); + var it = m.entries(); + assertElementsEquals(it.next().value, ['asdf', 'hello world']); + assertElementsEquals(it.next().value, ['jkl;', 'key 2']); + assertEquals(it.next().done, true); + checkMapEquals(m, [ + ['asdf', 'hello world'], + ['jkl;', 'key 2'] + ]); + m.del('jkl;'); + assertEquals(m.has('jkl;'), false); + assertEquals(m.get('jkl;'), undefined); + assertEquals(m.getLength(), 1); + it = m.keys(); + assertEquals(it.next().value, 'asdf'); + assertEquals(it.next().done, true); + it = m.values(); + assertEquals(it.next().value, 'hello world'); + assertEquals(it.next().done, true); + + var count = 0; + m.forEach(function(value, key, map) { + assertEquals(map, m); + assertEquals(key, 'asdf'); + assertEquals(value, 'hello world'); + count++; + }); + assertEquals(count, 1); + + m.clear(); + assertEquals(m.getLength(), 0); + }); + + + /** + * Tests operations on maps with all key and value types. + */ + it('testAllMapTypes' + suffix, function() { + var msg = new msgInfo.constructor(); + fillMapFields(msg); + checkMapFields(msg); + }); + + + if (msgInfo.deserializeBinary) { + /** + * Tests serialization and deserialization in binary format. + */ + it('testBinaryFormat' + suffix, function() { + if (goog.userAgent.IE && !goog.userAgent.isDocumentModeOrHigher(10)) { + // IE8/9 currently doesn't support binary format because they lack + // TypedArray. + return; + } + + // Check that the format is correct. + var msg = new msgInfo.constructor(); + msg.getMapStringStringMap().set('A', 'a'); + var serialized = msg.serializeBinary(); + var expectedSerialized = [ + 0x0a, 0x6, // field 1 (map_string_string), delimited, length 6 + 0x0a, 0x1, // field 1 in submessage (key), delimited, length 1 + 0x41, // ASCII 'A' + 0x12, 0x1, // field 2 in submessage (value), delimited, length 1 + 0x61 // ASCII 'a' + ]; + assertEquals(serialized.length, expectedSerialized.length); + for (var i = 0; i < serialized.length; i++) { + assertEquals(serialized[i], expectedSerialized[i]); + } + + // Check that all map fields successfully round-trip. + msg = new msgInfo.constructor(); + fillMapFields(msg); + serialized = msg.serializeBinary(); + var decoded = msgInfo.deserializeBinary(serialized); + checkMapFields(decoded); + }); + } + + + /** + * Tests serialization and deserialization in JSPB format. + */ + it('testJSPBFormat' + suffix, function() { + var msg = new msgInfo.constructor(); + fillMapFields(msg); + var serialized = msg.serialize(); + var decoded = msgInfo.deserialize(serialized); + checkMapFields(decoded); + }); + + /** + * Tests serialization and deserialization in JSPB format, when there is + * a submessage that also contains map entries. This tests recursive + * sync. + */ + it('testJSPBFormatNested' + suffix, function() { + var submsg = new msgInfo.constructor(); + var mapValue = new msgInfo.constructor(); + var msg = new msgInfo.constructor(); + + msg.getMapStringTestmapfieldsMap().set('test', mapValue); + msg.setTestMapFields(submsg); + + fillMapFields(submsg); + fillMapFields(msg); + fillMapFields(mapValue); + + var serialized = msg.serialize(); + + var decoded = msgInfo.deserialize(serialized); + checkMapFields(decoded); + + var decodedSubmsg = decoded.getTestMapFields(); + assertNotNull(decodedSubmsg); + checkMapFields(decodedSubmsg); + + var decodedMapValue = decoded.getMapStringTestmapfieldsMap().get('test'); + assertNotNull(decodedMapValue); + checkMapFields(decodedMapValue); + }); + + /** + * Tests toObject()/fromObject(). + */ + it('testToFromObject' + suffix, function() { + var msg = new msgInfo.constructor(); + fillMapFields(msg); + var obj = msg.toObject(); + var decoded = msgInfo.fromObject(obj); + checkMapFields(decoded); + obj = msgInfo.deserialize(msg.serialize()).toObject(); + decoded = msgInfo.fromObject(obj); + checkMapFields(decoded); + }); + + + /** + * Exercises the lazy map<->underlying array sync. + */ + it('testLazyMapSync' + suffix, function() { + // Start with a JSPB array containing a few map entries. + var entries = [ + ['a', 'entry 1'], + ['c', 'entry 2'], + ['b', 'entry 3'] + ]; + var msg = new msgInfo.constructor([entries]); + assertEquals(entries.length, 3); + assertEquals(entries[0][0], 'a'); + assertEquals(entries[1][0], 'c'); + assertEquals(entries[2][0], 'b'); + msg.getMapStringStringMap().del('a'); + assertEquals(entries.length, 3); // not yet sync'd + msg.toArray(); // force a sync + assertEquals(entries.length, 2); + assertEquals(entries[0][0], 'b'); // now in sorted order + assertEquals(entries[1][0], 'c'); + + var a = msg.toArray(); + assertEquals(a[0], entries); // retains original reference + }); +} + +describe('mapsTest', function() { + makeTests({ + constructor: proto.jspb.test.TestMapFields, + fromObject: proto.jspb.test.TestMapFields.fromObject, + deserialize: proto.jspb.test.TestMapFields.deserialize, + deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary + }, proto.jspb.test.MapValueMessage, "_Binary"); + makeTests({ + constructor: proto.jspb.test.TestMapFieldsNoBinary, + fromObject: proto.jspb.test.TestMapFieldsNoBinary.fromObject, + deserialize: proto.jspb.test.TestMapFieldsNoBinary.deserialize, + deserializeBinary: null + }, proto.jspb.test.MapValueMessageNoBinary, "_NoBinary"); +}); diff --git a/js/message.js b/js/message.js index 631ebe69..b150722a 100644 --- a/js/message.js +++ b/js/message.js @@ -106,17 +106,17 @@ jspb.ExtensionFieldInfo = function(fieldNumber, fieldName, ctor, toObjectFn, /** * Stores binary-related information for a single extension field. * @param {!jspb.ExtensionFieldInfo} fieldInfo - * @param {?function(number,?)=} binaryReaderFn - * @param {?function(number,?)|function(number,?,?,?,?,?)=} binaryWriterFn - * @param {?function(?,?)=} opt_binaryMessageSerializeFn - * @param {?function(?,?)=} opt_binaryMessageDeserializeFn - * @param {?boolean=} opt_isPacked + * @param {!function(number,?)} binaryReaderFn + * @param {!function(number,?)|function(number,?,?,?,?,?)} binaryWriterFn + * @param {function(?,?)=} opt_binaryMessageSerializeFn + * @param {function(?,?)=} opt_binaryMessageDeserializeFn + * @param {boolean=} opt_isPacked * @constructor * @struct * @template T */ jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriterFn, - binaryMessageSerializeFn, binaryMessageDeserializeFn, isPacked) { + opt_binaryMessageSerializeFn, opt_binaryMessageDeserializeFn, opt_isPacked) { /** @const */ this.fieldInfo = fieldInfo; /** @const */ @@ -124,11 +124,11 @@ jspb.ExtensionFieldBinaryInfo = function(fieldInfo, binaryReaderFn, binaryWriter /** @const */ this.binaryWriterFn = binaryWriterFn; /** @const */ - this.binaryMessageSerializeFn = binaryMessageSerializeFn; + this.binaryMessageSerializeFn = opt_binaryMessageSerializeFn; /** @const */ - this.binaryMessageDeserializeFn = binaryMessageDeserializeFn; + this.binaryMessageDeserializeFn = opt_binaryMessageDeserializeFn; /** @const */ - this.isPacked = isPacked; + this.isPacked = opt_isPacked; }; /** @@ -744,7 +744,7 @@ jspb.Message.assertConsistentTypes_ = function(array) { * @return {T} The field's value. * @protected */ -jspb.Message.getFieldProto3 = function(msg, fieldNumber, defaultValue) { +jspb.Message.getFieldWithDefault = function(msg, fieldNumber, defaultValue) { var value = jspb.Message.getField(msg, fieldNumber); if (value == null) { return defaultValue; @@ -810,6 +810,24 @@ jspb.Message.setField = function(msg, fieldNumber, value) { }; +/** + * Adds a value to a repeated, primitive field. + * @param {!jspb.Message} msg A jspb proto. + * @param {number} fieldNumber The field number. + * @param {string|number|boolean|!Uint8Array} value New value + * @param {number=} opt_index Index where to put new value. + * @protected + */ +jspb.Message.addToRepeatedField = function(msg, fieldNumber, value, opt_index) { + var arr = jspb.Message.getField(msg, fieldNumber); + if (opt_index != undefined) { + arr.splice(opt_index, 0, value); + } else { + arr.push(value); + } +}; + + /** * Sets the value of a field in a oneof union and clears all other fields in * the union. @@ -907,6 +925,24 @@ jspb.Message.getWrapperField = function(msg, ctor, fieldNumber, opt_required) { * @protected */ jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) { + jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber); + var val = msg.wrappers_[fieldNumber]; + if (val == jspb.Message.EMPTY_LIST_SENTINEL_) { + val = msg.wrappers_[fieldNumber] = []; + } + return /** @type {!Array} */ (val); +}; + + +/** + * Wraps underlying array into proto message representation if it wasn't done + * before. + * @param {!jspb.Message} msg A jspb proto. + * @param {function(new:jspb.Message, ?Array)} ctor Constructor for the field. + * @param {number} fieldNumber The field number. + * @private + */ +jspb.Message.wrapRepeatedField_ = function(msg, ctor, fieldNumber) { if (!msg.wrappers_) { msg.wrappers_ = {}; } @@ -917,11 +953,6 @@ jspb.Message.getRepeatedWrapperField = function(msg, ctor, fieldNumber) { } msg.wrappers_[fieldNumber] = wrappers; } - var val = msg.wrappers_[fieldNumber]; - if (val == jspb.Message.EMPTY_LIST_SENTINEL_) { - val = msg.wrappers_[fieldNumber] = []; - } - return /** @type {Array} */ (val); }; @@ -980,6 +1011,48 @@ jspb.Message.setRepeatedWrapperField = function(msg, fieldNumber, value) { }; +/** + * Add a message to a repeated proto field. + * @param {!jspb.Message} msg A jspb proto. + * @param {number} fieldNumber The field number. + * @param {T_CHILD|undefined} value Proto that will be added to the + * repeated field. + * @param {function(new:T_CHILD, ?Array=)} ctor The constructor of the + * message type. + * @param {number|undefined} index Index at which to insert the value. + * @return {T_CHILD_NOT_UNDEFINED} proto that was inserted to the repeated field + * @template MessageType + * Use go/closure-ttl to declare a non-undefined version of T_CHILD. Replace the + * undefined in blah|undefined with none. This is necessary because the compiler + * will infer T_CHILD to be |undefined. + * @template T_CHILD + * @template T_CHILD_NOT_UNDEFINED := + * cond(isUnknown(T_CHILD), unknown(), + * mapunion(T_CHILD, (X) => + * cond(eq(X, 'undefined'), none(), X))) + * =: + * @protected + */ +jspb.Message.addToRepeatedWrapperField = function( + msg, fieldNumber, value, ctor, index) { + jspb.Message.wrapRepeatedField_(msg, ctor, fieldNumber); + var wrapperArray = msg.wrappers_[fieldNumber]; + if (!wrapperArray) { + wrapperArray = msg.wrappers_[fieldNumber] = []; + } + var insertedValue = value ? value : new ctor(); + var array = jspb.Message.getField(msg, fieldNumber); + if (index != undefined) { + wrapperArray.splice(index, 0, insertedValue); + array.splice(index, 0, insertedValue.toArray()); + } else { + wrapperArray.push(insertedValue); + array.push(insertedValue.toArray()); + } + return insertedValue; +}; + + /** * Converts a JsPb repeated message field into a map. The map will contain * protos unless an optional toObject function is given, in which case it will @@ -1114,32 +1187,39 @@ jspb.Message.prototype.getExtension = function(fieldInfo) { * @param {jspb.ExtensionFieldInfo} fieldInfo Specifies the field to set. * @param {jspb.Message|string|Uint8Array|number|boolean|Array?} value The value * to set. + * @return {THIS} For chaining + * @this {THIS} + * @template THIS */ jspb.Message.prototype.setExtension = function(fieldInfo, value) { - if (!this.wrappers_) { - this.wrappers_ = {}; + // Cast self, since the inferred THIS is unknown inside the function body. + // https://github.com/google/closure-compiler/issues/1411#issuecomment-232442220 + var self = /** @type {!jspb.Message} */ (this); + if (!self.wrappers_) { + self.wrappers_ = {}; } - jspb.Message.maybeInitEmptyExtensionObject_(this); + jspb.Message.maybeInitEmptyExtensionObject_(self); var fieldNumber = fieldInfo.fieldIndex; if (fieldInfo.isRepeated) { value = value || []; if (fieldInfo.isMessageType()) { - this.wrappers_[fieldNumber] = value; - this.extensionObject_[fieldNumber] = goog.array.map( + self.wrappers_[fieldNumber] = value; + self.extensionObject_[fieldNumber] = goog.array.map( /** @type {Array} */ (value), function(msg) { return msg.toArray(); }); } else { - this.extensionObject_[fieldNumber] = value; + self.extensionObject_[fieldNumber] = value; } } else { if (fieldInfo.isMessageType()) { - this.wrappers_[fieldNumber] = value; - this.extensionObject_[fieldNumber] = value ? value.toArray() : value; + self.wrappers_[fieldNumber] = value; + self.extensionObject_[fieldNumber] = value ? value.toArray() : value; } else { - this.extensionObject_[fieldNumber] = value; + self.extensionObject_[fieldNumber] = value; } } + return self; }; @@ -1308,7 +1388,30 @@ jspb.Message.compareFields = function(field1, field2) { /** - * Static clone function. NOTE: A type-safe method called "cloneMessage" exists + * Templated, type-safe cloneMessage definition. + * @return {THIS} + * @this {THIS} + * @template THIS + */ +jspb.Message.prototype.cloneMessage = function() { + return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this)); +}; + +/** + * Alias clone to cloneMessage. goog.object.unsafeClone uses clone to + * efficiently copy objects. Without this alias, copying jspb messages comes + * with a large performance penalty. + * @return {THIS} + * @this {THIS} + * @template THIS + */ +jspb.Message.prototype.clone = function() { + return jspb.Message.cloneMessage(/** @type {!jspb.Message} */ (this)); +}; + +/** + * Static clone function. NOTE: A type-safe method called "cloneMessage" + * exists * on each generated JsPb class. Do not call this function directly. * @param {!jspb.Message} msg A message to clone. * @return {!jspb.Message} A deep clone of the given message. @@ -1429,3 +1532,4 @@ jspb.Message.registry_ = {}; * @type {!Object.} */ jspb.Message.messageSetExtensions = {}; +jspb.Message.messageSetExtensionsBinary = {}; diff --git a/js/message_test.js b/js/message_test.js index b7791431..97c594c8 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -269,7 +269,7 @@ describe('Message test suite', function() { assertFalse(response.hasEnumField()); }); - it('testMessageRegistration', function() { + it('testMessageRegistration', /** @suppress {visibility} */ function() { // goog.require(SomeResponse) will include its library, which will in // turn add SomeResponse to the message registry. assertEquals(jspb.Message.registry_['res'], proto.jspb.test.SomeResponse); @@ -297,47 +297,9 @@ describe('Message test suite', function() { var expected = [,,, [], []]; expected[0] = expected[1] = expected[2] = undefined; assertObjectEquals(expected, foo.toArray()); - - // Test set(null). We could deprecated this in favor of clear(), but - // it's also convenient to have. - data = ['str', true, [11], [[22], [33]], ['s1', 's2']]; - foo = new proto.jspb.test.OptionalFields(data); - foo.setAString(null); - foo.setABool(null); - foo.setANestedMessage(null); - foo.setARepeatedMessageList(null); - foo.setARepeatedStringList(null); - assertEquals('', foo.getAString()); - assertEquals(false, foo.getABool()); - assertNull(foo.getANestedMessage()); - assertFalse(foo.hasAString()); - assertFalse(foo.hasABool()); - assertObjectEquals([], foo.getARepeatedMessageList()); - assertObjectEquals([], foo.getARepeatedStringList()); - assertObjectEquals([null, null, null, [], []], foo.toArray()); - - // Test set(undefined). Again, not something we really need, and not - // supported directly by our typing, but it should 'do the right thing'. - data = ['str', true, [11], [[22], [33]], ['s1', 's2']]; - foo = new proto.jspb.test.OptionalFields(data); - foo.setAString(undefined); - foo.setABool(undefined); - foo.setANestedMessage(undefined); - foo.setARepeatedMessageList(undefined); - foo.setARepeatedStringList(undefined); - assertEquals('', foo.getAString()); - assertEquals(false, foo.getABool()); - assertUndefined(foo.getANestedMessage()); - assertFalse(foo.hasAString()); - assertFalse(foo.hasABool()); - assertObjectEquals([], foo.getARepeatedMessageList()); - assertObjectEquals([], foo.getARepeatedStringList()); - expected = [,,, [], []]; - expected[0] = expected[1] = expected[2] = undefined; - assertObjectEquals(expected, foo.toArray()); }); - it('testDifferenceRawObject', function() { + it('testDifferenceRawObject', /** @suppress {visibility} */ function() { var p1 = new proto.jspb.test.HasExtensions(['hi', 'diff', {}]); var p2 = new proto.jspb.test.HasExtensions(['hi', 'what', {1000: 'unique'}]); @@ -477,7 +439,7 @@ describe('Message test suite', function() { var extension = new proto.jspb.test.CloneExtension(); extension.setExt('e1'); original.setExtension(proto.jspb.test.IsExtension.extField, extension); - var clone = original.cloneMessage(); + var clone = original.clone(); assertArrayEquals(['v1',, ['x1', ['y1', 'z1']],, [['x2', ['y2', 'z2']], ['x3', ['y3', 'z3']]], bytes1,, { 100: [, 'e1'] }], clone.toArray()); @@ -712,11 +674,12 @@ describe('Message test suite', function() { assertArrayEquals([1, 2, 3, {1: 'hi'}], msg.toArray()); }); - it('testExtendedMessageEnsureObject', function() { - var data = new proto.jspb.test.HasExtensions(['str1', - {'a_key': 'an_object'}]); - assertEquals('an_object', data.extensionObject_['a_key']); - }); + it('testExtendedMessageEnsureObject', + /** @suppress {visibility} */ function() { + var data = + new proto.jspb.test.HasExtensions(['str1', {'a_key': 'an_object'}]); + assertEquals('an_object', data.extensionObject_['a_key']); + }); it('testToObject_hasExtensionField', function() { var data = new proto.jspb.test.HasExtensions(['str1', {100: ['ext1']}]); diff --git a/js/proto3_test.js b/js/proto3_test.js index fab0fd44..3c929eff 100644 --- a/js/proto3_test.js +++ b/js/proto3_test.js @@ -294,7 +294,7 @@ describe('proto3Test', function() { msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_BAR); msg.setOptionalForeignEnum(proto.jspb.test.Proto3Enum.PROTO3_FOO); msg.setOneofUint32(32); - msg.setOneofUint32(null); + msg.clearOneofUint32(); var serialized = msg.serializeBinary(); -- cgit v1.2.3 From 679381fba8b44d79a1e69d3ba1f9275f623fa62e Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Tue, 20 Sep 2016 13:56:18 -0700 Subject: Fix for maps_test.js in JavaScript. (#2145) Had to strip out some JSPB-format test code, but also added some .proto test messages that had been improperly stripped out. --- js/maps_test.js | 68 +++++---------------------------------------------------- js/test.proto | 26 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 63 deletions(-) (limited to 'js') diff --git a/js/maps_test.js b/js/maps_test.js index 3ffb510b..0d442f4f 100755 --- a/js/maps_test.js +++ b/js/maps_test.js @@ -30,10 +30,14 @@ goog.require('goog.testing.asserts'); goog.require('goog.userAgent'); + +// CommonJS-LoadFromFile: testbinary_pb proto.jspb.test goog.require('proto.jspb.test.MapValueEnum'); goog.require('proto.jspb.test.MapValueMessage'); -goog.require('proto.jspb.test.MapValueMessageNoBinary'); goog.require('proto.jspb.test.TestMapFields'); + +// CommonJS-LoadFromFile: test_pb proto.jspb.test +goog.require('proto.jspb.test.MapValueMessageNoBinary'); goog.require('proto.jspb.test.TestMapFieldsNoBinary'); /** @@ -258,64 +262,6 @@ function makeTests(msgInfo, submessageCtor, suffix) { }); } - - /** - * Tests serialization and deserialization in JSPB format. - */ - it('testJSPBFormat' + suffix, function() { - var msg = new msgInfo.constructor(); - fillMapFields(msg); - var serialized = msg.serialize(); - var decoded = msgInfo.deserialize(serialized); - checkMapFields(decoded); - }); - - /** - * Tests serialization and deserialization in JSPB format, when there is - * a submessage that also contains map entries. This tests recursive - * sync. - */ - it('testJSPBFormatNested' + suffix, function() { - var submsg = new msgInfo.constructor(); - var mapValue = new msgInfo.constructor(); - var msg = new msgInfo.constructor(); - - msg.getMapStringTestmapfieldsMap().set('test', mapValue); - msg.setTestMapFields(submsg); - - fillMapFields(submsg); - fillMapFields(msg); - fillMapFields(mapValue); - - var serialized = msg.serialize(); - - var decoded = msgInfo.deserialize(serialized); - checkMapFields(decoded); - - var decodedSubmsg = decoded.getTestMapFields(); - assertNotNull(decodedSubmsg); - checkMapFields(decodedSubmsg); - - var decodedMapValue = decoded.getMapStringTestmapfieldsMap().get('test'); - assertNotNull(decodedMapValue); - checkMapFields(decodedMapValue); - }); - - /** - * Tests toObject()/fromObject(). - */ - it('testToFromObject' + suffix, function() { - var msg = new msgInfo.constructor(); - fillMapFields(msg); - var obj = msg.toObject(); - var decoded = msgInfo.fromObject(obj); - checkMapFields(decoded); - obj = msgInfo.deserialize(msg.serialize()).toObject(); - decoded = msgInfo.fromObject(obj); - checkMapFields(decoded); - }); - - /** * Exercises the lazy map<->underlying array sync. */ @@ -346,14 +292,10 @@ function makeTests(msgInfo, submessageCtor, suffix) { describe('mapsTest', function() { makeTests({ constructor: proto.jspb.test.TestMapFields, - fromObject: proto.jspb.test.TestMapFields.fromObject, - deserialize: proto.jspb.test.TestMapFields.deserialize, deserializeBinary: proto.jspb.test.TestMapFields.deserializeBinary }, proto.jspb.test.MapValueMessage, "_Binary"); makeTests({ constructor: proto.jspb.test.TestMapFieldsNoBinary, - fromObject: proto.jspb.test.TestMapFieldsNoBinary.fromObject, - deserialize: proto.jspb.test.TestMapFieldsNoBinary.deserialize, deserializeBinary: null }, proto.jspb.test.MapValueMessageNoBinary, "_NoBinary"); }); diff --git a/js/test.proto b/js/test.proto index 937ffb89..48cb37e1 100644 --- a/js/test.proto +++ b/js/test.proto @@ -234,3 +234,29 @@ message TestEndsWithBytes { optional bytes data = 2; } +message TestMapFieldsNoBinary { + map map_string_string = 1; + map map_string_int32 = 2; + map map_string_int64 = 3; + map map_string_bool = 4; + map map_string_double = 5; + map map_string_enum = 6; + map map_string_msg = 7; + + map map_int32_string = 8; + map map_int64_string = 9; + map map_bool_string = 10; + + optional TestMapFieldsNoBinary test_map_fields = 11; + map map_string_testmapfields = 12; +} + +enum MapValueEnumNoBinary { + MAP_VALUE_FOO_NOBINARY = 0; + MAP_VALUE_BAR_NOBINARY = 1; + MAP_VALUE_BAZ_NOBINARY = 2; +} + +message MapValueMessageNoBinary { + optional int32 foo = 1; +} -- cgit v1.2.3 From ebcda12102f2beaa630a81f5675854abb44746c1 Mon Sep 17 00:00:00 2001 From: Bo Yang Date: Tue, 20 Sep 2016 21:29:02 +0000 Subject: Bump version number to 3.1.0-alpha-1. --- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- csharp/src/Google.Protobuf/project.json | 2 +- java/core/pom.xml | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- java/util/pom.xml | 2 +- javanano/pom.xml | 2 +- js/package.json | 2 +- php/ext/google/protobuf/package.xml | 2 +- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/Gemfile.lock | 2 +- ruby/google-protobuf.gemspec | 2 +- 15 files changed, 15 insertions(+), 15 deletions(-) (limited to 'js') diff --git a/Protobuf.podspec b/Protobuf.podspec index 8d1ab357..2aebdda4 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.0.2' + s.version = '3.1.0-alpha-1' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/google/protobuf' s.license = 'New BSD' diff --git a/configure.ac b/configure.ac index 757f55c9..c21990b5 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.0.2],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.1.0-alpha-1],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index ce7514b4..79f32bab 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.0.2 + 3.1.0-alpha1 Google Inc. protobuf-packages https://github.com/google/protobuf/blob/master/LICENSE diff --git a/csharp/src/Google.Protobuf/project.json b/csharp/src/Google.Protobuf/project.json index 607b65ef..dd958c98 100644 --- a/csharp/src/Google.Protobuf/project.json +++ b/csharp/src/Google.Protobuf/project.json @@ -1,5 +1,5 @@ { - "version": "3.0.2", + "version": "3.1.0-alpha-1", "title": "Google Protocol Buffers", "description": "See project site for more info.", "authors": [ "Google Inc." ], diff --git a/java/core/pom.xml b/java/core/pom.xml index 28bc99a0..790f0af3 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -6,7 +6,7 @@ com.google.protobuf protobuf-parent - 3.0.2 + 3.1.0-alpha-1 protobuf-java diff --git a/java/lite/pom.xml b/java/lite/pom.xml index 9862cd94..d6490247 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -6,7 +6,7 @@ com.google.protobuf protobuf-parent - 3.0.0 + 3.1.0-alpha-1 protobuf-lite diff --git a/java/pom.xml b/java/pom.xml index ccfb229e..3fa0a85b 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -11,7 +11,7 @@ com.google.protobuf protobuf-parent - 3.0.2 + 3.1.0-alpha-1 pom Protocol Buffers [Parent] diff --git a/java/util/pom.xml b/java/util/pom.xml index 58cc4b30..4d6ad7fa 100644 --- a/java/util/pom.xml +++ b/java/util/pom.xml @@ -6,7 +6,7 @@ com.google.protobuf protobuf-parent - 3.0.2 + 3.1.0-alpha-1 protobuf-java-util diff --git a/javanano/pom.xml b/javanano/pom.xml index 6ebba3cf..291ed27a 100644 --- a/javanano/pom.xml +++ b/javanano/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf.nano protobuf-javanano - 3.0.0-alpha-7 + 3.1.0-alpha-1 bundle Protocol Buffer JavaNano API diff --git a/js/package.json b/js/package.json index 5df7283c..cc0db47b 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.0.2", + "version": "3.1.0-alpha.1", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ diff --git a/php/ext/google/protobuf/package.xml b/php/ext/google/protobuf/package.xml index 83719091..cfb33acb 100644 --- a/php/ext/google/protobuf/package.xml +++ b/php/ext/google/protobuf/package.xml @@ -13,7 +13,7 @@ 2016-09-02 - 3.1.0 + 3.1.0a1 3.1.0 diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index c4f0a73d..b8581da1 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf protoc - 3.0.2 + 3.1.0-alpha-1 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index 30ee6e81..f52137c4 100755 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,7 +30,7 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '3.0.2' +__version__ = '3.1.0a1' if __name__ != '__main__': try: diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index d0eb9cc4..7a89c866 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - google-protobuf (3.0.0.alpha.5.0.5) + google-protobuf (3.1.0.alpha.1.0) GEM remote: https://rubygems.org/ diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 67b15c33..26d9b20d 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.0.2" + s.version = "3.1.0.alpha.1.0" s.licenses = ["BSD"] s.summary = "Protocol Buffers" s.description = "Protocol Buffers are Google's data interchange format." -- cgit v1.2.3 From 2649844cabcaf72649b686f25a0a5f6396bd52f8 Mon Sep 17 00:00:00 2001 From: Feng Xiao Date: Thu, 22 Sep 2016 14:28:55 -0700 Subject: Update version number. [skip ci] Change-Id: I1ba6f6372a08b5796570851336e1a548602f60da --- Protobuf.podspec | 2 +- configure.ac | 2 +- csharp/Google.Protobuf.Tools.nuspec | 2 +- csharp/src/Google.Protobuf/project.json | 2 +- java/core/pom.xml | 2 +- java/lite/pom.xml | 2 +- java/pom.xml | 2 +- javanano/pom.xml | 2 +- js/package.json | 2 +- protoc-artifacts/pom.xml | 2 +- python/google/protobuf/__init__.py | 2 +- ruby/Gemfile.lock | 2 +- ruby/google-protobuf.gemspec | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) (limited to 'js') diff --git a/Protobuf.podspec b/Protobuf.podspec index 2aebdda4..217f6d20 100644 --- a/Protobuf.podspec +++ b/Protobuf.podspec @@ -5,7 +5,7 @@ # dependent projects use the :git notation to refer to the library. Pod::Spec.new do |s| s.name = 'Protobuf' - s.version = '3.1.0-alpha-1' + s.version = '3.1.0' s.summary = 'Protocol Buffers v.3 runtime library for Objective-C.' s.homepage = 'https://github.com/google/protobuf' s.license = 'New BSD' diff --git a/configure.ac b/configure.ac index c21990b5..a454bbe0 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.59) # In the SVN trunk, the version should always be the next anticipated release # version with the "-pre" suffix. (We used to use "-SNAPSHOT" but this pushed # the size of one file name in the dist tarfile over the 99-char limit.) -AC_INIT([Protocol Buffers],[3.1.0-alpha-1],[protobuf@googlegroups.com],[protobuf]) +AC_INIT([Protocol Buffers],[3.1.0],[protobuf@googlegroups.com],[protobuf]) AM_MAINTAINER_MODE([enable]) diff --git a/csharp/Google.Protobuf.Tools.nuspec b/csharp/Google.Protobuf.Tools.nuspec index 79f32bab..d079c683 100644 --- a/csharp/Google.Protobuf.Tools.nuspec +++ b/csharp/Google.Protobuf.Tools.nuspec @@ -5,7 +5,7 @@ Google Protocol Buffers tools Tools for Protocol Buffers - Google's data interchange format. See project site for more info. - 3.1.0-alpha1 + 3.1.0 Google Inc. protobuf-packages https://github.com/google/protobuf/blob/master/LICENSE diff --git a/csharp/src/Google.Protobuf/project.json b/csharp/src/Google.Protobuf/project.json index dd958c98..12e86248 100644 --- a/csharp/src/Google.Protobuf/project.json +++ b/csharp/src/Google.Protobuf/project.json @@ -1,5 +1,5 @@ { - "version": "3.1.0-alpha-1", + "version": "3.1.0", "title": "Google Protocol Buffers", "description": "See project site for more info.", "authors": [ "Google Inc." ], diff --git a/java/core/pom.xml b/java/core/pom.xml index 790f0af3..8a83eb4e 100644 --- a/java/core/pom.xml +++ b/java/core/pom.xml @@ -6,7 +6,7 @@ com.google.protobuf protobuf-parent - 3.1.0-alpha-1 + 3.1.0 protobuf-java diff --git a/java/lite/pom.xml b/java/lite/pom.xml index d6490247..9862cd94 100644 --- a/java/lite/pom.xml +++ b/java/lite/pom.xml @@ -6,7 +6,7 @@ com.google.protobuf protobuf-parent - 3.1.0-alpha-1 + 3.0.0 protobuf-lite diff --git a/java/pom.xml b/java/pom.xml index 3fa0a85b..881473f3 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -11,7 +11,7 @@ com.google.protobuf protobuf-parent - 3.1.0-alpha-1 + 3.1.0 pom Protocol Buffers [Parent] diff --git a/javanano/pom.xml b/javanano/pom.xml index 291ed27a..6bac76c9 100644 --- a/javanano/pom.xml +++ b/javanano/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf.nano protobuf-javanano - 3.1.0-alpha-1 + 3.1.0 bundle Protocol Buffer JavaNano API diff --git a/js/package.json b/js/package.json index cc0db47b..ee4181ff 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "google-protobuf", - "version": "3.1.0-alpha.1", + "version": "3.1.0", "description": "Protocol Buffers for JavaScript", "main": "google-protobuf.js", "files": [ diff --git a/protoc-artifacts/pom.xml b/protoc-artifacts/pom.xml index b8581da1..680154b1 100644 --- a/protoc-artifacts/pom.xml +++ b/protoc-artifacts/pom.xml @@ -10,7 +10,7 @@ com.google.protobuf protoc - 3.1.0-alpha-1 + 3.1.0 pom Protobuf Compiler diff --git a/python/google/protobuf/__init__.py b/python/google/protobuf/__init__.py index f52137c4..0e2a89ff 100755 --- a/python/google/protobuf/__init__.py +++ b/python/google/protobuf/__init__.py @@ -30,7 +30,7 @@ # Copyright 2007 Google Inc. All Rights Reserved. -__version__ = '3.1.0a1' +__version__ = '3.1.0' if __name__ != '__main__': try: diff --git a/ruby/Gemfile.lock b/ruby/Gemfile.lock index 7a89c866..46244fdf 100644 --- a/ruby/Gemfile.lock +++ b/ruby/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - google-protobuf (3.1.0.alpha.1.0) + google-protobuf (3.1.0) GEM remote: https://rubygems.org/ diff --git a/ruby/google-protobuf.gemspec b/ruby/google-protobuf.gemspec index 26d9b20d..c7357f78 100644 --- a/ruby/google-protobuf.gemspec +++ b/ruby/google-protobuf.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |s| s.name = "google-protobuf" - s.version = "3.1.0.alpha.1.0" + s.version = "3.1.0" s.licenses = ["BSD"] s.summary = "Protocol Buffers" s.description = "Protocol Buffers are Google's data interchange format." -- cgit v1.2.3 From c4d70123ac99ff1a0886fc7dfa492010b027210a Mon Sep 17 00:00:00 2001 From: Adam Cozzette Date: Tue, 27 Sep 2016 15:36:41 -0700 Subject: Fixed references to foreign nested messages with CommonJS-style imports A bug was causing generated JSPB code with CommonJS-style imports to refer incorrectly to nested messages from other .proto files. The generated code would have things like "test_pb.InnerMessage" instead of "test_pb.OuterMessage.InnerMessage". This commit fixes the problem by correctly taking into account any message nesting. --- js/message_test.js | 14 ++++++++++++ js/test.proto | 8 +++++++ js/test2.proto | 6 +++++ src/google/protobuf/compiler/js/js_generator.cc | 30 +++++++++++++------------ 4 files changed, 44 insertions(+), 14 deletions(-) (limited to 'js') diff --git a/js/message_test.js b/js/message_test.js index 97c594c8..b0a0a72e 100644 --- a/js/message_test.js +++ b/js/message_test.js @@ -1040,4 +1040,18 @@ 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); + + // 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/test.proto b/js/test.proto index 48cb37e1..db238e1a 100644 --- a/js/test.proto +++ b/js/test.proto @@ -260,3 +260,11 @@ enum MapValueEnumNoBinary { message MapValueMessageNoBinary { optional int32 foo = 1; } + +message Deeply { + message Nested { + message Message { + optional int32 count = 1; + } + } +} diff --git a/js/test2.proto b/js/test2.proto index 44e55eff..b67f93fa 100644 --- a/js/test2.proto +++ b/js/test2.proto @@ -35,6 +35,8 @@ option java_multiple_files = true; package jspb.test; +import "test.proto"; + message TestExtensionsMessage { optional int32 intfield = 1; extensions 100 to max; @@ -52,3 +54,7 @@ extend TestExtensionsMessage { optional ExtensionMessage floating_msg_field = 101; optional string floating_str_field = 102; } + +message ForeignNestedFieldMessage { + optional Deeply.Nested.Message deeply_nested_message = 1; +} diff --git a/src/google/protobuf/compiler/js/js_generator.cc b/src/google/protobuf/compiler/js/js_generator.cc index fec465fe..58597b4c 100755 --- a/src/google/protobuf/compiler/js/js_generator.cc +++ b/src/google/protobuf/compiler/js/js_generator.cc @@ -208,28 +208,28 @@ string GetPath(const GeneratorOptions& options, } } -// Forward declare, so that GetPrefix can call this method, -// which in turn, calls GetPrefix. -string GetPath(const GeneratorOptions& options, - const Descriptor* descriptor); +// Returns the name of the message with a leading dot and taking into account +// nesting, for example ".OuterMessage.InnerMessage", or returns empty if +// descriptor is null. This function does not handle namespacing, only message +// nesting. +string GetNestedMessageName(const Descriptor* descriptor) { + if (descriptor == NULL) { + return ""; + } + return StripPrefixString(descriptor->full_name(), + descriptor->file()->package()); +} // Returns the path prefix for a message or enumeration that // lives under the given file and containing type. string GetPrefix(const GeneratorOptions& options, const FileDescriptor* file_descriptor, const Descriptor* containing_type) { - string prefix = ""; - - if (containing_type == NULL) { - prefix = GetPath(options, file_descriptor); - } else { - prefix = GetPath(options, containing_type); - } - + string prefix = GetPath(options, file_descriptor) + + GetNestedMessageName(containing_type); if (!prefix.empty()) { prefix += "."; } - return prefix; } @@ -277,7 +277,9 @@ string MaybeCrossFileRef(const GeneratorOptions& options, from_file != to_message->file()) { // Cross-file ref in CommonJS needs to use the module alias instead of // the global name. - return ModuleAlias(to_message->file()->name()) + "." + to_message->name(); + return ModuleAlias(to_message->file()->name()) + + GetNestedMessageName(to_message->containing_type()) + + "." + to_message->name(); } else { // Within a single file we use a full name. return GetPath(options, to_message); -- cgit v1.2.3 From 8b54280395fe9236428c7a50c9b6c0e57c3131e5 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Wed, 28 Sep 2016 10:52:32 -0700 Subject: Added alias getFieldProto3 as used by older generated code. Un-breaks users who have old generated code and upgrade to the 3.1.0 release. --- js/message.js | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'js') diff --git a/js/message.js b/js/message.js index b150722a..8def763e 100644 --- a/js/message.js +++ b/js/message.js @@ -754,6 +754,18 @@ jspb.Message.getFieldWithDefault = function(msg, fieldNumber, defaultValue) { }; +/** + * Alias for getFieldWithDefault used by older generated code. + * @template T + * @param {!jspb.Message} msg A jspb proto. + * @param {number} fieldNumber The field number. + * @param {T} defaultValue The default value. + * @return {T} The field's value. + * @protected + */ +jspb.Message.getFieldProto3 = jspb.Message.getFieldWithDefault; + + /** * Gets the value of a map field, lazily creating the map container if * necessary. -- cgit v1.2.3 From 23f108d471ec6488efbef1a5b96d7a2abbf785c2 Mon Sep 17 00:00:00 2001 From: Wojciech Mandrysz Date: Tue, 2 Aug 2016 17:12:27 +0200 Subject: JS: Fixed UTF-8 string encoder/decoder for high codepoints. --- js/binary/decoder.js | 41 ++++++++++++++++++++++++++++------------- js/binary/encoder.js | 10 ++++++++-- 2 files changed, 36 insertions(+), 15 deletions(-) (limited to 'js') diff --git a/js/binary/decoder.js b/js/binary/decoder.js index 41094a36..62f7b8b6 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -895,11 +895,9 @@ 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, with - * the exception that the implementation here does not get confused if it - * encounters characters longer than three bytes. These characters are ignored - * though, as they are extremely rare: three UTF-8 bytes cover virtually all - * characters in common use (http://en.wikipedia.org/wiki/UTF-8). + * The code is inspired by maps.vectortown.parse.StreamedDataViewReader. + * 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. */ @@ -907,30 +905,47 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var bytes = this.bytes_; var cursor = this.cursor_; var end = cursor + length; - var chars = []; + var codepoints = []; while (cursor < end) { var c = bytes[cursor++]; if (c < 128) { // Regular 7-bit ASCII. - chars.push(c); + codepoints.push(c); } else if (c < 192) { // UTF-8 continuation mark. We are out of sync. This // might happen if we attempted to read a character - // with more than three bytes. + // with more than four bytes. continue; } else if (c < 224) { // UTF-8 with two bytes. var c2 = bytes[cursor++]; - chars.push(((c & 31) << 6) | (c2 & 63)); + codepoints.push(((c & 31) << 6) | (c2 & 63)); } else if (c < 240) { // UTF-8 with three bytes. var c2 = bytes[cursor++]; var c3 = bytes[cursor++]; - chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + codepoints.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + } else if (c < 248) { // UTF-8 with 4 bytes. + var c2 = bytes[cursor++]; + var c3 = bytes[cursor++]; + var c4 = bytes[cursor++]; + // Characters written on 4 bytes have 21 bits for a codepoint. + // We can't fit that on 16bit characters, so we use surrogates. + var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63); + // Surrogates formula from wikipedia. + // 1. Subtract 0x10000 from codepoint + codepoint -= 65536; + // 2. Split this into the high 10-bit value and the low 10-bit value + var low = codepoint & 1023; + var high = (codepoint >> 10) & 1023; + // 3. Add 0xD800 to the high value to form the high surrogate + high += 55296; + // 4. Add 0xDC00 to the low value to form the low surrogate: + low += 56320; + codepoints.push(high); + codepoints.push(low); } } - // String.fromCharCode.apply is faster than manually appending characters on - // Chrome 25+, and generates no additional cons string garbage. - var result = String.fromCharCode.apply(null, chars); + var result = String.fromCodePoint.apply(null, codepoints); this.cursor_ = cursor; return result; }; diff --git a/js/binary/encoder.js b/js/binary/encoder.js index c9b0c2ae..59c4ccb9 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -412,16 +412,22 @@ jspb.BinaryEncoder.prototype.writeString = function(value) { // UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray. for (var i = 0; i < value.length; i++) { - var c = value.charCodeAt(i); + var c = value.codePointAt(i); if (c < 128) { this.buffer_.push(c); } else if (c < 2048) { this.buffer_.push((c >> 6) | 192); this.buffer_.push((c & 63) | 128); - } else { + } else if (c < 65536) { this.buffer_.push((c >> 12) | 224); this.buffer_.push(((c >> 6) & 63) | 128); this.buffer_.push((c & 63) | 128); + } else { + this.buffer_.push((c >> 18) | 240); + this.buffer_.push(((c >> 12) & 63 ) | 128); + this.buffer_.push(((c >> 6) & 63) | 128); + this.buffer_.push((c & 63) | 128); + i++; } } -- cgit v1.2.3 From fe1d0a1f5a32fe144ee125eb0058927d7a359926 Mon Sep 17 00:00:00 2001 From: Wojciech Mandrysz Date: Mon, 3 Oct 2016 01:42:58 +0200 Subject: JS: Added string encoding/decoding tests for UTF-8 --- js/binary/decoder_test.js | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) (limited to 'js') diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js index ac312648..12da72a7 100644 --- a/js/binary/decoder_test.js +++ b/js/binary/decoder_test.js @@ -209,7 +209,30 @@ 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 utf8_two_bytes = "©"; + var utf8_tree_bytes = "❄"; + var utf8_four_bytes = "😁"; + + encoder.writeString(ascii); + encoder.writeString(utf8_two_bytes); + encoder.writeString(utf8_tree_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_tree_bytes, decoder.readString(utf8_tree_bytes.length)); + assertEquals(utf8_four_bytes, decoder.readString(utf8_four_bytes.length)); + }); /** * Verifies that misuse of the decoder class triggers assertions. -- cgit v1.2.3 From 7332ffb1f08c9414119aa0a59ec8334c7599bfd8 Mon Sep 17 00:00:00 2001 From: Wojciech Mandrysz Date: Mon, 3 Oct 2016 18:59:34 +0200 Subject: JS: Replaced fromCodePoint/codePointAt with fromCharCode/charCodeAt because of functions limited availability, fixed typo in tests. --- js/binary/decoder.js | 21 +++++++++------------ js/binary/decoder_test.js | 6 +++--- js/binary/encoder.js | 15 ++++++++++++--- 3 files changed, 24 insertions(+), 18 deletions(-) (limited to 'js') diff --git a/js/binary/decoder.js b/js/binary/decoder.js index 62f7b8b6..e4fb9148 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -905,12 +905,12 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var bytes = this.bytes_; var cursor = this.cursor_; var end = cursor + length; - var codepoints = []; + var codeUnits = []; while (cursor < end) { var c = bytes[cursor++]; if (c < 128) { // Regular 7-bit ASCII. - codepoints.push(c); + codeUnits.push(c); } else if (c < 192) { // UTF-8 continuation mark. We are out of sync. This // might happen if we attempted to read a character @@ -918,11 +918,11 @@ jspb.BinaryDecoder.prototype.readString = function(length) { continue; } else if (c < 224) { // UTF-8 with two bytes. var c2 = bytes[cursor++]; - codepoints.push(((c & 31) << 6) | (c2 & 63)); + codeUnits.push(((c & 31) << 6) | (c2 & 63)); } else if (c < 240) { // UTF-8 with three bytes. var c2 = bytes[cursor++]; var c3 = bytes[cursor++]; - codepoints.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); + codeUnits.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63)); } else if (c < 248) { // UTF-8 with 4 bytes. var c2 = bytes[cursor++]; var c3 = bytes[cursor++]; @@ -932,20 +932,17 @@ jspb.BinaryDecoder.prototype.readString = function(length) { var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63); // Surrogates formula from wikipedia. // 1. Subtract 0x10000 from codepoint - codepoint -= 65536; + codepoint -= 0x10000; // 2. Split this into the high 10-bit value and the low 10-bit value - var low = codepoint & 1023; - var high = (codepoint >> 10) & 1023; // 3. Add 0xD800 to the high value to form the high surrogate - high += 55296; // 4. Add 0xDC00 to the low value to form the low surrogate: - low += 56320; - codepoints.push(high); - codepoints.push(low); + var low = (codepoint & 1023) + 0xDC00; + var high = ((codepoint >> 10) & 1023) + 0xD800; + codeUnits.push(high, low) } } - var result = String.fromCodePoint.apply(null, codepoints); + var result = String.fromCharCode.apply(null, codeUnits); this.cursor_ = cursor; return result; }; diff --git a/js/binary/decoder_test.js b/js/binary/decoder_test.js index 12da72a7..9f947b99 100644 --- a/js/binary/decoder_test.js +++ b/js/binary/decoder_test.js @@ -218,19 +218,19 @@ describe('binaryDecoderTest', function() { var ascii = "ASCII should work in 3, 2, 1..." var utf8_two_bytes = "©"; - var utf8_tree_bytes = "❄"; + var utf8_three_bytes = "❄"; var utf8_four_bytes = "😁"; encoder.writeString(ascii); encoder.writeString(utf8_two_bytes); - encoder.writeString(utf8_tree_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_tree_bytes, decoder.readString(utf8_tree_bytes.length)); + assertEquals(utf8_three_bytes, decoder.readString(utf8_three_bytes.length)); assertEquals(utf8_four_bytes, decoder.readString(utf8_four_bytes.length)); }); diff --git a/js/binary/encoder.js b/js/binary/encoder.js index 59c4ccb9..fe5e34e9 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -409,10 +409,19 @@ jspb.BinaryEncoder.prototype.writeFixedHash64 = function(hash) { */ jspb.BinaryEncoder.prototype.writeString = function(value) { var oldLength = this.buffer_.length; - - // UTF16 to UTF8 conversion loop swiped from goog.crypt.stringToUtf8ByteArray. + for (var i = 0; i < value.length; i++) { - var c = value.codePointAt(i); + + var c = value.charCodeAt(i); + // Look for surrogates + if (c >= 0xD800 && c <= 0xDBFF && i + 1 < value.length) { + var second = value.charCodeAt(i + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } + if (c < 128) { this.buffer_.push(c); } else if (c < 2048) { -- cgit v1.2.3 From 5d9dbe3ecc7553017b036bbabdc8d4dda7b1c0a2 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Mon, 14 Nov 2016 10:37:51 -0800 Subject: Fixed JavaScript license declaration. --- js/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'js') diff --git a/js/package.json b/js/package.json index ee4181ff..d3c77eb6 100644 --- a/js/package.json +++ b/js/package.json @@ -22,5 +22,5 @@ "url": "https://github.com/google/protobuf/tree/master/js" }, "author": "Google Protocol Buffers Team", - "license": "Apache-2.0" + "license" : "BSD-3-Clause" } -- cgit v1.2.3 From 292c2c91cfc16eda5dc8f835ef6073febef118e5 Mon Sep 17 00:00:00 2001 From: Wojciech Mandrysz Date: Tue, 15 Nov 2016 12:44:15 +0100 Subject: JS: Re-added comment, moved surrogates code to the right place --- js/binary/decoder.js | 3 ++- js/binary/encoder.js | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) (limited to 'js') diff --git a/js/binary/decoder.js b/js/binary/decoder.js index e4fb9148..040cf715 100644 --- a/js/binary/decoder.js +++ b/js/binary/decoder.js @@ -941,7 +941,8 @@ jspb.BinaryDecoder.prototype.readString = function(length) { codeUnits.push(high, low) } } - + // String.fromCharCode.apply is faster than manually appending characters on + // Chrome 25+, and generates no additional cons string garbage. var result = String.fromCharCode.apply(null, codeUnits); this.cursor_ = cursor; return result; diff --git a/js/binary/encoder.js b/js/binary/encoder.js index fe5e34e9..a9d09d72 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -413,14 +413,6 @@ jspb.BinaryEncoder.prototype.writeString = function(value) { for (var i = 0; i < value.length; i++) { var c = value.charCodeAt(i); - // Look for surrogates - if (c >= 0xD800 && c <= 0xDBFF && i + 1 < value.length) { - var second = value.charCodeAt(i + 1); - if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate - // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae - c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; - } - } if (c < 128) { this.buffer_.push(c); @@ -428,6 +420,14 @@ jspb.BinaryEncoder.prototype.writeString = function(value) { this.buffer_.push((c >> 6) | 192); this.buffer_.push((c & 63) | 128); } else if (c < 65536) { + // Look for surrogates + if (c >= 0xD800 && c <= 0xDBFF && i + 1 < value.length) { + var second = value.charCodeAt(i + 1); + if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate + // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + } + } this.buffer_.push((c >> 12) | 224); this.buffer_.push(((c >> 6) & 63) | 128); this.buffer_.push((c & 63) | 128); -- cgit v1.2.3 From bd850a25f51dfb662a761473c151c016c815bcb5 Mon Sep 17 00:00:00 2001 From: Wojciech Mandrysz Date: Tue, 15 Nov 2016 14:08:49 +0100 Subject: JS: Well, this is the right place for surrogates. --- js/binary/encoder.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) (limited to 'js') diff --git a/js/binary/encoder.js b/js/binary/encoder.js index a9d09d72..d952d714 100644 --- a/js/binary/encoder.js +++ b/js/binary/encoder.js @@ -426,17 +426,19 @@ jspb.BinaryEncoder.prototype.writeString = function(value) { if (second >= 0xDC00 && second <= 0xDFFF) { // low surrogate // http://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae c = (c - 0xD800) * 0x400 + second - 0xDC00 + 0x10000; + + this.buffer_.push((c >> 18) | 240); + this.buffer_.push(((c >> 12) & 63 ) | 128); + this.buffer_.push(((c >> 6) & 63) | 128); + this.buffer_.push((c & 63) | 128); + i++; } } - this.buffer_.push((c >> 12) | 224); - this.buffer_.push(((c >> 6) & 63) | 128); - this.buffer_.push((c & 63) | 128); - } else { - this.buffer_.push((c >> 18) | 240); - this.buffer_.push(((c >> 12) & 63 ) | 128); - this.buffer_.push(((c >> 6) & 63) | 128); - this.buffer_.push((c & 63) | 128); - i++; + else { + this.buffer_.push((c >> 12) | 224); + this.buffer_.push(((c >> 6) & 63) | 128); + this.buffer_.push((c & 63) | 128); + } } } -- cgit v1.2.3