PageRenderTime 104ms CodeModel.GetById 3ms app.highlight 86ms RepoModel.GetById 1ms app.codeStats 0ms

/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
   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"": ""3"",
1554            ""EventName"": ""EventName!"",
1555            ""Venue"": null,
1556            ""Performances"": null
1557          },
1558          {
1559            ""$ref"": ""3""
1560          }
1561        ],
1562        [
1563          {
1564            ""$ref"": ""3""
1565          },
1566          {
1567            ""$ref"": ""3""
1568          }
1569        ]
1570      ]
1571    },
1572    {
1573      ""$ref"": ""2""
1574    }
1575  ]
1576}", json);
1577        }
1578
1579        [Test]
1580        public void SerializeTypeName3DArray()
1581        {
1582            Event1 e1 = new Event1
1583            {
1584                EventName = "EventName!"
1585            };
1586            Event1[,] array1 = new[,] { { e1, e1 }, { e1, e1 } };
1587            IList<Event1[,]> values1 = new List<Event1[,]>
1588            {
1589                array1,
1590                array1
1591            };
1592
1593            string json = JsonConvert.SerializeObject(values1, new JsonSerializerSettings
1594            {
1595                TypeNameHandling = TypeNameHandling.All,
1596                Formatting = Formatting.Indented
1597            });
1598
1599            StringAssert.AreEqual(@"{
1600  ""$type"": """ + ReflectionUtils.GetTypeName(typeof(List<Event1[,]>), 0, DefaultSerializationBinder.Instance) + @""",
1601  ""$values"": [
1602    {
1603      ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1[,], Newtonsoft.Json.Tests"",
1604      ""$values"": [
1605        [
1606          {
1607            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1608            ""EventName"": ""EventName!"",
1609            ""Venue"": null,
1610            ""Performances"": null
1611          },
1612          {
1613            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1614            ""EventName"": ""EventName!"",
1615            ""Venue"": null,
1616            ""Performances"": null
1617          }
1618        ],
1619        [
1620          {
1621            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1622            ""EventName"": ""EventName!"",
1623            ""Venue"": null,
1624            ""Performances"": null
1625          },
1626          {
1627            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1628            ""EventName"": ""EventName!"",
1629            ""Venue"": null,
1630            ""Performances"": null
1631          }
1632        ]
1633      ]
1634    },
1635    {
1636      ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1[,], Newtonsoft.Json.Tests"",
1637      ""$values"": [
1638        [
1639          {
1640            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1641            ""EventName"": ""EventName!"",
1642            ""Venue"": null,
1643            ""Performances"": null
1644          },
1645          {
1646            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1647            ""EventName"": ""EventName!"",
1648            ""Venue"": null,
1649            ""Performances"": null
1650          }
1651        ],
1652        [
1653          {
1654            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1655            ""EventName"": ""EventName!"",
1656            ""Venue"": null,
1657            ""Performances"": null
1658          },
1659          {
1660            ""$type"": ""Newtonsoft.Json.Tests.TestObjects.Events.Event1, Newtonsoft.Json.Tests"",
1661            ""EventName"": ""EventName!"",
1662            ""Venue"": null,
1663            ""Performances"": null
1664          }
1665        ]
1666      ]
1667    }
1668  ]
1669}", json);
1670
1671            IList<Event1[,]> values2 = (IList<Event1[,]>)JsonConvert.DeserializeObject(json, new JsonSerializerSettings
1672            {
1673                TypeNameHandling = TypeNameHandling.All
1674            });
1675
1676            Assert.AreEqual(2, values2.Count);
1677            Assert.AreEqual("EventName!", values2[0][0, 0].EventName);
1678        }
1679
1680        [Test]
1681        public void PrimitiveValuesInObjectArray()
1682        {
1683            string json = @"{""action"":""Router"",""method"":""Navigate"",""data"":[""dashboard"",null],""type"":""rpc"",""tid"":2}";
1684
1685            ObjectArrayPropertyTest o = JsonConvert.DeserializeObject<ObjectArrayPropertyTest>(json);
1686
1687            Assert.AreEqual("Router", o.Action);
1688            Assert.AreEqual("Navigate", o.Method);
1689            Assert.AreEqual(2, o.Data.Length);
1690            Assert.AreEqual("dashboard", o.Data[0]);
1691            Assert.AreEqual(null, o.Data[1]);
1692        }
1693
1694        [Test]
1695        public void ComplexValuesInObjectArray()
1696        {
1697            string json = @"{""action"":""Router"",""method"":""Navigate"",""data"":[""dashboard"",[""id"", 1, ""teststring"", ""test""],{""one"":1}],""type"":""rpc"",""tid"":2}";
1698
1699            ObjectArrayPropertyTest o = JsonConvert.DeserializeObject<ObjectArrayPropertyTest>(json);
1700
1701            Assert.AreEqual("Router", o.Action);
1702            Assert.AreEqual("Navigate", o.Method);
1703            Assert.AreEqual(3, o.Data.Length);
1704            Assert.AreEqual("dashboard", o.Data[0]);
1705            CustomAssert.IsInstanceOfType(typeof(JArray), o.Data[1]);
1706            Assert.AreEqual(4, ((JArray)o.Data[1]).Count);
1707            CustomAssert.IsInstanceOfType(typeof(JObject), o.Data[2]);
1708            Assert.AreEqual(1, ((JObject)o.Data[2]).Count);
1709            Assert.AreEqual(1, (int)((JObject)o.Data[2])["one"]);
1710        }
1711
1712#if !(DNXCORE50)
1713        [Test]
1714        public void SerializeArrayAsArrayList()
1715        {
1716            string jsonText = @"[3, ""somestring"",[1,2,3],{}]";
1717            ArrayList o = JsonConvert.DeserializeObject<ArrayList>(jsonText);
1718
1719            Assert.AreEqual(4, o.Count);
1720            Assert.AreEqual(3, ((JArray)o[2]).Count);
1721            Assert.AreEqual(0, ((JObject)o[3]).Count);
1722        }
1723#endif
1724
1725        [Test]
1726        public void SerializeMemberGenericList()
1727        {
1728            Name name = new Name("The Idiot in Next To Me");
1729
1730            PhoneNumber p1 = new PhoneNumber("555-1212");
1731            PhoneNumber p2 = new PhoneNumber("444-1212");
1732
1733            name.pNumbers.Add(p1);
1734            name.pNumbers.Add(p2);
1735
1736            string json = JsonConvert.SerializeObject(name, Formatting.Indented);
1737
1738            StringAssert.AreEqual(@"{
1739  ""personsName"": ""The Idiot in Next To Me"",
1740  ""pNumbers"": [
1741    {
1742      ""phoneNumber"": ""555-1212""
1743    },
1744    {
1745      ""phoneNumber"": ""444-1212""
1746    }
1747  ]
1748}", json);
1749
1750            Name newName = JsonConvert.DeserializeObject<Name>(json);
1751
1752            Assert.AreEqual("The Idiot in Next To Me", newName.personsName);
1753
1754            // not passed in as part of the constructor but assigned to pNumbers property
1755            Assert.AreEqual(2, newName.pNumbers.Count);
1756            Assert.AreEqual("555-1212", newName.pNumbers[0].phoneNumber);
1757            Assert.AreEqual("444-1212", newName.pNumbers[1].phoneNumber);
1758        }
1759
1760        [Test]
1761        public void CustomCollectionSerialization()
1762        {
1763            ProductCollection collection = new ProductCollection()
1764            {
1765                new Product() { Name = "Test1" },
1766                new Product() { Name = "Test2" },
1767                new Product() { Name = "Test3" }
1768            };
1769
1770            JsonSerializer jsonSerializer = new JsonSerializer();
1771            jsonSerializer.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
1772
1773            StringWriter sw = new StringWriter();
1774
1775            jsonSerializer.Serialize(sw, collection);
1776
1777            Assert.AreEqual(@"[{""Name"":""Test1"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null},{""Name"":""Test2"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null},{""Name"":""Test3"",""ExpiryDate"":""2000-01-01T00:00:00Z"",""Price"":0.0,""Sizes"":null}]",
1778                sw.GetStringBuilder().ToString());
1779
1780            ProductCollection collectionNew = (ProductCollection)jsonSerializer.Deserialize(new JsonTextReader(new StringReader(sw.GetStringBuilder().ToString())), typeof(ProductCollection));
1781
1782            CollectionAssert.AreEqual(collection, collectionNew);
1783        }
1784
1785        [Test]
1786        public void GenericCollectionInheritance()
1787        {
1788            string json;
1789
1790            GenericClass<GenericItem<string>, string> foo1 = new GenericClass<GenericItem<string>, string>();
1791            foo1.Items.Add(new GenericItem<string> { Value = "Hello" });
1792
1793            json = JsonConvert.SerializeObject(new { selectList = foo1 });
1794            Assert.AreEqual(@"{""selectList"":[{""Value"":""Hello""}]}", json);
1795
1796            GenericClass<NonGenericItem, string> foo2 = new GenericClass<NonGenericItem, string>();
1797            foo2.Items.Add(new NonGenericItem { Value = "Hello" });
1798
1799            json = JsonConvert.SerializeObject(new { selectList = foo2 });
1800            Assert.AreEqual(@"{""selectList"":[{""Value"":""Hello""}]}", json);
1801
1802            NonGenericClass foo3 = new NonGenericClass();
1803            foo3.Items.Add(new NonGenericItem { Value = "Hello" });
1804
1805            json = JsonConvert.SerializeObject(new { selectList = foo3 });
1806            Assert.AreEqual(@"{""selectList"":[{""Value"":""Hello""}]}", json);
1807        }
1808
1809        [Test]
1810        public void InheritedListSerialize()
1811        {
1812            Article a1 = new Article("a1");
1813            Article a2 = new Article("a2");
1814
1815            ArticleCollection articles1 = new ArticleCollection();
1816            articles1.Add(a1);
1817            articles1.Add(a2);
1818
1819            string jsonText = JsonConvert.SerializeObject(articles1);
1820
1821            ArticleCollection articles2 = JsonConvert.DeserializeObject<ArticleCollection>(jsonText);
1822
1823            Assert.AreEqual(articles1.Count, articles2.Count);
1824            Assert.AreEqual(articles1[0].Name, articles2[0].Name);
1825        }
1826
1827        [Test]
1828        public void ReadOnlyCollectionSerialize()
1829        {
1830            ReadOnlyCollection<int> r1 = new ReadOnlyCollection<int>(new int[] { 0, 1, 2, 3, 4 });
1831
1832            string jsonText = JsonConvert.SerializeObject(r1);
1833
1834            Assert.AreEqual("[0,1,2,3,4]", jsonText);
1835
1836            ReadOnlyCollection<int> r2 = JsonConvert.DeserializeObject<ReadOnlyCollection<int>>(jsonText);
1837
1838            CollectionAssert.AreEqual(r1, r2);
1839        }
1840
1841        [Test]
1842        public void SerializeGenericList()
1843        {
1844            Product p1 = new Product
1845            {
1846                Name = "Product 1",
1847                Price = 99.95m,
1848                ExpiryDate = new DateTime(2000, 12, 29, 0, 0, 0, DateTimeKind.Utc),
1849            };
1850            Product p2 = new Product
1851            {
1852                Name = "Product 2",
1853                Price = 12.50m,
1854                ExpiryDate = new DateTime(2009, 7, 31, 0, 0, 0, DateTimeKind.Utc),
1855            };
1856
1857            List<Product> products = new List<Product>();
1858            products.Add(p1);
1859            products.Add(p2);
1860
1861            string json = JsonConvert.SerializeObject(products, Formatting.Indented);
1862            //[
1863            //  {
1864            //    "Name": "Product 1",
1865            //    "ExpiryDate": "\/Date(978048000000)\/",
1866            //    "Price": 99.95,
1867            //    "Sizes": null
1868            //  },
1869            //  {
1870            //    "Name": "Product 2",
1871            //    "ExpiryDate": "\/Date(1248998400000)\/",
1872            //    "Price": 12.50,
1873            //    "Sizes": null
1874            //  }
1875            //]
1876
1877            StringAssert.AreEqual(@"[
1878  {
1879    ""Name"": ""Product 1"",
1880    ""ExpiryDate"": ""2000-12-29T00:00:00Z"",
1881    ""Price"": 99.95,
1882    ""Sizes"": null
1883  },
1884  {
1885    ""Name"": ""Product 2"",
1886    ""ExpiryDate"": ""2009-07-31T00:00:00Z"",
1887    ""Price"": 12.50,
1888    ""Sizes"": null
1889  }
1890]", json);
1891        }
1892
1893        [Test]
1894        public void DeserializeGenericList()
1895        {
1896            string json = @"[
1897        {
1898          ""Name"": ""Product 1"",
1899          ""ExpiryDate"": ""\/Date(978048000000)\/"",
1900          ""Price"": 99.95,
1901          ""Sizes"": null
1902        },
1903        {
1904          ""Name"": ""Product 2"",
1905          ""ExpiryDate"": ""\/Date(1248998400000)\/"",
1906          ""Price"": 12.50,
1907          ""Sizes"": null
1908        }
1909      ]";
1910
1911            List<Product> products = JsonConvert.DeserializeObject<List<Product>>(json);
1912
1913            Product p1 = products[0];
1914
1915            Assert.AreEqual(2, products.Count);
1916            Assert.AreEqual("Product 1", p1.Name);
1917        }
1918
1919#if !(NET40 || NET35 || NET20 || PORTABLE40)
1920        [Test]
1921        public void ReadOnlyIntegerList()
1922        {
1923            ReadOnlyIntegerList l = new ReadOnlyIntegerList(new List<int>
1924            {
1925                1,
1926                2,
1927                3,
1928                int.MaxValue
1929            });
1930
1931            string json = JsonConvert.SerializeObject(l, Formatting.Indented);
1932
1933            StringAssert.AreEqual(@"[
1934  1,
1935  2,
1936  3,
1937  2147483647
1938]", json);
1939        }
1940#endif
1941
1942#if !DNXCORE50
1943        [Test]
1944        public void EmptyStringInHashtableIsDeserialized()
1945        {
1946            string externalJson = @"{""$type"":""System.Collections.Hashtable, mscorlib"",""testkey"":""""}";
1947
1948            JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All };
1949
1950            JsonConvert.SerializeObject(new Hashtable { { "testkey", "" } }, settings);
1951            Hashtable deserializeTest2 = JsonConvert.DeserializeObject<Hashtable>(externalJson, settings);
1952
1953            Assert.AreEqual(deserializeTest2["testkey"], "");
1954        }
1955#endif
1956
1957        [Test]
1958        public void DeserializeCollectionWithConstructorArrayArgument()
1959        {
1960            var v = new ReadOnlyCollectionWithArrayArgument<double>(new[] { -0.014147478859765236, -0.011419606805541858, -0.010038461483676238 });
1961            var json = JsonConvert.SerializeObject(v);
1962
1963            ExceptionAssert.Throws<JsonSerializationException>(() =>
1964            {
1965                JsonConvert.DeserializeObject<ReadOnlyCollectionWithArrayArgument<double>>(json);
1966            }, "Unable to find a constructor to use for type Newtonsoft.Json.Tests.Serialization.ReadOnlyCollectionWithArrayArgument`1[System.Double]. Path '', line 1, position 1.");
1967        }
1968
1969#if !NET20 && !PORTABLE40
1970        [Test]
1971        public void NonDefaultConstructor_DuplicateKeyInDictionary_Replace()
1972        {
1973            string json = @"{ ""user"":""bpan"", ""Person"":{ ""groups"":""replaced!"", ""domain"":""adm"", ""mail"":""bpan@sdu.dk"", ""sn"":""Pan"", ""gn"":""Benzhi"", ""cn"":""Benzhi Pan"", ""eo"":""BQHLJaVTMr0eWsi1jaIut4Ls/pSuMeNEmsWfWsfKo="", ""guid"":""9A38CE8E5B288942A8DA415CF5E687"", ""employeenumber"":""2674"", ""omk1"":""930"", ""language"":""da"" }, ""XMLResponce"":""<?xml version='1.0' encoding='iso-8859-1' ?>\n<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>\n\t<cas:authenticationSuccess>\n\t\t<cas:user>bpan</cas:user>\n\t\t<norEduPerson>\n\t\t\t<groups>FNC-PRI-APP-SUNDB-EDOR-A,FNC-RI-APP-SUB-EDITOR-B</groups>\n\t\t\t<domain>adm</domain>\n\t\t\t<mail>bpan@sdu.dk</mail>\n\t\t\t<sn>Pan</sn>\n\t\t\t<gn>Benzhi</gn>\n\t\t\t<cn>Benzhi Pan</cn>\n\t\t\t<eo>BQHLJaVTMr0eWsi1jaIut4Lsfr/pSuMeNEmsWfWsfKo=</eo>\n\t\t\t<guid>9A38CE8E5B288942A8DA415C2C687</guid>\n\t\t\t<employeenumber>274</employeenumber>\n\t\t\t<omk1>930</omk1>\n\t\t\t<language>da</language>\n\t\t</norEduPerson>\n\t</cas:authenticationSuccess>\n</cas:serviceResponse>\n"", ""Language"":1, ""Groups"":[ ""FNC-PRI-APP-SNDB-EDOR-A"", ""FNC-PI-APP-SUNDB-EDOR-B"" ], ""Domain"":""adm"", ""Mail"":""bpan@sdu.dk"", ""Surname"":""Pan"", ""Givenname"":""Benzhi"", ""CommonName"":""Benzhi Pan"", ""OrganizationName"":null }";
1974
1975            var result = JsonConvert.DeserializeObject<CASResponce>(json);
1976
1977            Assert.AreEqual("replaced!", result.Person["groups"]);
1978        }
1979#endif
1980
1981        [Test]
1982        public void GenericIListAndOverrideConstructor()
1983        {
1984            MyClass deserialized = JsonConvert.DeserializeObject<MyClass>(@"[""apple"", ""monkey"", ""goose""]");
1985
1986            Assert.AreEqual("apple", deserialized[0]);
1987            Assert.AreEqual("monkey", deserialized[1]);
1988            Assert.AreEqual("goose", deserialized[2]);
1989        }
1990
1991        public class MyClass : IList<string>
1992        {
1993            private List<string> _storage;
1994
1995            [JsonConstructor]
1996            private MyClass()
1997            {
1998                _storage = new List<string>();
1999            }
2000
2001            public MyClass(IEnumerable<string> source)
2002            {
2003                _storage = new List<string>(source);
2004            }
2005
2006            //Below is generated by VS to implement IList<string>
2007            public string this[int index]
2008            {
2009                get
2010                {
2011                    return ((IList<string>)_storage)[index];
2012                }
2013
2014                set
2015                {
2016                    ((IList<string>)_storage)[index] = value;
2017                }
2018            }
2019
2020            public int Count
2021            {
2022                get
2023                {
2024                    return ((IList<string>)_storage).Count;
2025                }
2026            }
2027
2028            public bool IsReadOnly
2029            {
2030                get
2031                {
2032                    return ((IList<string>)_storage).IsReadOnly;
2033                }
2034            }
2035
2036            public void Add(string item)
2037            {
2038                ((IList<string>)_storage).Add(item);
2039            }
2040
2041            public void Clear()
2042            {
2043                ((IList<string>)_storage).Clear();
2044            }
2045
2046            public bool Contains(string item)
2047            {
2048                return ((IList<string>)_storage).Contains(item);
2049            }
2050
2051            public void CopyTo(string[] array, int arrayIndex)
2052            {
2053                ((IList<string>)_storage).CopyTo(array, arrayIndex);
2054            }
2055
2056            public IEnumerator<string> GetEnumerator()
2057            {
2058                return ((IList<string>)_storage).GetEnumerator();
2059            }
2060
2061            public int IndexOf(string item)
2062            {
2063                return ((IList<string>)_storage).IndexOf(item);
2064            }
2065
2066            public void Insert(int index, string item)
2067            {
2068                ((IList<string>)_storage).Insert(index, item);
2069            }
2070
2071            public bool Remove(string item)
2072            {
2073                return ((IList<string>)_storage).Remove(item);
2074            }
2075
2076            public void RemoveAt(int index)
2077            {
2078                ((IList<string>)_storage).RemoveAt(index);
2079            }
2080
2081            IEnumerator IEnumerable.GetEnumerator()
2082            {
2083                return ((IList<string>)_storage).GetEnumerator();
2084            }
2085        }
2086    }
2087
2088#if !NET20 && !PORTABLE40
2089    public class CASResponce
2090    {
2091        //<?xml version='1.0' encoding='iso-8859-1' ?>
2092        //<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
2093        //    <cas:authenticationSuccess>
2094        //        <cas:user>and</cas:user>
2095        //        <norEduPerson>
2096        //            <groups>IT-service-OD,USR-IT-service,IT-service-udvikling</groups>
2097        //            <domain>adm</domain>
2098        //            <mail>and@sdu.dk</mail>
2099        //            <sn>And</sn>
2100        //            <gn>Anders</gn>
2101        //            <cn>Anders And</cn>
2102        //            <eo>QQT3tKSKjCxQSGsDiR8HTP9L5VsojBvOYyjOu8pwLMA=</eo>
2103        //            <guid>DE423352CC763649B8F2ECF1DA304750</guid>
2104        //            <language>da</language>  
2105        //        </norEduPerson>
2106        //    </cas:authenticationSuccess>
2107        //</cas:serviceResponse>
2108
2109        // NemID
2110        //<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
2111        //  <cas:authenticationSuccess>
2112        //      <cas:user>
2113        //          2903851921
2114        //      </cas:user>
2115        //  </cas:authenticationSuccess>
2116        //</cas:serviceResponse>
2117
2118
2119        //WAYF
2120        //<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
2121        //  <cas:authenticationSuccess>
2122        //     <cas:user>
2123        //          jj@testidp.wayf.dk
2124        //     </cas:user>
2125        //  <norEduPerson>
2126        //     <sn>Jensen</sn>
2127        //     <gn>Jens</gn>
2128        //     <cn>Jens farmer</cn>
2129        //      <eduPersonPrincipalName>jj @testidp.wayf.dk</eduPersonPrincipalName>
2130        //        <mail>jens.jensen @institution.dk</mail>
2131        //        <organizationName>Institution</organizationName>
2132        //        <eduPersonAssurance>2</eduPersonAssurance>
2133        //        <schacPersonalUniqueID>urn:mace:terena.org:schac:personalUniqueID:dk:CPR:0708741234</schacPersonalUniqueID>
2134        //        <eduPersonScopedAffiliation>student @course1.testidp.wayf.dk</eduPersonScopedAffiliation>
2135        //        <eduPersonScopedAffiliation>staff @course1.testidp.wayf.dk</eduPersonScopedAffiliation>
2136        //        <eduPersonScopedAffiliation>staff @course1.testidp.wsayf.dk</eduPersonScopedAffiliation>
2137        //        <preferredLanguage>en</preferredLanguage>
2138        //        <eduPersonEntitlement>test</eduPersonEntitlement>
2139        //        <eduPersonPrimaryAffiliation>student</eduPersonPrimaryAffiliation>
2140        //        <schacCountryOfCitizenship>DK</schacCountryOfCitizenship>
2141        //        <eduPersonTargetedID>WAYF-DK-7a86d1c3b69a9639d7650b64f2eb773bd21a8c6d</eduPersonTargetedID>
2142        //        <schacHomeOrganization>testidp.wayf.dk</schacHomeOrganization>
2143        //        <givenName>Jens</givenName>
2144        //      <o>Institution</o>
2145        //     <idp>https://testbridge.wayf.dk</idp>
2146        //  </norEduPerson>
2147        // </cas:authenticationSuccess>
2148        //</cas:serviceResponse>
2149
2150
2151        public enum ssoLanguage
2152        {
2153            Unknown,
2154            Danish,
2155            English
2156        }
2157
2158
2159        public CASResponce(string xmlResponce)
2160        {
2161            this.Domain = "";
2162            this.Mail = "";
2163            this.Surname = "";
2164            this.Givenname = "";
2165            this.CommonName = "";
2166
2167            ParseReplyXML(xmlResponce);
2168            ExtractGroups();
2169            ExtractLanguage();
2170        }
2171
2172        private void ExtractGroups()
2173        {
2174            this.Groups = new List<string>();
2175            if (this.Person.ContainsKey("groups"))
2176            {
2177                string groupsString = this.Person["groups"];
2178                string[] stringList = groupsString.Split(',');
2179
2180                foreach (string group in stringList)
2181                {
2182                    this.Groups.Add(group);
2183                }
2184            }
2185
2186        }
2187
2188        private void ExtractLanguage()
2189        {
2190            if (Person.ContainsKey("language"))
2191            {
2192                switch (Person["language"].Trim())
2193                {
2194                    case "da":
2195                        this.Language = ssoLanguage.Danish;
2196                        break;
2197                    case "en":
2198                        this.Language = ssoLanguage.English;
2199                        break;
2200                    default:
2201                        this.Language = ssoLanguage.Unknown;
2202                        break;
2203                }
2204            }
2205            else
2206            {
2207                this.Language = ssoLanguage.Unknown;
2208            }
2209        }
2210
2211
2212
2213
2214        private void ParseReplyXML(string xmlString)
2215        {
2216            try
2217            {
2218                System.Xml.Linq.XDocument xDoc = XDocument.Parse(xmlString);
2219
2220                var root = xDoc.Root;
2221
2222                string ns = "http://www.yale.edu/tp/cas";
2223
2224                XElement auth = root.Element(XName.Get("authenticationSuccess", ns));
2225
2226                if (auth == null)
2227                    auth = root.Element(XName.Get("authenticationFailure", ns));
2228
2229                XElement xNodeUser = auth.Element(XName.Get("user", ns));
2230
2231                XElement eduPers = auth.Element(XName.Get("norEduPerson", ""));
2232
2233                string casUser = "";
2234                Dictionary<string, string> eduPerson = new Dictionary<string, string>();
2235
2236                if (xNodeUser != null)
2237                {
2238                    casUser = xNodeUser.Value;
2239
2240                    if (eduPers != null)
2241                    {
2242                        foreach (XElement xPersonValue in eduPers.Elements())
2243                        {
2244                            if (!eduPerson.ContainsKey(xPersonValue.Name.LocalName))
2245                            {
2246                                eduPerson.Add(xPersonValue.Name.LocalName, xPersonValue.Value);
2247                            }
2248                            else
2249                            {
2250                                eduPerson[xPersonValue.Name.LocalName] = eduPerson[xPersonValue.Name.LocalName] + ";" + xPersonValue.Value;
2251                            }
2252                        }
2253                    }
2254                }
2255
2256                if (casUser.Trim() != "")
2257                {
2258                    this.user = casUser;
2259                }
2260
2261                if (eduPerson.ContainsKey("domain"))
2262                    this.Domain = eduPerson["domain"];
2263                if (eduPerson.ContainsKey("organizationName"))
2264                    this.OrganizationName = eduPerson["organizationName"];
2265                if (eduPerson.ContainsKey("mail"))
2266                    this.Mail = eduPerson["mail"];
2267                if (eduPerson.ContainsKey("sn"))
2268                    this.Surname = eduPerson["sn"];
2269                if (eduPerson.ContainsKey("gn"))
2270                    this.Givenname = eduPerson["gn"];
2271                if (eduPerson.ContainsKey("cn"))
2272                    this.CommonName = eduPerson["cn"];
2273
2274                this.Person = eduPerson;
2275                this.XMLResponce = xmlString;
2276            }
2277            catch
2278            {
2279                this.user = "";
2280
2281            }
2282        }
2283
2284        /// <summary>
2285        /// Fast felt der altid findes.
2286        /// </summary>
2287        public string user { get; private set; }
2288
2289        /// <summary>
2290        /// Person type som dictionary indeholdende de ekstra informationer returneret ved login.
2291        /// </summary>
2292        public Dictionary<string, string> Person { get; private set; }
2293
2294        /// <summary>
2295        /// Den oprindelige xml returneret fra CAS.
2296        /// </summary>
2297        public string XMLResponce { get; private set; }
2298
2299        /// <summary>
2300        /// Det sprog der benyttes i SSO. Muligheder er da eller en.
2301        /// </summary>
2302        public ssoLanguage Language { get; private set; }
2303
2304        /// <summary>
2305        /// Liste af grupper som man er medlem af. Kun udvalgt iblandt dem der blev puttet ind i systemet.
2306        /// </summary>
2307        public List<string> Groups { get; private set; }
2308
2309        public string Domain { get; private set; }
2310
2311        public string Mail { get; private set; }
2312
2313        public string Surname { get; private set; }
2314
2315        public string Givenname { get; private set; }
2316
2317        public string CommonName { get; private set; }
2318
2319        public string OrganizationName { get; private set; }
2320
2321    }
2322#endif
2323
2324    public class ReadOnlyCollectionWithArrayArgument<T> : IList<T>
2325    {
2326        private readonly IList<T> _values;
2327
2328        public ReadOnlyCollectionWithArrayArgument(T[] args)
2329        {
2330            _values = args ?? (IList<T>)new List<T>();
2331        }
2332
2333        public IEnumerator<T> GetEnumerator()
2334        {
2335            return _values.GetEnumerator();
2336        }
2337
2338        IEnumerator IEnumerable.GetEnumerator()
2339        {
2340            return _values.GetEnumerator();
2341        }
2342
2343        public void Add(T item)
2344        {
2345            throw new NotImplementedException();
2346        }
2347
2348        public void Clear()
2349        {
2350            throw new NotImplementedException();
2351        }
2352
2353        public bool Contains(T item)
2354        {
2355            throw new NotImplementedException();
2356        }
2357
2358        public void CopyTo(T[] array, int arrayIndex)
2359        {
2360            throw new NotImplementedException();
2361        }
2362
2363        public bool Remove(T item)
2364        {
2365            throw new NotImplementedException();
2366        }
2367
2368        public int Count { get; }
2369        public bool IsReadOnly { get; }
2370        public int IndexOf(T item)
2371        {
2372            throw new NotImplementedException();
2373        }
2374
2375        public void Insert(int index, T item)
2376        {
2377            throw new NotImplementedException();
2378        }
2379
2380        public void RemoveAt(int index)
2381        {
2382            throw new NotImplementedException();
2383        }
2384
2385        public T this[int index]
2386        {
2387            get { throw new NotImplementedException(); }
2388            set { throw new NotImplementedException(); }
2389        }
2390    }
2391
2392#if !(NET40 || NET35 || NET20 || PORTABLE40)
2393    public class ReadOnlyIntegerList : IReadOnlyCollection<int>
2394    {
2395        private readonly List<int> _list;
2396
2397        public ReadOnlyIntegerList(List<int> l)
2398        {
2399            _list = l;
2400        }
2401
2402        public int Count
2403        {
2404            get { return _list.Count; }
2405        }
2406
2407        public IEnumerator<int> GetEnumerator()
2408        {
2409            return _list.GetEnumerator();
2410        }
2411
2412        IEnumerator IEnumerable.GetEnumerator()
2413        {
2414            return GetEnumerator();
2415        }
2416    }
2417#endif
2418
2419    public class Array2D
2420    {
2421        public string Before { get; set; }
2422        public int[,] Coordinates { get; set; }
2423        public string After { get; set; }
2424    }
2425
2426    public class Array3D
2427    {
2428        public string Before { get; set; }
2429        public int[,,] Coordinates { get; set; }
2430        public string After { get; set; }
2431    }
2432
2433    public class Array3DWithConverter
2434    {
2435        public string Before { get; set; }
2436
2437        [JsonProperty(ItemConverterType = typeof(IntToFloatConverter))]
2438        public int[,,] Coordinates { get; set; }
2439
2440        public string After { get; set; }
2441    }
2442
2443    public class GenericItem<T>
2444    {
2445        public T Value { get; set; }
2446    }
2447
2448    public class NonGenericItem : GenericItem<string>
2449    {
2450    }
2451
2452    public class GenericClass<T, TValue> : IEnumerable<T>
2453        where T : GenericItem<TValue>, new()
2454    {
2455        public IList<T> Items { get; set; }
2456
2457        public GenericClass()
2458        {
2459            Items = new List<T>();
2460        }
2461
2462        public IEnumerator<T> GetEnumerator()
2463        {
2464            if (Items != null)
2465            {
2466                foreach (T item in Items)
2467                {
2468                    yield return item;
2469                }
2470            }
2471            else
2472            {
2473                yield break;
2474            }
2475        }
2476
2477        IEnumerator IEnumerable.GetEnumerator()
2478        {
2479            return GetEnumerator();
2480        }
2481    }
2482
2483    public class NonGenericClass : GenericClass<GenericItem<string>, string>
2484    {
2485    }
2486
2487    public class StringListAppenderConverter : JsonConverter
2488    {
2489        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
2490        {
2491            writer.WriteValue(value);
2492        }
2493
2494        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
2495        {
2496            List<string> existingStrings = (List<string>)existingValue;
2497            List<string> newStrings = new List<string>(existingStrings);
2498
2499            reader.Read();
2500
2501            while (reader.TokenType != JsonToken.EndArray)
2502            {
2503                string s = (string)reader.Value;
2504                newStrings.Add(s);
2505
2506                reader.Read();
2507            }
2508
2509            return newStrings;
2510        }
2511
2512        public override bool CanConvert(Type objectType)
2513        {
2514            return (objectType == typeof(List<string>));
2515        }
2516    }
2517
2518    public class StringAppenderConverter : JsonConverter
2519    {
2520        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
2521        {
2522            writer.WriteValue(value);
2523        }
2524
2525        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
2526        {
2527            string existingString = (string)existingValue;
2528            string newString = existingString + (string)reader.Value;
2529
2530            return newString;
2531        }
2532
2533        public override bool CanConvert(Type objectType)
2534        {
2535            return (objectType == typeof(string));
2536        }
2537    }
2538}