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