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