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 }