PageRenderTime 69ms CodeModel.GetById 17ms app.highlight 40ms RepoModel.GetById 1ms app.codeStats 1ms

/Src/Newtonsoft.Json.Tests/Serialization/JsonSerializerCollectionsTests.cs

https://bitbucket.org/Ecarestia/newtonsoft.json
C# | 2538 lines | 2208 code | 234 blank | 96 comment | 44 complexity | 3549c8bf3b2937013152eeb8adb41132 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

   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
  26using System;
  27using System.Collections;
  28using System.Collections.Specialized;
  29using System.Runtime.Serialization;
  30#if !(NET35 || NET20 || PORTABLE || PORTABLE40)
  31using System.Collections.Concurrent;
  32#endif
  33using System.Collections.Generic;
  34using System.Collections.ObjectModel;
  35using System.Globalization;
  36using System.IO;
  37#if NET20
  38using Newtonsoft.Json.Utilities.LinqBridge;
  39#else
  40using System.Linq;
  41#endif
  42using System.Text;
  43using System.Xml;
  44using Newtonsoft.Json.Linq;
  45using Newtonsoft.Json.Serialization;
  46using Newtonsoft.Json.Tests.TestObjects;
  47using Newtonsoft.Json.Tests.TestObjects.Events;
  48using Newtonsoft.Json.Tests.TestObjects.Organization;
  49using Newtonsoft.Json.Utilities;
  50#if DNXCORE50
  51using Xunit;
  52using Test = Xunit.FactAttribute;
  53using Assert = Newtonsoft.Json.Tests.XUnitAssert;
  54#else
  55using NUnit.Framework;
  56#endif
  57#if !NET20 && !PORTABLE40
  58using System.Xml.Linq;
  59#endif
  60
  61namespace Newtonsoft.Json.Tests.Serialization
  62{
  63    [TestFixture]
  64    public class JsonSerializerCollectionsTests : TestFixtureBase
  65    {
  66        [Test]
  67        public void DoubleKey_WholeValue()
  68        {
  69            Dictionary<double, int> dictionary = new Dictionary<double, int> { { 1d, 1 } };
  70            string output = JsonConvert.SerializeObject(dictionary);
  71            Assert.AreEqual(@"{""1"":1}", output);
  72
  73            Dictionary<double, int> deserializedValue = JsonConvert.DeserializeObject<Dictionary<double, int>>(output);
  74            Assert.AreEqual(1d, deserializedValue.First().Key);
  75        }
  76
  77        [Test]
  78        public void DoubleKey_MaxValue()
  79        {
  80            Dictionary<double, int> dictionary = new Dictionary<double, int> { { double.MaxValue, 1 } };
  81            string output = JsonConvert.SerializeObject(dictionary);
  82            Assert.AreEqual(@"{""1.7976931348623157E+308"":1}", output);
  83
  84            Dictionary<double, int> deserializedValue = JsonConvert.DeserializeObject<Dictionary<double, int>>(output);
  85            Assert.AreEqual(double.MaxValue, deserializedValue.First().Key);
  86        }
  87
  88        [Test]
  89        public void FloatKey_MaxValue()
  90        {
  91            Dictionary<float, int> dictionary = new Dictionary<float, int> { { float.MaxValue, 1 } };
  92            string output = JsonConvert.SerializeObject(dictionary);
  93            Assert.AreEqual(@"{""3.40282347E+38"":1}", output);
  94
  95            Dictionary<float, int> deserializedValue = JsonConvert.DeserializeObject<Dictionary<float, int>>(output);
  96            Assert.AreEqual(float.MaxValue, deserializedValue.First().Key);
  97        }
  98
  99        public class TestCollectionPrivateParameterized : IEnumerable<int>
 100        {
 101            private readonly List<int> _bars;
 102
 103            public TestCollectionPrivateParameterized()
 104            {
 105                _bars = new List<int>();
 106            }
 107
 108            [JsonConstructor]
 109            private TestCollectionPrivateParameterized(IEnumerable<int> bars)
 110            {
 111                _bars = new List<int>(bars);
 112            }
 113
 114            public void Add(int bar)
 115            {
 116                _bars.Add(bar);
 117            }
 118
 119            public IEnumerator<int> GetEnumerator() => _bars.GetEnumerator();
 120
 121            IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
 122        }
 123
 124        [Test]
 125        public void CollectionJsonConstructorPrivateParameterized()
 126        {
 127            TestCollectionPrivateParameterized c1 = new TestCollectionPrivateParameterized();
 128            c1.Add(0);
 129            c1.Add(1);
 130            c1.Add(2);
 131            string json = JsonConvert.SerializeObject(c1);
 132            TestCollectionPrivateParameterized c2 = JsonConvert.DeserializeObject<TestCollectionPrivateParameterized>(json);
 133
 134            List<int> values = c2.ToList();
 135
 136            Assert.AreEqual(3, values.Count);
 137            Assert.AreEqual(0, values[0]);
 138            Assert.AreEqual(1, values[1]);
 139            Assert.AreEqual(2, values[2]);
 140        }
 141
 142        public class TestCollectionPrivate : List<int>
 143        {
 144            [JsonConstructor]
 145            private TestCollectionPrivate()
 146            {
 147            }
 148
 149            public static TestCollectionPrivate Create()
 150            {
 151                return new TestCollectionPrivate();
 152            }
 153        }
 154
 155        [Test]
 156        public void CollectionJsonConstructorPrivate()
 157        {
 158            TestCollectionPrivate c1 = TestCollectionPrivate.Create();
 159            c1.Add(0);
 160            c1.Add(1);
 161            c1.Add(2);
 162            string json = JsonConvert.SerializeObject(c1);
 163            TestCollectionPrivate c2 = JsonConvert.DeserializeObject<TestCollectionPrivate>(json);
 164
 165            List<int> values = c2.ToList();
 166
 167            Assert.AreEqual(3, values.Count);
 168            Assert.AreEqual(0, values[0]);
 169            Assert.AreEqual(1, values[1]);
 170            Assert.AreEqual(2, values[2]);
 171        }
 172
 173        public class TestCollectionMultipleParameters : List<int>
 174        {
 175            [JsonConstructor]
 176            public TestCollectionMultipleParameters(string s1, string s2)
 177            {
 178            }
 179        }
 180
 181        [Test]
 182        public void CollectionJsonConstructorMultipleParameters()
 183        {
 184            ExceptionAssert.Throws<JsonException>(
 185                () => JsonConvert.SerializeObject(new TestCollectionMultipleParameters(null, null)),
 186                "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestCollectionMultipleParameters' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Int32]'.");
 187        }
 188
 189        public class TestCollectionBadIEnumerableParameter : List<int>
 190        {
 191            [JsonConstructor]
 192            public TestCollectionBadIEnumerableParameter(List<string> l)
 193            {
 194            }
 195        }
 196
 197        [Test]
 198        public void CollectionJsonConstructorBadIEnumerableParameter()
 199        {
 200            ExceptionAssert.Throws<JsonException>(
 201                () => JsonConvert.SerializeObject(new TestCollectionBadIEnumerableParameter(null)),
 202                "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestCollectionBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Int32]'.");
 203        }
 204
 205#if !(DNXCORE50 || PORTABLE)
 206        public class TestCollectionNonGeneric : ArrayList
 207        {
 208            [JsonConstructor]
 209            public TestCollectionNonGeneric(IEnumerable l)
 210                : base(l.Cast<object>().ToList())
 211            {
 212            }
 213        }
 214
 215        [Test]
 216        public void CollectionJsonConstructorNonGeneric()
 217        {
 218            string json = @"[1,2,3]";
 219            TestCollectionNonGeneric l = JsonConvert.DeserializeObject<TestCollectionNonGeneric>(json);
 220
 221            Assert.AreEqual(3, l.Count);
 222            Assert.AreEqual(1, l[0]);
 223            Assert.AreEqual(2, l[1]);
 224            Assert.AreEqual(3, l[2]);
 225        }
 226#endif
 227
 228        public class TestDictionaryPrivateParameterized : Dictionary<string, int>
 229        {
 230            public TestDictionaryPrivateParameterized()
 231            {
 232            }
 233
 234            [JsonConstructor]
 235            private TestDictionaryPrivateParameterized(IEnumerable<KeyValuePair<string, int>> bars)
 236                : base(bars.ToDictionary(k => k.Key, k => k.Value))
 237            {
 238            }
 239        }
 240
 241        [Test]
 242        public void DictionaryJsonConstructorPrivateParameterized()
 243        {
 244            TestDictionaryPrivateParameterized c1 = new TestDictionaryPrivateParameterized();
 245            c1.Add("zero", 0);
 246            c1.Add("one", 1);
 247            c1.Add("two", 2);
 248            string json = JsonConvert.SerializeObject(c1);
 249            TestDictionaryPrivateParameterized c2 = JsonConvert.DeserializeObject<TestDictionaryPrivateParameterized>(json);
 250
 251            Assert.AreEqual(3, c2.Count);
 252            Assert.AreEqual(0, c2["zero"]);
 253            Assert.AreEqual(1, c2["one"]);
 254            Assert.AreEqual(2, c2["two"]);
 255        }
 256
 257        public class TestDictionaryPrivate : Dictionary<string, int>
 258        {
 259            [JsonConstructor]
 260            private TestDictionaryPrivate()
 261            {
 262            }
 263
 264            public static TestDictionaryPrivate Create()
 265            {
 266                return new TestDictionaryPrivate();
 267            }
 268        }
 269
 270        [Test]
 271        public void DictionaryJsonConstructorPrivate()
 272        {
 273            TestDictionaryPrivate c1 = TestDictionaryPrivate.Create();
 274            c1.Add("zero", 0);
 275            c1.Add("one", 1);
 276            c1.Add("two", 2);
 277            string json = JsonConvert.SerializeObject(c1);
 278            TestDictionaryPrivate c2 = JsonConvert.DeserializeObject<TestDictionaryPrivate>(json);
 279
 280            Assert.AreEqual(3, c2.Count);
 281            Assert.AreEqual(0, c2["zero"]);
 282            Assert.AreEqual(1, c2["one"]);
 283            Assert.AreEqual(2, c2["two"]);
 284        }
 285
 286        public class TestDictionaryMultipleParameters : Dictionary<string, int>
 287        {
 288            [JsonConstructor]
 289            public TestDictionaryMultipleParameters(string s1, string s2)
 290            {
 291            }
 292        }
 293
 294        [Test]
 295        public void DictionaryJsonConstructorMultipleParameters()
 296        {
 297            ExceptionAssert.Throws<JsonException>(
 298                () => JsonConvert.SerializeObject(new TestDictionaryMultipleParameters(null, null)),
 299                "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestDictionaryMultipleParameters' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]'.");
 300        }
 301
 302        public class TestDictionaryBadIEnumerableParameter : Dictionary<string, int>
 303        {
 304            [JsonConstructor]
 305            public TestDictionaryBadIEnumerableParameter(Dictionary<string, string> l)
 306            {
 307            }
 308        }
 309
 310        [Test]
 311        public void DictionaryJsonConstructorBadIEnumerableParameter()
 312        {
 313            ExceptionAssert.Throws<JsonException>(
 314                () => JsonConvert.SerializeObject(new TestDictionaryBadIEnumerableParameter(null)),
 315                "Constructor for 'Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+TestDictionaryBadIEnumerableParameter' must have no parameters or a single parameter that implements 'System.Collections.Generic.IEnumerable`1[System.Collections.Generic.KeyValuePair`2[System.String,System.Int32]]'.");
 316        }
 317
 318#if !(DNXCORE50 || PORTABLE)
 319        public class TestDictionaryNonGeneric : Hashtable
 320        {
 321            [JsonConstructor]
 322            public TestDictionaryNonGeneric(IDictionary d)
 323                : base(d)
 324            {
 325            }
 326        }
 327
 328        [Test]
 329        public void DictionaryJsonConstructorNonGeneric()
 330        {
 331            string json = @"{'zero':0,'one':1,'two':2}";
 332            TestDictionaryNonGeneric d = JsonConvert.DeserializeObject<TestDictionaryNonGeneric>(json);
 333
 334            Assert.AreEqual(3, d.Count);
 335            Assert.AreEqual(0, d["zero"]);
 336            Assert.AreEqual(1, d["one"]);
 337            Assert.AreEqual(2, d["two"]);
 338        }
 339#endif
 340
 341#if !(DNXCORE50)
 342        public class NameValueCollectionTestClass
 343        {
 344            public NameValueCollection Collection { get; set; }
 345        }
 346
 347        [Test]
 348        public void DeserializeNameValueCollection()
 349        {
 350            ExceptionAssert.Throws<JsonSerializationException>(
 351                () => JsonConvert.DeserializeObject<NameValueCollectionTestClass>("{Collection:[]}"),
 352                "Cannot create and populate list type System.Collections.Specialized.NameValueCollection. Path 'Collection', line 1, position 13.");
 353        }
 354#endif
 355
 356#if !(NET35 || NET20 || PORTABLE || PORTABLE40)
 357        public class SomeObject
 358        {
 359            public string Text1 { get; set; }
 360        }
 361
 362        public class CustomConcurrentDictionary : ConcurrentDictionary<string, List<SomeObject>>
 363        {
 364            [OnDeserialized]
 365            internal void OnDeserializedMethod(StreamingContext context)
 366            {
 367                ((IDictionary)this).Add("key2", new List<SomeObject>
 368                {
 369                    new SomeObject
 370                    {
 371                        Text1 = "value2"
 372                    }
 373                });
 374            }
 375        }
 376
 377        [Test]
 378        public void SerializeCustomConcurrentDictionary()
 379        {
 380            IDictionary d = new CustomConcurrentDictionary();
 381            d.Add("key", new List<SomeObject>
 382            {
 383                new SomeObject
 384                {
 385                    Text1 = "value1"
 386                }
 387            });
 388
 389            string json = JsonConvert.SerializeObject(d, Formatting.Indented);
 390
 391            Assert.AreEqual(@"{
 392  ""key"": [
 393    {
 394      ""Text1"": ""value1""
 395    }
 396  ]
 397}", json);
 398
 399            CustomConcurrentDictionary d2 = JsonConvert.DeserializeObject<CustomConcurrentDictionary>(json);
 400
 401            Assert.AreEqual(2, d2.Count);
 402            Assert.AreEqual("value1", d2["key"][0].Text1);
 403            Assert.AreEqual("value2", d2["key2"][0].Text1);
 404        }
 405#endif
 406
 407        [Test]
 408        public void NonZeroBasedArray()
 409        {
 410            var onebasedArray = Array.CreateInstance(typeof(string), new[] { 3 }, new[] { 2 });
 411
 412            for (var i = onebasedArray.GetLowerBound(0); i <= onebasedArray.GetUpperBound(0); i++)
 413            {
 414                onebasedArray.SetValue(i.ToString(CultureInfo.InvariantCulture), new[] { i, });
 415            }
 416
 417            string output = JsonConvert.SerializeObject(onebasedArray, Formatting.Indented);
 418
 419            StringAssert.AreEqual(@"[
 420  ""2"",
 421  ""3"",
 422  ""4""
 423]", output);
 424        }
 425
 426        [Test]
 427        public void NonZeroBasedMultiArray()
 428        {
 429            // lets create a two dimensional array, each rank is 1-based of with a capacity of 4.
 430            var onebasedArray = Array.CreateInstance(typeof(string), new[] { 3, 3 }, new[] { 1, 2 });
 431
 432            // Iterate of the array elements and assign a random double
 433            for (var i = onebasedArray.GetLowerBound(0); i <= onebasedArray.GetUpperBound(0); i++)
 434            {
 435                for (var j = onebasedArray.GetLowerBound(1); j <= onebasedArray.GetUpperBound(1); j++)
 436                {
 437                    onebasedArray.SetValue(i + "_" + j, new[] { i, j });
 438                }
 439            }
 440
 441            // Now lets try and serialize the Array
 442            string output = JsonConvert.SerializeObject(onebasedArray, Formatting.Indented);
 443
 444            StringAssert.AreEqual(@"[
 445  [
 446    ""1_2"",
 447    ""1_3"",
 448    ""1_4""
 449  ],
 450  [
 451    ""2_2"",
 452    ""2_3"",
 453    ""2_4""
 454  ],
 455  [
 456    ""3_2"",
 457    ""3_3"",
 458    ""3_4""
 459  ]
 460]", output);
 461        }
 462
 463        [Test]
 464        public void MultiDObjectArray()
 465        {
 466            object[,] myOtherArray =
 467            {
 468                { new KeyValuePair<string, double>("my value", 0.8), "foobar" },
 469                { true, 0.4d },
 470                { 0.05f, 6 }
 471            };
 472
 473            string myOtherArrayAsString = JsonConvert.SerializeObject(myOtherArray, Formatting.Indented);
 474
 475            StringAssert.AreEqual(@"[
 476  [
 477    {
 478      ""Key"": ""my value"",
 479      ""Value"": 0.8
 480    },
 481    ""foobar""
 482  ],
 483  [
 484    true,
 485    0.4
 486  ],
 487  [
 488    0.05,
 489    6
 490  ]
 491]", myOtherArrayAsString);
 492
 493            JObject o = JObject.Parse(@"{
 494              ""Key"": ""my value"",
 495              ""Value"": 0.8
 496            }");
 497
 498            object[,] myOtherResult = JsonConvert.DeserializeObject<object[,]>(myOtherArrayAsString);
 499            Assert.IsTrue(JToken.DeepEquals(o, (JToken)myOtherResult[0, 0]));
 500            Assert.AreEqual("foobar", myOtherResult[0, 1]);
 501
 502            Assert.AreEqual(true, myOtherResult[1, 0]);
 503            Assert.AreEqual(0.4, myOtherResult[1, 1]);
 504
 505            Assert.AreEqual(0.05, myOtherResult[2, 0]);
 506            Assert.AreEqual(6L, myOtherResult[2, 1]);
 507        }
 508
 509        public class EnumerableClass<T> : IEnumerable<T>
 510        {
 511            private readonly IList<T> _values;
 512
 513            public EnumerableClass(IEnumerable<T> values)
 514            {
 515                _values = new List<T>(values);
 516            }
 517
 518            public IEnumerator<T> GetEnumerator()
 519            {
 520                return _values.GetEnumerator();
 521            }
 522
 523            IEnumerator IEnumerable.GetEnumerator()
 524            {
 525                return GetEnumerator();
 526            }
 527        }
 528
 529        [Test]
 530        public void DeserializeIEnumerableFromConstructor()
 531        {
 532            string json = @"[
 533  1,
 534  2,
 535  null
 536]";
 537
 538            var result = JsonConvert.DeserializeObject<EnumerableClass<int?>>(json);
 539
 540            Assert.AreEqual(3, result.Count());
 541            Assert.AreEqual(1, result.ElementAt(0));
 542            Assert.AreEqual(2, result.ElementAt(1));
 543            Assert.AreEqual(null, result.ElementAt(2));
 544        }
 545
 546        public class EnumerableClassFailure<T> : IEnumerable<T>
 547        {
 548            private readonly IList<T> _values;
 549
 550            public EnumerableClassFailure()
 551            {
 552                _values = new List<T>();
 553            }
 554
 555            public IEnumerator<T> GetEnumerator()
 556            {
 557                return _values.GetEnumerator();
 558            }
 559
 560            IEnumerator IEnumerable.GetEnumerator()
 561            {
 562                return GetEnumerator();
 563            }
 564        }
 565
 566        [Test]
 567        public void DeserializeIEnumerableFromConstructor_Failure()
 568        {
 569            string json = @"[
 570  ""One"",
 571  ""II"",
 572  ""3""
 573]";
 574
 575            ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<EnumerableClassFailure<string>>(json), "Cannot create and populate list type Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+EnumerableClassFailure`1[System.String]. Path '', line 1, position 1.");
 576        }
 577
 578        public class PrivateDefaultCtorList<T> : List<T>
 579        {
 580            private PrivateDefaultCtorList()
 581            {
 582            }
 583        }
 584
 585        [Test]
 586        public void DeserializePrivateListCtor()
 587        {
 588            ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<PrivateDefaultCtorList<int>>("[1,2]"), "Unable to find a constructor to use for type Newtonsoft.Json.Tests.Serialization.JsonSerializerCollectionsTests+PrivateDefaultCtorList`1[System.Int32]. Path '', line 1, position 1.");
 589
 590            var list = JsonConvert.DeserializeObject<PrivateDefaultCtorList<int>>("[1,2]", new JsonSerializerSettings
 591            {
 592                ConstructorHandling = ConstructorHandling.AllowNonPublicDefaultConstructor
 593            });
 594
 595            Assert.AreEqual(2, list.Count);
 596        }
 597
 598        public class PrivateDefaultCtorWithIEnumerableCtorList<T> : List<T>
 599        {
 600            private PrivateDefaultCtorWithIEnumerableCtorList()
 601            {
 602            }
 603
 604            public PrivateDefaultCtorWithIEnumerableCtorList(IEnumerable<T> values)
 605                : base(values)
 606            {
 607                Add(default(T));
 608            }
 609        }
 610
 611        [Test]
 612        public void DeserializePrivateListConstructor()
 613        {
 614            var list = JsonConvert.DeserializeObject<PrivateDefaultCtorWithIEnumerableCtorList<int>>("[1,2]");
 615
 616            Assert.AreEqual(3, list.Count);
 617            Assert.AreEqual(1, list[0]);
 618            Assert.AreEqual(2, list[1]);
 619            Assert.AreEqual(0, list[2]);
 620        }
 621
 622        [Test]
 623        public void DeserializeNonIsoDateDictionaryKey()
 624        {
 625            Dictionary<DateTime, string> d = JsonConvert.DeserializeObject<Dictionary<DateTime, string>>(@"{""04/28/2013 00:00:00"":""test""}");
 626
 627            Assert.AreEqual(1, d.Count);
 628
 629            DateTime key = DateTime.Parse("04/28/2013 00:00:00", CultureInfo.InvariantCulture);
 630            Assert.AreEqual("test", d[key]);
 631        }
 632
 633        [Test]
 634        public void DeserializeNonGenericList()
 635        {
 636            IList l = JsonConvert.DeserializeObject<IList>("['string!']");
 637
 638            Assert.AreEqual(typeof(List<object>), l.GetType());
 639            Assert.AreEqual(1, l.Count);
 640            Assert.AreEqual("string!", l[0]);
 641        }
 642
 643#if !(NET40 || NET35 || NET20 || PORTABLE40)
 644        [Test]
 645        public void DeserializeReadOnlyListInterface()
 646        {
 647            IReadOnlyList<int> list = JsonConvert.DeserializeObject<IReadOnlyList<int>>("[1,2,3]");
 648
 649            Assert.AreEqual(3, list.Count);
 650            Assert.AreEqual(1, list[0]);
 651            Assert.AreEqual(2, list[1]);
 652            Assert.AreEqual(3, list[2]);
 653        }
 654
 655        [Test]
 656        public void DeserializeReadOnlyCollectionInterface()
 657        {
 658            IReadOnlyCollection<int> list = JsonConvert.DeserializeObject<IReadOnlyCollection<int>>("[1,2,3]");
 659
 660            Assert.AreEqual(3, list.Count);
 661
 662            Assert.AreEqual(1, list.ElementAt(0));
 663            Assert.AreEqual(2, list.ElementAt(1));
 664            Assert.AreEqual(3, list.ElementAt(2));
 665        }
 666
 667        [Test]
 668        public void DeserializeReadOnlyCollection()
 669        {
 670            ReadOnlyCollection<int> list = JsonConvert.DeserializeObject<ReadOnlyCollection<int>>("[1,2,3]");
 671
 672            Assert.AreEqual(3, list.Count);
 673
 674            Assert.AreEqual(1, list[0]);
 675            Assert.AreEqual(2, list[1]);
 676            Assert.AreEqual(3, list[2]);
 677        }
 678
 679        [Test]
 680        public void DeserializeReadOnlyDictionaryInterface()
 681        {
 682            IReadOnlyDictionary<string, int> dic = JsonConvert.DeserializeObject<IReadOnlyDictionary<string, int>>("{'one':1,'two':2}");
 683
 684            Assert.AreEqual(2, dic.Count);
 685
 686            Assert.AreEqual(1, dic["one"]);
 687            Assert.AreEqual(2, dic["two"]);
 688
 689            CustomAssert.IsInstanceOfType(typeof(ReadOnlyDictionary<string, int>), dic);
 690        }
 691
 692        [Test]
 693        public void DeserializeReadOnlyDictionary()
 694        {
 695            ReadOnlyDictionary<string, int> dic = JsonConvert.DeserializeObject<ReadOnlyDictionary<string, int>>("{'one':1,'two':2}");
 696
 697            Assert.AreEqual(2, dic.Count);
 698
 699            Assert.AreEqual(1, dic["one"]);
 700            Assert.AreEqual(2, dic["two"]);
 701        }
 702
 703        public class CustomReadOnlyDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
 704        {
 705            private readonly IDictionary<TKey, TValue> _dictionary;
 706
 707            public CustomReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
 708            {
 709                _dictionary = dictionary;
 710            }
 711
 712            public bool ContainsKey(TKey key)
 713            {
 714                return _dictionary.ContainsKey(key);
 715            }
 716
 717            public IEnumerable<TKey> Keys
 718            {
 719                get { return _dictionary.Keys; }
 720            }
 721
 722            public bool TryGetValue(TKey key, out TValue value)
 723            {
 724                return _dictionary.TryGetValue(key, out value);
 725            }
 726
 727            public IEnumerable<TValue> Values
 728            {
 729                get { return _dictionary.Values; }
 730            }
 731
 732            public TValue this[TKey key]
 733            {
 734                get { return _dictionary[key]; }
 735            }
 736
 737            public int Count
 738            {
 739                get { return _dictionary.Count; }
 740            }
 741
 742            public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
 743            {
 744                return _dictionary.GetEnumerator();
 745            }
 746
 747            IEnumerator IEnumerable.GetEnumerator()
 748            {
 749                return _dictionary.GetEnumerator();
 750            }
 751        }
 752
 753        [Test]
 754        public void SerializeCustomReadOnlyDictionary()
 755        {
 756            IDictionary<string, int> d = new Dictionary<string, int>
 757            {
 758                { "one", 1 },
 759                { "two", 2 }
 760            };
 761
 762            CustomReadOnlyDictionary<string, int> dic = new CustomReadOnlyDictionary<string, int>(d);
 763
 764            string json = JsonConvert.SerializeObject(dic, Formatting.Indented);
 765            StringAssert.AreEqual(@"{
 766  ""one"": 1,
 767  ""two"": 2
 768}", json);
 769        }
 770
 771        public class CustomReadOnlyCollection<T> : IReadOnlyCollection<T>
 772        {
 773            private readonly IList<T> _values;
 774
 775            public CustomReadOnlyCollection(IList<T> values)
 776            {
 777                _values = values;
 778            }
 779
 780            public int Count
 781            {
 782                get { return _values.Count; }
 783            }
 784
 785            public IEnumerator<T> GetEnumerator()
 786            {
 787                return _values.GetEnumerator();
 788            }
 789
 790            IEnumerator IEnumerable.GetEnumerator()
 791            {
 792                return _values.GetEnumerator();
 793            }
 794        }
 795
 796        [Test]
 797        public void SerializeCustomReadOnlyCollection()
 798        {
 799            IList<int> l = new List<int>
 800            {
 801                1,
 802                2,
 803                3
 804            };
 805
 806            CustomReadOnlyCollection<int> list = new CustomReadOnlyCollection<int>(l);
 807
 808            string json = JsonConvert.SerializeObject(list, Formatting.Indented);
 809            StringAssert.AreEqual(@"[
 810  1,
 811  2,
 812  3
 813]", json);
 814        }
 815#endif
 816
 817        [Test]
 818        public void TestEscapeDictionaryStrings()
 819        {
 820            const string s = @"host\user";
 821            string serialized = JsonConvert.SerializeObject(s);
 822            Assert.AreEqual(@"""host\\user""", serialized);
 823
 824            Dictionary<int, object> d1 = new Dictionary<int, object>();
 825            d1.Add(5, s);
 826            Assert.AreEqual(@"{""5"":""host\\user""}", JsonConvert.SerializeObject(d1));
 827
 828            Dictionary<string, object> d2 = new Dictionary<string, object>();
 829            d2.Add(s, 5);
 830            Assert.AreEqual(@"{""host\\user"":5}", JsonConvert.SerializeObject(d2));
 831        }
 832
 833        public class GenericListTestClass
 834        {
 835            public List<string> GenericList { get; set; }
 836
 837            public GenericListTestClass()
 838            {
 839                GenericList = new List<string>();
 840            }
 841        }
 842
 843        [Test]
 844        public void DeserializeExistingGenericList()
 845        {
 846            GenericListTestClass c = new GenericListTestClass();
 847            c.GenericList.Add("1");
 848            c.GenericList.Add("2");
 849
 850            string json = JsonConvert.SerializeObject(c, Formatting.Indented);
 851
 852            GenericListTestClass newValue = JsonConvert.DeserializeObject<GenericListTestClass>(json);
 853            Assert.AreEqual(2, newValue.GenericList.Count);
 854            Assert.AreEqual(typeof(List<string>), newValue.GenericList.GetType());
 855        }
 856
 857        [Test]
 858        public void DeserializeSimpleKeyValuePair()
 859        {
 860            List<KeyValuePair<string, string>> list = new List<KeyValuePair<string, string>>();
 861            list.Add(new KeyValuePair<string, string>("key1", "value1"));
 862            list.Add(new KeyValuePair<string, string>("key2", "value2"));
 863
 864            string json = JsonConvert.SerializeObject(list);
 865
 866            Assert.AreEqual(@"[{""Key"":""key1"",""Value"":""value1""},{""Key"":""key2"",""Value"":""value2""}]", json);
 867
 868            List<KeyValuePair<string, string>> result = JsonConvert.DeserializeObject<List<KeyValuePair<string, string>>>(json);
 869            Assert.AreEqual(2, result.Count);
 870            Assert.AreEqual("key1", result[0].Key);
 871            Assert.AreEqual("value1", result[0].Value);
 872            Assert.AreEqual("key2", result[1].Key);
 873            Assert.AreEqual("value2", result[1].Value);
 874        }
 875
 876        [Test]
 877        public void DeserializeComplexKeyValuePair()
 878        {
 879            DateTime dateTime = new DateTime(2000, 12, 1, 23, 1, 1, DateTimeKind.Utc);
 880
 881            List<KeyValuePair<string, WagePerson>> list = new List<KeyValuePair<string, WagePerson>>();
 882            list.Add(new KeyValuePair<string, WagePerson>("key1", new WagePerson
 883            {
 884                BirthDate = dateTime,
 885                Department = "Department1",
 886                LastModified = dateTime,
 887                HourlyWage = 1
 888            }));
 889            list.Add(new KeyValuePair<string, WagePerson>("key2", new WagePerson
 890            {
 891                BirthDate = dateTime,
 892                Department = "Department2",
 893                LastModified = dateTime,
 894                HourlyWage = 2
 895            }));
 896
 897            string json = JsonConvert.SerializeObject(list, Formatting.Indented);
 898
 899            StringAssert.AreEqual(@"[
 900  {
 901    ""Key"": ""key1"",
 902    ""Value"": {
 903      ""HourlyWage"": 1.0,
 904      ""Name"": null,
 905      ""BirthDate"": ""2000-12-01T23:01:01Z"",
 906      ""LastModified"": ""2000-12-01T23:01:01Z""
 907    }
 908  },
 909  {
 910    ""Key"": ""key2"",
 911    ""Value"": {
 912      ""HourlyWage"": 2.0,
 913      ""Name"": null,
 914      ""BirthDate"": ""2000-12-01T23:01:01Z"",
 915      ""LastModified"": ""2000-12-01T23:01:01Z""
 916    }
 917  }
 918]", json);
 919
 920            List<KeyValuePair<string, WagePerson>> result = JsonConvert.DeserializeObject<List<KeyValuePair<string, WagePerson>>>(json);
 921            Assert.AreEqual(2, result.Count);
 922            Assert.AreEqual("key1", result[0].Key);
 923            Assert.AreEqual(1, result[0].Value.HourlyWage);
 924            Assert.AreEqual("key2", result[1].Key);
 925            Assert.AreEqual(2, result[1].Value.HourlyWage);
 926        }
 927
 928        [Test]
 929        public void StringListAppenderConverterTest()
 930        {
 931            Movie p = new Movie();
 932            p.ReleaseCountries = new List<string> { "Existing" };
 933
 934            JsonConvert.PopulateObject("{'ReleaseCountries':['Appended']}", p, new JsonSerializerSettings
 935            {
 936                Converters = new List<JsonConverter> { new StringListAppenderConverter() }
 937            });
 938
 939            Assert.AreEqual(2, p.ReleaseCountries.Count);
 940            Assert.AreEqual("Existing", p.ReleaseCountries[0]);
 941            Assert.AreEqual("Appended", p.ReleaseCountries[1]);
 942        }
 943
 944        [Test]
 945        public void StringAppenderConverterTest()
 946        {
 947            Movie p = new Movie();
 948            p.Name = "Existing,";
 949
 950            JsonConvert.PopulateObject("{'Name':'Appended'}", p, new JsonSerializerSettings
 951            {
 952                Converters = new List<JsonConverter> { new StringAppenderConverter() }
 953            });
 954
 955            Assert.AreEqual("Existing,Appended", p.Name);
 956        }
 957
 958        [Test]
 959        public void DeserializeIDictionary()
 960        {
 961            IDictionary dictionary = JsonConvert.DeserializeObject<IDictionary>("{'name':'value!'}");
 962            Assert.AreEqual(1, dictionary.Count);
 963            Assert.AreEqual("value!", dictionary["name"]);
 964        }
 965
 966        [Test]
 967        public void DeserializeIList()
 968        {
 969            IList list = JsonConvert.DeserializeObject<IList>("['1', 'two', 'III']");
 970            Assert.AreEqual(3, list.Count);
 971        }
 972
 973        [Test]
 974        public void NullableValueGenericDictionary()
 975        {
 976            IDictionary<string, int?> v1 = new Dictionary<string, int?>
 977            {
 978                { "First", 1 },
 979                { "Second", null },
 980                { "Third", 3 }
 981            };
 982
 983            string json = JsonConvert.SerializeObject(v1, Formatting.Indented);
 984
 985            StringAssert.AreEqual(@"{
 986  ""First"": 1,
 987  ""Second"": null,
 988  ""Third"": 3
 989}", json);
 990
 991            IDictionary<string, int?> v2 = JsonConvert.DeserializeObject<IDictionary<string, int?>>(json);
 992            Assert.AreEqual(3, v2.Count);
 993            Assert.AreEqual(1, v2["First"]);
 994            Assert.AreEqual(null, v2["Second"]);
 995            Assert.AreEqual(3, v2["Third"]);
 996        }
 997
 998#if !(NET35 || NET20 || PORTABLE || PORTABLE40)
 999        [Test]
