1*1b3f573fSAndroid Build Coastguard Worker #region Copyright notice and license 2*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format 3*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc. All rights reserved. 4*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/ 5*1b3f573fSAndroid Build Coastguard Worker // 6*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without 7*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are 8*1b3f573fSAndroid Build Coastguard Worker // met: 9*1b3f573fSAndroid Build Coastguard Worker // 10*1b3f573fSAndroid Build Coastguard Worker // * Redistributions of source code must retain the above copyright 11*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer. 12*1b3f573fSAndroid Build Coastguard Worker // * Redistributions in binary form must reproduce the above 13*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer 14*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the 15*1b3f573fSAndroid Build Coastguard Worker // distribution. 16*1b3f573fSAndroid Build Coastguard Worker // * Neither the name of Google Inc. nor the names of its 17*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from 18*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission. 19*1b3f573fSAndroid Build Coastguard Worker // 20*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31*1b3f573fSAndroid Build Coastguard Worker #endregion 32*1b3f573fSAndroid Build Coastguard Worker 33*1b3f573fSAndroid Build Coastguard Worker using System; 34*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.TestProtos; 35*1b3f573fSAndroid Build Coastguard Worker using NUnit.Framework; 36*1b3f573fSAndroid Build Coastguard Worker using UnitTest.Issues.TestProtos; 37*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.WellKnownTypes; 38*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Reflection; 39*1b3f573fSAndroid Build Coastguard Worker 40*1b3f573fSAndroid Build Coastguard Worker using static Google.Protobuf.JsonParserTest; // For WrapInQuotes 41*1b3f573fSAndroid Build Coastguard Worker using System.IO; 42*1b3f573fSAndroid Build Coastguard Worker using Google.Protobuf.Collections; 43*1b3f573fSAndroid Build Coastguard Worker using ProtobufUnittest; 44*1b3f573fSAndroid Build Coastguard Worker 45*1b3f573fSAndroid Build Coastguard Worker namespace Google.Protobuf 46*1b3f573fSAndroid Build Coastguard Worker { 47*1b3f573fSAndroid Build Coastguard Worker /// <summary> 48*1b3f573fSAndroid Build Coastguard Worker /// Tests for the JSON formatter. Note that in these tests, double quotes are replaced with apostrophes 49*1b3f573fSAndroid Build Coastguard Worker /// for the sake of readability (embedding \" everywhere is painful). See the AssertJson method for details. 50*1b3f573fSAndroid Build Coastguard Worker /// </summary> 51*1b3f573fSAndroid Build Coastguard Worker public class JsonFormatterTest 52*1b3f573fSAndroid Build Coastguard Worker { 53*1b3f573fSAndroid Build Coastguard Worker [Test] DefaultValues_WhenOmitted()54*1b3f573fSAndroid Build Coastguard Worker public void DefaultValues_WhenOmitted() 55*1b3f573fSAndroid Build Coastguard Worker { 56*1b3f573fSAndroid Build Coastguard Worker var formatter = JsonFormatter.Default; 57*1b3f573fSAndroid Build Coastguard Worker 58*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ }", formatter.Format(new ForeignMessage())); 59*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ }", formatter.Format(new TestAllTypes())); 60*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ }", formatter.Format(new TestMap())); 61*1b3f573fSAndroid Build Coastguard Worker } 62*1b3f573fSAndroid Build Coastguard Worker 63*1b3f573fSAndroid Build Coastguard Worker [Test] DefaultValues_WhenIncluded()64*1b3f573fSAndroid Build Coastguard Worker public void DefaultValues_WhenIncluded() 65*1b3f573fSAndroid Build Coastguard Worker { 66*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 67*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'c': 0 }", formatter.Format(new ForeignMessage())); 68*1b3f573fSAndroid Build Coastguard Worker } 69*1b3f573fSAndroid Build Coastguard Worker 70*1b3f573fSAndroid Build Coastguard Worker [Test] EnumAllowAlias()71*1b3f573fSAndroid Build Coastguard Worker public void EnumAllowAlias() 72*1b3f573fSAndroid Build Coastguard Worker { 73*1b3f573fSAndroid Build Coastguard Worker var message = new TestEnumAllowAlias 74*1b3f573fSAndroid Build Coastguard Worker { 75*1b3f573fSAndroid Build Coastguard Worker Value = TestEnumWithDupValue.Foo2, 76*1b3f573fSAndroid Build Coastguard Worker }; 77*1b3f573fSAndroid Build Coastguard Worker var actualText = JsonFormatter.Default.Format(message); 78*1b3f573fSAndroid Build Coastguard Worker var expectedText = "{ 'value': 'FOO1' }"; 79*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedText, actualText); 80*1b3f573fSAndroid Build Coastguard Worker } 81*1b3f573fSAndroid Build Coastguard Worker 82*1b3f573fSAndroid Build Coastguard Worker [Test] EnumAsInt()83*1b3f573fSAndroid Build Coastguard Worker public void EnumAsInt() 84*1b3f573fSAndroid Build Coastguard Worker { 85*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes 86*1b3f573fSAndroid Build Coastguard Worker { 87*1b3f573fSAndroid Build Coastguard Worker SingleForeignEnum = ForeignEnum.ForeignBar, 88*1b3f573fSAndroid Build Coastguard Worker RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } 89*1b3f573fSAndroid Build Coastguard Worker }; 90*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatEnumsAsIntegers(true)); 91*1b3f573fSAndroid Build Coastguard Worker var actualText = formatter.Format(message); 92*1b3f573fSAndroid Build Coastguard Worker var expectedText = "{ " + 93*1b3f573fSAndroid Build Coastguard Worker "'singleForeignEnum': 5, " + 94*1b3f573fSAndroid Build Coastguard Worker "'repeatedForeignEnum': [ 6, 100, 4 ]" + 95*1b3f573fSAndroid Build Coastguard Worker " }"; 96*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedText, actualText); 97*1b3f573fSAndroid Build Coastguard Worker } 98*1b3f573fSAndroid Build Coastguard Worker 99*1b3f573fSAndroid Build Coastguard Worker [Test] AllSingleFields()100*1b3f573fSAndroid Build Coastguard Worker public void AllSingleFields() 101*1b3f573fSAndroid Build Coastguard Worker { 102*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes 103*1b3f573fSAndroid Build Coastguard Worker { 104*1b3f573fSAndroid Build Coastguard Worker SingleBool = true, 105*1b3f573fSAndroid Build Coastguard Worker SingleBytes = ByteString.CopyFrom(1, 2, 3, 4), 106*1b3f573fSAndroid Build Coastguard Worker SingleDouble = 23.5, 107*1b3f573fSAndroid Build Coastguard Worker SingleFixed32 = 23, 108*1b3f573fSAndroid Build Coastguard Worker SingleFixed64 = 1234567890123, 109*1b3f573fSAndroid Build Coastguard Worker SingleFloat = 12.25f, 110*1b3f573fSAndroid Build Coastguard Worker SingleForeignEnum = ForeignEnum.ForeignBar, 111*1b3f573fSAndroid Build Coastguard Worker SingleForeignMessage = new ForeignMessage { C = 10 }, 112*1b3f573fSAndroid Build Coastguard Worker SingleImportEnum = ImportEnum.ImportBaz, 113*1b3f573fSAndroid Build Coastguard Worker SingleImportMessage = new ImportMessage { D = 20 }, 114*1b3f573fSAndroid Build Coastguard Worker SingleInt32 = 100, 115*1b3f573fSAndroid Build Coastguard Worker SingleInt64 = 3210987654321, 116*1b3f573fSAndroid Build Coastguard Worker SingleNestedEnum = TestAllTypes.Types.NestedEnum.Foo, 117*1b3f573fSAndroid Build Coastguard Worker SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 35 }, 118*1b3f573fSAndroid Build Coastguard Worker SinglePublicImportMessage = new PublicImportMessage { E = 54 }, 119*1b3f573fSAndroid Build Coastguard Worker SingleSfixed32 = -123, 120*1b3f573fSAndroid Build Coastguard Worker SingleSfixed64 = -12345678901234, 121*1b3f573fSAndroid Build Coastguard Worker SingleSint32 = -456, 122*1b3f573fSAndroid Build Coastguard Worker SingleSint64 = -12345678901235, 123*1b3f573fSAndroid Build Coastguard Worker SingleString = "test\twith\ttabs", 124*1b3f573fSAndroid Build Coastguard Worker SingleUint32 = uint.MaxValue, 125*1b3f573fSAndroid Build Coastguard Worker SingleUint64 = ulong.MaxValue, 126*1b3f573fSAndroid Build Coastguard Worker }; 127*1b3f573fSAndroid Build Coastguard Worker var actualText = JsonFormatter.Default.Format(message); 128*1b3f573fSAndroid Build Coastguard Worker 129*1b3f573fSAndroid Build Coastguard Worker // Fields in numeric order 130*1b3f573fSAndroid Build Coastguard Worker var expectedText = "{ " + 131*1b3f573fSAndroid Build Coastguard Worker "'singleInt32': 100, " + 132*1b3f573fSAndroid Build Coastguard Worker "'singleInt64': '3210987654321', " + 133*1b3f573fSAndroid Build Coastguard Worker "'singleUint32': 4294967295, " + 134*1b3f573fSAndroid Build Coastguard Worker "'singleUint64': '18446744073709551615', " + 135*1b3f573fSAndroid Build Coastguard Worker "'singleSint32': -456, " + 136*1b3f573fSAndroid Build Coastguard Worker "'singleSint64': '-12345678901235', " + 137*1b3f573fSAndroid Build Coastguard Worker "'singleFixed32': 23, " + 138*1b3f573fSAndroid Build Coastguard Worker "'singleFixed64': '1234567890123', " + 139*1b3f573fSAndroid Build Coastguard Worker "'singleSfixed32': -123, " + 140*1b3f573fSAndroid Build Coastguard Worker "'singleSfixed64': '-12345678901234', " + 141*1b3f573fSAndroid Build Coastguard Worker "'singleFloat': 12.25, " + 142*1b3f573fSAndroid Build Coastguard Worker "'singleDouble': 23.5, " + 143*1b3f573fSAndroid Build Coastguard Worker "'singleBool': true, " + 144*1b3f573fSAndroid Build Coastguard Worker "'singleString': 'test\\twith\\ttabs', " + 145*1b3f573fSAndroid Build Coastguard Worker "'singleBytes': 'AQIDBA==', " + 146*1b3f573fSAndroid Build Coastguard Worker "'singleNestedMessage': { 'bb': 35 }, " + 147*1b3f573fSAndroid Build Coastguard Worker "'singleForeignMessage': { 'c': 10 }, " + 148*1b3f573fSAndroid Build Coastguard Worker "'singleImportMessage': { 'd': 20 }, " + 149*1b3f573fSAndroid Build Coastguard Worker "'singleNestedEnum': 'FOO', " + 150*1b3f573fSAndroid Build Coastguard Worker "'singleForeignEnum': 'FOREIGN_BAR', " + 151*1b3f573fSAndroid Build Coastguard Worker "'singleImportEnum': 'IMPORT_BAZ', " + 152*1b3f573fSAndroid Build Coastguard Worker "'singlePublicImportMessage': { 'e': 54 }" + 153*1b3f573fSAndroid Build Coastguard Worker " }"; 154*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedText, actualText); 155*1b3f573fSAndroid Build Coastguard Worker } 156*1b3f573fSAndroid Build Coastguard Worker 157*1b3f573fSAndroid Build Coastguard Worker [Test] WithFormatDefaultValues_DoesNotAffectMessageFields()158*1b3f573fSAndroid Build Coastguard Worker public void WithFormatDefaultValues_DoesNotAffectMessageFields() 159*1b3f573fSAndroid Build Coastguard Worker { 160*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes(); 161*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 162*1b3f573fSAndroid Build Coastguard Worker var json = formatter.Format(message); 163*1b3f573fSAndroid Build Coastguard Worker Assert.IsFalse(json.Contains("\"singleNestedMessage\"")); 164*1b3f573fSAndroid Build Coastguard Worker Assert.IsFalse(json.Contains("\"singleForeignMessage\"")); 165*1b3f573fSAndroid Build Coastguard Worker Assert.IsFalse(json.Contains("\"singleImportMessage\"")); 166*1b3f573fSAndroid Build Coastguard Worker } 167*1b3f573fSAndroid Build Coastguard Worker 168*1b3f573fSAndroid Build Coastguard Worker [Test] WithFormatDefaultValues_DoesNotAffectProto3OptionalFields()169*1b3f573fSAndroid Build Coastguard Worker public void WithFormatDefaultValues_DoesNotAffectProto3OptionalFields() 170*1b3f573fSAndroid Build Coastguard Worker { 171*1b3f573fSAndroid Build Coastguard Worker var message = new TestProto3Optional(); 172*1b3f573fSAndroid Build Coastguard Worker message.OptionalInt32 = 0; 173*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 174*1b3f573fSAndroid Build Coastguard Worker var json = formatter.Format(message); 175*1b3f573fSAndroid Build Coastguard Worker // The non-optional proto3 fields are formatted, as is the optional-but-specified field. 176*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'optionalInt32': 0, 'singularInt32': 0, 'singularInt64': '0' }", json); 177*1b3f573fSAndroid Build Coastguard Worker } 178*1b3f573fSAndroid Build Coastguard Worker 179*1b3f573fSAndroid Build Coastguard Worker [Test] WithFormatDefaultValues_DoesNotAffectProto2Fields()180*1b3f573fSAndroid Build Coastguard Worker public void WithFormatDefaultValues_DoesNotAffectProto2Fields() 181*1b3f573fSAndroid Build Coastguard Worker { 182*1b3f573fSAndroid Build Coastguard Worker var message = new TestProtos.Proto2.ForeignMessage(); 183*1b3f573fSAndroid Build Coastguard Worker message.C = 0; 184*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 185*1b3f573fSAndroid Build Coastguard Worker var json = formatter.Format(message); 186*1b3f573fSAndroid Build Coastguard Worker // The specified field is formatted, but the non-specified field (d) is not. 187*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'c': 0 }", json); 188*1b3f573fSAndroid Build Coastguard Worker } 189*1b3f573fSAndroid Build Coastguard Worker 190*1b3f573fSAndroid Build Coastguard Worker [Test] WithFormatDefaultValues_DoesNotAffectOneofFields()191*1b3f573fSAndroid Build Coastguard Worker public void WithFormatDefaultValues_DoesNotAffectOneofFields() 192*1b3f573fSAndroid Build Coastguard Worker { 193*1b3f573fSAndroid Build Coastguard Worker var message = new TestOneof(); 194*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 195*1b3f573fSAndroid Build Coastguard Worker var json = formatter.Format(message); 196*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ }", json); 197*1b3f573fSAndroid Build Coastguard Worker } 198*1b3f573fSAndroid Build Coastguard Worker 199*1b3f573fSAndroid Build Coastguard Worker [Test] RepeatedField()200*1b3f573fSAndroid Build Coastguard Worker public void RepeatedField() 201*1b3f573fSAndroid Build Coastguard Worker { 202*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'repeatedInt32': [ 1, 2, 3, 4, 5 ] }", 203*1b3f573fSAndroid Build Coastguard Worker JsonFormatter.Default.Format(new TestAllTypes { RepeatedInt32 = { 1, 2, 3, 4, 5 } })); 204*1b3f573fSAndroid Build Coastguard Worker } 205*1b3f573fSAndroid Build Coastguard Worker 206*1b3f573fSAndroid Build Coastguard Worker [Test] MapField_StringString()207*1b3f573fSAndroid Build Coastguard Worker public void MapField_StringString() 208*1b3f573fSAndroid Build Coastguard Worker { 209*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'mapStringString': { 'with spaces': 'bar', 'a': 'b' } }", 210*1b3f573fSAndroid Build Coastguard Worker JsonFormatter.Default.Format(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } })); 211*1b3f573fSAndroid Build Coastguard Worker } 212*1b3f573fSAndroid Build Coastguard Worker 213*1b3f573fSAndroid Build Coastguard Worker [Test] MapField_Int32Int32()214*1b3f573fSAndroid Build Coastguard Worker public void MapField_Int32Int32() 215*1b3f573fSAndroid Build Coastguard Worker { 216*1b3f573fSAndroid Build Coastguard Worker // The keys are quoted, but the values aren't. 217*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'mapInt32Int32': { '0': 1, '2': 3 } }", 218*1b3f573fSAndroid Build Coastguard Worker JsonFormatter.Default.Format(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } })); 219*1b3f573fSAndroid Build Coastguard Worker } 220*1b3f573fSAndroid Build Coastguard Worker 221*1b3f573fSAndroid Build Coastguard Worker [Test] MapField_BoolBool()222*1b3f573fSAndroid Build Coastguard Worker public void MapField_BoolBool() 223*1b3f573fSAndroid Build Coastguard Worker { 224*1b3f573fSAndroid Build Coastguard Worker // The keys are quoted, but the values aren't. 225*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'mapBoolBool': { 'false': true, 'true': false } }", 226*1b3f573fSAndroid Build Coastguard Worker JsonFormatter.Default.Format(new TestMap { MapBoolBool = { { false, true }, { true, false } } })); 227*1b3f573fSAndroid Build Coastguard Worker } 228*1b3f573fSAndroid Build Coastguard Worker 229*1b3f573fSAndroid Build Coastguard Worker [Test] NullValueOutsideStruct()230*1b3f573fSAndroid Build Coastguard Worker public void NullValueOutsideStruct() 231*1b3f573fSAndroid Build Coastguard Worker { 232*1b3f573fSAndroid Build Coastguard Worker var message = new NullValueOutsideStruct { NullValue = NullValue.NullValue }; 233*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'nullValue': null }", JsonFormatter.Default.Format(message)); 234*1b3f573fSAndroid Build Coastguard Worker } 235*1b3f573fSAndroid Build Coastguard Worker 236*1b3f573fSAndroid Build Coastguard Worker [Test] NullValueNotInOneof()237*1b3f573fSAndroid Build Coastguard Worker public void NullValueNotInOneof() 238*1b3f573fSAndroid Build Coastguard Worker { 239*1b3f573fSAndroid Build Coastguard Worker var message = new NullValueNotInOneof(); 240*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ }", JsonFormatter.Default.Format(message)); 241*1b3f573fSAndroid Build Coastguard Worker } 242*1b3f573fSAndroid Build Coastguard Worker 243*1b3f573fSAndroid Build Coastguard Worker [Test] NullValueNotInOneof_FormatDefaults()244*1b3f573fSAndroid Build Coastguard Worker public void NullValueNotInOneof_FormatDefaults() 245*1b3f573fSAndroid Build Coastguard Worker { 246*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 247*1b3f573fSAndroid Build Coastguard Worker var message = new NullValueNotInOneof(); 248*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'nullValue': null }", formatter.Format(message)); 249*1b3f573fSAndroid Build Coastguard Worker } 250*1b3f573fSAndroid Build Coastguard Worker 251*1b3f573fSAndroid Build Coastguard Worker [TestCase(1.0, "1")] 252*1b3f573fSAndroid Build Coastguard Worker [TestCase(double.NaN, "'NaN'")] 253*1b3f573fSAndroid Build Coastguard Worker [TestCase(double.PositiveInfinity, "'Infinity'")] 254*1b3f573fSAndroid Build Coastguard Worker [TestCase(double.NegativeInfinity, "'-Infinity'")] DoubleRepresentations(double value, string expectedValueText)255*1b3f573fSAndroid Build Coastguard Worker public void DoubleRepresentations(double value, string expectedValueText) 256*1b3f573fSAndroid Build Coastguard Worker { 257*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleDouble = value }; 258*1b3f573fSAndroid Build Coastguard Worker string actualText = JsonFormatter.Default.Format(message); 259*1b3f573fSAndroid Build Coastguard Worker string expectedText = "{ 'singleDouble': " + expectedValueText + " }"; 260*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedText, actualText); 261*1b3f573fSAndroid Build Coastguard Worker } 262*1b3f573fSAndroid Build Coastguard Worker 263*1b3f573fSAndroid Build Coastguard Worker [Test] UnknownEnumValueNumeric_SingleField()264*1b3f573fSAndroid Build Coastguard Worker public void UnknownEnumValueNumeric_SingleField() 265*1b3f573fSAndroid Build Coastguard Worker { 266*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleForeignEnum = (ForeignEnum) 100 }; 267*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'singleForeignEnum': 100 }", JsonFormatter.Default.Format(message)); 268*1b3f573fSAndroid Build Coastguard Worker } 269*1b3f573fSAndroid Build Coastguard Worker 270*1b3f573fSAndroid Build Coastguard Worker [Test] UnknownEnumValueNumeric_RepeatedField()271*1b3f573fSAndroid Build Coastguard Worker public void UnknownEnumValueNumeric_RepeatedField() 272*1b3f573fSAndroid Build Coastguard Worker { 273*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { RepeatedForeignEnum = { ForeignEnum.ForeignBaz, (ForeignEnum) 100, ForeignEnum.ForeignFoo } }; 274*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'repeatedForeignEnum': [ 'FOREIGN_BAZ', 100, 'FOREIGN_FOO' ] }", JsonFormatter.Default.Format(message)); 275*1b3f573fSAndroid Build Coastguard Worker } 276*1b3f573fSAndroid Build Coastguard Worker 277*1b3f573fSAndroid Build Coastguard Worker [Test] UnknownEnumValueNumeric_MapField()278*1b3f573fSAndroid Build Coastguard Worker public void UnknownEnumValueNumeric_MapField() 279*1b3f573fSAndroid Build Coastguard Worker { 280*1b3f573fSAndroid Build Coastguard Worker var message = new TestMap { MapInt32Enum = { { 1, MapEnum.Foo }, { 2, (MapEnum) 100 }, { 3, MapEnum.Bar } } }; 281*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'mapInt32Enum': { '1': 'MAP_ENUM_FOO', '2': 100, '3': 'MAP_ENUM_BAR' } }", JsonFormatter.Default.Format(message)); 282*1b3f573fSAndroid Build Coastguard Worker } 283*1b3f573fSAndroid Build Coastguard Worker 284*1b3f573fSAndroid Build Coastguard Worker [Test] UnknownEnumValue_RepeatedField_AllEntriesUnknown()285*1b3f573fSAndroid Build Coastguard Worker public void UnknownEnumValue_RepeatedField_AllEntriesUnknown() 286*1b3f573fSAndroid Build Coastguard Worker { 287*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { RepeatedForeignEnum = { (ForeignEnum) 200, (ForeignEnum) 100 } }; 288*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'repeatedForeignEnum': [ 200, 100 ] }", JsonFormatter.Default.Format(message)); 289*1b3f573fSAndroid Build Coastguard Worker } 290*1b3f573fSAndroid Build Coastguard Worker 291*1b3f573fSAndroid Build Coastguard Worker [Test] 292*1b3f573fSAndroid Build Coastguard Worker [TestCase("a\u17b4b", "a\\u17b4b")] // Explicit 293*1b3f573fSAndroid Build Coastguard Worker [TestCase("a\u0601b", "a\\u0601b")] // Ranged 294*1b3f573fSAndroid Build Coastguard Worker [TestCase("a\u0605b", "a\u0605b")] // Passthrough (note lack of double backslash...) SimpleNonAscii(string text, string encoded)295*1b3f573fSAndroid Build Coastguard Worker public void SimpleNonAscii(string text, string encoded) 296*1b3f573fSAndroid Build Coastguard Worker { 297*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleString = text }; 298*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'singleString': '" + encoded + "' }", JsonFormatter.Default.Format(message)); 299*1b3f573fSAndroid Build Coastguard Worker } 300*1b3f573fSAndroid Build Coastguard Worker 301*1b3f573fSAndroid Build Coastguard Worker [Test] SurrogatePairEscaping()302*1b3f573fSAndroid Build Coastguard Worker public void SurrogatePairEscaping() 303*1b3f573fSAndroid Build Coastguard Worker { 304*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleString = "a\uD801\uDC01b" }; 305*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'singleString': 'a\\ud801\\udc01b' }", JsonFormatter.Default.Format(message)); 306*1b3f573fSAndroid Build Coastguard Worker } 307*1b3f573fSAndroid Build Coastguard Worker 308*1b3f573fSAndroid Build Coastguard Worker [Test] InvalidSurrogatePairsFail()309*1b3f573fSAndroid Build Coastguard Worker public void InvalidSurrogatePairsFail() 310*1b3f573fSAndroid Build Coastguard Worker { 311*1b3f573fSAndroid Build Coastguard Worker // Note: don't use TestCase for these, as the strings can't be reliably represented 312*1b3f573fSAndroid Build Coastguard Worker // See http://codeblog.jonskeet.uk/2014/11/07/when-is-a-string-not-a-string/ 313*1b3f573fSAndroid Build Coastguard Worker 314*1b3f573fSAndroid Build Coastguard Worker // Lone low surrogate 315*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleString = "a\uDC01b" }; 316*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<ArgumentException>(() => JsonFormatter.Default.Format(message)); 317*1b3f573fSAndroid Build Coastguard Worker 318*1b3f573fSAndroid Build Coastguard Worker // Lone high surrogate 319*1b3f573fSAndroid Build Coastguard Worker message = new TestAllTypes { SingleString = "a\uD801b" }; 320*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<ArgumentException>(() => JsonFormatter.Default.Format(message)); 321*1b3f573fSAndroid Build Coastguard Worker } 322*1b3f573fSAndroid Build Coastguard Worker 323*1b3f573fSAndroid Build Coastguard Worker [Test] 324*1b3f573fSAndroid Build Coastguard Worker [TestCase("foo_bar", "fooBar")] 325*1b3f573fSAndroid Build Coastguard Worker [TestCase("bananaBanana", "bananaBanana")] 326*1b3f573fSAndroid Build Coastguard Worker [TestCase("BANANABanana", "BANANABanana")] 327*1b3f573fSAndroid Build Coastguard Worker [TestCase("simple", "simple")] 328*1b3f573fSAndroid Build Coastguard Worker [TestCase("ACTION_AND_ADVENTURE", "ACTIONANDADVENTURE")] 329*1b3f573fSAndroid Build Coastguard Worker [TestCase("action_and_adventure", "actionAndAdventure")] 330*1b3f573fSAndroid Build Coastguard Worker [TestCase("kFoo", "kFoo")] 331*1b3f573fSAndroid Build Coastguard Worker [TestCase("HTTPServer", "HTTPServer")] 332*1b3f573fSAndroid Build Coastguard Worker [TestCase("CLIENT", "CLIENT")] ToJsonName(string original, string expected)333*1b3f573fSAndroid Build Coastguard Worker public void ToJsonName(string original, string expected) 334*1b3f573fSAndroid Build Coastguard Worker { 335*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(expected, JsonFormatter.ToJsonName(original)); 336*1b3f573fSAndroid Build Coastguard Worker } 337*1b3f573fSAndroid Build Coastguard Worker 338*1b3f573fSAndroid Build Coastguard Worker [Test] 339*1b3f573fSAndroid Build Coastguard Worker [TestCase(null, "{ }")] 340*1b3f573fSAndroid Build Coastguard Worker [TestCase("x", "{ 'fooString': 'x' }")] 341*1b3f573fSAndroid Build Coastguard Worker [TestCase("", "{ 'fooString': '' }")] Oneof(string fooStringValue, string expectedJson)342*1b3f573fSAndroid Build Coastguard Worker public void Oneof(string fooStringValue, string expectedJson) 343*1b3f573fSAndroid Build Coastguard Worker { 344*1b3f573fSAndroid Build Coastguard Worker var message = new TestOneof(); 345*1b3f573fSAndroid Build Coastguard Worker if (fooStringValue != null) 346*1b3f573fSAndroid Build Coastguard Worker { 347*1b3f573fSAndroid Build Coastguard Worker message.FooString = fooStringValue; 348*1b3f573fSAndroid Build Coastguard Worker } 349*1b3f573fSAndroid Build Coastguard Worker 350*1b3f573fSAndroid Build Coastguard Worker // We should get the same result both with and without "format default values". 351*1b3f573fSAndroid Build Coastguard Worker var formatter = JsonFormatter.Default; 352*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedJson, formatter.Format(message)); 353*1b3f573fSAndroid Build Coastguard Worker formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 354*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedJson, formatter.Format(message)); 355*1b3f573fSAndroid Build Coastguard Worker } 356*1b3f573fSAndroid Build Coastguard Worker 357*1b3f573fSAndroid Build Coastguard Worker [Test] WrapperFormatting_Single()358*1b3f573fSAndroid Build Coastguard Worker public void WrapperFormatting_Single() 359*1b3f573fSAndroid Build Coastguard Worker { 360*1b3f573fSAndroid Build Coastguard Worker // Just a few examples, handling both classes and value types, and 361*1b3f573fSAndroid Build Coastguard Worker // default vs non-default values 362*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes 363*1b3f573fSAndroid Build Coastguard Worker { 364*1b3f573fSAndroid Build Coastguard Worker Int64Field = 10, 365*1b3f573fSAndroid Build Coastguard Worker Int32Field = 0, 366*1b3f573fSAndroid Build Coastguard Worker BytesField = ByteString.FromBase64("ABCD"), 367*1b3f573fSAndroid Build Coastguard Worker StringField = "" 368*1b3f573fSAndroid Build Coastguard Worker }; 369*1b3f573fSAndroid Build Coastguard Worker var expectedJson = "{ 'int64Field': '10', 'int32Field': 0, 'stringField': '', 'bytesField': 'ABCD' }"; 370*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedJson, JsonFormatter.Default.Format(message)); 371*1b3f573fSAndroid Build Coastguard Worker } 372*1b3f573fSAndroid Build Coastguard Worker 373*1b3f573fSAndroid Build Coastguard Worker [Test] WrapperFormatting_Message()374*1b3f573fSAndroid Build Coastguard Worker public void WrapperFormatting_Message() 375*1b3f573fSAndroid Build Coastguard Worker { 376*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual("\"\"", JsonFormatter.Default.Format(new StringValue())); 377*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual("0", JsonFormatter.Default.Format(new Int32Value())); 378*1b3f573fSAndroid Build Coastguard Worker } 379*1b3f573fSAndroid Build Coastguard Worker 380*1b3f573fSAndroid Build Coastguard Worker [Test] WrapperFormatting_FormatDefaultValuesDoesNotFormatNull()381*1b3f573fSAndroid Build Coastguard Worker public void WrapperFormatting_FormatDefaultValuesDoesNotFormatNull() 382*1b3f573fSAndroid Build Coastguard Worker { 383*1b3f573fSAndroid Build Coastguard Worker // The actual JSON here is very large because there are lots of fields. Just test a couple of them. 384*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes { Int32Field = 10 }; 385*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 386*1b3f573fSAndroid Build Coastguard Worker var actualJson = formatter.Format(message); 387*1b3f573fSAndroid Build Coastguard Worker // This *used* to include "int64Field": null, but that was a bug. 388*1b3f573fSAndroid Build Coastguard Worker // WithDefaultValues should not affect message fields, including wrapper types. 389*1b3f573fSAndroid Build Coastguard Worker Assert.IsFalse(actualJson.Contains("\"int64Field\": null")); 390*1b3f573fSAndroid Build Coastguard Worker Assert.IsTrue(actualJson.Contains("\"int32Field\": 10")); 391*1b3f573fSAndroid Build Coastguard Worker } 392*1b3f573fSAndroid Build Coastguard Worker 393*1b3f573fSAndroid Build Coastguard Worker [Test] OutputIsInNumericFieldOrder_NoDefaults()394*1b3f573fSAndroid Build Coastguard Worker public void OutputIsInNumericFieldOrder_NoDefaults() 395*1b3f573fSAndroid Build Coastguard Worker { 396*1b3f573fSAndroid Build Coastguard Worker var formatter = JsonFormatter.Default; 397*1b3f573fSAndroid Build Coastguard Worker var message = new TestJsonFieldOrdering { PlainString = "p1", PlainInt32 = 2 }; 398*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': 'p1', 'plainInt32': 2 }", formatter.Format(message)); 399*1b3f573fSAndroid Build Coastguard Worker message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; 400*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); 401*1b3f573fSAndroid Build Coastguard Worker message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; 402*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); 403*1b3f573fSAndroid Build Coastguard Worker } 404*1b3f573fSAndroid Build Coastguard Worker 405*1b3f573fSAndroid Build Coastguard Worker [Test] OutputIsInNumericFieldOrder_WithDefaults()406*1b3f573fSAndroid Build Coastguard Worker public void OutputIsInNumericFieldOrder_WithDefaults() 407*1b3f573fSAndroid Build Coastguard Worker { 408*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithFormatDefaultValues(true)); 409*1b3f573fSAndroid Build Coastguard Worker var message = new TestJsonFieldOrdering(); 410*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': '', 'plainInt32': 0 }", formatter.Format(message)); 411*1b3f573fSAndroid Build Coastguard Worker message = new TestJsonFieldOrdering { O1Int32 = 5, O2String = "o2", PlainInt32 = 10, PlainString = "plain" }; 412*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': 'plain', 'o2String': 'o2', 'plainInt32': 10, 'o1Int32': 5 }", formatter.Format(message)); 413*1b3f573fSAndroid Build Coastguard Worker message = new TestJsonFieldOrdering { O1String = "", O2Int32 = 0, PlainInt32 = 10, PlainString = "plain" }; 414*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'plainString': 'plain', 'o1String': '', 'plainInt32': 10, 'o2Int32': 0 }", formatter.Format(message)); 415*1b3f573fSAndroid Build Coastguard Worker } 416*1b3f573fSAndroid Build Coastguard Worker 417*1b3f573fSAndroid Build Coastguard Worker [Test] 418*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00Z", 0)] 419*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000000001Z", 1)] 420*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000000010Z", 10)] 421*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000000100Z", 100)] 422*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000001Z", 1000)] 423*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000010Z", 10000)] 424*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.000100Z", 100000)] 425*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.001Z", 1000000)] 426*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.010Z", 10000000)] 427*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.100Z", 100000000)] 428*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.120Z", 120000000)] 429*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123Z", 123000000)] 430*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123400Z", 123400000)] 431*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123450Z", 123450000)] 432*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123456Z", 123456000)] 433*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123456700Z", 123456700)] 434*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123456780Z", 123456780)] 435*1b3f573fSAndroid Build Coastguard Worker [TestCase("1970-01-01T00:00:00.123456789Z", 123456789)] TimestampStandalone(string expected, int nanos)436*1b3f573fSAndroid Build Coastguard Worker public void TimestampStandalone(string expected, int nanos) 437*1b3f573fSAndroid Build Coastguard Worker { 438*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(WrapInQuotes(expected), new Timestamp { Nanos = nanos }.ToString()); 439*1b3f573fSAndroid Build Coastguard Worker } 440*1b3f573fSAndroid Build Coastguard Worker 441*1b3f573fSAndroid Build Coastguard Worker [Test] TimestampStandalone_FromDateTime()442*1b3f573fSAndroid Build Coastguard Worker public void TimestampStandalone_FromDateTime() 443*1b3f573fSAndroid Build Coastguard Worker { 444*1b3f573fSAndroid Build Coastguard Worker // One before and one after the Unix epoch, more easily represented via DateTime. 445*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual("\"1673-06-19T12:34:56Z\"", 446*1b3f573fSAndroid Build Coastguard Worker new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp().ToString()); 447*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual("\"2015-07-31T10:29:34Z\"", 448*1b3f573fSAndroid Build Coastguard Worker new DateTime(2015, 7, 31, 10, 29, 34, DateTimeKind.Utc).ToTimestamp().ToString()); 449*1b3f573fSAndroid Build Coastguard Worker } 450*1b3f573fSAndroid Build Coastguard Worker 451*1b3f573fSAndroid Build Coastguard Worker [Test] 452*1b3f573fSAndroid Build Coastguard Worker [TestCase(-1, -1)] // Would be valid as duration 453*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, Timestamp.MaxNanos + 1)] 454*1b3f573fSAndroid Build Coastguard Worker [TestCase(Timestamp.UnixSecondsAtBclMaxValue + 1, 0)] 455*1b3f573fSAndroid Build Coastguard Worker [TestCase(Timestamp.UnixSecondsAtBclMinValue - 1, 0)] TimestampStandalone_NonNormalized(long seconds, int nanoseconds)456*1b3f573fSAndroid Build Coastguard Worker public void TimestampStandalone_NonNormalized(long seconds, int nanoseconds) 457*1b3f573fSAndroid Build Coastguard Worker { 458*1b3f573fSAndroid Build Coastguard Worker var timestamp = new Timestamp { Seconds = seconds, Nanos = nanoseconds }; 459*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(timestamp)); 460*1b3f573fSAndroid Build Coastguard Worker } 461*1b3f573fSAndroid Build Coastguard Worker 462*1b3f573fSAndroid Build Coastguard Worker [Test] TimestampField()463*1b3f573fSAndroid Build Coastguard Worker public void TimestampField() 464*1b3f573fSAndroid Build Coastguard Worker { 465*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes { TimestampField = new Timestamp() }; 466*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'timestampField': '1970-01-01T00:00:00Z' }", JsonFormatter.Default.Format(message)); 467*1b3f573fSAndroid Build Coastguard Worker } 468*1b3f573fSAndroid Build Coastguard Worker 469*1b3f573fSAndroid Build Coastguard Worker [Test] 470*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 0, "0s")] 471*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, 0, "1s")] 472*1b3f573fSAndroid Build Coastguard Worker [TestCase(-1, 0, "-1s")] 473*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 1, "0.000000001s")] 474*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 10, "0.000000010s")] 475*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 100, "0.000000100s")] 476*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 1000, "0.000001s")] 477*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 10000, "0.000010s")] 478*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 100000, "0.000100s")] 479*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 1000000, "0.001s")] 480*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 10000000, "0.010s")] 481*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 100000000, "0.100s")] 482*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 120000000, "0.120s")] 483*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123000000, "0.123s")] 484*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123400000, "0.123400s")] 485*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123450000, "0.123450s")] 486*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123456000, "0.123456s")] 487*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123456700, "0.123456700s")] 488*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123456780, "0.123456780s")] 489*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, 123456789, "0.123456789s")] 490*1b3f573fSAndroid Build Coastguard Worker [TestCase(0, -100000000, "-0.100s")] 491*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, 100000000, "1.100s")] 492*1b3f573fSAndroid Build Coastguard Worker [TestCase(-1, -100000000, "-1.100s")] DurationStandalone(long seconds, int nanoseconds, string expected)493*1b3f573fSAndroid Build Coastguard Worker public void DurationStandalone(long seconds, int nanoseconds, string expected) 494*1b3f573fSAndroid Build Coastguard Worker { 495*1b3f573fSAndroid Build Coastguard Worker var json = JsonFormatter.Default.Format(new Duration { Seconds = seconds, Nanos = nanoseconds }); 496*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(WrapInQuotes(expected), json); 497*1b3f573fSAndroid Build Coastguard Worker } 498*1b3f573fSAndroid Build Coastguard Worker 499*1b3f573fSAndroid Build Coastguard Worker [Test] 500*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, 2123456789)] 501*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, -100000000)] DurationStandalone_NonNormalized(long seconds, int nanoseconds)502*1b3f573fSAndroid Build Coastguard Worker public void DurationStandalone_NonNormalized(long seconds, int nanoseconds) 503*1b3f573fSAndroid Build Coastguard Worker { 504*1b3f573fSAndroid Build Coastguard Worker var duration = new Duration { Seconds = seconds, Nanos = nanoseconds }; 505*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(duration)); 506*1b3f573fSAndroid Build Coastguard Worker } 507*1b3f573fSAndroid Build Coastguard Worker 508*1b3f573fSAndroid Build Coastguard Worker [Test] DurationField()509*1b3f573fSAndroid Build Coastguard Worker public void DurationField() 510*1b3f573fSAndroid Build Coastguard Worker { 511*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes { DurationField = new Duration() }; 512*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'durationField': '0s' }", JsonFormatter.Default.Format(message)); 513*1b3f573fSAndroid Build Coastguard Worker } 514*1b3f573fSAndroid Build Coastguard Worker 515*1b3f573fSAndroid Build Coastguard Worker [Test] StructSample()516*1b3f573fSAndroid Build Coastguard Worker public void StructSample() 517*1b3f573fSAndroid Build Coastguard Worker { 518*1b3f573fSAndroid Build Coastguard Worker var message = new Struct 519*1b3f573fSAndroid Build Coastguard Worker { 520*1b3f573fSAndroid Build Coastguard Worker Fields = 521*1b3f573fSAndroid Build Coastguard Worker { 522*1b3f573fSAndroid Build Coastguard Worker { "a", Value.ForNull() }, 523*1b3f573fSAndroid Build Coastguard Worker { "b", Value.ForBool(false) }, 524*1b3f573fSAndroid Build Coastguard Worker { "c", Value.ForNumber(10.5) }, 525*1b3f573fSAndroid Build Coastguard Worker { "d", Value.ForString("text") }, 526*1b3f573fSAndroid Build Coastguard Worker { "e", Value.ForList(Value.ForString("t1"), Value.ForNumber(5)) }, 527*1b3f573fSAndroid Build Coastguard Worker { "f", Value.ForStruct(new Struct { Fields = { { "nested", Value.ForString("value") } } }) } 528*1b3f573fSAndroid Build Coastguard Worker } 529*1b3f573fSAndroid Build Coastguard Worker }; 530*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'a': null, 'b': false, 'c': 10.5, 'd': 'text', 'e': [ 't1', 5 ], 'f': { 'nested': 'value' } }", message.ToString()); 531*1b3f573fSAndroid Build Coastguard Worker } 532*1b3f573fSAndroid Build Coastguard Worker 533*1b3f573fSAndroid Build Coastguard Worker [Test] 534*1b3f573fSAndroid Build Coastguard Worker [TestCase("foo__bar")] 535*1b3f573fSAndroid Build Coastguard Worker [TestCase("foo_3_ar")] 536*1b3f573fSAndroid Build Coastguard Worker [TestCase("fooBar")] FieldMaskInvalid(string input)537*1b3f573fSAndroid Build Coastguard Worker public void FieldMaskInvalid(string input) 538*1b3f573fSAndroid Build Coastguard Worker { 539*1b3f573fSAndroid Build Coastguard Worker var mask = new FieldMask { Paths = { input } }; 540*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(mask)); 541*1b3f573fSAndroid Build Coastguard Worker } 542*1b3f573fSAndroid Build Coastguard Worker 543*1b3f573fSAndroid Build Coastguard Worker [Test] FieldMaskStandalone()544*1b3f573fSAndroid Build Coastguard Worker public void FieldMaskStandalone() 545*1b3f573fSAndroid Build Coastguard Worker { 546*1b3f573fSAndroid Build Coastguard Worker var fieldMask = new FieldMask { Paths = { "", "single", "with_underscore", "nested.field.name", "nested..double_dot" } }; 547*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual("\",single,withUnderscore,nested.field.name,nested..doubleDot\"", fieldMask.ToString()); 548*1b3f573fSAndroid Build Coastguard Worker 549*1b3f573fSAndroid Build Coastguard Worker // Invalid, but we shouldn't create broken JSON... 550*1b3f573fSAndroid Build Coastguard Worker fieldMask = new FieldMask { Paths = { "x\\y" } }; 551*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(@"""x\\y""", fieldMask.ToString()); 552*1b3f573fSAndroid Build Coastguard Worker } 553*1b3f573fSAndroid Build Coastguard Worker 554*1b3f573fSAndroid Build Coastguard Worker [Test] FieldMaskField()555*1b3f573fSAndroid Build Coastguard Worker public void FieldMaskField() 556*1b3f573fSAndroid Build Coastguard Worker { 557*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes { FieldMaskField = new FieldMask { Paths = { "user.display_name", "photo" } } }; 558*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'fieldMaskField': 'user.displayName,photo' }", JsonFormatter.Default.Format(message)); 559*1b3f573fSAndroid Build Coastguard Worker } 560*1b3f573fSAndroid Build Coastguard Worker 561*1b3f573fSAndroid Build Coastguard Worker // SourceContext is an example of a well-known type with no special JSON handling 562*1b3f573fSAndroid Build Coastguard Worker [Test] SourceContextStandalone()563*1b3f573fSAndroid Build Coastguard Worker public void SourceContextStandalone() 564*1b3f573fSAndroid Build Coastguard Worker { 565*1b3f573fSAndroid Build Coastguard Worker var message = new SourceContext { FileName = "foo.proto" }; 566*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'fileName': 'foo.proto' }", JsonFormatter.Default.Format(message)); 567*1b3f573fSAndroid Build Coastguard Worker } 568*1b3f573fSAndroid Build Coastguard Worker 569*1b3f573fSAndroid Build Coastguard Worker [Test] AnyWellKnownType()570*1b3f573fSAndroid Build Coastguard Worker public void AnyWellKnownType() 571*1b3f573fSAndroid Build Coastguard Worker { 572*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(Timestamp.Descriptor))); 573*1b3f573fSAndroid Build Coastguard Worker var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); 574*1b3f573fSAndroid Build Coastguard Worker var any = Any.Pack(timestamp); 575*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ '@type': 'type.googleapis.com/google.protobuf.Timestamp', 'value': '1673-06-19T12:34:56Z' }", formatter.Format(any)); 576*1b3f573fSAndroid Build Coastguard Worker } 577*1b3f573fSAndroid Build Coastguard Worker 578*1b3f573fSAndroid Build Coastguard Worker [Test] AnyMessageType()579*1b3f573fSAndroid Build Coastguard Worker public void AnyMessageType() 580*1b3f573fSAndroid Build Coastguard Worker { 581*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); 582*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } }; 583*1b3f573fSAndroid Build Coastguard Worker var any = Any.Pack(message); 584*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 10, 'singleNestedMessage': { 'bb': 20 } }", formatter.Format(any)); 585*1b3f573fSAndroid Build Coastguard Worker } 586*1b3f573fSAndroid Build Coastguard Worker 587*1b3f573fSAndroid Build Coastguard Worker [Test] AnyMessageType_CustomPrefix()588*1b3f573fSAndroid Build Coastguard Worker public void AnyMessageType_CustomPrefix() 589*1b3f573fSAndroid Build Coastguard Worker { 590*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(TypeRegistry.FromMessages(TestAllTypes.Descriptor))); 591*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes { SingleInt32 = 10 }; 592*1b3f573fSAndroid Build Coastguard Worker var any = Any.Pack(message, "foo.bar/baz"); 593*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ '@type': 'foo.bar/baz/protobuf_unittest3.TestAllTypes', 'singleInt32': 10 }", formatter.Format(any)); 594*1b3f573fSAndroid Build Coastguard Worker } 595*1b3f573fSAndroid Build Coastguard Worker 596*1b3f573fSAndroid Build Coastguard Worker [Test] AnyNested()597*1b3f573fSAndroid Build Coastguard Worker public void AnyNested() 598*1b3f573fSAndroid Build Coastguard Worker { 599*1b3f573fSAndroid Build Coastguard Worker var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor); 600*1b3f573fSAndroid Build Coastguard Worker var formatter = new JsonFormatter(JsonFormatter.Settings.Default.WithTypeRegistry(registry)); 601*1b3f573fSAndroid Build Coastguard Worker 602*1b3f573fSAndroid Build Coastguard Worker // Nest an Any as the value of an Any. 603*1b3f573fSAndroid Build Coastguard Worker var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 }; 604*1b3f573fSAndroid Build Coastguard Worker var nestedMessage = Any.Pack(doubleNestedMessage); 605*1b3f573fSAndroid Build Coastguard Worker var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) }; 606*1b3f573fSAndroid Build Coastguard Worker AssertJson("{ 'anyField': { '@type': 'type.googleapis.com/google.protobuf.Any', 'value': { '@type': 'type.googleapis.com/protobuf_unittest3.TestAllTypes', 'singleInt32': 20 } } }", 607*1b3f573fSAndroid Build Coastguard Worker formatter.Format(message)); 608*1b3f573fSAndroid Build Coastguard Worker } 609*1b3f573fSAndroid Build Coastguard Worker 610*1b3f573fSAndroid Build Coastguard Worker [Test] AnyUnknownType()611*1b3f573fSAndroid Build Coastguard Worker public void AnyUnknownType() 612*1b3f573fSAndroid Build Coastguard Worker { 613*1b3f573fSAndroid Build Coastguard Worker // The default type registry doesn't have any types in it. 614*1b3f573fSAndroid Build Coastguard Worker var message = new TestAllTypes(); 615*1b3f573fSAndroid Build Coastguard Worker var any = Any.Pack(message); 616*1b3f573fSAndroid Build Coastguard Worker Assert.Throws<InvalidOperationException>(() => JsonFormatter.Default.Format(any)); 617*1b3f573fSAndroid Build Coastguard Worker } 618*1b3f573fSAndroid Build Coastguard Worker 619*1b3f573fSAndroid Build Coastguard Worker [Test] 620*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(BoolValue), true, "true")] 621*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(Int32Value), 32, "32")] 622*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(Int64Value), 32L, "\"32\"")] 623*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(UInt32Value), 32U, "32")] 624*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(UInt64Value), 32UL, "\"32\"")] 625*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(StringValue), "foo", "\"foo\"")] 626*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(FloatValue), 1.5f, "1.5")] 627*1b3f573fSAndroid Build Coastguard Worker [TestCase(typeof(DoubleValue), 1.5d, "1.5")] Wrappers_Standalone(System.Type wrapperType, object value, string expectedJson)628*1b3f573fSAndroid Build Coastguard Worker public void Wrappers_Standalone(System.Type wrapperType, object value, string expectedJson) 629*1b3f573fSAndroid Build Coastguard Worker { 630*1b3f573fSAndroid Build Coastguard Worker IMessage populated = (IMessage)Activator.CreateInstance(wrapperType); 631*1b3f573fSAndroid Build Coastguard Worker populated.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(populated, value); 632*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(expectedJson, JsonFormatter.Default.Format(populated)); 633*1b3f573fSAndroid Build Coastguard Worker } 634*1b3f573fSAndroid Build Coastguard Worker 635*1b3f573fSAndroid Build Coastguard Worker // Sanity tests for WriteValue. Not particularly comprehensive, as it's all covered above already, 636*1b3f573fSAndroid Build Coastguard Worker // as FormatMessage uses WriteValue. 637*1b3f573fSAndroid Build Coastguard Worker 638*1b3f573fSAndroid Build Coastguard Worker [TestCase(null, "null")] 639*1b3f573fSAndroid Build Coastguard Worker [TestCase(1, "1")] 640*1b3f573fSAndroid Build Coastguard Worker [TestCase(1L, "'1'")] 641*1b3f573fSAndroid Build Coastguard Worker [TestCase(0.5f, "0.5")] 642*1b3f573fSAndroid Build Coastguard Worker [TestCase(0.5d, "0.5")] 643*1b3f573fSAndroid Build Coastguard Worker [TestCase("text", "'text'")] 644*1b3f573fSAndroid Build Coastguard Worker [TestCase("x\ny", @"'x\ny'")] 645*1b3f573fSAndroid Build Coastguard Worker [TestCase(ForeignEnum.ForeignBar, "'FOREIGN_BAR'")] WriteValue_Constant(object value, string expectedJson)646*1b3f573fSAndroid Build Coastguard Worker public void WriteValue_Constant(object value, string expectedJson) 647*1b3f573fSAndroid Build Coastguard Worker { 648*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, expectedJson); 649*1b3f573fSAndroid Build Coastguard Worker } 650*1b3f573fSAndroid Build Coastguard Worker 651*1b3f573fSAndroid Build Coastguard Worker [Test] WriteValue_Timestamp()652*1b3f573fSAndroid Build Coastguard Worker public void WriteValue_Timestamp() 653*1b3f573fSAndroid Build Coastguard Worker { 654*1b3f573fSAndroid Build Coastguard Worker var value = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp(); 655*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, "'1673-06-19T12:34:56Z'"); 656*1b3f573fSAndroid Build Coastguard Worker } 657*1b3f573fSAndroid Build Coastguard Worker 658*1b3f573fSAndroid Build Coastguard Worker [Test] WriteValue_Message()659*1b3f573fSAndroid Build Coastguard Worker public void WriteValue_Message() 660*1b3f573fSAndroid Build Coastguard Worker { 661*1b3f573fSAndroid Build Coastguard Worker var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; 662*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, "{ 'singleInt32': 100, 'singleInt64': '3210987654321' }"); 663*1b3f573fSAndroid Build Coastguard Worker } 664*1b3f573fSAndroid Build Coastguard Worker 665*1b3f573fSAndroid Build Coastguard Worker [Test] WriteValue_Message_PreserveNames()666*1b3f573fSAndroid Build Coastguard Worker public void WriteValue_Message_PreserveNames() 667*1b3f573fSAndroid Build Coastguard Worker { 668*1b3f573fSAndroid Build Coastguard Worker var value = new TestAllTypes { SingleInt32 = 100, SingleInt64 = 3210987654321L }; 669*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, "{ 'single_int32': 100, 'single_int64': '3210987654321' }", JsonFormatter.Settings.Default.WithPreserveProtoFieldNames(true)); 670*1b3f573fSAndroid Build Coastguard Worker } 671*1b3f573fSAndroid Build Coastguard Worker 672*1b3f573fSAndroid Build Coastguard Worker [Test] WriteValue_List()673*1b3f573fSAndroid Build Coastguard Worker public void WriteValue_List() 674*1b3f573fSAndroid Build Coastguard Worker { 675*1b3f573fSAndroid Build Coastguard Worker var value = new RepeatedField<int> { 1, 2, 3 }; 676*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, "[ 1, 2, 3 ]"); 677*1b3f573fSAndroid Build Coastguard Worker } 678*1b3f573fSAndroid Build Coastguard Worker 679*1b3f573fSAndroid Build Coastguard Worker [Test] Proto2_DefaultValuesWritten()680*1b3f573fSAndroid Build Coastguard Worker public void Proto2_DefaultValuesWritten() 681*1b3f573fSAndroid Build Coastguard Worker { 682*1b3f573fSAndroid Build Coastguard Worker var value = new ProtobufTestMessages.Proto2.TestAllTypesProto2() { FieldName13 = 0 }; 683*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(value, "{ 'FieldName13': 0 }"); 684*1b3f573fSAndroid Build Coastguard Worker } 685*1b3f573fSAndroid Build Coastguard Worker AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null)686*1b3f573fSAndroid Build Coastguard Worker private static void AssertWriteValue(object value, string expectedJson, JsonFormatter.Settings settings = null) 687*1b3f573fSAndroid Build Coastguard Worker { 688*1b3f573fSAndroid Build Coastguard Worker var writer = new StringWriter(); 689*1b3f573fSAndroid Build Coastguard Worker new JsonFormatter(settings ?? JsonFormatter.Settings.Default).WriteValue(writer, value); 690*1b3f573fSAndroid Build Coastguard Worker string actual = writer.ToString(); 691*1b3f573fSAndroid Build Coastguard Worker AssertJson(expectedJson, actual); 692*1b3f573fSAndroid Build Coastguard Worker } 693*1b3f573fSAndroid Build Coastguard Worker 694*1b3f573fSAndroid Build Coastguard Worker /// <summary> 695*1b3f573fSAndroid Build Coastguard Worker /// Checks that the actual JSON is the same as the expected JSON - but after replacing 696*1b3f573fSAndroid Build Coastguard Worker /// all apostrophes in the expected JSON with double quotes. This basically makes the tests easier 697*1b3f573fSAndroid Build Coastguard Worker /// to read. 698*1b3f573fSAndroid Build Coastguard Worker /// </summary> AssertJson(string expectedJsonWithApostrophes, string actualJson)699*1b3f573fSAndroid Build Coastguard Worker private static void AssertJson(string expectedJsonWithApostrophes, string actualJson) 700*1b3f573fSAndroid Build Coastguard Worker { 701*1b3f573fSAndroid Build Coastguard Worker var expectedJson = expectedJsonWithApostrophes.Replace("'", "\""); 702*1b3f573fSAndroid Build Coastguard Worker Assert.AreEqual(expectedJson, actualJson); 703*1b3f573fSAndroid Build Coastguard Worker } 704*1b3f573fSAndroid Build Coastguard Worker } 705*1b3f573fSAndroid Build Coastguard Worker } 706