blob: d21da58a64d4cc9444080fe7a92cada88b50ea6c [file] [log] [blame]
Jon Skeetfb248822015-09-04 12:41:14 +01001#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
Jon Skeet3de2fce2015-11-23 16:21:47 +000033using Google.Protobuf.Reflection;
Jon Skeetfb248822015-09-04 12:41:14 +010034using Google.Protobuf.TestProtos;
35using Google.Protobuf.WellKnownTypes;
36using NUnit.Framework;
37using System;
38
39namespace Google.Protobuf
40{
41 /// <summary>
Jon Skeetaa431a02016-01-05 09:25:32 +000042 /// Unit tests for JSON parsing.
Jon Skeetfb248822015-09-04 12:41:14 +010043 /// </summary>
44 public class JsonParserTest
45 {
46 // Sanity smoke test
47 [Test]
48 public void AllTypesRoundtrip()
49 {
50 AssertRoundtrip(SampleMessages.CreateFullTestAllTypes());
51 }
52
53 [Test]
54 public void Maps()
55 {
56 AssertRoundtrip(new TestMap { MapStringString = { { "with spaces", "bar" }, { "a", "b" } } });
57 AssertRoundtrip(new TestMap { MapInt32Int32 = { { 0, 1 }, { 2, 3 } } });
58 AssertRoundtrip(new TestMap { MapBoolBool = { { false, true }, { true, false } } });
59 }
60
61 [Test]
62 [TestCase(" 1 ")]
63 [TestCase("+1")]
64 [TestCase("1,000")]
65 [TestCase("1.5")]
66 public void IntegerMapKeysAreStrict(string keyText)
67 {
68 // Test that integer parsing is strict. We assume that if this is correct for int32,
69 // it's correct for other numeric key types.
70 var json = "{ \"mapInt32Int32\": { \"" + keyText + "\" : \"1\" } }";
71 Assert.Throws<InvalidProtocolBufferException>(() => JsonParser.Default.Parse<TestMap>(json));
72 }
73
74 [Test]
Jon Skeet022a9b22016-01-15 11:39:54 +000075 public void OriginalFieldNameAccepted()
76 {
77 var json = "{ \"single_int32\": 10 }";
78 var expected = new TestAllTypes { SingleInt32 = 10 };
79 Assert.AreEqual(expected, TestAllTypes.Parser.ParseJson(json));
80 }
81
82 [Test]
Jon Skeetfb248822015-09-04 12:41:14 +010083 public void SourceContextRoundtrip()
84 {
85 AssertRoundtrip(new SourceContext { FileName = "foo.proto" });
86 }
87
88 [Test]
89 public void SingularWrappers_DefaultNonNullValues()
90 {
91 var message = new TestWellKnownTypes
92 {
93 StringField = "",
94 BytesField = ByteString.Empty,
95 BoolField = false,
96 FloatField = 0f,
97 DoubleField = 0d,
98 Int32Field = 0,
99 Int64Field = 0,
100 Uint32Field = 0,
101 Uint64Field = 0
102 };
103 AssertRoundtrip(message);
104 }
105
106 [Test]
107 public void SingularWrappers_NonDefaultValues()
108 {
109 var message = new TestWellKnownTypes
110 {
111 StringField = "x",
112 BytesField = ByteString.CopyFrom(1, 2, 3),
113 BoolField = true,
114 FloatField = 12.5f,
115 DoubleField = 12.25d,
116 Int32Field = 1,
117 Int64Field = 2,
118 Uint32Field = 3,
119 Uint64Field = 4
120 };
121 AssertRoundtrip(message);
122 }
123
124 [Test]
125 public void SingularWrappers_ExplicitNulls()
126 {
Jon Skeetb1ea15f2016-01-15 14:18:16 +0000127 // When we parse the "valueField": null part, we remember it... basically, it's one case
128 // where explicit default values don't fully roundtrip.
129 var message = new TestWellKnownTypes { ValueField = Value.ForNull() };
Jon Skeetfb248822015-09-04 12:41:14 +0100130 var json = new JsonFormatter(new JsonFormatter.Settings(true)).Format(message);
131 var parsed = JsonParser.Default.Parse<TestWellKnownTypes>(json);
132 Assert.AreEqual(message, parsed);
133 }
134
135 [Test]
136 [TestCase(typeof(Int32Value), "32", 32)]
137 [TestCase(typeof(Int64Value), "32", 32L)]
138 [TestCase(typeof(UInt32Value), "32", 32U)]
139 [TestCase(typeof(UInt64Value), "32", 32UL)]
140 [TestCase(typeof(StringValue), "\"foo\"", "foo")]
141 [TestCase(typeof(FloatValue), "1.5", 1.5f)]
142 [TestCase(typeof(DoubleValue), "1.5", 1.5d)]
143 public void Wrappers_Standalone(System.Type wrapperType, string json, object expectedValue)
144 {
145 IMessage parsed = (IMessage) Activator.CreateInstance(wrapperType);
146 IMessage expected = (IMessage) Activator.CreateInstance(wrapperType);
147 JsonParser.Default.Merge(parsed, "null");
148 Assert.AreEqual(expected, parsed);
149
150 JsonParser.Default.Merge(parsed, json);
Jon Skeet284bb452015-11-05 09:13:53 +0000151 expected.Descriptor.Fields[WrappersReflection.WrapperValueFieldNumber].Accessor.SetValue(expected, expectedValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100152 Assert.AreEqual(expected, parsed);
153 }
154
155 [Test]
Jon Skeetb1ea15f2016-01-15 14:18:16 +0000156 public void ExplicitNullValue()
157 {
158 string json = "{\"valueField\": null}";
159 var message = JsonParser.Default.Parse<TestWellKnownTypes>(json);
160 Assert.AreEqual(new TestWellKnownTypes { ValueField = Value.ForNull() }, message);
161 }
162
163 [Test]
Jon Skeetfb248822015-09-04 12:41:14 +0100164 public void BytesWrapper_Standalone()
165 {
166 ByteString data = ByteString.CopyFrom(1, 2, 3);
167 // Can't do this with attributes...
Jon Skeetb4a58172016-01-06 12:05:31 +0000168 var parsed = JsonParser.Default.Parse<BytesValue>(WrapInQuotes(data.ToBase64()));
Jon Skeetfb248822015-09-04 12:41:14 +0100169 var expected = new BytesValue { Value = data };
170 Assert.AreEqual(expected, parsed);
171 }
172
173 [Test]
174 public void RepeatedWrappers()
175 {
176 var message = new RepeatedWellKnownTypes
177 {
178 BoolField = { true, false },
179 BytesField = { ByteString.CopyFrom(1, 2, 3), ByteString.CopyFrom(4, 5, 6), ByteString.Empty },
180 DoubleField = { 12.5, -1.5, 0d },
181 FloatField = { 123.25f, -20f, 0f },
182 Int32Field = { int.MaxValue, int.MinValue, 0 },
183 Int64Field = { long.MaxValue, long.MinValue, 0L },
184 StringField = { "First", "Second", "" },
185 Uint32Field = { uint.MaxValue, uint.MinValue, 0U },
186 Uint64Field = { ulong.MaxValue, ulong.MinValue, 0UL },
187 };
188 AssertRoundtrip(message);
189 }
190
191 [Test]
Jon Skeet888e71b2016-01-15 10:55:36 +0000192 public void RepeatedField_NullElementProhibited()
193 {
194 string json = "{ \"repeated_foreign_message\": [null] }";
195 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
196 }
197
198 [Test]
199 public void RepeatedField_NullOverallValueAllowed()
200 {
201 string json = "{ \"repeated_foreign_message\": null }";
202 Assert.AreEqual(new TestAllTypes(), TestAllTypes.Parser.ParseJson(json));
203 }
204
205 [Test]
206 [TestCase("{ \"mapInt32Int32\": { \"10\": null }")]
207 [TestCase("{ \"mapStringString\": { \"abc\": null }")]
208 [TestCase("{ \"mapInt32ForeignMessage\": { \"10\": null }")]
209 public void MapField_NullValueProhibited(string json)
210 {
211 Assert.Throws<InvalidProtocolBufferException>(() => TestMap.Parser.ParseJson(json));
212 }
213
214 [Test]
215 public void MapField_NullOverallValueAllowed()
216 {
217 string json = "{ \"mapInt32Int32\": null }";
218 Assert.AreEqual(new TestMap(), TestMap.Parser.ParseJson(json));
219 }
220
221 [Test]
Jon Skeetfb248822015-09-04 12:41:14 +0100222 public void IndividualWrapperTypes()
223 {
224 Assert.AreEqual(new StringValue { Value = "foo" }, StringValue.Parser.ParseJson("\"foo\""));
225 Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("1"));
226 // Can parse strings directly too
227 Assert.AreEqual(new Int32Value { Value = 1 }, Int32Value.Parser.ParseJson("\"1\""));
228 }
229
230 private static void AssertRoundtrip<T>(T message) where T : IMessage<T>, new()
231 {
232 var clone = message.Clone();
Jon Skeet5dba7d72016-01-06 11:12:56 +0000233 var json = JsonFormatter.Default.Format(message);
Jon Skeetfb248822015-09-04 12:41:14 +0100234 var parsed = JsonParser.Default.Parse<T>(json);
235 Assert.AreEqual(clone, parsed);
236 }
237
238 [Test]
239 [TestCase("0", 0)]
240 [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
241 [TestCase("1", 1)]
242 [TestCase("-1", -1)]
243 [TestCase("2147483647", 2147483647)]
244 [TestCase("-2147483648", -2147483648)]
245 public void StringToInt32_Valid(string jsonValue, int expectedParsedValue)
246 {
247 string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
248 var parsed = TestAllTypes.Parser.ParseJson(json);
249 Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
250 }
251
252 [Test]
253 [TestCase("+0")]
Jon Skeetaa431a02016-01-05 09:25:32 +0000254 [TestCase(" 1")]
255 [TestCase("1 ")]
Jon Skeetfb248822015-09-04 12:41:14 +0100256 [TestCase("00")]
257 [TestCase("-00")]
258 [TestCase("--1")]
259 [TestCase("+1")]
260 [TestCase("1.5")]
261 [TestCase("1e10")]
262 [TestCase("2147483648")]
263 [TestCase("-2147483649")]
264 public void StringToInt32_Invalid(string jsonValue)
265 {
266 string json = "{ \"singleInt32\": \"" + jsonValue + "\"}";
267 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
268 }
269
270 [Test]
271 [TestCase("0", 0U)]
272 [TestCase("1", 1U)]
273 [TestCase("4294967295", 4294967295U)]
274 public void StringToUInt32_Valid(string jsonValue, uint expectedParsedValue)
275 {
276 string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
277 var parsed = TestAllTypes.Parser.ParseJson(json);
278 Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
279 }
280
281 // Assume that anything non-bounds-related is covered in the Int32 case
282 [Test]
283 [TestCase("-1")]
284 [TestCase("4294967296")]
285 public void StringToUInt32_Invalid(string jsonValue)
286 {
287 string json = "{ \"singleUint32\": \"" + jsonValue + "\"}";
288 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
289 }
290
291 [Test]
292 [TestCase("0", 0L)]
293 [TestCase("1", 1L)]
294 [TestCase("-1", -1L)]
295 [TestCase("9223372036854775807", 9223372036854775807)]
296 [TestCase("-9223372036854775808", -9223372036854775808)]
297 public void StringToInt64_Valid(string jsonValue, long expectedParsedValue)
298 {
299 string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
300 var parsed = TestAllTypes.Parser.ParseJson(json);
301 Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
302 }
303
304 // Assume that anything non-bounds-related is covered in the Int32 case
305 [Test]
306 [TestCase("-9223372036854775809")]
307 [TestCase("9223372036854775808")]
308 public void StringToInt64_Invalid(string jsonValue)
309 {
310 string json = "{ \"singleInt64\": \"" + jsonValue + "\"}";
311 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
312 }
313
314 [Test]
315 [TestCase("0", 0UL)]
316 [TestCase("1", 1UL)]
317 [TestCase("18446744073709551615", 18446744073709551615)]
318 public void StringToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
319 {
320 string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
321 var parsed = TestAllTypes.Parser.ParseJson(json);
322 Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
323 }
324
325 // Assume that anything non-bounds-related is covered in the Int32 case
326 [Test]
327 [TestCase("-1")]
328 [TestCase("18446744073709551616")]
329 public void StringToUInt64_Invalid(string jsonValue)
330 {
331 string json = "{ \"singleUint64\": \"" + jsonValue + "\"}";
332 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
333 }
334
335 [Test]
336 [TestCase("0", 0d)]
337 [TestCase("1", 1d)]
338 [TestCase("1.000000", 1d)]
339 [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
340 [TestCase("-1", -1d)]
341 [TestCase("1e1", 10d)]
342 [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
343 [TestCase("1E1", 10d)] // Either case is fine
344 [TestCase("-1e1", -10d)]
345 [TestCase("1.5e1", 15d)]
346 [TestCase("-1.5e1", -15d)]
347 [TestCase("15e-1", 1.5d)]
348 [TestCase("-15e-1", -1.5d)]
349 [TestCase("1.79769e308", 1.79769e308)]
350 [TestCase("-1.79769e308", -1.79769e308)]
351 [TestCase("Infinity", double.PositiveInfinity)]
352 [TestCase("-Infinity", double.NegativeInfinity)]
353 [TestCase("NaN", double.NaN)]
354 public void StringToDouble_Valid(string jsonValue, double expectedParsedValue)
355 {
356 string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
357 var parsed = TestAllTypes.Parser.ParseJson(json);
358 Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
359 }
360
361 [Test]
362 [TestCase("1.7977e308")]
363 [TestCase("-1.7977e308")]
364 [TestCase("1e309")]
365 [TestCase("1,0")]
366 [TestCase("1.0.0")]
367 [TestCase("+1")]
368 [TestCase("00")]
Jon Skeetaa431a02016-01-05 09:25:32 +0000369 [TestCase("01")]
370 [TestCase("-00")]
371 [TestCase("-01")]
Jon Skeetfb248822015-09-04 12:41:14 +0100372 [TestCase("--1")]
Jon Skeetaa431a02016-01-05 09:25:32 +0000373 [TestCase(" Infinity")]
374 [TestCase(" -Infinity")]
375 [TestCase("NaN ")]
376 [TestCase("Infinity ")]
377 [TestCase("-Infinity ")]
378 [TestCase(" NaN")]
379 [TestCase("INFINITY")]
380 [TestCase("nan")]
Jon Skeetfb248822015-09-04 12:41:14 +0100381 [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
382 public void StringToDouble_Invalid(string jsonValue)
383 {
384 string json = "{ \"singleDouble\": \"" + jsonValue + "\"}";
385 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
386 }
387
388 [Test]
389 [TestCase("0", 0f)]
390 [TestCase("1", 1f)]
391 [TestCase("1.000000", 1f)]
392 [TestCase("-1", -1f)]
393 [TestCase("3.402823e38", 3.402823e38f)]
394 [TestCase("-3.402823e38", -3.402823e38f)]
395 [TestCase("1.5e1", 15f)]
396 [TestCase("15e-1", 1.5f)]
397 public void StringToFloat_Valid(string jsonValue, float expectedParsedValue)
398 {
399 string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
400 var parsed = TestAllTypes.Parser.ParseJson(json);
401 Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
402 }
403
404 [Test]
405 [TestCase("3.402824e38")]
406 [TestCase("-3.402824e38")]
407 [TestCase("1,0")]
408 [TestCase("1.0.0")]
409 [TestCase("+1")]
410 [TestCase("00")]
411 [TestCase("--1")]
412 public void StringToFloat_Invalid(string jsonValue)
413 {
414 string json = "{ \"singleFloat\": \"" + jsonValue + "\"}";
415 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
416 }
417
418 [Test]
419 [TestCase("0", 0)]
420 [TestCase("-0", 0)] // Not entirely clear whether we intend to allow this...
421 [TestCase("1", 1)]
422 [TestCase("-1", -1)]
423 [TestCase("2147483647", 2147483647)]
424 [TestCase("-2147483648", -2147483648)]
Jon Skeetaa431a02016-01-05 09:25:32 +0000425 [TestCase("1e1", 10)]
426 [TestCase("-1e1", -10)]
427 [TestCase("10.00", 10)]
428 [TestCase("-10.00", -10)]
Jon Skeetfb248822015-09-04 12:41:14 +0100429 public void NumberToInt32_Valid(string jsonValue, int expectedParsedValue)
430 {
431 string json = "{ \"singleInt32\": " + jsonValue + "}";
432 var parsed = TestAllTypes.Parser.ParseJson(json);
433 Assert.AreEqual(expectedParsedValue, parsed.SingleInt32);
434 }
435
436 [Test]
Jon Skeet0fb39c42015-11-04 11:49:15 +0000437 [TestCase("+0", typeof(InvalidJsonException))]
438 [TestCase("00", typeof(InvalidJsonException))]
439 [TestCase("-00", typeof(InvalidJsonException))]
440 [TestCase("--1", typeof(InvalidJsonException))]
441 [TestCase("+1", typeof(InvalidJsonException))]
Jon Skeetaa431a02016-01-05 09:25:32 +0000442 [TestCase("1.5", typeof(InvalidProtocolBufferException))]
443 // Value is out of range
Jon Skeet0fb39c42015-11-04 11:49:15 +0000444 [TestCase("1e10", typeof(InvalidProtocolBufferException))]
445 [TestCase("2147483648", typeof(InvalidProtocolBufferException))]
446 [TestCase("-2147483649", typeof(InvalidProtocolBufferException))]
447 public void NumberToInt32_Invalid(string jsonValue, System.Type expectedExceptionType)
Jon Skeetfb248822015-09-04 12:41:14 +0100448 {
449 string json = "{ \"singleInt32\": " + jsonValue + "}";
Jon Skeet0fb39c42015-11-04 11:49:15 +0000450 Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
Jon Skeetfb248822015-09-04 12:41:14 +0100451 }
452
453 [Test]
454 [TestCase("0", 0U)]
455 [TestCase("1", 1U)]
456 [TestCase("4294967295", 4294967295U)]
457 public void NumberToUInt32_Valid(string jsonValue, uint expectedParsedValue)
458 {
459 string json = "{ \"singleUint32\": " + jsonValue + "}";
460 var parsed = TestAllTypes.Parser.ParseJson(json);
461 Assert.AreEqual(expectedParsedValue, parsed.SingleUint32);
462 }
463
464 // Assume that anything non-bounds-related is covered in the Int32 case
465 [Test]
466 [TestCase("-1")]
467 [TestCase("4294967296")]
468 public void NumberToUInt32_Invalid(string jsonValue)
469 {
470 string json = "{ \"singleUint32\": " + jsonValue + "}";
471 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
472 }
473
474 [Test]
475 [TestCase("0", 0L)]
476 [TestCase("1", 1L)]
477 [TestCase("-1", -1L)]
Jon Skeetaa431a02016-01-05 09:25:32 +0000478 // long.MaxValue isn't actually representable as a double. This string value is the highest
479 // representable value which isn't greater than long.MaxValue.
Jon Skeet3878d842016-01-21 10:49:57 +0000480 [TestCase("9223372036854774784", 9223372036854774784)]
Jon Skeetaa431a02016-01-05 09:25:32 +0000481 [TestCase("-9223372036854775808", -9223372036854775808)]
Jon Skeetfb248822015-09-04 12:41:14 +0100482 public void NumberToInt64_Valid(string jsonValue, long expectedParsedValue)
483 {
484 string json = "{ \"singleInt64\": " + jsonValue + "}";
485 var parsed = TestAllTypes.Parser.ParseJson(json);
486 Assert.AreEqual(expectedParsedValue, parsed.SingleInt64);
487 }
488
489 // Assume that anything non-bounds-related is covered in the Int32 case
490 [Test]
Jon Skeetaa431a02016-01-05 09:25:32 +0000491 [TestCase("9223372036854775808")]
492 // Theoretical bound would be -9223372036854775809, but when that is parsed to a double
493 // we end up with the exact value of long.MinValue due to lack of precision. The value here
494 // is the "next double down".
495 [TestCase("-9223372036854780000")]
Jon Skeetfb248822015-09-04 12:41:14 +0100496 public void NumberToInt64_Invalid(string jsonValue)
497 {
498 string json = "{ \"singleInt64\": " + jsonValue + "}";
499 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
500 }
501
502 [Test]
503 [TestCase("0", 0UL)]
504 [TestCase("1", 1UL)]
Jon Skeetaa431a02016-01-05 09:25:32 +0000505 // ulong.MaxValue isn't representable as a double. This value is the largest double within
506 // the range of ulong.
Jon Skeet3878d842016-01-21 10:49:57 +0000507 [TestCase("18446744073709549568", 18446744073709549568UL)]
Jon Skeetfb248822015-09-04 12:41:14 +0100508 public void NumberToUInt64_Valid(string jsonValue, ulong expectedParsedValue)
509 {
510 string json = "{ \"singleUint64\": " + jsonValue + "}";
511 var parsed = TestAllTypes.Parser.ParseJson(json);
512 Assert.AreEqual(expectedParsedValue, parsed.SingleUint64);
513 }
514
515 // Assume that anything non-bounds-related is covered in the Int32 case
516 [Test]
517 [TestCase("-1")]
518 [TestCase("18446744073709551616")]
519 public void NumberToUInt64_Invalid(string jsonValue)
520 {
521 string json = "{ \"singleUint64\": " + jsonValue + "}";
522 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
523 }
524
525 [Test]
526 [TestCase("0", 0d)]
527 [TestCase("1", 1d)]
528 [TestCase("1.000000", 1d)]
529 [TestCase("1.0000000000000000000000001", 1d)] // We don't notice that we haven't preserved the exact value
530 [TestCase("-1", -1d)]
531 [TestCase("1e1", 10d)]
532 [TestCase("1e01", 10d)] // Leading decimals are allowed in exponents
533 [TestCase("1E1", 10d)] // Either case is fine
534 [TestCase("-1e1", -10d)]
535 [TestCase("1.5e1", 15d)]
536 [TestCase("-1.5e1", -15d)]
537 [TestCase("15e-1", 1.5d)]
538 [TestCase("-15e-1", -1.5d)]
539 [TestCase("1.79769e308", 1.79769e308)]
540 [TestCase("-1.79769e308", -1.79769e308)]
541 public void NumberToDouble_Valid(string jsonValue, double expectedParsedValue)
542 {
543 string json = "{ \"singleDouble\": " + jsonValue + "}";
544 var parsed = TestAllTypes.Parser.ParseJson(json);
545 Assert.AreEqual(expectedParsedValue, parsed.SingleDouble);
546 }
547
548 [Test]
Jon Skeetaa431a02016-01-05 09:25:32 +0000549 [TestCase("1.7977e308")]
550 [TestCase("-1.7977e308")]
551 [TestCase("1e309")]
Jon Skeetfb248822015-09-04 12:41:14 +0100552 [TestCase("1,0")]
553 [TestCase("1.0.0")]
554 [TestCase("+1")]
555 [TestCase("00")]
556 [TestCase("--1")]
557 [TestCase("\u00BD")] // 1/2 as a single Unicode character. Just sanity checking...
558 public void NumberToDouble_Invalid(string jsonValue)
559 {
560 string json = "{ \"singleDouble\": " + jsonValue + "}";
Jon Skeet0fb39c42015-11-04 11:49:15 +0000561 Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
Jon Skeetfb248822015-09-04 12:41:14 +0100562 }
563
564 [Test]
565 [TestCase("0", 0f)]
566 [TestCase("1", 1f)]
567 [TestCase("1.000000", 1f)]
568 [TestCase("-1", -1f)]
569 [TestCase("3.402823e38", 3.402823e38f)]
570 [TestCase("-3.402823e38", -3.402823e38f)]
571 [TestCase("1.5e1", 15f)]
572 [TestCase("15e-1", 1.5f)]
573 public void NumberToFloat_Valid(string jsonValue, float expectedParsedValue)
574 {
575 string json = "{ \"singleFloat\": " + jsonValue + "}";
576 var parsed = TestAllTypes.Parser.ParseJson(json);
577 Assert.AreEqual(expectedParsedValue, parsed.SingleFloat);
578 }
579
580 [Test]
Jon Skeet0fb39c42015-11-04 11:49:15 +0000581 [TestCase("3.402824e38", typeof(InvalidProtocolBufferException))]
582 [TestCase("-3.402824e38", typeof(InvalidProtocolBufferException))]
583 [TestCase("1,0", typeof(InvalidJsonException))]
584 [TestCase("1.0.0", typeof(InvalidJsonException))]
585 [TestCase("+1", typeof(InvalidJsonException))]
586 [TestCase("00", typeof(InvalidJsonException))]
587 [TestCase("--1", typeof(InvalidJsonException))]
588 public void NumberToFloat_Invalid(string jsonValue, System.Type expectedExceptionType)
Jon Skeetfb248822015-09-04 12:41:14 +0100589 {
590 string json = "{ \"singleFloat\": " + jsonValue + "}";
Jon Skeet0fb39c42015-11-04 11:49:15 +0000591 Assert.Throws(expectedExceptionType, () => TestAllTypes.Parser.ParseJson(json));
Jon Skeetfb248822015-09-04 12:41:14 +0100592 }
593
594 // The simplest way of testing that the value has parsed correctly is to reformat it,
595 // as we trust the formatting. In many cases that will give the same result as the input,
596 // so in those cases we accept an expectedFormatted value of null. Sometimes the results
597 // will be different though, due to a different number of digits being provided.
598 [Test]
599 // Z offset
600 [TestCase("2015-10-09T14:46:23.123456789Z", null)]
601 [TestCase("2015-10-09T14:46:23.123456Z", null)]
602 [TestCase("2015-10-09T14:46:23.123Z", null)]
603 [TestCase("2015-10-09T14:46:23Z", null)]
604 [TestCase("2015-10-09T14:46:23.123456000Z", "2015-10-09T14:46:23.123456Z")]
605 [TestCase("2015-10-09T14:46:23.1234560Z", "2015-10-09T14:46:23.123456Z")]
606 [TestCase("2015-10-09T14:46:23.123000000Z", "2015-10-09T14:46:23.123Z")]
607 [TestCase("2015-10-09T14:46:23.1230Z", "2015-10-09T14:46:23.123Z")]
608 [TestCase("2015-10-09T14:46:23.00Z", "2015-10-09T14:46:23Z")]
609
610 // +00:00 offset
611 [TestCase("2015-10-09T14:46:23.123456789+00:00", "2015-10-09T14:46:23.123456789Z")]
612 [TestCase("2015-10-09T14:46:23.123456+00:00", "2015-10-09T14:46:23.123456Z")]
613 [TestCase("2015-10-09T14:46:23.123+00:00", "2015-10-09T14:46:23.123Z")]
614 [TestCase("2015-10-09T14:46:23+00:00", "2015-10-09T14:46:23Z")]
615 [TestCase("2015-10-09T14:46:23.123456000+00:00", "2015-10-09T14:46:23.123456Z")]
616 [TestCase("2015-10-09T14:46:23.1234560+00:00", "2015-10-09T14:46:23.123456Z")]
617 [TestCase("2015-10-09T14:46:23.123000000+00:00", "2015-10-09T14:46:23.123Z")]
618 [TestCase("2015-10-09T14:46:23.1230+00:00", "2015-10-09T14:46:23.123Z")]
619 [TestCase("2015-10-09T14:46:23.00+00:00", "2015-10-09T14:46:23Z")]
620
621 // Other offsets (assume by now that the subsecond handling is okay)
622 [TestCase("2015-10-09T15:46:23.123456789+01:00", "2015-10-09T14:46:23.123456789Z")]
623 [TestCase("2015-10-09T13:46:23.123456789-01:00", "2015-10-09T14:46:23.123456789Z")]
624 [TestCase("2015-10-09T15:16:23.123456789+00:30", "2015-10-09T14:46:23.123456789Z")]
625 [TestCase("2015-10-09T14:16:23.123456789-00:30", "2015-10-09T14:46:23.123456789Z")]
626 [TestCase("2015-10-09T16:31:23.123456789+01:45", "2015-10-09T14:46:23.123456789Z")]
627 [TestCase("2015-10-09T13:01:23.123456789-01:45", "2015-10-09T14:46:23.123456789Z")]
628 [TestCase("2015-10-10T08:46:23.123456789+18:00", "2015-10-09T14:46:23.123456789Z")]
629 [TestCase("2015-10-08T20:46:23.123456789-18:00", "2015-10-09T14:46:23.123456789Z")]
630
631 // Leap years and min/max
632 [TestCase("2016-02-29T14:46:23.123456789Z", null)]
633 [TestCase("2000-02-29T14:46:23.123456789Z", null)]
634 [TestCase("0001-01-01T00:00:00Z", null)]
635 [TestCase("9999-12-31T23:59:59.999999999Z", null)]
636 public void Timestamp_Valid(string jsonValue, string expectedFormatted)
637 {
638 expectedFormatted = expectedFormatted ?? jsonValue;
Jon Skeetb4a58172016-01-06 12:05:31 +0000639 string json = WrapInQuotes(jsonValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100640 var parsed = Timestamp.Parser.ParseJson(json);
Jon Skeetb4a58172016-01-06 12:05:31 +0000641 Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
Jon Skeetfb248822015-09-04 12:41:14 +0100642 }
643
644 [Test]
645 [TestCase("2015-10-09 14:46:23.123456789Z", Description = "No T between date and time")]
646 [TestCase("2015/10/09T14:46:23.123456789Z", Description = "Wrong date separators")]
647 [TestCase("2015-10-09T14.46.23.123456789Z", Description = "Wrong time separators")]
648 [TestCase("2015-10-09T14:46:23,123456789Z", Description = "Wrong fractional second separators (valid ISO-8601 though)")]
649 [TestCase(" 2015-10-09T14:46:23.123456789Z", Description = "Whitespace at start")]
650 [TestCase("2015-10-09T14:46:23.123456789Z ", Description = "Whitespace at end")]
651 [TestCase("2015-10-09T14:46:23.1234567890", Description = "Too many digits")]
652 [TestCase("2015-10-09T14:46:23.123456789", Description = "No offset")]
653 [TestCase("2015-13-09T14:46:23.123456789Z", Description = "Invalid month")]
654 [TestCase("2015-10-32T14:46:23.123456789Z", Description = "Invalid day")]
655 [TestCase("2015-10-09T24:00:00.000000000Z", Description = "Invalid hour (valid ISO-8601 though)")]
656 [TestCase("2015-10-09T14:60:23.123456789Z", Description = "Invalid minutes")]
657 [TestCase("2015-10-09T14:46:60.123456789Z", Description = "Invalid seconds")]
658 [TestCase("2015-10-09T14:46:23.123456789+18:01", Description = "Offset too large (positive)")]
659 [TestCase("2015-10-09T14:46:23.123456789-18:01", Description = "Offset too large (negative)")]
660 [TestCase("2015-10-09T14:46:23.123456789-00:00", Description = "Local offset (-00:00) makes no sense here")]
661 [TestCase("0001-01-01T00:00:00+00:01", Description = "Value before earliest when offset applied")]
662 [TestCase("9999-12-31T23:59:59.999999999-00:01", Description = "Value after latest when offset applied")]
663 [TestCase("2100-02-29T14:46:23.123456789Z", Description = "Feb 29th on a non-leap-year")]
664 public void Timestamp_Invalid(string jsonValue)
665 {
Jon Skeetb4a58172016-01-06 12:05:31 +0000666 string json = WrapInQuotes(jsonValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100667 Assert.Throws<InvalidProtocolBufferException>(() => Timestamp.Parser.ParseJson(json));
668 }
669
670 [Test]
671 public void StructValue_Null()
672 {
673 Assert.AreEqual(new Value { NullValue = 0 }, Value.Parser.ParseJson("null"));
674 }
675
676 [Test]
677 public void StructValue_String()
678 {
679 Assert.AreEqual(new Value { StringValue = "hi" }, Value.Parser.ParseJson("\"hi\""));
680 }
681
682 [Test]
683 public void StructValue_Bool()
684 {
685 Assert.AreEqual(new Value { BoolValue = true }, Value.Parser.ParseJson("true"));
686 Assert.AreEqual(new Value { BoolValue = false }, Value.Parser.ParseJson("false"));
687 }
688
689 [Test]
690 public void StructValue_List()
691 {
692 Assert.AreEqual(Value.ForList(Value.ForNumber(1), Value.ForString("x")), Value.Parser.ParseJson("[1, \"x\"]"));
693 }
694
695 [Test]
696 public void ParseListValue()
697 {
698 Assert.AreEqual(new ListValue { Values = { Value.ForNumber(1), Value.ForString("x") } }, ListValue.Parser.ParseJson("[1, \"x\"]"));
699 }
700
701 [Test]
702 public void StructValue_Struct()
703 {
704 Assert.AreEqual(
705 Value.ForStruct(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } }),
706 Value.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
707 }
708
709 [Test]
710 public void ParseStruct()
711 {
712 Assert.AreEqual(new Struct { Fields = { { "x", Value.ForNumber(1) }, { "y", Value.ForString("z") } } },
713 Struct.Parser.ParseJson("{ \"x\": 1, \"y\": \"z\" }"));
714 }
715
716 // TODO for duration parsing: upper and lower bounds.
717 // +/- 315576000000 seconds
718
719 [Test]
720 [TestCase("1.123456789s", null)]
721 [TestCase("1.123456s", null)]
722 [TestCase("1.123s", null)]
723 [TestCase("1.12300s", "1.123s")]
724 [TestCase("1.12345s", "1.123450s")]
725 [TestCase("1s", null)]
726 [TestCase("-1.123456789s", null)]
727 [TestCase("-1.123456s", null)]
728 [TestCase("-1.123s", null)]
729 [TestCase("-1s", null)]
730 [TestCase("0.123s", null)]
731 [TestCase("-0.123s", null)]
732 [TestCase("123456.123s", null)]
733 [TestCase("-123456.123s", null)]
734 // Upper and lower bounds
735 [TestCase("315576000000s", null)]
736 [TestCase("-315576000000s", null)]
737 public void Duration_Valid(string jsonValue, string expectedFormatted)
738 {
739 expectedFormatted = expectedFormatted ?? jsonValue;
Jon Skeetb4a58172016-01-06 12:05:31 +0000740 string json = WrapInQuotes(jsonValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100741 var parsed = Duration.Parser.ParseJson(json);
Jon Skeetb4a58172016-01-06 12:05:31 +0000742 Assert.AreEqual(WrapInQuotes(expectedFormatted), parsed.ToString());
Jon Skeetfb248822015-09-04 12:41:14 +0100743 }
744
745 // The simplest way of testing that the value has parsed correctly is to reformat it,
746 // as we trust the formatting. In many cases that will give the same result as the input,
747 // so in those cases we accept an expectedFormatted value of null. Sometimes the results
748 // will be different though, due to a different number of digits being provided.
749 [Test]
750 [TestCase("1.1234567890s", Description = "Too many digits")]
751 [TestCase("1.123456789", Description = "No suffix")]
752 [TestCase("1.123456789ss", Description = "Too much suffix")]
753 [TestCase("1.123456789S", Description = "Upper case suffix")]
754 [TestCase("+1.123456789s", Description = "Leading +")]
755 [TestCase(".123456789s", Description = "No integer before the fraction")]
756 [TestCase("1,123456789s", Description = "Comma as decimal separator")]
757 [TestCase("1x1.123456789s", Description = "Non-digit in integer part")]
758 [TestCase("1.1x3456789s", Description = "Non-digit in fractional part")]
759 [TestCase(" 1.123456789s", Description = "Whitespace before fraction")]
760 [TestCase("1.123456789s ", Description = "Whitespace after value")]
761 [TestCase("01.123456789s", Description = "Leading zero (positive)")]
762 [TestCase("-01.123456789s", Description = "Leading zero (negative)")]
763 [TestCase("--0.123456789s", Description = "Double minus sign")]
764 // Violate upper/lower bounds in various ways
765 [TestCase("315576000001s", Description = "Integer part too large")]
Jon Skeetfb248822015-09-04 12:41:14 +0100766 [TestCase("3155760000000s", Description = "Integer part too long (positive)")]
767 [TestCase("-3155760000000s", Description = "Integer part too long (negative)")]
768 public void Duration_Invalid(string jsonValue)
769 {
Jon Skeetb4a58172016-01-06 12:05:31 +0000770 string json = WrapInQuotes(jsonValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100771 Assert.Throws<InvalidProtocolBufferException>(() => Duration.Parser.ParseJson(json));
772 }
773
774 // Not as many tests for field masks as I'd like; more to be added when we have more
775 // detailed specifications.
776
777 [Test]
778 [TestCase("")]
779 [TestCase("foo", "foo")]
780 [TestCase("foo,bar", "foo", "bar")]
781 [TestCase("foo.bar", "foo.bar")]
782 [TestCase("fooBar", "foo_bar")]
783 [TestCase("fooBar.bazQux", "foo_bar.baz_qux")]
784 public void FieldMask_Valid(string jsonValue, params string[] expectedPaths)
785 {
Jon Skeetb4a58172016-01-06 12:05:31 +0000786 string json = WrapInQuotes(jsonValue);
Jon Skeetfb248822015-09-04 12:41:14 +0100787 var parsed = FieldMask.Parser.ParseJson(json);
788 CollectionAssert.AreEqual(expectedPaths, parsed.Paths);
789 }
790
791 [Test]
Jon Skeetf437b672016-01-15 12:02:07 +0000792 [TestCase("foo_bar")]
793 public void FieldMask_Invalid(string jsonValue)
794 {
795 string json = WrapInQuotes(jsonValue);
796 Assert.Throws<InvalidProtocolBufferException>(() => FieldMask.Parser.ParseJson(json));
797 }
798
799 [Test]
Jon Skeet3de2fce2015-11-23 16:21:47 +0000800 public void Any_RegularMessage()
801 {
802 var registry = TypeRegistry.FromMessages(TestAllTypes.Descriptor);
803 var formatter = new JsonFormatter(new JsonFormatter.Settings(false, TypeRegistry.FromMessages(TestAllTypes.Descriptor)));
804 var message = new TestAllTypes { SingleInt32 = 10, SingleNestedMessage = new TestAllTypes.Types.NestedMessage { Bb = 20 } };
805 var original = Any.Pack(message);
806 var json = formatter.Format(original); // This is tested in JsonFormatterTest
807 var parser = new JsonParser(new JsonParser.Settings(10, registry));
808 Assert.AreEqual(original, parser.Parse<Any>(json));
809 string valueFirstJson = "{ \"singleInt32\": 10, \"singleNestedMessage\": { \"bb\": 20 }, \"@type\": \"type.googleapis.com/protobuf_unittest.TestAllTypes\" }";
810 Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
811 }
812
813 [Test]
814 public void Any_UnknownType()
815 {
816 string json = "{ \"@type\": \"type.googleapis.com/bogus\" }";
817 Assert.Throws<InvalidOperationException>(() => Any.Parser.ParseJson(json));
818 }
819
820 [Test]
Jon Skeetf2fe50b2016-01-13 14:05:06 +0000821 public void Any_NoTypeUrl()
822 {
823 string json = "{ \"foo\": \"bar\" }";
824 Assert.Throws<InvalidProtocolBufferException>(() => Any.Parser.ParseJson(json));
825 }
826
827 [Test]
Jon Skeet3de2fce2015-11-23 16:21:47 +0000828 public void Any_WellKnownType()
829 {
830 var registry = TypeRegistry.FromMessages(Timestamp.Descriptor);
831 var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
832 var timestamp = new DateTime(1673, 6, 19, 12, 34, 56, DateTimeKind.Utc).ToTimestamp();
833 var original = Any.Pack(timestamp);
834 var json = formatter.Format(original); // This is tested in JsonFormatterTest
835 var parser = new JsonParser(new JsonParser.Settings(10, registry));
836 Assert.AreEqual(original, parser.Parse<Any>(json));
837 string valueFirstJson = "{ \"value\": \"1673-06-19T12:34:56Z\", \"@type\": \"type.googleapis.com/google.protobuf.Timestamp\" }";
838 Assert.AreEqual(original, parser.Parse<Any>(valueFirstJson));
839 }
840
841 [Test]
842 public void Any_Nested()
843 {
844 var registry = TypeRegistry.FromMessages(TestWellKnownTypes.Descriptor, TestAllTypes.Descriptor);
845 var formatter = new JsonFormatter(new JsonFormatter.Settings(false, registry));
846 var parser = new JsonParser(new JsonParser.Settings(10, registry));
847 var doubleNestedMessage = new TestAllTypes { SingleInt32 = 20 };
848 var nestedMessage = Any.Pack(doubleNestedMessage);
849 var message = new TestWellKnownTypes { AnyField = Any.Pack(nestedMessage) };
850 var json = formatter.Format(message);
851 // Use the descriptor-based parser just for a change.
852 Assert.AreEqual(message, parser.Parse(json, TestWellKnownTypes.Descriptor));
853 }
854
855 [Test]
Jon Skeetfb248822015-09-04 12:41:14 +0100856 public void DataAfterObject()
857 {
858 string json = "{} 10";
Jon Skeet0fb39c42015-11-04 11:49:15 +0000859 Assert.Throws<InvalidJsonException>(() => TestAllTypes.Parser.ParseJson(json));
Jon Skeetfb248822015-09-04 12:41:14 +0100860 }
Jon Skeet3d257a92015-11-04 09:28:28 +0000861
862 /// <summary>
863 /// JSON equivalent to <see cref="CodedInputStreamTest.MaliciousRecursion"/>
864 /// </summary>
865 [Test]
866 public void MaliciousRecursion()
867 {
868 string data64 = CodedInputStreamTest.MakeRecursiveMessage(64).ToString();
869 string data65 = CodedInputStreamTest.MakeRecursiveMessage(65).ToString();
870
871 var parser64 = new JsonParser(new JsonParser.Settings(64));
872 CodedInputStreamTest.AssertMessageDepth(parser64.Parse<TestRecursiveMessage>(data64), 64);
873 Assert.Throws<InvalidProtocolBufferException>(() => parser64.Parse<TestRecursiveMessage>(data65));
874
875 var parser63 = new JsonParser(new JsonParser.Settings(63));
876 Assert.Throws<InvalidProtocolBufferException>(() => parser63.Parse<TestRecursiveMessage>(data64));
Jon Skeetb4a58172016-01-06 12:05:31 +0000877 }
Jon Skeet3d257a92015-11-04 09:28:28 +0000878
Jon Skeet730c38a2016-01-15 10:41:56 +0000879 [Test]
Jon Skeet1a34ac02016-01-15 10:43:06 +0000880 [TestCase("AQI")]
881 [TestCase("_-==")]
882 public void Bytes_InvalidBase64(string badBase64)
883 {
884 string json = "{ \"singleBytes\": \"" + badBase64 + "\" }";
885 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
886 }
887
888 [Test]
Jon Skeet52db5132016-01-15 13:45:53 +0000889 [TestCase("\"FOREIGN_BAR\"", ForeignEnum.FOREIGN_BAR)]
890 [TestCase("5", ForeignEnum.FOREIGN_BAR)]
891 [TestCase("100", (ForeignEnum) 100)]
892 public void EnumValid(string value, ForeignEnum expectedValue)
Jon Skeet730c38a2016-01-15 10:41:56 +0000893 {
894 string json = "{ \"singleForeignEnum\": " + value + " }";
895 var parsed = TestAllTypes.Parser.ParseJson(json);
Jon Skeet52db5132016-01-15 13:45:53 +0000896 Assert.AreEqual(new TestAllTypes { SingleForeignEnum = expectedValue }, parsed);
Jon Skeet730c38a2016-01-15 10:41:56 +0000897 }
898
899 [Test]
900 [TestCase("\"NOT_A_VALID_VALUE\"")]
Jon Skeet730c38a2016-01-15 10:41:56 +0000901 [TestCase("5.5")]
902 public void Enum_Invalid(string value)
903 {
904 string json = "{ \"singleForeignEnum\": " + value + " }";
905 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
906 }
907
Jon Skeet8866d6a2016-01-15 13:54:17 +0000908 [Test]
909 public void OneofDuplicate_Invalid()
910 {
911 string json = "{ \"oneofString\": \"x\", \"oneofUint32\": 10 }";
912 Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseJson(json));
913 }
914
Jon Skeetb4a58172016-01-06 12:05:31 +0000915 /// <summary>
916 /// Various tests use strings which have quotes round them for parsing or as the result
917 /// of formatting, but without those quotes being specified in the tests (for the sake of readability).
918 /// This method simply returns the input, wrapped in double quotes.
919 /// </summary>
920 internal static string WrapInQuotes(string text)
921 {
922 return '"' + text + '"';
Jon Skeet3d257a92015-11-04 09:28:28 +0000923 }
Jon Skeetfb248822015-09-04 12:41:14 +0100924 }
925}