1000        public void DeserializeConcurrentDictionary()
1001        {
1002            IDictionary<string, TestObjects.Component> components = new Dictionary<string, TestObjects.Component>
1003            {
1004                { "Key!", new TestObjects.Component() }
1005            };
1006            GameObject go = new GameObject
1007            {
1008                Components = new ConcurrentDictionary<string, TestObjects.Component>(components),
1009                Id = "Id!",
1010                Name = "Name!"
1011            };
1012
1013            string originalJson = JsonConvert.SerializeObject(go, Formatting.Indented);
1014
1015            StringAssert.AreEqual(@"{
1016  ""Components"": {
1017    ""Key!"": {}
1018  },
1019  ""Id"": ""Id!"",
1020  ""Name"": ""Name!""
1021}", originalJson);
1022
1023            GameObject newObject = JsonConvert.DeserializeObject<GameObject>(originalJson);
1024
1025            Assert.AreEqual(1, newObject.Components.Count);
1026            Assert.AreEqual("Id!", newObject.Id);
1027            Assert.AreEqual("Name!", newObject.Name);
1028        }
1029#endif
1030
1031        [Test]
1032        public void DeserializeKeyValuePairArray()
1033        {
1034            string json = @"[ { ""Value"": [ ""1"", ""2"" ], ""Key"": ""aaa"", ""BadContent"": [ 0 ] }, { ""Value"": [ ""3"", ""4"" ], ""Key"": ""bbb"" } ]";
1035
1036            IList<KeyValuePair<string, IList<string>>> values = JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>>>(json);
1037
1038            Assert.AreEqual(2, values.Count);
1039            Assert.AreEqual("aaa", values[0].Key);
1040            Assert.AreEqual(2, values[0].Value.Count);
1041            Assert.AreEqual("1", values[0].Value[0]);
1042            Assert.AreEqual("2", values[0].Value[1]);
1043            Assert.AreEqual("bbb", values[1].Key);
1044            Assert.AreEqual(2, values[1].Value.Count);
1045            Assert.AreEqual("3", values[1].Value[0]);
1046            Assert.AreEqual("4", values[1].Value[1]);
1047        }
1048
1049        [Test]
1050        public void DeserializeNullableKeyValuePairArray()
1051        {
1052            string json = @"[ { ""Value"": [ ""1"", ""2"" ], ""Key"": ""aaa"", ""BadContent"": [ 0 ] }, null, { ""Value"": [ ""3"", ""4"" ], ""Key"": ""bbb"" } ]";
1053
1054            IList<KeyValuePair<string, IList<string>>?> values = JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>?>>(json);
1055
1056            Assert.AreEqual(3, values.Count);
1057            Assert.AreEqual("aaa", values[0].Value.Key);
1058            Assert.AreEqual(2, values[0].Value.Value.Count);
1059            Assert.AreEqual("1", values[0].Value.Value[0]);
1060            Assert.AreEqual("2", values[0].Value.Value[1]);
1061            Assert.AreEqual(null, values[1]);
1062            Assert.AreEqual("bbb", values[2].Value.Key);
1063            Assert.AreEqual(2, values[2].Value.Value.Count);
1064            Assert.AreEqual("3", values[2].Value.Value[0]);
1065            Assert.AreEqual("4", values[2].Value.Value[1]);
1066        }
1067
1068        [Test]
1069        public void DeserializeNullToNonNullableKeyValuePairArray()
1070        {
1071            string json = @"[ null ]";
1072
1073            ExceptionAssert.Throws<JsonSerializationException>(() => { JsonConvert.DeserializeObject<IList<KeyValuePair<string, IList<string>>>>(json); }, "Cannot convert null value to KeyValuePair. Path '[0]', line 1, position 6.");
1074        }
1075
1076#if !(NET40 || NET35 || NET20 || PORTABLE40)
1077        public class PopulateReadOnlyTestClass
1078        {
1079            public IList<int> NonReadOnlyList { get; set; }
1080            public IDictionary<string, int> NonReadOnlyDictionary { get; set; }
1081
1082            public IList<int> Array { get; set; }
1083
1084            public IList<int> List { get; set; }
1085            public IDictionary<string, int> Dictionary { get; set; }
1086
1087            public IReadOnlyCollection<int> IReadOnlyCollection { get; set; }
1088            public ReadOnlyCollection<int> ReadOnlyCollection { get; set; }
1089            public IReadOnlyList<int> IReadOnlyList { get; set; }
1090
1091            public IReadOnlyDictionary<string, int> IReadOnlyDictionary { get; set; }
1092            public ReadOnlyDictionary<string, int> ReadOnlyDictionary { get; set; }
1093
1094            public PopulateReadOnlyTestClass()
1095            {
1096                NonReadOnlyList = new List<int> { 1 };
1097                NonReadOnlyDictionary = new Dictionary<string, int> { { "first", 2 } };
1098
1099                Array = new[] { 3 };
1100
1101                List = new ReadOnlyCollection<int>(new[] { 4 });
1102                Dictionary = new ReadOnlyDictionary<string, int>(new Dictionary<string, int> { { "first", 5 } });
1103
1104                IReadOnlyCollection = new ReadOnlyCollection<int>(new[] { 6 });
1105                ReadOnlyCollection = new ReadOnlyCollection<int>(new[] { 7 });
1106                IReadOnlyList = new ReadOnlyCollection<int>(new[] { 8 });
1107
1108                IReadOnlyDictionary = new ReadOnlyDictionary<string, int>(new Dictionary<string, int> { { "first", 9 } });
1109                ReadOnlyDictionary = new ReadOnlyDictionary<string, int>(new Dictionary<string, int> { { "first", 10 } });
1110            }
1111        }
1112
1113        [Test]
1114        public void SerializeReadOnlyCollections()
1115        {
1116            PopulateReadOnlyTestClass c1 = new PopulateReadOnlyTestClass();
1117
1118            string json = JsonConvert.SerializeObject(c1, Formatting.Indented);
1119
1120            StringAssert.AreEqual(@"{
1121  ""NonReadOnlyList"": [
1122    1
1123  ],
1124  ""NonReadOnlyDictionary"": {
1125    ""first"": 2
1126  },
1127  ""Array"": [
1128    3
1129  ],
1130  ""List"": [
1131    4
1132  ],
1133  ""Dictionary"": {
1134    ""first"": 5
1135  },
1136  ""IReadOnlyCollection"": [
1137    6
1138  ],
1139  ""ReadOnlyCollection"": [
1140    7
1141  ],
1142  ""IReadOnlyList"": [
1143    8
1144  ],
1145  ""IReadOnlyDictionary"": {
1146    ""first"": 9
1147  },
1148  ""ReadOnlyDictionary"": {
1149    ""first"": 10
1150  }
1151}", json);
1152        }
1153
1154        [Test]
1155        public void PopulateReadOnlyCollections()
1156        {
1157            string json = @"{
1158  ""NonReadOnlyList"": [
1159    11
1160  ],
1161  ""NonReadOnlyDictionary"": {
1162    ""first"": 12
1163  },
1164  ""Array"": [
1165    13
1166  ],
1167  ""List"": [
1168    14
1169  ],
1170  ""Dictionary"": {
1171    ""first"": 15
1172  },
1173  ""IReadOnlyCollection"": [
1174    16
1175  ],
1176  ""ReadOnlyCollection"": [
1177    17
1178  ],
1179  ""IReadOnlyList"": [
1180    18
1181  ],
1182  ""IReadOnlyDictionary"": {
1183    ""first"": 19
1184  },
1185  ""ReadOnlyDictionary"": {
1186    ""first"": 20
1187  }
1188}";
1189
1190            var c2 = JsonConvert.DeserializeObject<PopulateReadOnlyTestClass>(json);
1191
1192            Assert.AreEqual(1, c2.NonReadOnlyDictionary.Count);
1193            Assert.AreEqual(12, c2.NonReadOnlyDictionary["first"]);
1194
1195            Assert.AreEqual(2, c2.NonReadOnlyList.Count);
1196            Assert.AreEqual(1, c2.NonReadOnlyList[0]);
1197            Assert.AreEqual(11, c2.NonReadOnlyList[1]);
1198
1199            Assert.AreEqual(1, c2.Array.Count);
1200            Assert.AreEqual(13, c2.Array[0]);
1201        }
1202#endif
1203
1204        [Test]
1205        public void SerializeArray2D()
1206        {
1207            Array2D aa = new Array2D();
1208            aa.Before = "Before!";
1209            aa.After = "After!";
1210            aa.Coordinates = new[,] { { 1, 1 }, { 1, 2 }, { 2, 1 }, { 2, 2 } };
1211
1212            string json = JsonConvert.SerializeObject(aa);
1213
1214            Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2],[2,1],[2,2]],""After"":""After!""}", json);
1215        }
1216
1217        [Test]
1218        public void SerializeArray3D()
1219        {
1220            Array3D aa = new Array3D();
1221            aa.Before = "Before!";
1222            aa.After = "After!";
1223            aa.Coordinates = new[,,] { { { 1, 1, 1 }, { 1, 1, 2 } }, { { 1, 2, 1 }, { 1, 2, 2 } }, { { 2, 1, 1 }, { 2, 1, 2 } }, { { 2, 2, 1 }, { 2, 2, 2 } } };
1224
1225            string json = JsonConvert.SerializeObject(aa);
1226
1227            Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}", json);
1228        }
1229
1230        [Test]
1231        public void SerializeArray3DWithConverter()
1232        {
1233            Array3DWithConverter aa = new Array3DWithConverter();
1234            aa.Before = "Before!";
1235            aa.After = "After!";
1236            aa.Coordinates = new[,,] { { { 1, 1, 1 }, { 1, 1, 2 } }, { { 1, 2, 1 }, { 1, 2, 2 } }, { { 2, 1, 1 }, { 2, 1, 2 } }, { { 2, 2, 1 }, { 2, 2, 2 } } };
1237
1238            string json = JsonConvert.SerializeObject(aa, Formatting.Indented);
1239
1240            StringAssert.AreEqual(@"{
1241  ""Before"": ""Before!"",
1242  ""Coordinates"": [
1243    [
1244      [
1245        1.0,
1246        1.0,
1247        1.0
1248      ],
1249      [
1250        1.0,
1251        1.0,
1252        2.0
1253      ]
1254    ],
1255    [
1256      [
1257        1.0,
1258        2.0,
1259        1.0
1260      ],
1261      [
1262        1.0,
1263        2.0,
1264        2.0
1265      ]
1266    ],
1267    [
1268      [
1269        2.0,
1270        1.0,
1271        1.0
1272      ],
1273      [
1274        2.0,
1275        1.0,
1276        2.0
1277      ]
1278    ],
1279    [
1280      [
1281        2.0,
1282        2.0,
1283        1.0
1284      ],
1285      [
1286        2.0,
1287        2.0,
1288        2.0
1289      ]
1290    ]
1291  ],
1292  ""After"": ""After!""
1293}", json);
1294        }
1295
1296        [Test]
1297        public void DeserializeArray3DWithConverter()
1298        {
1299            string json = @"{
1300  ""Before"": ""Before!"",
1301  ""Coordinates"": [
1302    [
1303      [
1304        1.0,
1305        1.0,
1306        1.0
1307      ],
1308      [
1309        1.0,
1310        1.0,
1311        2.0
1312      ]
1313    ],
1314    [
1315      [
1316        1.0,
1317        2.0,
1318        1.0
1319      ],
1320      [
1321        1.0,
1322        2.0,
1323        2.0
1324      ]
1325    ],
1326    [
1327      [
1328        2.0,
1329        1.0,
1330        1.0
1331      ],
1332      [
1333        2.0,
1334        1.0,
1335        2.0
1336      ]
1337    ],
1338    [
1339      [
1340        2.0,
1341        2.0,
1342        1.0
1343      ],
1344      [
1345        2.0,
1346        2.0,
1347        2.0
1348      ]
1349    ]
1350  ],
1351  ""After"": ""After!""
1352}";
1353
1354            Array3DWithConverter aa = JsonConvert.DeserializeObject<Array3DWithConverter>(json);
1355
1356            Assert.AreEqual("Before!", aa.Before);
1357            Assert.AreEqual("After!", aa.After);
1358            Assert.AreEqual(4, aa.Coordinates.GetLength(0));
1359            Assert.AreEqual(2, aa.Coordinates.GetLength(1));
1360            Assert.AreEqual(3, aa.Coordinates.GetLength(2));
1361            Assert.AreEqual(1, aa.Coordinates[0, 0, 0]);
1362            Assert.AreEqual(2, aa.Coordinates[1, 1, 1]);
1363        }
1364
1365        [Test]
1366        public void DeserializeArray2D()
1367        {
1368            string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2],[2,1],[2,2]],""After"":""After!""}";
1369
1370            Array2D aa = JsonConvert.DeserializeObject<Array2D>(json);
1371
1372            Assert.AreEqual("Before!", aa.Before);
1373            Assert.AreEqual("After!", aa.After);
1374            Assert.AreEqual(4, aa.Coordinates.GetLength(0));
1375            Assert.AreEqual(2, aa.Coordinates.GetLength(1));
1376            Assert.AreEqual(1, aa.Coordinates[0, 0]);
1377            Assert.AreEqual(2, aa.Coordinates[1, 1]);
1378
1379            string after = JsonConvert.SerializeObject(aa);
1380
1381            Assert.AreEqual(json, after);
1382        }
1383
1384        [Test]
1385        public void DeserializeArray2D_WithTooManyItems()
1386        {
1387            string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1,2,3],[2,1],[2,2]],""After"":""After!""}";
1388
1389            ExceptionAssert.Throws<Exception>(() => JsonConvert.DeserializeObject<Array2D>(json), "Cannot deserialize non-cubical array as multidimensional array.");
1390        }
1391
1392        [Test]
1393        public void DeserializeArray2D_WithTooFewItems()
1394        {
1395            string json = @"{""Before"":""Before!"",""Coordinates"":[[1,1],[1],[2,1],[2,2]],""After"":""After!""}";
1396
1397            ExceptionAssert.Throws<Exception>(() => JsonConvert.DeserializeObject<Array2D>(json), "Cannot deserialize non-cubical array as multidimensional array.");
1398        }
1399
1400        [Test]
1401        public void DeserializeArray3D()
1402        {
1403            string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
1404
1405            Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
1406
1407            Assert.AreEqual("Before!", aa.Before);
1408            Assert.AreEqual("After!", aa.After);
1409            Assert.AreEqual(4, aa.Coordinates.GetLength(0));
1410            Assert.AreEqual(2, aa.Coordinates.GetLength(1));
1411            Assert.AreEqual(3, aa.Coordinates.GetLength(2));
1412            Assert.AreEqual(1, aa.Coordinates[0, 0, 0]);
1413            Assert.AreEqual(2, aa.Coordinates[1, 1, 1]);
1414
1415            string after = JsonConvert.SerializeObject(aa);
1416
1417            Assert.AreEqual(json, after);
1418        }
1419
1420        [Test]
1421        public void DeserializeArray3D_WithTooManyItems()
1422        {
1423            string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2,1]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
1424
1425            ExceptionAssert.Throws<Exception>(() => JsonConvert.DeserializeObject<Array3D>(json), "Cannot deserialize non-cubical array as multidimensional array.");
1426        }
1427
1428        [Test]
1429        public void DeserializeArray3D_WithBadItems()
1430        {
1431            string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1,2]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],{}]],""After"":""After!""}";
1432
1433            ExceptionAssert.Throws<JsonSerializationException>(() => JsonConvert.DeserializeObject<Array3D>(json), "Unexpected token when deserializing multidimensional array: StartObject. Path 'Coordinates[3][1]', line 1, position 99.");
1434        }
1435
1436        [Test]
1437        public void DeserializeArray3D_WithTooFewItems()
1438        {
1439            string json = @"{""Before"":""Before!"",""Coordinates"":[[[1,1,1],[1,1]],[[1,2,1],[1,2,2]],[[2,1,1],[2,1,2]],[[2,2,1],[2,2,2]]],""After"":""After!""}";
1440
1441            ExceptionAssert.Throws<Exception>(() => JsonConvert.DeserializeObject<Array3D>(json), "Cannot deserialize non-cubical array as multidimensional array.");
1442        }
1443
1444        [Test]
1445        public void SerializeEmpty3DArray()
1446        {
1447            Array3D aa = new Array3D();
1448            aa.Before = "Before!";
1449            aa.After = "After!";
1450            aa.Coordinates = new int[0, 0, 0];
1451
1452            string json = JsonConvert.SerializeObject(aa);
1453
1454            Assert.AreEqual(@"{""Before"":""Before!"",""Coordinates"":[],""After"":""After!""}", json);
1455        }
1456
1457        [Test]
1458        public void DeserializeEmpty3DArray()
1459        {
1460            string json = @"{""Before"":""Before!"",""Coordinates"":[],""After"":""After!""}";
1461
1462            Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
1463
1464            Assert.AreEqual("Before!", aa.Before);
1465            Assert.AreEqual("After!", aa.After);
1466            Assert.AreEqual(0, aa.Coordinates.GetLength(0));
1467            Assert.AreEqual(0, aa.Coordinates.GetLength(1));
1468            Assert.AreEqual(0, aa.Coordinates.GetLength(2));
1469
1470            string after = JsonConvert.SerializeObject(aa);
1471
1472            Assert.AreEqual(json, after);
1473        }
1474
1475        [Test]
1476        public void DeserializeIncomplete3DArray()
1477        {
1478            string json = @"{""Before"":""Before!"",""Coordinates"":[/*hi*/[/*hi*/[1/*hi*/,/*hi*/1/*hi*/,1]/*hi*/,/*hi*/[1,1";
1479
1480            ExceptionAssert.Throws<JsonException>(() => JsonConvert.DeserializeObject<Array3D>(json));
1481        }
1482
1483        [Test]
1484        public void DeserializeIncompleteNotTopLevel3DArray()
1485        {
1486            string json = @"{""Before"":""Before!"",""Coordinates"":[/*hi*/[/*hi*/";
1487
1488            ExceptionAssert.Throws<JsonException>(() => JsonConvert.DeserializeObject<Array3D>(json));
1489        }
1490
1491        [Test]
1492        public void DeserializeNull3DArray()
1493        {
1494            string json = @"{""Before"":""Before!"",""Coordinates"":null,""After"":""After!""}";
1495
1496            Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
1497
1498            Assert.AreEqual("Before!", aa.Before);
1499            Assert.AreEqual("After!", aa.After);
1500            Assert.AreEqual(null, aa.Coordinates);
1501
1502            string after = JsonConvert.SerializeObject(aa);
1503
1504            Assert.AreEqual(json, after);
1505        }
1506
1507        [Test]
1508        public void DeserializeSemiEmpty3DArray()
1509        {
1510            string json = @"{""Before"":""Before!"",""Coordinates"":[[]],""After"":""After!""}";
1511
1512            Array3D aa = JsonConvert.DeserializeObject<Array3D>(json);
1513
1514            Assert.AreEqual("Before!", aa.Before);
1515            Assert.AreEqual("After!", aa.After);
1516            Assert.AreEqual(1, aa.Coordinates.GetLength(0));
1517            Assert.AreEqual(0, aa.Coordinates.GetLength(1));
1518            Assert.AreEqual(0, aa.Coordinates.GetLength(2));
1519
1520            string after = JsonConvert.SerializeObject(aa);
1521
1522            Assert.AreEqual(json, after);
1523        }
1524
1525        [Test]
1526        public void SerializeReferenceTracked3DArray()
1527        {
1528            Event1 e1 = new Event1
1529            {
1530                EventName = "EventName!"
1531            };
1532            Event1[,] array1 = new[,] { { e1, e1 }, { e1, e1 } };
1533            IList<Event1[,]> values1 = new List<Event1[,]>
1534            {
1535                array1,
1536                array1
1537            };
1538
1539            string json = JsonConvert.SerializeObject(values1, new JsonSerializerSettings
1540            {
1541                PreserveReferencesHandling = PreserveReferencesHandling.All,
1542                Formatting = Formatting.Indented
1543            });
1544
1545            StringAssert.AreEqual(@"{
1546  ""$id"": ""1"",
1547  ""$values"": [
1548    {
1549      ""$id"": ""2"",
1550      ""$values"": [
1551        [
1552          {
1553            ""$id"": "

Large files files are truncated, but you can click here to view the full file