1 #region License 2 // Copyright (c) 2007 James Newton-King 3 // 4 // Permission is hereby granted, free of charge, to any person 5 // obtaining a copy of this software and associated documentation 6 // files (the "Software"), to deal in the Software without 7 // restriction, including without limitation the rights to use, 8 // copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the 10 // Software is furnished to do so, subject to the following 11 // conditions: 12 // 13 // The above copyright notice and this permission notice shall be 14 // included in all copies or substantial portions of the Software. 15 // 16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 18 // OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 20 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 21 // WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 22 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 // OTHER DEALINGS IN THE SOFTWARE. 24 #endregion 25 26 using System; 27 using System.Collections.Generic; 28 using System.Globalization; 29 using System.IO; 30 using Newtonsoft.Json.Schema; 31 #if !(NET20 || NET35 || PORTABLE40 || PORTABLE) 32 using System.Numerics; 33 #endif 34 using System.Runtime.Serialization; 35 using System.Text; 36 #if !(NET20 || NET35) 37 using System.Threading.Tasks; 38 #endif 39 using System.Xml; 40 using Newtonsoft.Json.Converters; 41 using Newtonsoft.Json.Linq; 42 using Newtonsoft.Json.Serialization; 43 using Newtonsoft.Json.Tests.Serialization; 44 using Newtonsoft.Json.Tests.TestObjects; 45 using Newtonsoft.Json.Utilities; 46 #if NETFX_CORE 47 using Microsoft.VisualStudio.TestPlatform.UnitTestFramework; 48 using TestFixture = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestClassAttribute; 49 using Test = Microsoft.VisualStudio.TestPlatform.UnitTestFramework.TestMethodAttribute; 50 #elif DNXCORE50 51 using Xunit; 52 using Test = Xunit.FactAttribute; 53 using Assert = Newtonsoft.Json.Tests.XUnitAssert; 54 #else 55 using NUnit.Framework; 56 57 #endif 58 59 namespace Newtonsoft.Json.Tests 60 { 61 [TestFixture] 62 public class JsonConvertTest : TestFixtureBase 63 { 64 [Test] ToStringEnsureEscapedArrayLength()65 public void ToStringEnsureEscapedArrayLength() 66 { 67 const char nonAsciiChar = (char)257; 68 const char escapableNonQuoteAsciiChar = '\0'; 69 70 string value = nonAsciiChar + @"\" + escapableNonQuoteAsciiChar; 71 72 string convertedValue = JsonConvert.ToString((object)value); 73 Assert.AreEqual(@"""" + nonAsciiChar + @"\\\u0000""", convertedValue); 74 } 75 76 public class PopulateTestObject 77 { 78 public decimal Prop { get; set; } 79 } 80 81 [Test] PopulateObjectWithHeaderComment()82 public void PopulateObjectWithHeaderComment() 83 { 84 string json = @"// file header 85 { 86 ""prop"": 1.0 87 }"; 88 89 PopulateTestObject o = new PopulateTestObject(); 90 JsonConvert.PopulateObject(json, o); 91 92 Assert.AreEqual(1m, o.Prop); 93 } 94 95 [Test] PopulateObjectWithMultipleHeaderComment()96 public void PopulateObjectWithMultipleHeaderComment() 97 { 98 string json = @"// file header 99 // another file header? 100 { 101 ""prop"": 1.0 102 }"; 103 104 PopulateTestObject o = new PopulateTestObject(); 105 JsonConvert.PopulateObject(json, o); 106 107 Assert.AreEqual(1m, o.Prop); 108 } 109 110 [Test] PopulateObjectWithNoContent()111 public void PopulateObjectWithNoContent() 112 { 113 ExceptionAssert.Throws<JsonSerializationException>(() => 114 { 115 string json = @""; 116 117 PopulateTestObject o = new PopulateTestObject(); 118 JsonConvert.PopulateObject(json, o); 119 }, "No JSON content found. Path '', line 0, position 0."); 120 } 121 122 [Test] PopulateObjectWithOnlyComment()123 public void PopulateObjectWithOnlyComment() 124 { 125 ExceptionAssert.Throws<JsonSerializationException>(() => 126 { 127 string json = @"// file header"; 128 129 PopulateTestObject o = new PopulateTestObject(); 130 JsonConvert.PopulateObject(json, o); 131 }, "No JSON content found. Path '', line 1, position 14."); 132 } 133 134 [Test] DefaultSettings()135 public void DefaultSettings() 136 { 137 try 138 { 139 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 140 { 141 Formatting = Formatting.Indented 142 }; 143 144 string json = JsonConvert.SerializeObject(new { test = new[] { 1, 2, 3 } }); 145 146 StringAssert.AreEqual(@"{ 147 ""test"": [ 148 1, 149 2, 150 3 151 ] 152 }", json); 153 } 154 finally 155 { 156 JsonConvert.DefaultSettings = null; 157 } 158 } 159 160 public class NameTableTestClass 161 { 162 public string Value { get; set; } 163 } 164 165 public class NameTableTestClassConverter : JsonConverter 166 { WriteJson(JsonWriter writer, object value, JsonSerializer serializer)167 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 168 { 169 throw new NotImplementedException(); 170 } 171 ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)172 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 173 { 174 reader.Read(); 175 reader.Read(); 176 177 JsonTextReader jsonTextReader = (JsonTextReader)reader; 178 Assert.IsNotNull(jsonTextReader.NameTable); 179 180 string s = serializer.Deserialize<string>(reader); 181 Assert.AreEqual("hi", s); 182 Assert.IsNotNull(jsonTextReader.NameTable); 183 184 NameTableTestClass o = new NameTableTestClass 185 { 186 Value = s 187 }; 188 189 return o; 190 } 191 CanConvert(Type objectType)192 public override bool CanConvert(Type objectType) 193 { 194 return objectType == typeof(NameTableTestClass); 195 } 196 } 197 198 [Test] NameTableTest()199 public void NameTableTest() 200 { 201 StringReader sr = new StringReader("{'property':'hi'}"); 202 JsonTextReader jsonTextReader = new JsonTextReader(sr); 203 204 Assert.IsNull(jsonTextReader.NameTable); 205 206 JsonSerializer serializer = new JsonSerializer(); 207 serializer.Converters.Add(new NameTableTestClassConverter()); 208 NameTableTestClass o = serializer.Deserialize<NameTableTestClass>(jsonTextReader); 209 210 Assert.IsNull(jsonTextReader.NameTable); 211 Assert.AreEqual("hi", o.Value); 212 } 213 214 [Test] DefaultSettings_Example()215 public void DefaultSettings_Example() 216 { 217 try 218 { 219 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 220 { 221 Formatting = Formatting.Indented, 222 ContractResolver = new CamelCasePropertyNamesContractResolver() 223 }; 224 225 Employee e = new Employee 226 { 227 FirstName = "Eric", 228 LastName = "Example", 229 BirthDate = new DateTime(1980, 4, 20, 0, 0, 0, DateTimeKind.Utc), 230 Department = "IT", 231 JobTitle = "Web Dude" 232 }; 233 234 string json = JsonConvert.SerializeObject(e); 235 // { 236 // "firstName": "Eric", 237 // "lastName": "Example", 238 // "birthDate": "1980-04-20T00:00:00Z", 239 // "department": "IT", 240 // "jobTitle": "Web Dude" 241 // } 242 243 StringAssert.AreEqual(@"{ 244 ""firstName"": ""Eric"", 245 ""lastName"": ""Example"", 246 ""birthDate"": ""1980-04-20T00:00:00Z"", 247 ""department"": ""IT"", 248 ""jobTitle"": ""Web Dude"" 249 }", json); 250 } 251 finally 252 { 253 JsonConvert.DefaultSettings = null; 254 } 255 } 256 257 [Test] DefaultSettings_Override()258 public void DefaultSettings_Override() 259 { 260 try 261 { 262 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 263 { 264 Formatting = Formatting.Indented 265 }; 266 267 string json = JsonConvert.SerializeObject(new { test = new[] { 1, 2, 3 } }, new JsonSerializerSettings 268 { 269 Formatting = Formatting.None 270 }); 271 272 Assert.AreEqual(@"{""test"":[1,2,3]}", json); 273 } 274 finally 275 { 276 JsonConvert.DefaultSettings = null; 277 } 278 } 279 280 [Test] DefaultSettings_Override_JsonConverterOrder()281 public void DefaultSettings_Override_JsonConverterOrder() 282 { 283 try 284 { 285 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 286 { 287 Formatting = Formatting.Indented, 288 Converters = { new IsoDateTimeConverter { DateTimeFormat = "yyyy" } } 289 }; 290 291 string json = JsonConvert.SerializeObject(new[] { new DateTime(2000, 12, 12, 4, 2, 4, DateTimeKind.Utc) }, new JsonSerializerSettings 292 { 293 Formatting = Formatting.None, 294 Converters = 295 { 296 // should take precedence 297 new JavaScriptDateTimeConverter(), 298 new IsoDateTimeConverter { DateTimeFormat = "dd" } 299 } 300 }); 301 302 Assert.AreEqual(@"[new Date(976593724000)]", json); 303 } 304 finally 305 { 306 JsonConvert.DefaultSettings = null; 307 } 308 } 309 310 [Test] DefaultSettings_Create()311 public void DefaultSettings_Create() 312 { 313 try 314 { 315 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 316 { 317 Formatting = Formatting.Indented 318 }; 319 320 IList<int> l = new List<int> { 1, 2, 3 }; 321 322 StringWriter sw = new StringWriter(); 323 JsonSerializer serializer = JsonSerializer.CreateDefault(); 324 serializer.Serialize(sw, l); 325 326 StringAssert.AreEqual(@"[ 327 1, 328 2, 329 3 330 ]", sw.ToString()); 331 332 sw = new StringWriter(); 333 serializer.Formatting = Formatting.None; 334 serializer.Serialize(sw, l); 335 336 Assert.AreEqual(@"[1,2,3]", sw.ToString()); 337 338 sw = new StringWriter(); 339 serializer = new JsonSerializer(); 340 serializer.Serialize(sw, l); 341 342 Assert.AreEqual(@"[1,2,3]", sw.ToString()); 343 344 sw = new StringWriter(); 345 serializer = JsonSerializer.Create(); 346 serializer.Serialize(sw, l); 347 348 Assert.AreEqual(@"[1,2,3]", sw.ToString()); 349 } 350 finally 351 { 352 JsonConvert.DefaultSettings = null; 353 } 354 } 355 356 [Test] DefaultSettings_CreateWithSettings()357 public void DefaultSettings_CreateWithSettings() 358 { 359 try 360 { 361 JsonConvert.DefaultSettings = () => new JsonSerializerSettings 362 { 363 Formatting = Formatting.Indented 364 }; 365 366 IList<int> l = new List<int> { 1, 2, 3 }; 367 368 StringWriter sw = new StringWriter(); 369 JsonSerializer serializer = JsonSerializer.CreateDefault(new JsonSerializerSettings 370 { 371 Converters = { new IntConverter() } 372 }); 373 serializer.Serialize(sw, l); 374 375 StringAssert.AreEqual(@"[ 376 2, 377 4, 378 6 379 ]", sw.ToString()); 380 381 sw = new StringWriter(); 382 serializer.Converters.Clear(); 383 serializer.Serialize(sw, l); 384 385 StringAssert.AreEqual(@"[ 386 1, 387 2, 388 3 389 ]", sw.ToString()); 390 391 sw = new StringWriter(); 392 serializer = JsonSerializer.Create(new JsonSerializerSettings { Formatting = Formatting.Indented }); 393 serializer.Serialize(sw, l); 394 395 StringAssert.AreEqual(@"[ 396 1, 397 2, 398 3 399 ]", sw.ToString()); 400 } 401 finally 402 { 403 JsonConvert.DefaultSettings = null; 404 } 405 } 406 407 public class IntConverter : JsonConverter 408 { WriteJson(JsonWriter writer, object value, JsonSerializer serializer)409 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 410 { 411 int i = (int)value; 412 writer.WriteValue(i * 2); 413 } 414 ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)415 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 416 { 417 throw new NotImplementedException(); 418 } 419 CanConvert(Type objectType)420 public override bool CanConvert(Type objectType) 421 { 422 return objectType == typeof(int); 423 } 424 } 425 426 [Test] DeserializeObject_EmptyString()427 public void DeserializeObject_EmptyString() 428 { 429 object result = JsonConvert.DeserializeObject(string.Empty); 430 Assert.IsNull(result); 431 } 432 433 [Test] DeserializeObject_Integer()434 public void DeserializeObject_Integer() 435 { 436 object result = JsonConvert.DeserializeObject("1"); 437 Assert.AreEqual(1L, result); 438 } 439 440 [Test] DeserializeObject_Integer_EmptyString()441 public void DeserializeObject_Integer_EmptyString() 442 { 443 int? value = JsonConvert.DeserializeObject<int?>(""); 444 Assert.IsNull(value); 445 } 446 447 [Test] DeserializeObject_Decimal_EmptyString()448 public void DeserializeObject_Decimal_EmptyString() 449 { 450 decimal? value = JsonConvert.DeserializeObject<decimal?>(""); 451 Assert.IsNull(value); 452 } 453 454 [Test] DeserializeObject_DateTime_EmptyString()455 public void DeserializeObject_DateTime_EmptyString() 456 { 457 DateTime? value = JsonConvert.DeserializeObject<DateTime?>(""); 458 Assert.IsNull(value); 459 } 460 461 [Test] EscapeJavaScriptString()462 public void EscapeJavaScriptString() 463 { 464 string result; 465 466 result = JavaScriptUtils.ToEscapedJavaScriptString("How now brown cow?", '"', true, StringEscapeHandling.Default); 467 Assert.AreEqual(@"""How now brown cow?""", result); 468 469 result = JavaScriptUtils.ToEscapedJavaScriptString("How now 'brown' cow?", '"', true, StringEscapeHandling.Default); 470 Assert.AreEqual(@"""How now 'brown' cow?""", result); 471 472 result = JavaScriptUtils.ToEscapedJavaScriptString("How now <brown> cow?", '"', true, StringEscapeHandling.Default); 473 Assert.AreEqual(@"""How now <brown> cow?""", result); 474 475 result = JavaScriptUtils.ToEscapedJavaScriptString("How \r\nnow brown cow?", '"', true, StringEscapeHandling.Default); 476 Assert.AreEqual(@"""How \r\nnow brown cow?""", result); 477 478 result = JavaScriptUtils.ToEscapedJavaScriptString("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007", '"', true, StringEscapeHandling.Default); 479 Assert.AreEqual(@"""\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007""", result); 480 481 result = 482 JavaScriptUtils.ToEscapedJavaScriptString("\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013", '"', true, StringEscapeHandling.Default); 483 Assert.AreEqual(@"""\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013""", result); 484 485 result = 486 JavaScriptUtils.ToEscapedJavaScriptString( 487 "\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f ", '"', true, StringEscapeHandling.Default); 488 Assert.AreEqual(@"""\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f """, result); 489 490 result = 491 JavaScriptUtils.ToEscapedJavaScriptString( 492 "!\"#$%&\u0027()*+,-./0123456789:;\u003c=\u003e?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]", '"', true, StringEscapeHandling.Default); 493 Assert.AreEqual(@"""!\""#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]""", result); 494 495 result = JavaScriptUtils.ToEscapedJavaScriptString("^_`abcdefghijklmnopqrstuvwxyz{|}~", '"', true, StringEscapeHandling.Default); 496 Assert.AreEqual(@"""^_`abcdefghijklmnopqrstuvwxyz{|}~""", result); 497 498 string data = 499 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&\u0027()*+,-./0123456789:;\u003c=\u003e?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; 500 string expected = 501 @"""\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\""#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"""; 502 503 result = JavaScriptUtils.ToEscapedJavaScriptString(data, '"', true, StringEscapeHandling.Default); 504 Assert.AreEqual(expected, result); 505 506 result = JavaScriptUtils.ToEscapedJavaScriptString("Fred's cat.", '\'', true, StringEscapeHandling.Default); 507 Assert.AreEqual(result, @"'Fred\'s cat.'"); 508 509 result = JavaScriptUtils.ToEscapedJavaScriptString(@"""How are you gentlemen?"" said Cats.", '"', true, StringEscapeHandling.Default); 510 Assert.AreEqual(result, @"""\""How are you gentlemen?\"" said Cats."""); 511 512 result = JavaScriptUtils.ToEscapedJavaScriptString(@"""How are' you gentlemen?"" said Cats.", '"', true, StringEscapeHandling.Default); 513 Assert.AreEqual(result, @"""\""How are' you gentlemen?\"" said Cats."""); 514 515 result = JavaScriptUtils.ToEscapedJavaScriptString(@"Fred's ""cat"".", '\'', true, StringEscapeHandling.Default); 516 Assert.AreEqual(result, @"'Fred\'s ""cat"".'"); 517 518 result = JavaScriptUtils.ToEscapedJavaScriptString("\u001farray\u003caddress", '"', true, StringEscapeHandling.Default); 519 Assert.AreEqual(result, @"""\u001farray<address"""); 520 } 521 522 [Test] EscapeJavaScriptString_UnicodeLinefeeds()523 public void EscapeJavaScriptString_UnicodeLinefeeds() 524 { 525 string result; 526 527 result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u0085' + "after", '"', true, StringEscapeHandling.Default); 528 Assert.AreEqual(@"""before\u0085after""", result); 529 530 result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u2028' + "after", '"', true, StringEscapeHandling.Default); 531 Assert.AreEqual(@"""before\u2028after""", result); 532 533 result = JavaScriptUtils.ToEscapedJavaScriptString("before" + '\u2029' + "after", '"', true, StringEscapeHandling.Default); 534 Assert.AreEqual(@"""before\u2029after""", result); 535 } 536 537 [Test] ToStringInvalid()538 public void ToStringInvalid() 539 { 540 ExceptionAssert.Throws<ArgumentException>(() => { JsonConvert.ToString(new Version(1, 0)); }, "Unsupported type: System.Version. Use the JsonSerializer class to get the object's JSON representation."); 541 } 542 543 [Test] GuidToString()544 public void GuidToString() 545 { 546 Guid guid = new Guid("BED7F4EA-1A96-11d2-8F08-00A0C9A6186D"); 547 string json = JsonConvert.ToString(guid); 548 Assert.AreEqual(@"""bed7f4ea-1a96-11d2-8f08-00a0c9a6186d""", json); 549 } 550 551 [Test] EnumToString()552 public void EnumToString() 553 { 554 string json = JsonConvert.ToString(StringComparison.CurrentCultureIgnoreCase); 555 Assert.AreEqual("1", json); 556 } 557 558 [Test] ObjectToString()559 public void ObjectToString() 560 { 561 object value; 562 563 value = 1; 564 Assert.AreEqual("1", JsonConvert.ToString(value)); 565 566 value = 1.1; 567 Assert.AreEqual("1.1", JsonConvert.ToString(value)); 568 569 value = 1.1m; 570 Assert.AreEqual("1.1", JsonConvert.ToString(value)); 571 572 value = (float)1.1; 573 Assert.AreEqual("1.1", JsonConvert.ToString(value)); 574 575 value = (short)1; 576 Assert.AreEqual("1", JsonConvert.ToString(value)); 577 578 value = (long)1; 579 Assert.AreEqual("1", JsonConvert.ToString(value)); 580 581 value = (byte)1; 582 Assert.AreEqual("1", JsonConvert.ToString(value)); 583 584 value = (uint)1; 585 Assert.AreEqual("1", JsonConvert.ToString(value)); 586 587 value = (ushort)1; 588 Assert.AreEqual("1", JsonConvert.ToString(value)); 589 590 value = (sbyte)1; 591 Assert.AreEqual("1", JsonConvert.ToString(value)); 592 593 value = (ulong)1; 594 Assert.AreEqual("1", JsonConvert.ToString(value)); 595 596 value = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); 597 Assert.AreEqual(@"""1970-01-01T00:00:00Z""", JsonConvert.ToString(value)); 598 599 value = new DateTime(DateTimeUtils.InitialJavaScriptDateTicks, DateTimeKind.Utc); 600 Assert.AreEqual(@"""\/Date(0)\/""", JsonConvert.ToString((DateTime)value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.RoundtripKind)); 601 602 #if !NET20 603 value = new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero); 604 Assert.AreEqual(@"""1970-01-01T00:00:00+00:00""", JsonConvert.ToString(value)); 605 606 value = new DateTimeOffset(DateTimeUtils.InitialJavaScriptDateTicks, TimeSpan.Zero); 607 Assert.AreEqual(@"""\/Date(0+0000)\/""", JsonConvert.ToString((DateTimeOffset)value, DateFormatHandling.MicrosoftDateFormat)); 608 #endif 609 610 value = null; 611 Assert.AreEqual("null", JsonConvert.ToString(value)); 612 613 #if !(NETFX_CORE || PORTABLE || DNXCORE50 || PORTABLE40) 614 value = DBNull.Value; 615 Assert.AreEqual("null", JsonConvert.ToString(value)); 616 #endif 617 618 value = "I am a string"; 619 Assert.AreEqual(@"""I am a string""", JsonConvert.ToString(value)); 620 621 value = true; 622 Assert.AreEqual("true", JsonConvert.ToString(value)); 623 624 value = 'c'; 625 Assert.AreEqual(@"""c""", JsonConvert.ToString(value)); 626 } 627 628 [Test] TestInvalidStrings()629 public void TestInvalidStrings() 630 { 631 ExceptionAssert.Throws<JsonReaderException>(() => 632 { 633 string orig = @"this is a string ""that has quotes"" "; 634 635 string serialized = JsonConvert.SerializeObject(orig); 636 637 // *** Make string invalid by stripping \" \" 638 serialized = serialized.Replace(@"\""", "\""); 639 640 JsonConvert.DeserializeObject<string>(serialized); 641 }, "Additional text encountered after finished reading JSON content: t. Path '', line 1, position 19."); 642 } 643 644 [Test] DeserializeValueObjects()645 public void DeserializeValueObjects() 646 { 647 int i = JsonConvert.DeserializeObject<int>("1"); 648 Assert.AreEqual(1, i); 649 650 #if !NET20 651 DateTimeOffset d = JsonConvert.DeserializeObject<DateTimeOffset>(@"""\/Date(-59011455539000+0000)\/"""); 652 Assert.AreEqual(new DateTimeOffset(new DateTime(100, 1, 1, 1, 1, 1, DateTimeKind.Utc)), d); 653 #endif 654 655 bool b = JsonConvert.DeserializeObject<bool>("true"); 656 Assert.AreEqual(true, b); 657 658 object n = JsonConvert.DeserializeObject<object>("null"); 659 Assert.AreEqual(null, n); 660 661 object u = JsonConvert.DeserializeObject<object>("undefined"); 662 Assert.AreEqual(null, u); 663 } 664 665 [Test] FloatToString()666 public void FloatToString() 667 { 668 Assert.AreEqual("1.1", JsonConvert.ToString(1.1)); 669 Assert.AreEqual("1.11", JsonConvert.ToString(1.11)); 670 Assert.AreEqual("1.111", JsonConvert.ToString(1.111)); 671 Assert.AreEqual("1.1111", JsonConvert.ToString(1.1111)); 672 Assert.AreEqual("1.11111", JsonConvert.ToString(1.11111)); 673 Assert.AreEqual("1.111111", JsonConvert.ToString(1.111111)); 674 Assert.AreEqual("1.0", JsonConvert.ToString(1.0)); 675 Assert.AreEqual("1.0", JsonConvert.ToString(1d)); 676 Assert.AreEqual("-1.0", JsonConvert.ToString(-1d)); 677 Assert.AreEqual("1.01", JsonConvert.ToString(1.01)); 678 Assert.AreEqual("1.001", JsonConvert.ToString(1.001)); 679 Assert.AreEqual(JsonConvert.PositiveInfinity, JsonConvert.ToString(Double.PositiveInfinity)); 680 Assert.AreEqual(JsonConvert.NegativeInfinity, JsonConvert.ToString(Double.NegativeInfinity)); 681 Assert.AreEqual(JsonConvert.NaN, JsonConvert.ToString(Double.NaN)); 682 } 683 684 [Test] DecimalToString()685 public void DecimalToString() 686 { 687 Assert.AreEqual("1.1", JsonConvert.ToString(1.1m)); 688 Assert.AreEqual("1.11", JsonConvert.ToString(1.11m)); 689 Assert.AreEqual("1.111", JsonConvert.ToString(1.111m)); 690 Assert.AreEqual("1.1111", JsonConvert.ToString(1.1111m)); 691 Assert.AreEqual("1.11111", JsonConvert.ToString(1.11111m)); 692 Assert.AreEqual("1.111111", JsonConvert.ToString(1.111111m)); 693 Assert.AreEqual("1.0", JsonConvert.ToString(1.0m)); 694 Assert.AreEqual("-1.0", JsonConvert.ToString(-1.0m)); 695 Assert.AreEqual("-1.0", JsonConvert.ToString(-1m)); 696 Assert.AreEqual("1.0", JsonConvert.ToString(1m)); 697 Assert.AreEqual("1.01", JsonConvert.ToString(1.01m)); 698 Assert.AreEqual("1.001", JsonConvert.ToString(1.001m)); 699 Assert.AreEqual("79228162514264337593543950335.0", JsonConvert.ToString(Decimal.MaxValue)); 700 Assert.AreEqual("-79228162514264337593543950335.0", JsonConvert.ToString(Decimal.MinValue)); 701 } 702 703 [Test] StringEscaping()704 public void StringEscaping() 705 { 706 string v = "It's a good day\r\n\"sunshine\""; 707 708 string json = JsonConvert.ToString(v); 709 Assert.AreEqual(@"""It's a good day\r\n\""sunshine\""""", json); 710 } 711 712 [Test] 713 public void ToStringStringEscapeHandling() 714 { 715 string v = "<b>hi " + '\u20AC' + "</b>"; 716 717 string json = JsonConvert.ToString(v, '"'); 718 Assert.AreEqual(@"""<b>hi " + '\u20AC' + @"</b>""", json); 719 720 json = JsonConvert.ToString(v, '"', StringEscapeHandling.EscapeHtml); 721 Assert.AreEqual(@"""\u003cb\u003ehi " + '\u20AC' + @"\u003c/b\u003e""", json); 722 723 json = JsonConvert.ToString(v, '"', StringEscapeHandling.EscapeNonAscii); 724 Assert.AreEqual(@"""<b>hi \u20ac</b>""", json); 725 } 726 727 [Test] WriteDateTime()728 public void WriteDateTime() 729 { 730 DateTimeResult result = null; 731 732 result = TestDateTime("DateTime Max", DateTime.MaxValue); 733 Assert.AreEqual("9999-12-31T23:59:59.9999999", result.IsoDateRoundtrip); 734 Assert.AreEqual("9999-12-31T23:59:59.9999999" + GetOffset(DateTime.MaxValue, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 735 Assert.AreEqual("9999-12-31T23:59:59.9999999", result.IsoDateUnspecified); 736 Assert.AreEqual("9999-12-31T23:59:59.9999999Z", result.IsoDateUtc); 737 Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateRoundtrip); 738 Assert.AreEqual(@"\/Date(253402300799999" + GetOffset(DateTime.MaxValue, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 739 Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateUnspecified); 740 Assert.AreEqual(@"\/Date(253402300799999)\/", result.MsDateUtc); 741 742 DateTime year2000local = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Local); 743 string localToUtcDate = year2000local.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); 744 745 result = TestDateTime("DateTime Local", year2000local); 746 Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000local, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); 747 Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000local, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 748 Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateUnspecified); 749 Assert.AreEqual(localToUtcDate, result.IsoDateUtc); 750 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); 751 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 752 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + GetOffset(year2000local, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 753 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000local) + @")\/", result.MsDateUtc); 754 755 DateTime millisecondsLocal = new DateTime(2000, 1, 1, 1, 1, 1, 999, DateTimeKind.Local); 756 localToUtcDate = millisecondsLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); 757 758 result = TestDateTime("DateTime Local with milliseconds", millisecondsLocal); 759 Assert.AreEqual("2000-01-01T01:01:01.999" + GetOffset(millisecondsLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); 760 Assert.AreEqual("2000-01-01T01:01:01.999" + GetOffset(millisecondsLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 761 Assert.AreEqual("2000-01-01T01:01:01.999", result.IsoDateUnspecified); 762 Assert.AreEqual(localToUtcDate, result.IsoDateUtc); 763 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); 764 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 765 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + GetOffset(millisecondsLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 766 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(millisecondsLocal) + @")\/", result.MsDateUtc); 767 768 DateTime ticksLocal = new DateTime(634663873826822481, DateTimeKind.Local); 769 localToUtcDate = ticksLocal.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.FFFFFFFK"); 770 771 result = TestDateTime("DateTime Local with ticks", ticksLocal); 772 Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateRoundtrip); 773 Assert.AreEqual("2012-03-03T16:03:02.6822481" + GetOffset(ticksLocal, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 774 Assert.AreEqual("2012-03-03T16:03:02.6822481", result.IsoDateUnspecified); 775 Assert.AreEqual(localToUtcDate, result.IsoDateUtc); 776 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); 777 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 778 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + GetOffset(ticksLocal, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 779 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(ticksLocal) + @")\/", result.MsDateUtc); 780 781 DateTime year2000Unspecified = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified); 782 783 result = TestDateTime("DateTime Unspecified", year2000Unspecified); 784 Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateRoundtrip); 785 Assert.AreEqual("2000-01-01T01:01:01" + GetOffset(year2000Unspecified, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 786 Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateUnspecified); 787 Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateUtc); 788 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateRoundtrip); 789 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 790 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified) + GetOffset(year2000Unspecified, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 791 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(year2000Unspecified.ToLocalTime()) + @")\/", result.MsDateUtc); 792 793 DateTime year2000Utc = new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Utc); 794 string utcTolocalDate = year2000Utc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss"); 795 796 result = TestDateTime("DateTime Utc", year2000Utc); 797 Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateRoundtrip); 798 Assert.AreEqual(utcTolocalDate + GetOffset(year2000Utc, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 799 Assert.AreEqual("2000-01-01T01:01:01", result.IsoDateUnspecified); 800 Assert.AreEqual("2000-01-01T01:01:01Z", result.IsoDateUtc); 801 Assert.AreEqual(@"\/Date(946688461000)\/", result.MsDateRoundtrip); 802 Assert.AreEqual(@"\/Date(946688461000" + GetOffset(year2000Utc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 803 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(year2000Utc, DateTimeKind.Unspecified)) + GetOffset(year2000Utc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 804 Assert.AreEqual(@"\/Date(946688461000)\/", result.MsDateUtc); 805 806 DateTime unixEpoc = new DateTime(621355968000000000, DateTimeKind.Utc); 807 utcTolocalDate = unixEpoc.ToLocalTime().ToString("yyyy-MM-ddTHH:mm:ss"); 808 809 result = TestDateTime("DateTime Unix Epoc", unixEpoc); 810 Assert.AreEqual("1970-01-01T00:00:00Z", result.IsoDateRoundtrip); 811 Assert.AreEqual(utcTolocalDate + GetOffset(unixEpoc, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 812 Assert.AreEqual("1970-01-01T00:00:00", result.IsoDateUnspecified); 813 Assert.AreEqual("1970-01-01T00:00:00Z", result.IsoDateUtc); 814 Assert.AreEqual(@"\/Date(0)\/", result.MsDateRoundtrip); 815 Assert.AreEqual(@"\/Date(0" + GetOffset(unixEpoc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 816 Assert.AreEqual(@"\/Date(" + DateTimeUtils.ConvertDateTimeToJavaScriptTicks(DateTime.SpecifyKind(unixEpoc, DateTimeKind.Unspecified)) + GetOffset(unixEpoc, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateUnspecified); 817 Assert.AreEqual(@"\/Date(0)\/", result.MsDateUtc); 818 819 result = TestDateTime("DateTime Min", DateTime.MinValue); 820 Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateRoundtrip); 821 Assert.AreEqual("0001-01-01T00:00:00" + GetOffset(DateTime.MinValue, DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 822 Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateUnspecified); 823 Assert.AreEqual("0001-01-01T00:00:00Z", result.IsoDateUtc); 824 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateRoundtrip); 825 Assert.AreEqual(@"\/Date(-62135596800000" + GetOffset(DateTime.MinValue, DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 826 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUnspecified); 827 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUtc); 828 829 result = TestDateTime("DateTime Default", default(DateTime)); 830 Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateRoundtrip); 831 Assert.AreEqual("0001-01-01T00:00:00" + GetOffset(default(DateTime), DateFormatHandling.IsoDateFormat), result.IsoDateLocal); 832 Assert.AreEqual("0001-01-01T00:00:00", result.IsoDateUnspecified); 833 Assert.AreEqual("0001-01-01T00:00:00Z", result.IsoDateUtc); 834 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateRoundtrip); 835 Assert.AreEqual(@"\/Date(-62135596800000" + GetOffset(default(DateTime), DateFormatHandling.MicrosoftDateFormat) + @")\/", result.MsDateLocal); 836 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUnspecified); 837 Assert.AreEqual(@"\/Date(-62135596800000)\/", result.MsDateUtc); 838 839 #if !NET20 840 result = TestDateTime("DateTimeOffset TimeSpan Zero", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.Zero)); 841 Assert.AreEqual("2000-01-01T01:01:01+00:00", result.IsoDateRoundtrip); 842 Assert.AreEqual(@"\/Date(946688461000+0000)\/", result.MsDateRoundtrip); 843 844 result = TestDateTime("DateTimeOffset TimeSpan 1 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(1))); 845 Assert.AreEqual("2000-01-01T01:01:01+01:00", result.IsoDateRoundtrip); 846 Assert.AreEqual(@"\/Date(946684861000+0100)\/", result.MsDateRoundtrip); 847 848 result = TestDateTime("DateTimeOffset TimeSpan 1.5 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(1.5))); 849 Assert.AreEqual("2000-01-01T01:01:01+01:30", result.IsoDateRoundtrip); 850 Assert.AreEqual(@"\/Date(946683061000+0130)\/", result.MsDateRoundtrip); 851 852 result = TestDateTime("DateTimeOffset TimeSpan 13 hour", new DateTimeOffset(2000, 1, 1, 1, 1, 1, TimeSpan.FromHours(13))); 853 Assert.AreEqual("2000-01-01T01:01:01+13:00", result.IsoDateRoundtrip); 854 Assert.AreEqual(@"\/Date(946641661000+1300)\/", result.MsDateRoundtrip); 855 856 result = TestDateTime("DateTimeOffset TimeSpan with ticks", new DateTimeOffset(634663873826822481, TimeSpan.Zero)); 857 Assert.AreEqual("2012-03-03T16:03:02.6822481+00:00", result.IsoDateRoundtrip); 858 Assert.AreEqual(@"\/Date(1330790582682+0000)\/", result.MsDateRoundtrip); 859 860 result = TestDateTime("DateTimeOffset Min", DateTimeOffset.MinValue); 861 Assert.AreEqual("0001-01-01T00:00:00+00:00", result.IsoDateRoundtrip); 862 Assert.AreEqual(@"\/Date(-62135596800000+0000)\/", result.MsDateRoundtrip); 863 864 result = TestDateTime("DateTimeOffset Max", DateTimeOffset.MaxValue); 865 Assert.AreEqual("9999-12-31T23:59:59.9999999+00:00", result.IsoDateRoundtrip); 866 Assert.AreEqual(@"\/Date(253402300799999+0000)\/", result.MsDateRoundtrip); 867 868 result = TestDateTime("DateTimeOffset Default", default(DateTimeOffset)); 869 Assert.AreEqual("0001-01-01T00:00:00+00:00", result.IsoDateRoundtrip); 870 Assert.AreEqual(@"\/Date(-62135596800000+0000)\/", result.MsDateRoundtrip); 871 #endif 872 } 873 874 public class DateTimeResult 875 { 876 public string IsoDateRoundtrip { get; set; } 877 public string IsoDateLocal { get; set; } 878 public string IsoDateUnspecified { get; set; } 879 public string IsoDateUtc { get; set; } 880 881 public string MsDateRoundtrip { get; set; } 882 public string MsDateLocal { get; set; } 883 public string MsDateUnspecified { get; set; } 884 public string MsDateUtc { get; set; } 885 } 886 TestDateTime(string name, T value)887 private DateTimeResult TestDateTime<T>(string name, T value) 888 { 889 Console.WriteLine(name); 890 891 DateTimeResult result = new DateTimeResult(); 892 893 result.IsoDateRoundtrip = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.RoundtripKind); 894 if (value is DateTime) 895 { 896 result.IsoDateLocal = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Local); 897 result.IsoDateUnspecified = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Unspecified); 898 result.IsoDateUtc = TestDateTimeFormat(value, DateFormatHandling.IsoDateFormat, DateTimeZoneHandling.Utc); 899 } 900 901 result.MsDateRoundtrip = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.RoundtripKind); 902 if (value is DateTime) 903 { 904 result.MsDateLocal = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Local); 905 result.MsDateUnspecified = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Unspecified); 906 result.MsDateUtc = TestDateTimeFormat(value, DateFormatHandling.MicrosoftDateFormat, DateTimeZoneHandling.Utc); 907 } 908 909 TestDateTimeFormat(value, new IsoDateTimeConverter()); 910 911 #if !NETFX_CORE 912 if (value is DateTime) 913 { 914 Console.WriteLine(XmlConvert.ToString((DateTime)(object)value, XmlDateTimeSerializationMode.RoundtripKind)); 915 } 916 else 917 { 918 Console.WriteLine(XmlConvert.ToString((DateTimeOffset)(object)value)); 919 } 920 #endif 921 922 #if !NET20 923 MemoryStream ms = new MemoryStream(); 924 DataContractSerializer s = new DataContractSerializer(typeof(T)); 925 s.WriteObject(ms, value); 926 string json = Encoding.UTF8.GetString(ms.ToArray(), 0, Convert.ToInt32(ms.Length)); 927 Console.WriteLine(json); 928 #endif 929 930 Console.WriteLine(); 931 932 return result; 933 } 934 TestDateTimeFormat(T value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling)935 private static string TestDateTimeFormat<T>(T value, DateFormatHandling format, DateTimeZoneHandling timeZoneHandling) 936 { 937 string date = null; 938 939 if (value is DateTime) 940 { 941 date = JsonConvert.ToString((DateTime)(object)value, format, timeZoneHandling); 942 } 943 else 944 { 945 #if !NET20 946 date = JsonConvert.ToString((DateTimeOffset)(object)value, format); 947 #endif 948 } 949 950 Console.WriteLine(format.ToString("g") + "-" + timeZoneHandling.ToString("g") + ": " + date); 951 952 if (timeZoneHandling == DateTimeZoneHandling.RoundtripKind) 953 { 954 T parsed = JsonConvert.DeserializeObject<T>(date); 955 try 956 { 957 Assert.AreEqual(value, parsed); 958 } 959 catch (Exception) 960 { 961 long valueTicks = GetTicks(value); 962 long parsedTicks = GetTicks(parsed); 963 964 valueTicks = (valueTicks / 10000) * 10000; 965 966 Assert.AreEqual(valueTicks, parsedTicks); 967 } 968 } 969 970 return date.Trim('"'); 971 } 972 TestDateTimeFormat(T value, JsonConverter converter)973 private static void TestDateTimeFormat<T>(T value, JsonConverter converter) 974 { 975 string date = Write(value, converter); 976 977 Console.WriteLine(converter.GetType().Name + ": " + date); 978 979 T parsed = Read<T>(date, converter); 980 981 try 982 { 983 Assert.AreEqual(value, parsed); 984 } 985 catch (Exception) 986 { 987 // JavaScript ticks aren't as precise, recheck after rounding 988 long valueTicks = GetTicks(value); 989 long parsedTicks = GetTicks(parsed); 990 991 valueTicks = (valueTicks / 10000) * 10000; 992 993 Assert.AreEqual(valueTicks, parsedTicks); 994 } 995 } 996 GetTicks(object value)997 public static long GetTicks(object value) 998 { 999 return (value is DateTime) ? ((DateTime)value).Ticks : ((DateTimeOffset)value).Ticks; 1000 } 1001 Write(object value, JsonConverter converter)1002 public static string Write(object value, JsonConverter converter) 1003 { 1004 StringWriter sw = new StringWriter(); 1005 JsonTextWriter writer = new JsonTextWriter(sw); 1006 converter.WriteJson(writer, value, null); 1007 1008 writer.Flush(); 1009 return sw.ToString(); 1010 } 1011 Read(string text, JsonConverter converter)1012 public static T Read<T>(string text, JsonConverter converter) 1013 { 1014 JsonTextReader reader = new JsonTextReader(new StringReader(text)); 1015 reader.ReadAsString(); 1016 1017 return (T)converter.ReadJson(reader, typeof(T), null, null); 1018 } 1019 1020 #if !(NET20 || NET35 || PORTABLE40) 1021 [Test] Async()1022 public void Async() 1023 { 1024 Task<string> task = null; 1025 1026 #pragma warning disable 612,618 1027 task = JsonConvert.SerializeObjectAsync(42); 1028 #pragma warning restore 612,618 1029 task.Wait(); 1030 1031 Assert.AreEqual("42", task.Result); 1032 1033 #pragma warning disable 612,618 1034 task = JsonConvert.SerializeObjectAsync(new[] { 1, 2, 3, 4, 5 }, Formatting.Indented); 1035 #pragma warning restore 612,618 1036 task.Wait(); 1037 1038 StringAssert.AreEqual(@"[ 1039 1, 1040 2, 1041 3, 1042 4, 1043 5 1044 ]", task.Result); 1045 1046 #pragma warning disable 612,618 1047 task = JsonConvert.SerializeObjectAsync(DateTime.MaxValue, Formatting.None, new JsonSerializerSettings 1048 { 1049 DateFormatHandling = DateFormatHandling.MicrosoftDateFormat 1050 }); 1051 #pragma warning restore 612,618 1052 task.Wait(); 1053 1054 Assert.AreEqual(@"""\/Date(253402300799999)\/""", task.Result); 1055 1056 #pragma warning disable 612,618 1057 var taskObject = JsonConvert.DeserializeObjectAsync("[]"); 1058 #pragma warning restore 612,618 1059 taskObject.Wait(); 1060 1061 CollectionAssert.AreEquivalent(new JArray(), (JArray)taskObject.Result); 1062 1063 #pragma warning disable 612,618 1064 Task<object> taskVersionArray = JsonConvert.DeserializeObjectAsync("['2.0']", typeof(Version[]), new JsonSerializerSettings 1065 { 1066 Converters = { new VersionConverter() } 1067 }); 1068 #pragma warning restore 612,618 1069 taskVersionArray.Wait(); 1070 1071 Version[] versionArray = (Version[])taskVersionArray.Result; 1072 1073 Assert.AreEqual(1, versionArray.Length); 1074 Assert.AreEqual(2, versionArray[0].Major); 1075 1076 #pragma warning disable 612,618 1077 Task<int> taskInt = JsonConvert.DeserializeObjectAsync<int>("5"); 1078 #pragma warning restore 612,618 1079 taskInt.Wait(); 1080 1081 Assert.AreEqual(5, taskInt.Result); 1082 1083 #pragma warning disable 612,618 1084 var taskVersion = JsonConvert.DeserializeObjectAsync<Version>("'2.0'", new JsonSerializerSettings 1085 { 1086 Converters = { new VersionConverter() } 1087 }); 1088 #pragma warning restore 612,618 1089 taskVersion.Wait(); 1090 1091 Assert.AreEqual(2, taskVersion.Result.Major); 1092 1093 Movie p = new Movie(); 1094 p.Name = "Existing,"; 1095 1096 #pragma warning disable 612,618 1097 Task taskVoid = JsonConvert.PopulateObjectAsync("{'Name':'Appended'}", p, new JsonSerializerSettings 1098 { 1099 Converters = new List<JsonConverter> { new StringAppenderConverter() } 1100 }); 1101 #pragma warning restore 612,618 1102 1103 taskVoid.Wait(); 1104 1105 Assert.AreEqual("Existing,Appended", p.Name); 1106 } 1107 #endif 1108 1109 [Test] SerializeObjectDateTimeZoneHandling()1110 public void SerializeObjectDateTimeZoneHandling() 1111 { 1112 string json = JsonConvert.SerializeObject( 1113 new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified), 1114 new JsonSerializerSettings 1115 { 1116 DateTimeZoneHandling = DateTimeZoneHandling.Utc 1117 }); 1118 1119 Assert.AreEqual(@"""2000-01-01T01:01:01Z""", json); 1120 } 1121 1122 [Test] DeserializeObject()1123 public void DeserializeObject() 1124 { 1125 string json = @"{ 1126 'Name': 'Bad Boys', 1127 'ReleaseDate': '1995-4-7T00:00:00', 1128 'Genres': [ 1129 'Action', 1130 'Comedy' 1131 ] 1132 }"; 1133 1134 Movie m = JsonConvert.DeserializeObject<Movie>(json); 1135 1136 string name = m.Name; 1137 // Bad Boys 1138 1139 Assert.AreEqual("Bad Boys", m.Name); 1140 } 1141 1142 #if !NET20 1143 [Test] TestJsonDateTimeOffsetRoundtrip()1144 public void TestJsonDateTimeOffsetRoundtrip() 1145 { 1146 var now = DateTimeOffset.Now; 1147 var dict = new Dictionary<string, object> { { "foo", now } }; 1148 1149 var settings = new JsonSerializerSettings(); 1150 settings.DateFormatHandling = DateFormatHandling.IsoDateFormat; 1151 settings.DateParseHandling = DateParseHandling.DateTimeOffset; 1152 settings.DateTimeZoneHandling = DateTimeZoneHandling.RoundtripKind; 1153 var json = JsonConvert.SerializeObject(dict, settings); 1154 1155 var newDict = new Dictionary<string, object>(); 1156 JsonConvert.PopulateObject(json, newDict, settings); 1157 1158 var date = newDict["foo"]; 1159 1160 Assert.AreEqual(date, now); 1161 } 1162 1163 [Test] MaximumDateTimeOffsetLength()1164 public void MaximumDateTimeOffsetLength() 1165 { 1166 DateTimeOffset dt = new DateTimeOffset(2000, 12, 31, 20, 59, 59, new TimeSpan(0, 11, 33, 0, 0)); 1167 dt = dt.AddTicks(9999999); 1168 1169 StringWriter sw = new StringWriter(); 1170 JsonTextWriter writer = new JsonTextWriter(sw); 1171 1172 writer.WriteValue(dt); 1173 writer.Flush(); 1174 1175 Assert.AreEqual(@"""2000-12-31T20:59:59.9999999+11:33""", sw.ToString()); 1176 } 1177 #endif 1178 1179 [Test] MaximumDateTimeLength()1180 public void MaximumDateTimeLength() 1181 { 1182 DateTime dt = new DateTime(2000, 12, 31, 20, 59, 59, DateTimeKind.Local); 1183 dt = dt.AddTicks(9999999); 1184 1185 StringWriter sw = new StringWriter(); 1186 JsonTextWriter writer = new JsonTextWriter(sw); 1187 1188 writer.WriteValue(dt); 1189 writer.Flush(); 1190 } 1191 1192 [Test] MaximumDateTimeMicrosoftDateFormatLength()1193 public void MaximumDateTimeMicrosoftDateFormatLength() 1194 { 1195 DateTime dt = DateTime.MaxValue; 1196 1197 StringWriter sw = new StringWriter(); 1198 JsonTextWriter writer = new JsonTextWriter(sw); 1199 writer.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat; 1200 1201 writer.WriteValue(dt); 1202 writer.Flush(); 1203 } 1204 1205 #if !(NET20 || NET35 || PORTABLE40 || PORTABLE) 1206 [Test] IntegerLengthOverflows()1207 public void IntegerLengthOverflows() 1208 { 1209 // Maximum javascript number length (in characters) is 380 1210 JObject o = JObject.Parse(@"{""biginteger"":" + new String('9', 380) + "}"); 1211 JValue v = (JValue)o["biginteger"]; 1212 Assert.AreEqual(JTokenType.Integer, v.Type); 1213 Assert.AreEqual(typeof(BigInteger), v.Value.GetType()); 1214 Assert.AreEqual(BigInteger.Parse(new String('9', 380)), (BigInteger)v.Value); 1215 1216 ExceptionAssert.Throws<JsonReaderException>(() => JObject.Parse(@"{""biginteger"":" + new String('9', 381) + "}"), "JSON integer " + new String('9', 381) + " is too large to parse. Path 'biginteger', line 1, position 395."); 1217 } 1218 #endif 1219 1220 [Test] ParseIsoDate()1221 public void ParseIsoDate() 1222 { 1223 StringReader sr = new StringReader(@"""2014-02-14T14:25:02-13:00"""); 1224 1225 JsonReader jsonReader = new JsonTextReader(sr); 1226 1227 Assert.IsTrue(jsonReader.Read()); 1228 Assert.AreEqual(typeof(DateTime), jsonReader.ValueType); 1229 } 1230 1231 //[Test] StackOverflowTest()1232 public void StackOverflowTest() 1233 { 1234 StringBuilder sb = new StringBuilder(); 1235 1236 int depth = 900; 1237 for (int i = 0; i < depth; i++) 1238 { 1239 sb.Append("{'A':"); 1240 } 1241 1242 // invalid json 1243 sb.Append("{***}"); 1244 for (int i = 0; i < depth; i++) 1245 { 1246 sb.Append("}"); 1247 } 1248 1249 string json = sb.ToString(); 1250 JsonSerializer serializer = new JsonSerializer() { }; 1251 serializer.Deserialize<Nest>(new JsonTextReader(new StringReader(json))); 1252 } 1253 1254 public class Nest 1255 { 1256 public Nest A { get; set; } 1257 } 1258 1259 [Test] ParametersPassedToJsonConverterConstructor()1260 public void ParametersPassedToJsonConverterConstructor() 1261 { 1262 ClobberMyProperties clobber = new ClobberMyProperties { One = "Red", Two = "Green", Three = "Yellow", Four = "Black" }; 1263 string json = JsonConvert.SerializeObject(clobber); 1264 1265 Assert.AreEqual("{\"One\":\"Uno-1-Red\",\"Two\":\"Dos-2-Green\",\"Three\":\"Tres-1337-Yellow\",\"Four\":\"Black\"}", json); 1266 } 1267 1268 public class ClobberMyProperties 1269 { 1270 [JsonConverter(typeof(ClobberingJsonConverter), "Uno", 1)] 1271 public string One { get; set; } 1272 1273 [JsonConverter(typeof(ClobberingJsonConverter), "Dos", 2)] 1274 public string Two { get; set; } 1275 1276 [JsonConverter(typeof(ClobberingJsonConverter), "Tres")] 1277 public string Three { get; set; } 1278 1279 public string Four { get; set; } 1280 } 1281 1282 public class ClobberingJsonConverter : JsonConverter 1283 { 1284 public string ClobberValueString { get; private set; } 1285 1286 public int ClobberValueInt { get; private set; } 1287 ClobberingJsonConverter(string clobberValueString, int clobberValueInt)1288 public ClobberingJsonConverter(string clobberValueString, int clobberValueInt) 1289 { 1290 ClobberValueString = clobberValueString; 1291 ClobberValueInt = clobberValueInt; 1292 } 1293 ClobberingJsonConverter(string clobberValueString)1294 public ClobberingJsonConverter(string clobberValueString) 1295 : this(clobberValueString, 1337) 1296 { 1297 } 1298 WriteJson(JsonWriter writer, object value, JsonSerializer serializer)1299 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 1300 { 1301 writer.WriteValue(ClobberValueString + "-" + ClobberValueInt.ToString() + "-" + value.ToString()); 1302 } 1303 ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)1304 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 1305 { 1306 throw new NotImplementedException(); 1307 } 1308 CanConvert(Type objectType)1309 public override bool CanConvert(Type objectType) 1310 { 1311 return objectType == typeof(string); 1312 } 1313 } 1314 1315 [Test] WrongParametersPassedToJsonConvertConstructorShouldThrow()1316 public void WrongParametersPassedToJsonConvertConstructorShouldThrow() 1317 { 1318 IncorrectJsonConvertParameters value = new IncorrectJsonConvertParameters { One = "Boom" }; 1319 1320 ExceptionAssert.Throws<JsonException>(() => { JsonConvert.SerializeObject(value); }); 1321 } 1322 1323 public class IncorrectJsonConvertParameters 1324 { 1325 /// <summary> 1326 /// We deliberately use the wrong number/type of arguments for ClobberingJsonConverter to ensure an 1327 /// exception is thrown. 1328 /// </summary> 1329 [JsonConverter(typeof(ClobberingJsonConverter), "Uno", "Blammo")] 1330 public string One { get; set; } 1331 } 1332 1333 [Test] CustomDoubleRounding()1334 public void CustomDoubleRounding() 1335 { 1336 var measurements = new Measurements 1337 { 1338 Loads = new List<double> { 23283.567554707258, 23224.849899771067, 23062.5, 22846.272519910868, 22594.281246368635 }, 1339 Positions = new List<double> { 57.724227689317019, 60.440934405753069, 63.444192925248643, 66.813119113482557, 70.4496501404433 }, 1340 Gain = 12345.67895111213 1341 }; 1342 1343 string json = JsonConvert.SerializeObject(measurements); 1344 1345 Assert.AreEqual("{\"Positions\":[57.72,60.44,63.44,66.81,70.45],\"Loads\":[23284.0,23225.0,23062.0,22846.0,22594.0],\"Gain\":12345.679}", json); 1346 } 1347 1348 public class Measurements 1349 { 1350 [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter))] 1351 public List<double> Positions { get; set; } 1352 1353 [JsonProperty(ItemConverterType = typeof(RoundingJsonConverter), ItemConverterParameters = new object[] { 0, MidpointRounding.ToEven })] 1354 public List<double> Loads { get; set; } 1355 1356 [JsonConverter(typeof(RoundingJsonConverter), 4)] 1357 public double Gain { get; set; } 1358 } 1359 1360 public class RoundingJsonConverter : JsonConverter 1361 { 1362 int _precision; 1363 MidpointRounding _rounding; 1364 RoundingJsonConverter()1365 public RoundingJsonConverter() 1366 : this(2) 1367 { 1368 } 1369 RoundingJsonConverter(int precision)1370 public RoundingJsonConverter(int precision) 1371 : this(precision, MidpointRounding.AwayFromZero) 1372 { 1373 } 1374 RoundingJsonConverter(int precision, MidpointRounding rounding)1375 public RoundingJsonConverter(int precision, MidpointRounding rounding) 1376 { 1377 _precision = precision; 1378 _rounding = rounding; 1379 } 1380 1381 public override bool CanRead 1382 { 1383 get { return false; } 1384 } 1385 CanConvert(Type objectType)1386 public override bool CanConvert(Type objectType) 1387 { 1388 return objectType == typeof(double); 1389 } 1390 ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)1391 public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 1392 { 1393 throw new NotImplementedException(); 1394 } 1395 WriteJson(JsonWriter writer, object value, JsonSerializer serializer)1396 public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 1397 { 1398 writer.WriteValue(Math.Round((double)value, _precision, _rounding)); 1399 } 1400 } 1401 1402 [Test] GenericBaseClassSerialization()1403 public void GenericBaseClassSerialization() 1404 { 1405 string json = JsonConvert.SerializeObject(new NonGenericChildClass()); 1406 Assert.AreEqual("{\"Data\":null}", json); 1407 } 1408 1409 public class GenericBaseClass<O, T> 1410 { 1411 public virtual T Data { get; set; } 1412 } 1413 1414 public class GenericIntermediateClass<O> : GenericBaseClass<O, string> 1415 { 1416 public override string Data { get; set; } 1417 } 1418 1419 public class NonGenericChildClass : GenericIntermediateClass<int> 1420 { 1421 } 1422 } 1423 }