Add support for generic interface-based collections in JsonSerializer (dotnet/corefx...
authorLayomi Akinrinade <layomia@gmail.com>
Sat, 13 Apr 2019 01:44:18 +0000 (21:44 -0400)
committerGitHub <noreply@github.com>
Sat, 13 Apr 2019 01:44:18 +0000 (21:44 -0400)
* Add support for generic interface-based collections in JsonSerializer

Specifically, add enumerable converters for:

* IEnumerable<T>
* ICollection<T>
* IList<T>
* IReadOnlyCollection<T>
* IReadOnlyList<T>

This partially addresses https://github.com/dotnet/corefx/issues/36643

* Address review comments

* Add serialization tests for generic interface collection as members of class objects

Commit migrated from https://github.com/dotnet/corefx/commit/cc01ec9a781c4af5afd495c5b80a1f7d9616bed2

13 files changed:
src/libraries/System.Text.Json/src/System.Text.Json.csproj
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultEnumerableConverter.cs [new file with mode: 0644]
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs
src/libraries/System.Text.Json/tests/Serialization/Array.ReadTests.cs
src/libraries/System.Text.Json/tests/Serialization/Array.WriteTests.cs
src/libraries/System.Text.Json/tests/Serialization/Null.WriteTests.cs
src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.Polymorphic.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs
src/libraries/System.Text.Json/tests/Serialization/TestData.cs
src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs
src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.cs

index 0c8fe87..b22566c 100644 (file)
@@ -47,6 +47,7 @@
     <Compile Include="System\Text\Json\Serialization\Converters\DefaultArrayConverter.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\DefaultConverters.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\DefaultConvertersOfTValue.cs" />
+    <Compile Include="System\Text\Json\Serialization\Converters\DefaultEnumerableConverter.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterBoolean.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterByte.cs" />
     <Compile Include="System\Text\Json\Serialization\Converters\JsonValueConverterChar.cs" />
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultEnumerableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultEnumerableConverter.cs
new file mode 100644 (file)
index 0000000..afddd65
--- /dev/null
@@ -0,0 +1,90 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Text.Json.Serialization.Policies;
+
+namespace System.Text.Json.Serialization.Converters
+{
+    internal class JsonEnumerableT<T> : ICollection<T>, IEnumerable<T>, IList<T>, IReadOnlyCollection<T>, IReadOnlyList<T>
+    {
+        List<T> _list;
+
+        public JsonEnumerableT(IList sourceList)
+        {
+            // TODO: Change sourceList from IList to List<T> so we can do a direct assignment here.
+            _list = new List<T>();
+
+            foreach (object item in sourceList)
+            {
+                if (item is T itemT)
+                {
+                    _list.Add(itemT);
+                }
+            }
+        }
+
+        public T this[int index] { get => (T)_list[index]; set => _list[index] = value; }
+
+        public int Count => _list.Count;
+
+        public bool IsReadOnly => false;
+
+        public void Add(T item)
+        {
+            _list.Add(item);
+        }
+
+        public void Clear()
+        {
+            _list.Clear();
+        }
+
+        public bool Contains(T item)
+        {
+            return _list.Contains(item);
+        }
+
+        public void CopyTo(T[] array, int arrayIndex)
+        {
+            _list.CopyTo(array, arrayIndex);
+        }
+
+        public IEnumerator<T> GetEnumerator()
+        {
+            return _list.GetEnumerator();
+        }
+
+        public int IndexOf(T item)
+        {
+            return _list.IndexOf(item);
+        }
+
+        public void Insert(int index, T item)
+        {
+            _list.Insert(index, item);
+        }
+
+        public bool Remove(T item)
+        {
+            return _list.Remove(item);
+        }
+
+        public void RemoveAt(int index)
+        {
+            _list.RemoveAt(index);
+        }
+
+        IEnumerator IEnumerable.GetEnumerator()
+        {
+            return GetEnumerator();
+        }
+    }
+
+    internal sealed class DefaultEnumerableConverter : JsonEnumerableConverter
+    {
+        public override IEnumerable CreateFromList(Type elementType, IList sourceList)
+        {
+            Type t = typeof(JsonEnumerableT<>).MakeGenericType(elementType);
+            return (IEnumerable)Activator.CreateInstance(t, sourceList);
+        }
+    }
+}
index 3ce5bbc..621277b 100644 (file)
@@ -275,7 +275,7 @@ namespace System.Text.Json.Serialization
 
         }
 
