// Copyright 2008 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. goog.provide('goog.proto2.ObjectSerializerTest'); goog.setTestOnly('goog.proto2.ObjectSerializerTest'); goog.require('goog.proto2.ObjectSerializer'); goog.require('goog.proto2.Serializer'); goog.require('goog.testing.PropertyReplacer'); goog.require('goog.testing.jsunit'); goog.require('proto2.TestAllTypes'); var propertyReplacer = new goog.testing.PropertyReplacer(); function tearDown() { propertyReplacer.reset(); } function testSerialization() { var message = new proto2.TestAllTypes(); // Set the fields. // Singular. message.setOptionalInt32(101); message.setOptionalInt64('102'); message.setOptionalUint32(103); message.setOptionalUint64('104'); message.setOptionalSint32(105); message.setOptionalSint64('106'); message.setOptionalFixed32(107); message.setOptionalFixed64('108'); message.setOptionalSfixed32(109); message.setOptionalSfixed64('110'); message.setOptionalFloat(111.5); message.setOptionalDouble(112.5); message.setOptionalBool(true); message.setOptionalString('test'); message.setOptionalBytes('abcd'); var group = new proto2.TestAllTypes.OptionalGroup(); group.setA(111); message.setOptionalgroup(group); var nestedMessage = new proto2.TestAllTypes.NestedMessage(); nestedMessage.setB(112); message.setOptionalNestedMessage(nestedMessage); message.setOptionalNestedEnum(proto2.TestAllTypes.NestedEnum.FOO); // Repeated. message.addRepeatedInt32(201); message.addRepeatedInt32(202); // Serialize to a simplified object. var simplified = new goog.proto2.ObjectSerializer().serialize(message); // Assert that everything serialized properly. assertEquals(101, simplified[1]); assertEquals('102', simplified[2]); assertEquals(103, simplified[3]); assertEquals('104', simplified[4]); assertEquals(105, simplified[5]); assertEquals('106', simplified[6]); assertEquals(107, simplified[7]); assertEquals('108', simplified[8]); assertEquals(109, simplified[9]); assertEquals('110', simplified[10]); assertEquals(111.5, simplified[11]); assertEquals(112.5, simplified[12]); assertEquals(true, simplified[13]); assertEquals('test', simplified[14]); assertEquals('abcd', simplified[15]); assertEquals(111, simplified[16][17]); assertEquals(112, simplified[18][1]); assertEquals(proto2.TestAllTypes.NestedEnum.FOO, simplified[21]); assertEquals(201, simplified[31][0]); assertEquals(202, simplified[31][1]); // Serialize to a simplified object (with key as name). simplified = new goog.proto2 .ObjectSerializer(goog.proto2.ObjectSerializer.KeyOption.NAME) .serialize(message); // Assert that everything serialized properly. assertEquals(101, simplified['optional_int32']); assertEquals('102', simplified['optional_int64']); assertEquals(103, simplified['optional_uint32']); assertEquals('104', simplified['optional_uint64']); assertEquals(105, simplified['optional_sint32']); assertEquals('106', simplified['optional_sint64']); assertEquals(107, simplified['optional_fixed32']); assertEquals('108', simplified['optional_fixed64']); assertEquals(109, simplified['optional_sfixed32']); assertEquals('110', simplified['optional_sfixed64']); assertEquals(111.5, simplified['optional_float']); assertEquals(112.5, simplified['optional_double']); assertEquals(true, simplified['optional_bool']); assertEquals('test', simplified['optional_string']); assertEquals('abcd', simplified['optional_bytes']); assertEquals(111, simplified['optionalgroup']['a']); assertEquals(112, simplified['optional_nested_message']['b']); assertEquals( proto2.TestAllTypes.NestedEnum.FOO, simplified['optional_nested_enum']); assertEquals(201, simplified['repeated_int32'][0]); assertEquals(202, simplified['repeated_int32'][1]); } function testSerializationOfUnknown() { var message = new proto2.TestAllTypes(); // Set the fields. // Known. message.setOptionalInt32(101); message.setOptionalInt64('102'); message.addRepeatedInt32(201); message.addRepeatedInt32(202); // Unknown. message.setUnknown(1000, 301); message.setUnknown(1001, 302); // Serialize. var simplified = new goog.proto2.ObjectSerializer().serialize(message); assertEquals(101, simplified['1']); assertEquals('102', simplified['2']); assertEquals(201, simplified['31'][0]); assertEquals(202, simplified['31'][1]); assertEquals(301, simplified['1000']); assertEquals(302, simplified['1001']); } function testDeserializationOfUnknown() { var simplified = {1: 101, 2: '102', 1000: 103, 1001: 104}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertTrue(message.hasOptionalInt32()); assertTrue(message.hasOptionalInt64()); assertEquals(101, message.getOptionalInt32()); assertEquals('102', message.getOptionalInt64()); var count = 0; message.forEachUnknown(function(tag, value) { if (tag == 1000) { assertEquals(103, value); } if (tag == 1001) { assertEquals(104, value); } ++count; }); assertEquals(2, count); } function testDeserializationRepeated() { var simplified = { 31: [101, 102], 41: [201.5, 202.5, 203.5], 42: [], 43: [true, false], 44: ['he', 'llo'], 46: [{47: [101]}, {47: [102]}], 48: [{1: 201}, {1: 202}] }; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); // Ensure the fields are set as expected. assertTrue(message.hasRepeatedInt32()); assertTrue(message.hasRepeatedFloat()); assertFalse(message.hasRepeatedDouble()); assertTrue(message.hasRepeatedBool()); assertTrue(message.hasRepeatedgroup()); assertTrue(message.hasRepeatedNestedMessage()); // Ensure the counts match. assertEquals(2, message.repeatedInt32Count()); assertEquals(3, message.repeatedFloatCount()); assertEquals(0, message.repeatedDoubleCount()); assertEquals(2, message.repeatedBoolCount()); assertEquals(2, message.repeatedStringCount()); assertEquals(2, message.repeatedgroupCount()); assertEquals(2, message.repeatedNestedMessageCount()); // Ensure the values match. assertEquals(101, message.getRepeatedInt32(0)); assertEquals(102, message.getRepeatedInt32(1)); assertEquals(201.5, message.getRepeatedFloat(0)); assertEquals(202.5, message.getRepeatedFloat(1)); assertEquals(203.5, message.getRepeatedFloat(2)); assertEquals(true, message.getRepeatedBool(0)); assertEquals(false, message.getRepeatedBool(1)); assertEquals('he', message.getRepeatedString(0)); assertEquals('llo', message.getRepeatedString(1)); assertEquals(101, message.getRepeatedgroup(0).getA(0)); assertEquals(102, message.getRepeatedgroup(1).getA(0)); assertEquals(201, message.getRepeatedNestedMessage(0).getB()); assertEquals(202, message.getRepeatedNestedMessage(1).getB()); } function testDeserialization() { var simplified = { 1: 101, 2: '102', 3: 103, 4: '104', 5: 105, 6: '106', 7: 107, 8: '108', 9: 109, 10: '110', 11: 111.5, 12: 112.5, 13: true, 14: 'test', 15: 'abcd', 16: {17: 113}, 18: {1: 114}, 21: proto2.TestAllTypes.NestedEnum.FOO }; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertTrue(message.hasOptionalInt32()); assertTrue(message.hasOptionalInt64()); assertTrue(message.hasOptionalUint32()); assertTrue(message.hasOptionalUint64()); assertTrue(message.hasOptionalSint32()); assertTrue(message.hasOptionalSint64()); assertTrue(message.hasOptionalFixed32()); assertTrue(message.hasOptionalFixed64()); assertTrue(message.hasOptionalSfixed32()); assertTrue(message.hasOptionalSfixed64()); assertTrue(message.hasOptionalFloat()); assertTrue(message.hasOptionalDouble()); assertTrue(message.hasOptionalBool()); assertTrue(message.hasOptionalString()); assertTrue(message.hasOptionalBytes()); assertTrue(message.hasOptionalgroup()); assertTrue(message.hasOptionalNestedMessage()); assertTrue(message.hasOptionalNestedEnum()); assertEquals(1, message.optionalInt32Count()); assertEquals(1, message.optionalInt64Count()); assertEquals(1, message.optionalUint32Count()); assertEquals(1, message.optionalUint64Count()); assertEquals(1, message.optionalSint32Count()); assertEquals(1, message.optionalSint64Count()); assertEquals(1, message.optionalFixed32Count()); assertEquals(1, message.optionalFixed64Count()); assertEquals(1, message.optionalSfixed32Count()); assertEquals(1, message.optionalSfixed64Count()); assertEquals(1, message.optionalFloatCount()); assertEquals(1, message.optionalDoubleCount()); assertEquals(1, message.optionalBoolCount()); assertEquals(1, message.optionalStringCount()); assertEquals(1, message.optionalBytesCount()); assertEquals(1, message.optionalgroupCount()); assertEquals(1, message.optionalNestedMessageCount()); assertEquals(1, message.optionalNestedEnumCount()); assertEquals(101, message.getOptionalInt32()); assertEquals('102', message.getOptionalInt64()); assertEquals(103, message.getOptionalUint32()); assertEquals('104', message.getOptionalUint64()); assertEquals(105, message.getOptionalSint32()); assertEquals('106', message.getOptionalSint64()); assertEquals(107, message.getOptionalFixed32()); assertEquals('108', message.getOptionalFixed64()); assertEquals(109, message.getOptionalSfixed32()); assertEquals('110', message.getOptionalSfixed64()); assertEquals(111.5, message.getOptionalFloat()); assertEquals(112.5, message.getOptionalDouble()); assertEquals(true, message.getOptionalBool()); assertEquals('test', message.getOptionalString()); assertEquals('abcd', message.getOptionalBytes()); assertEquals(113, message.getOptionalgroup().getA()); assertEquals(114, message.getOptionalNestedMessage().getB()); assertEquals( proto2.TestAllTypes.NestedEnum.FOO, message.getOptionalNestedEnum()); } function testDeserializationUnknownEnumValue() { var simplified = {21: 1001}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertEquals(1001, message.getOptionalNestedEnum()); } function testDeserializationSymbolicEnumValue() { var simplified = {21: 'BAR'}; propertyReplacer.set(goog.proto2.Serializer, 'DECODE_SYMBOLIC_ENUMS', true); var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertEquals( proto2.TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); } function testDeserializationSymbolicEnumValueTurnedOff() { var simplified = {21: 'BAR'}; var serializer = new goog.proto2.ObjectSerializer(); assertThrows( 'Should have an assertion failure in deserialization', function() { serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); }); } function testDeserializationUnknownSymbolicEnumValue() { var simplified = {21: 'BARRED'}; var serializer = new goog.proto2.ObjectSerializer(); assertThrows( 'Should have an assertion failure in deserialization', function() { serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); }); } function testDeserializationEnumValueAsNumericString() { var simplified = {21: '2'}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertEquals( proto2.TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum()); } function testDeserializationEnumValueWithNegativeString() { var simplified = {21: '-2'}; var serializer = new goog.proto2.ObjectSerializer(); assertThrows( 'Should have an assertion failure in deserialization', function() { serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); }); } function testDeserializationNumbersOrStrings() { // 64-bit types may have been serialized as numbers or strings. // Deserialization should be able to handle either. var simplifiedWithNumbers = {50: 5000, 51: 5100, 52: [5200, 5201], 53: [5300, 5301]}; var simplifiedWithStrings = {50: '5000', 51: '5100', 52: ['5200', '5201'], 53: ['5300', '5301']}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize( proto2.TestAllTypes.getDescriptor(), simplifiedWithNumbers); assertNotNull(message); assertEquals(5000, message.getOptionalInt64Number()); assertEquals('5100', message.getOptionalInt64String()); assertEquals(5200, message.getRepeatedInt64Number(0)); assertEquals(5201, message.getRepeatedInt64Number(1)); assertEquals('5300', message.getRepeatedInt64String(0)); assertEquals('5301', message.getRepeatedInt64String(1)); assertArrayEquals([5200, 5201], message.repeatedInt64NumberArray()); assertArrayEquals(['5300', '5301'], message.repeatedInt64StringArray()); message = serializer.deserialize( proto2.TestAllTypes.getDescriptor(), simplifiedWithStrings); assertNotNull(message); assertEquals(5000, message.getOptionalInt64Number()); assertEquals('5100', message.getOptionalInt64String()); assertEquals(5200, message.getRepeatedInt64Number(0)); assertEquals(5201, message.getRepeatedInt64Number(1)); assertEquals('5300', message.getRepeatedInt64String(0)); assertEquals('5301', message.getRepeatedInt64String(1)); assertArrayEquals([5200, 5201], message.repeatedInt64NumberArray()); assertArrayEquals(['5300', '5301'], message.repeatedInt64StringArray()); } function testSerializationSpecialFloatDoubleValues() { // NaN, Infinity and -Infinity should get serialized as strings. var message = new proto2.TestAllTypes(); message.setOptionalFloat(Infinity); message.setOptionalDouble(-Infinity); message.addRepeatedFloat(Infinity); message.addRepeatedFloat(-Infinity); message.addRepeatedFloat(NaN); message.addRepeatedDouble(Infinity); message.addRepeatedDouble(-Infinity); message.addRepeatedDouble(NaN); var simplified = new goog.proto2.ObjectSerializer().serialize(message); // Assert that everything serialized properly. assertEquals('Infinity', simplified[11]); assertEquals('-Infinity', simplified[12]); assertEquals('Infinity', simplified[41][0]); assertEquals('-Infinity', simplified[41][1]); assertEquals('NaN', simplified[41][2]); assertEquals('Infinity', simplified[42][0]); assertEquals('-Infinity', simplified[42][1]); assertEquals('NaN', simplified[42][2]); } function testDeserializationSpecialFloatDoubleValues() { // NaN, Infinity and -Infinity values should be de-serialized from their // string representation. var simplified = { 41: ['Infinity', '-Infinity', 'NaN'], 42: ['Infinity', '-Infinity', 'NaN'] }; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); var floatArray = message.repeatedFloatArray(); assertEquals(Infinity, floatArray[0]); assertEquals(-Infinity, floatArray[1]); assertTrue(isNaN(floatArray[2])); var doubleArray = message.repeatedDoubleArray(); assertEquals(Infinity, doubleArray[0]); assertEquals(-Infinity, doubleArray[1]); assertTrue(isNaN(doubleArray[2])); } function testDeserializationConversionProhibited() { // 64-bit types may have been serialized as numbers or strings. // But 32-bit types must be serialized as numbers. // Test deserialization fails on 32-bit numbers as strings. var simplified = { 1: '1000' // optionalInt32 }; var serializer = new goog.proto2.ObjectSerializer(); assertThrows( 'Should have an assertion failure in deserialization', function() { serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); }); } function testDefaultValueNumbersOrStrings() { // 64-bit types may have been serialized as numbers or strings. // The default values should have the correct type. var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), {}); assertNotNull(message); // Default when using Number is a number, and precision is lost. var value = message.getOptionalInt64NumberOrDefault(); assertTrue('Expecting a number', typeof value === 'number'); assertEquals(1000000000000000000, value); assertEquals(1000000000000000001, value); assertEquals(1000000000000000002, value); assertEquals('1000000000000000000', String(value)); // Value is rounded! // When using a String, the value is preserved. assertEquals( '1000000000000000001', message.getOptionalInt64StringOrDefault()); } function testSerializationBooleanAsNumberFalse() { // Some libraries, such as GWT, can expect boolean field values as 0/1 var message = new proto2.TestAllTypes(); message.setOptionalBool(false); var serializer = new goog.proto2.ObjectSerializer( goog.proto2.ObjectSerializer.KeyOption.TAG, true /* opt_serializeBooleanAsNumber */); var simplified = serializer.serialize(message); assertEquals(0, simplified[13]); } function testSerializationBooleanAsNumberTrue() { var message = new proto2.TestAllTypes(); message.setOptionalBool(true); var serializer = new goog.proto2.ObjectSerializer( goog.proto2.ObjectSerializer.KeyOption.TAG, true /* opt_serializeBooleanAsNumber */); var simplified = serializer.serialize(message); assertEquals(1, simplified[13]); } function testDeserializationBooleanAsNumberFalse() { // Some libraries, such as GWT, can serialize boolean values as 0/1 var simplified = {13: 0}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertFalse(message.getOptionalBool()); } function testDeserializationBooleanAsNumberTrue() { var simplified = {13: 1}; var serializer = new goog.proto2.ObjectSerializer(); var message = serializer.deserialize(proto2.TestAllTypes.getDescriptor(), simplified); assertNotNull(message); assertTrue(message.getOptionalBool()); }