-        private static Type GetElementType(Type propertyType)
+        public static Type GetElementType(Type propertyType)
         {
             Type elementType = null;
             if (typeof(IEnumerable).IsAssignableFrom(propertyType))
index 7201cba..bcd3037 100644 (file)
@@ -2,6 +2,7 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections;
 using System.Reflection;
 using System.Text.Json.Serialization.Converters;
 using System.Text.Json.Serialization.Policies;
@@ -10,9 +11,6 @@ namespace System.Text.Json.Serialization
 {
     internal abstract class JsonPropertyInfo
     {
-        // For now, just a global converter.
-        private static JsonEnumerableConverter s_jsonEnumerableConverter = new DefaultArrayConverter();
-
         internal ClassType ClassType;
 
         internal byte[] _name = default;
@@ -70,7 +68,16 @@ namespace System.Text.Json.Serialization
         {
             if (RuntimePropertyType.IsArray)
             {
-                EnumerableConverter = s_jsonEnumerableConverter;
+                EnumerableConverter = new DefaultArrayConverter();
+            }
+            else if (typeof(IEnumerable).IsAssignableFrom(RuntimePropertyType))
+            {
+                Type elementType = JsonClassInfo.GetElementType(RuntimePropertyType);
+
+                if (RuntimePropertyType.IsAssignableFrom(typeof(JsonEnumerableT<>).MakeGenericType(elementType)))
+                {
+                    EnumerableConverter = new DefaultEnumerableConverter();
+                }
             }
         }
 
index d4db11d..a07b4d0 100644 (file)
@@ -35,5 +35,75 @@ namespace System.Text.Json.Serialization.Tests
             TestClassWithGenericList obj = JsonSerializer.Parse<TestClassWithGenericList>(TestClassWithGenericList.s_data);
             obj.Verify();
         }
+
+        [Fact]
+        public static void ReadClassWithObjectIEnumerableT()
+        {
+            TestClassWithObjectIEnumerableT obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableT>(TestClassWithObjectIEnumerableT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithObjectIListT()
+        {
+            TestClassWithObjectIListT obj = JsonSerializer.Parse<TestClassWithObjectIListT>(TestClassWithObjectIListT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithObjectICollectionT()
+        {
+            TestClassWithObjectICollectionT obj = JsonSerializer.Parse<TestClassWithObjectICollectionT>(TestClassWithObjectICollectionT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithObjectIReadOnlyCollectionT()
+        {
+            TestClassWithObjectIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyCollectionT>(TestClassWithObjectIReadOnlyCollectionT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithObjectIReadOnlyListT()
+        {
+            TestClassWithObjectIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyListT>(TestClassWithObjectIReadOnlyListT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithGenericIEnumerableT()
+        {
+            TestClassWithGenericIEnumerableT obj = JsonSerializer.Parse<TestClassWithGenericIEnumerableT>(TestClassWithGenericIEnumerableT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithGenericIListT()
+        {
+            TestClassWithGenericIListT obj = JsonSerializer.Parse<TestClassWithGenericIListT>(TestClassWithGenericIListT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithGenericICollectionT()
+        {
+            TestClassWithGenericICollectionT obj = JsonSerializer.Parse<TestClassWithGenericICollectionT>(TestClassWithGenericICollectionT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithGenericIReadOnlyCollectionT()
+        {
+            TestClassWithGenericIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyCollectionT>(TestClassWithGenericIReadOnlyCollectionT.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithGenericIReadOnlyListT()
+        {
+            TestClassWithGenericIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyListT>(TestClassWithGenericIReadOnlyListT.s_data);
+            obj.Verify();
+        }
     }
 }
index 5c0197f..1a63ef8 100644 (file)
@@ -37,6 +37,31 @@ namespace System.Text.Json.Serialization.Tests
             string json;
 
             {
+                TestClassWithObjectList obj = new TestClassWithObjectList();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectList obj = JsonSerializer.Parse<TestClassWithObjectList>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectList obj = JsonSerializer.Parse<TestClassWithObjectList>(TestClassWithObjectList.s_data);
+                obj.Verify();
+            }
+        }
+
+
+
+        [Fact]
+        public static void WriteClassWithGenericList()
+        {
+            string json;
+
+            {
                 TestClassWithGenericList obj = new TestClassWithGenericList();
                 obj.Initialize();
                 obj.Verify();
@@ -54,25 +79,231 @@ namespace System.Text.Json.Serialization.Tests
             }
         }
 
+        public static void WriteClassWithGenericIEnumerableT()
+        {
+            string json;
+
+            {
+                TestClassWithGenericIEnumerableT obj = new TestClassWithGenericIEnumerableT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithGenericIEnumerableT obj = JsonSerializer.Parse<TestClassWithGenericIEnumerableT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithGenericIEnumerableT obj = JsonSerializer.Parse<TestClassWithGenericIEnumerableT>(TestClassWithGenericIEnumerableT.s_data);
+                obj.Verify();
+            }
+        }
+
         [Fact]
-        public static void WriteClassWithGenericList()
+        public static void WriteClassWithGenericIListT()
         {
             string json;
 
             {
-                TestClassWithObjectList obj = new TestClassWithObjectList();
+                TestClassWithGenericIListT obj = new TestClassWithGenericIListT();
                 obj.Initialize();
                 obj.Verify();
                 json = JsonSerializer.ToString(obj);
             }
 
             {
-                TestClassWithObjectList obj = JsonSerializer.Parse<TestClassWithObjectList>(json);
+                TestClassWithGenericIListT obj = JsonSerializer.Parse<TestClassWithGenericIListT>(json);
                 obj.Verify();
             }
 
             {
-                TestClassWithObjectList obj = JsonSerializer.Parse<TestClassWithObjectList>(TestClassWithObjectList.s_data);
+                TestClassWithGenericIListT obj = JsonSerializer.Parse<TestClassWithGenericIListT>(TestClassWithGenericIListT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithGenericICollectionT()
+        {
+            string json;
+
+            {
+                TestClassWithGenericICollectionT obj = new TestClassWithGenericICollectionT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithGenericICollectionT obj = JsonSerializer.Parse<TestClassWithGenericICollectionT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithGenericICollectionT obj = JsonSerializer.Parse<TestClassWithGenericICollectionT>(TestClassWithGenericICollectionT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithGenericIReadOnlyCollectionT()
+        {
+            string json;
+
+            {
+                TestClassWithGenericIReadOnlyCollectionT obj = new TestClassWithGenericIReadOnlyCollectionT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithGenericIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyCollectionT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithGenericIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyCollectionT>(TestClassWithGenericIReadOnlyCollectionT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithGenericIReadOnlyListT()
+        {
+            string json;
+
+            {
+                TestClassWithGenericIReadOnlyListT obj = new TestClassWithGenericIReadOnlyListT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithGenericIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyListT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithGenericIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyListT>(TestClassWithGenericIEnumerableT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectIEnumerableT()
+        {
+            string json;
+
+            {
+                TestClassWithObjectIEnumerableT obj = new TestClassWithObjectIEnumerableT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectIEnumerableT obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectIEnumerableT obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableT>(TestClassWithObjectIEnumerableT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectIListT()
+        {
+            string json;
+
+            {
+                TestClassWithObjectIListT obj = new TestClassWithObjectIListT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectIListT obj = JsonSerializer.Parse<TestClassWithObjectIListT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectIListT obj = JsonSerializer.Parse<TestClassWithObjectIListT>(TestClassWithObjectIListT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectICollectionT()
+        {
+            string json;
+
+            {
+                TestClassWithObjectICollectionT obj = new TestClassWithObjectICollectionT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectICollectionT obj = JsonSerializer.Parse<TestClassWithObjectICollectionT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectICollectionT obj = JsonSerializer.Parse<TestClassWithObjectICollectionT>(TestClassWithObjectICollectionT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectIReadOnlyCollectionT()
+        {
+            string json;
+
+            {
+                TestClassWithObjectIReadOnlyCollectionT obj = new TestClassWithObjectIReadOnlyCollectionT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyCollectionT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectIReadOnlyCollectionT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyCollectionT>(TestClassWithObjectIReadOnlyCollectionT.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectIReadOnlyListT()
+        {
+            string json;
+
+            {
+                TestClassWithObjectIReadOnlyListT obj = new TestClassWithObjectIReadOnlyListT();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyListT>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithObjectIReadOnlyListT>(TestClassWithObjectIEnumerableT.s_data);
                 obj.Verify();
             }
         }
index 6dc32aa..2a53ce0 100644 (file)
@@ -34,6 +34,11 @@ namespace System.Text.Json.Serialization.Tests
             obj.Address = null;
             obj.Array = null;
             obj.List = null;
+            obj.IEnumerableT = null;
+            obj.IListT = null;
+            obj.ICollectionT = null;
+            obj.IReadOnlyCollectionT = null;
+            obj.IReadOnlyListT = null;
             obj.NullableInt = null;
             obj.NullableIntArray = null;
             obj.Object = null;
@@ -42,6 +47,11 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Contains(@"""Address"":null", json);
             Assert.Contains(@"""List"":null", json);
             Assert.Contains(@"""Array"":null", json);
+            Assert.Contains(@"""IEnumerableT"":null", json);
+            Assert.Contains(@"""IListT"":null", json);
+            Assert.Contains(@"""ICollectionT"":null", json);
+            Assert.Contains(@"""IReadOnlyCollectionT"":null", json);
+            Assert.Contains(@"""IReadOnlyListT"":null", json);
             Assert.Contains(@"""NullableInt"":null", json);
             Assert.Contains(@"""Object"":null", json);
             Assert.Contains(@"""NullableIntArray"":null", json);
index 0f036ef..da88e2a 100644 (file)
@@ -75,6 +75,41 @@ namespace System.Text.Json.Serialization.Tests
 
             json = JsonSerializer.ToString<object>(list);
             Assert.Equal(ExpectedJson, json);
+
+            IEnumerable<object> ienumerable = new List<object> { 1, true, address, null, "foo" };
+            json = JsonSerializer.ToString(ienumerable);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(ienumerable);
+            Assert.Equal(ExpectedJson, json);
+
+            IList<object> ilist = new List<object> { 1, true, address, null, "foo" };
+            json = JsonSerializer.ToString(ilist);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(ilist);
+            Assert.Equal(ExpectedJson, json);
+
+            ICollection<object> icollection = new List<object> { 1, true, address, null, "foo" };
+            json = JsonSerializer.ToString(icollection);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(icollection);
+            Assert.Equal(ExpectedJson, json);
+
+            IReadOnlyCollection<object> ireadonlycollection = new List<object> { 1, true, address, null, "foo" };
+            json = JsonSerializer.ToString(ireadonlycollection);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(ireadonlycollection);
+            Assert.Equal(ExpectedJson, json);
+
+            IReadOnlyList<object> ireadonlylist = new List<object> { 1, true, address, null, "foo" };
+            json = JsonSerializer.ToString(ireadonlylist);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(ireadonlylist);
+            Assert.Equal(ExpectedJson, json);
         }
 
         [Fact]
@@ -109,6 +144,11 @@ namespace System.Text.Json.Serialization.Tests
                 Assert.Contains(@"""Address"":{""City"":""MyCity""}", json);
                 Assert.Contains(@"""List"":[""Hello"",""World""]", json);
                 Assert.Contains(@"""Array"":[""Hello"",""Again""]", json);
+                Assert.Contains(@"""IEnumerableT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""IListT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""ICollectionT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""IReadOnlyCollectionT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""IReadOnlyListT"":[""Hello"",""World""]", json);
                 Assert.Contains(@"""NullableInt"":42", json);
                 Assert.Contains(@"""Object"":{}", json);
                 Assert.Contains(@"""NullableIntArray"":[null,42,null]", json);
index c55f43f..f97e14c 100644 (file)
@@ -110,6 +110,11 @@ namespace System.Text.Json.Serialization.Tests
         public object /*Address*/ Address { get; set; }
         public object /*List<string>*/ List { get; set; }
         public object /*string[]*/ Array { get; set; }
+        public object /*IEnumerable<string>*/ IEnumerableT { get; set; }
+        public object /*IList<string>*/ IListT { get; set; }
+        public object /*ICollection<string>*/ ICollectionT { get; set; }
+        public object /*IReadOnlyCollection<string>*/ IReadOnlyCollectionT { get; set; }
+        public object /*IReadOnlyList<string>*/ IReadOnlyListT { get; set; }
         public object /*int?*/ NullableInt { get; set; }
         public object /*object*/ Object { get; set; }
         public object /*int?[]*/ NullableIntArray { get; set; }
@@ -129,6 +134,31 @@ namespace System.Text.Json.Serialization.Tests
                 "Hello", "Again"
             };
 
+            IEnumerableT = new List<string>
+            {
+                "Hello", "World"
+            };
+
+            IListT = new List<string>
+            {
+                "Hello", "World"
+            };
+
+            ICollectionT = new List<string>
+            {
+                "Hello", "World"
+            };
+
+            IReadOnlyCollectionT = new List<string>
+            {
+                "Hello", "World"
+            };
+
+            IReadOnlyListT = new List<string>
+            {
+                "Hello", "World"
+            };
+
             NullableInt = new int?(42);
             Object = new object();
             NullableIntArray = new int?[] { null, 42, null };
index 9423414..c00cff0 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Linq;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -57,6 +58,12 @@ namespace System.Text.Json.Serialization.Tests
         public DateTime[] MyDateTimeArray { get; set; }
         public DateTimeOffset[] MyDateTimeOffsetArray { get; set; }
         public SampleEnum[] MyEnumArray { get; set; }
+        public List<string> MyStringList { get; set; }
+        public IEnumerable<string> MyStringIEnumerableT { get; set; }
+        public IList<string> MyStringIListT { get; set; }
+        public ICollection<string> MyStringICollectionT { get; set; }
+        public IReadOnlyCollection<string> MyStringIReadOnlyCollectionT { get; set; }
+        public IReadOnlyList<string> MyStringIReadOnlyListT { get; set; }
 
         public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}";
         public static readonly string s_json_flipped = $"{{{s_partialJsonArrays},{s_partialJsonProperties}}}";
@@ -99,7 +106,13 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDecimalArray"" : [3.3]," +
                 @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
                 @"""MyDateTimeOffsetArray"" : [""2019-01-30T12:01:02.0000000+01:00""]," +
-                @"""MyEnumArray"" : [2]"; // int by default
+                @"""MyEnumArray"" : [2]," + // int by default
+                @"""MyStringList"" : [""Hello""]," +
+                @"""MyStringIEnumerableT"" : [""Hello""]," +
+                @"""MyStringIListT"" : [""Hello""]," +
+                @"""MyStringICollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyListT"" : [""Hello""]";
 
         public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
 
@@ -142,6 +155,13 @@ namespace System.Text.Json.Serialization.Tests
             MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
             MyDateTimeOffsetArray = new DateTimeOffset[] { new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)) };
             MyEnumArray = new SampleEnum[] { SampleEnum.Two };
+
+            MyStringList = new List<string>() { "Hello" };
+            MyStringIEnumerableT = new string[] { "Hello" };
+            MyStringIListT = new string[] { "Hello" };
+            MyStringICollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyListT = new string[] { "Hello" };
         }
 
         public void Verify()
@@ -183,6 +203,13 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), MyDateTimeArray[0]);
             Assert.Equal(new DateTimeOffset(2019, 1, 30, 12, 1, 2, new TimeSpan(1, 0, 0)), MyDateTimeOffsetArray[0]);
             Assert.Equal(SampleEnum.Two, MyEnumArray[0]);
+
+            Assert.Equal("Hello", MyStringList[0]);
+            Assert.Equal("Hello", MyStringIEnumerableT.First());
+            Assert.Equal("Hello", MyStringIListT[0]);
+            Assert.Equal("Hello", MyStringICollectionT.First());
+            Assert.Equal("Hello", MyStringIReadOnlyCollectionT.First());
+            Assert.Equal("Hello", MyStringIReadOnlyListT[0]);
         }
     }
 
@@ -222,6 +249,12 @@ namespace System.Text.Json.Serialization.Tests
         public object MyDoubleArray { get; set; }
         public object MyDateTimeArray { get; set; }
         public object MyEnumArray { get; set; }
+        public object MyStringList { get; set; }
+        public object MyStringIEnumerableT { get; set; }
+        public object MyStringIListT { get; set; }
+        public object MyStringICollectionT { get; set; }
+        public object MyStringIReadOnlyCollectionT { get; set; }
+        public object MyStringIReadOnlyListT { get; set; }
 
         public static readonly string s_json =
                 @"{" +
@@ -258,7 +291,13 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyDoubleArray"" : [2.2]," +
                 @"""MyDecimalArray"" : [3.3]," +
                 @"""MyDateTimeArray"" : [""2019-01-30T12:01:02.0000000Z""]," +
-                @"""MyEnumArray"" : [2]" + // int by default
+                @"""MyEnumArray"" : [2]," + // int by default
+                @"""MyStringList"" : [""Hello""]," +
+                @"""MyStringIEnumerableT"" : [""Hello""]," +
+                @"""MyStringIListT"" : [""Hello""]," +
+                @"""MyStringICollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
+                @"""MyStringIReadOnlyListT"" : [""Hello""]" +
                 @"}";
 
         public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
@@ -300,6 +339,13 @@ namespace System.Text.Json.Serialization.Tests
             MyDecimalArray = new decimal[] { 3.3m };
             MyDateTimeArray = new DateTime[] { new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc) };
             MyEnumArray = new SampleEnum[] { SampleEnum.Two };
+
+            MyStringList = new List<string>() { "Hello" };
+            MyStringIEnumerableT = new string[] { "Hello" };
+            MyStringIListT = new string[] { "Hello" };
+            MyStringICollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyCollectionT = new string[] { "Hello" };
+            MyStringIReadOnlyListT = new string[] { "Hello" };
         }
 
         public void Verify()
@@ -339,6 +385,13 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(2.2d, ((double[])MyDoubleArray)[0]);
             Assert.Equal(new DateTime(2019, 1, 30, 12, 1, 2, DateTimeKind.Utc), ((DateTime[])MyDateTimeArray)[0]);
             Assert.Equal(SampleEnum.Two, ((SampleEnum[])MyEnumArray)[0]);
+
+            Assert.Equal("Hello", ((List<string>)MyStringList)[0]);
+            Assert.Equal("Hello", ((IEnumerable<string>)MyStringIEnumerableT).First());
+            Assert.Equal("Hello", ((IList<string>)MyStringIListT)[0]);
+            Assert.Equal("Hello", ((ICollection<string>)MyStringICollectionT).First());
+            Assert.Equal("Hello", ((IReadOnlyCollection<string>)MyStringIReadOnlyCollectionT).First());
+            Assert.Equal("Hello", ((IReadOnlyList<string>)MyStringIReadOnlyListT)[0]);
         }
     }
 
@@ -629,6 +682,185 @@ namespace System.Text.Json.Serialization.Tests
         }
     }
 
+    public class TestClassWithObjectIEnumerableT : ITestClass
+    {
+        public IEnumerable<SimpleTestClass> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            SimpleTestClass obj1 = new SimpleTestClass();
+            obj1.Initialize();
+
+            SimpleTestClass obj2 = new SimpleTestClass();
+            obj2.Initialize();
+
+            MyData = new SimpleTestClass[] { obj1, obj2 };
+        }
+
+        public void Verify()
+        {
+            int count = 0;
+
+            foreach (SimpleTestClass data in MyData)
+            {
+                data.Verify();
+                count++;
+            }
+
+            Assert.Equal(2, count);
+        }
+    }
+
+    public class TestClassWithObjectIListT : ITestClass
+    {
+        public IList<SimpleTestClass> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<SimpleTestClass>();
+
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyData.Add(obj);
+            }
+
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyData.Add(obj);
+            }
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyData.Count);
+            MyData[0].Verify();
+            MyData[1].Verify();
+        }
+    }
+
+    public class TestClassWithObjectICollectionT : ITestClass
+    {
+        public ICollection<SimpleTestClass> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<SimpleTestClass>();
+
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyData.Add(obj);
+            }
+
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyData.Add(obj);
+            }
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyData.Count);
+
+            foreach (SimpleTestClass data in MyData)
+            {
+                data.Verify();
+            }
+        }
+    }
+
+    public class TestClassWithObjectIReadOnlyCollectionT : ITestClass
+    {
+        public IReadOnlyCollection<SimpleTestClass> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            SimpleTestClass obj1 = new SimpleTestClass();
+            obj1.Initialize();
+
+            SimpleTestClass obj2 = new SimpleTestClass();
+            obj2.Initialize();
+
+            MyData = new SimpleTestClass[] { obj1, obj2 };
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyData.Count);
+
+            foreach (SimpleTestClass data in MyData)
+            {
+                data.Verify();
+            }
+        }
+    }
+
+    public class TestClassWithObjectIReadOnlyListT : ITestClass
+    {
+        public IReadOnlyList<SimpleTestClass> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            SimpleTestClass obj1 = new SimpleTestClass();
+            obj1.Initialize();
+
+            SimpleTestClass obj2 = new SimpleTestClass();
+            obj2.Initialize();
+
+            MyData = new SimpleTestClass[] { obj1, obj2 };
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyData.Count);
+            MyData[0].Verify();
+            MyData[1].Verify();
+        }
+    }
+
     public class TestClassWithStringArray : ITestClass
     {
         public string[] MyData { get; set; }
@@ -694,6 +926,181 @@ namespace System.Text.Json.Serialization.Tests
         }
     }
 
+    public class TestClassWithGenericIEnumerableT : ITestClass
+    {
+        public IEnumerable<string> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    @"""Hello""," +
+                    @"""World""" +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<string>
+            {
+                "Hello",
+                "World"
+            };
+
+            int count = 0;
+            foreach (string data in MyData)
+            {
+                count++;
+            }
+            Assert.Equal(2, count);
+        }
+
+        public void Verify()
+        {
+            string[] expected = { "Hello", "World" };
+            int count = 0;
+
+            foreach (string data in MyData)
+            {
+                Assert.Equal(expected[count], data);
+                count++;
+            }
+
+            Assert.Equal(2, count);
+        }
+    }
+
+    public class TestClassWithGenericIListT : ITestClass
+    {
+        public IList<string> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    @"""Hello""," +
+                    @"""World""" +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<string>
+            {
+                "Hello",
+                "World"
+            };
+            Assert.Equal(2, MyData.Count);
+        }
+
+        public void Verify()
+        {
+            Assert.Equal("Hello", MyData[0]);
+            Assert.Equal("World", MyData[1]);
+            Assert.Equal(2, MyData.Count);
+        }
+    }
+
+    public class TestClassWithGenericICollectionT : ITestClass
+    {
+        public ICollection<string> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    @"""Hello""," +
+                    @"""World""" +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<string>
+            {
+                "Hello",
+                "World"
+            };
+            Assert.Equal(2, MyData.Count);
+        }
+
+        public void Verify()
+        {
+            string[] expected = { "Hello", "World" };
+            int i = 0;
+
+            foreach (string data in MyData)
+            {
+                Assert.Equal(expected[i++], data);
+            }
+
+            Assert.Equal(2, MyData.Count);
+        }
+    }
+
+    public class TestClassWithGenericIReadOnlyCollectionT : ITestClass
+    {
+        public IReadOnlyCollection<string> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    @"""Hello""," +
+                    @"""World""" +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<string>
+            {
+                "Hello",
+                "World"
+            };
+            Assert.Equal(2, MyData.Count);
+        }
+
+        public void Verify()
+        {
+            string[] expected = { "Hello", "World" };
+            int i = 0;
+
+            foreach (string data in MyData)
+            {
+                Assert.Equal(expected[i++], data);
+            }
+
+            Assert.Equal(2, MyData.Count);
+        }
+    }
+
+    public class TestClassWithGenericIReadOnlyListT : ITestClass
+    {
+        public IReadOnlyList<string> MyData { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyData"":[" +
+                    @"""Hello""," +
+                    @"""World""" +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyData = new List<string>
+            {
+                "Hello",
+                "World"
+            };
+            Assert.Equal(2, MyData.Count);
+        }
+
+        public void Verify()
+        {
+            Assert.Equal("Hello", MyData[0]);
+            Assert.Equal("World", MyData[1]);
+            Assert.Equal(2, MyData.Count);
+        }
+    }
+
     public class SimpleDerivedTestClass : SimpleTestClass
     {
     }
index 4cb5072..de39bd4 100644 (file)
@@ -20,8 +20,18 @@ namespace System.Text.Json.Serialization.Tests
                 yield return new object[] { typeof(TestClassWithNestedObjectInner), TestClassWithNestedObjectInner.s_data };
                 yield return new object[] { typeof(TestClassWithNestedObjectOuter), TestClassWithNestedObjectOuter.s_data };
                 yield return new object[] { typeof(TestClassWithObjectArray), TestClassWithObjectArray.s_data };
+                yield return new object[] { typeof(TestClassWithObjectIEnumerableT), TestClassWithObjectIEnumerableT.s_data };
+                yield return new object[] { typeof(TestClassWithObjectIListT), TestClassWithObjectIListT.s_data };
+                yield return new object[] { typeof(TestClassWithObjectICollectionT), TestClassWithObjectICollectionT.s_data };
+                yield return new object[] { typeof(TestClassWithObjectIReadOnlyCollectionT), TestClassWithObjectIReadOnlyCollectionT.s_data };
+                yield return new object[] { typeof(TestClassWithObjectIReadOnlyListT), TestClassWithObjectIReadOnlyListT.s_data };
                 yield return new object[] { typeof(TestClassWithStringArray), TestClassWithStringArray.s_data };
                 yield return new object[] { typeof(TestClassWithGenericList), TestClassWithGenericList.s_data };
+                yield return new object[] { typeof(TestClassWithGenericIEnumerableT), TestClassWithGenericIEnumerableT.s_data };
+                yield return new object[] { typeof(TestClassWithGenericIListT), TestClassWithGenericIListT.s_data };
+                yield return new object[] { typeof(TestClassWithGenericICollectionT), TestClassWithGenericICollectionT.s_data };
+                yield return new object[] { typeof(TestClassWithGenericIReadOnlyCollectionT), TestClassWithGenericIReadOnlyCollectionT.s_data };
+                yield return new object[] { typeof(TestClassWithGenericIReadOnlyListT), TestClassWithGenericIReadOnlyListT.s_data };
             }
         }
         public static IEnumerable<object[]> WriteSuccessCases
@@ -36,8 +46,18 @@ namespace System.Text.Json.Serialization.Tests
                 yield return new object[] { new TestClassWithNestedObjectInner() };
                 yield return new object[] { new TestClassWithNestedObjectOuter() };
                 yield return new object[] { new TestClassWithObjectArray() };
+                yield return new object[] { new TestClassWithObjectIEnumerableT() };
+                yield return new object[] { new TestClassWithObjectIListT() };
+                yield return new object[] { new TestClassWithObjectICollectionT() };
+                yield return new object[] { new TestClassWithObjectIReadOnlyCollectionT() };
+                yield return new object[] { new TestClassWithObjectIReadOnlyListT() };
                 yield return new object[] { new TestClassWithStringArray() };
                 yield return new object[] { new TestClassWithGenericList() };
+                yield return new object[] { new TestClassWithGenericIEnumerableT() };
+                yield return new object[] { new TestClassWithGenericIListT() };
+                yield return new object[] { new TestClassWithGenericICollectionT() };
+                yield return new object[] { new TestClassWithGenericIReadOnlyCollectionT() };
+                yield return new object[] { new TestClassWithGenericIReadOnlyListT() };
             }
         }
     }
index 85967db..271c840 100644 (file)
@@ -304,6 +304,291 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(2, i[1]);
         }
 
+        [Fact]
+        public static void ReadIEnumerableTOfIEnumerableT()
+        {
+            IEnumerable<IEnumerable<int>> result = JsonSerializer.Parse<IEnumerable<IEnumerable<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IEnumerable<int> ie in result)
+            {
+                foreach (int i in ie)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIEnumerableTOfArray()
+        {
+            IEnumerable<int[]> result = JsonSerializer.Parse<IEnumerable<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIEnumerableT()
+        {
+            IEnumerable<int>[] result = JsonSerializer.Parse<IEnumerable<int>[]> (Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IEnumerable<int> arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIEnumerableT()
+        {
+            IEnumerable<int> result = JsonSerializer.Parse<IEnumerable<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+        }
+
+        [Fact]
+        public static void ReadIListTOfIListT()
+        {
+            IList<IList<int>> result = JsonSerializer.Parse<IList<IList<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IList<int> ie in result)
+            {
+                foreach (int i in ie)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIListTOfArray()
+        {
+            IList<int[]> result = JsonSerializer.Parse<IList<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIListT()
+        {
+            IList<int>[] result = JsonSerializer.Parse<IList<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IList<int> arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIListT()
+        {
+            IList<int> result = JsonSerializer.Parse<IList<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+        }
+
+        [Fact]
+        public static void ReadICollectionTOfICollectionT()
+        {
+            ICollection<ICollection<int>> result = JsonSerializer.Parse<ICollection<ICollection<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ICollection<int> ie in result)
+            {
+                foreach (int i in ie)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadICollectionTOfArray()
+        {
+            ICollection<int[]> result = JsonSerializer.Parse<ICollection<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfICollectionT()
+        {
+            ICollection<int>[] result = JsonSerializer.Parse<ICollection<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ICollection<int> arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveICollectionT()
+        {
+            ICollection<int> result = JsonSerializer.Parse<ICollection<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+        }
+
+        [Fact]
+        public static void ReadIReadOnlyCollectionTOfIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<IReadOnlyCollection<int>> result = JsonSerializer.Parse<IReadOnlyCollection<IReadOnlyCollection<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IReadOnlyCollection<int> ie in result)
+            {
+                foreach (int i in ie)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIReadOnlyCollectionTOfArray()
+        {
+            IReadOnlyCollection<int[]> result = JsonSerializer.Parse<IReadOnlyCollection<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<int>[] result = JsonSerializer.Parse<IReadOnlyCollection<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IReadOnlyCollection<int> arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<int> result = JsonSerializer.Parse<IReadOnlyCollection<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+        }
+
+        [Fact]
+        public static void ReadIReadOnlyListTOfIReadOnlyListT()
+        {
+            IReadOnlyList<IReadOnlyList<int>> result = JsonSerializer.Parse<IReadOnlyList<IReadOnlyList<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IReadOnlyList<int> ie in result)
+            {
+                foreach (int i in ie)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIReadOnlyListTOfArray()
+        {
+            IReadOnlyList<int[]> result = JsonSerializer.Parse<IReadOnlyList<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIReadOnlyListT()
+        {
+            IReadOnlyList<int>[] result = JsonSerializer.Parse<IReadOnlyList<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IReadOnlyList<int> arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIReadOnlyListT()
+        {
+            IReadOnlyList<int> result = JsonSerializer.Parse<IReadOnlyList<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+        }
+
         public class TestClassWithBadData
         {
             public TestChildClassWithBadData[] Children { get; set; }
index 32a1974..bd53182 100644 (file)
@@ -139,5 +139,235 @@ namespace System.Text.Json.Serialization.Tests
             string json = JsonSerializer.ToString(input);
             Assert.Equal("[1,2]", json);
         }
+
+        [Fact]
+        public static void WriteIEnumerableTOfIEnumerableT()
+        {
+            IEnumerable<IEnumerable<int>> input = new List<List<int>>
+            {
+                new List<int>() { 1, 2 },
+                new List<int>() { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIEnumerableTOfArray()
+        {
+            IEnumerable<int[]> input = new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfIEnumerableT()
+        {
+            IEnumerable<int>[] input = new List<int>[2];
+            input[0] = new List<int>() { 1, 2 };
+            input[1] = new List<int>() { 3, 4 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIEnumerableT()
+        {
+            IEnumerable<int> input = new List<int> { 1, 2 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteIListTOfIListT()
+        {
+            IList<IList<int>> input = new List<IList<int>>
+            {
+                new List<int>() { 1, 2 },
+                new List<int>() { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIListTOfArray()
+        {
+            IList<int[]> input = new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfIListT()
+        {
+            IList<int>[] input = new List<int>[2];
+            input[0] = new List<int>() { 1, 2 };
+            input[1] = new List<int>() { 3, 4 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIListT()
+        {
+            IList<int> input = new List<int> { 1, 2 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteICollectionTOfICollectionT()
+        {
+            ICollection<ICollection<int>> input = new List<ICollection<int>>
+            {
+                new List<int>() { 1, 2 },
+                new List<int>() { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteICollectionTOfArray()
+        {
+            ICollection<int[]> input = new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfICollectionT()
+        {
+            ICollection<int>[] input = new List<int>[2];
+            input[0] = new List<int>() { 1, 2 };
+            input[1] = new List<int>() { 3, 4 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveICollectionT()
+        {
+            ICollection<int> input = new List<int> { 1, 2 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteIReadOnlyCollectionTOfIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<IReadOnlyCollection<int>> input = new List<List<int>>
+            {
+                new List<int>() { 1, 2 },
+                new List<int>() { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIReadOnlyCollectionTOfArray()
+        {
+            IReadOnlyCollection<int[]> input = new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<int>[] input = new List<int>[2];
+            input[0] = new List<int>() { 1, 2 };
+            input[1] = new List<int>() { 3, 4 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIReadOnlyCollectionT()
+        {
+            IReadOnlyCollection<int> input = new List<int> { 1, 2 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteIReadOnlyListTOfIReadOnlyListT()
+        {
+            IReadOnlyList<IReadOnlyList<int>> input = new List<List<int>>
+            {
+                new List<int>() { 1, 2 },
+                new List<int>() { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIReadOnlyListTOfArray()
+        {
+            IReadOnlyList<int[]> input = new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfIReadOnlyListT()
+        {
+            IReadOnlyList<int>[] input = new List<int>[2];
+            input[0] = new List<int>() { 1, 2 };
+            input[1] = new List<int>() { 3, 4 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIReadOnlyListT()
+        {
+            IReadOnlyList<int> input = new List<int> { 1, 2 };
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
     }
 }