Add support for more collections (dotnet/corefx#37308)
authorLayomi Akinrinade <laakinri@microsoft.com>
Mon, 13 May 2019 21:19:31 +0000 (14:19 -0700)
committerGitHub <noreply@github.com>
Mon, 13 May 2019 21:19:31 +0000 (14:19 -0700)
* Add support for additional collections

* Add more tests

* Some changes

* Address review feedback

* Some nits

* Remove immutable dependency

* Use Invoke, not DyanmicInvoke

* Address review comments

* Utilize JsonPropertyInfoCommon generic TElement parameter

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

30 files changed:
src/libraries/System.Text.Json/src/Resources/Strings.resx
src/libraries/System.Text.Json/src/System.Text.Json.csproj
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ClassMaterializer.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultArrayConverter.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultEnumerableConverter.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultIEnumerableConstructibleConverter.cs [new file with mode: 0644]
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultImmutableConverter.cs [new file with mode: 0644]
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonClassInfo.AddProperty.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonEnumerableConverter.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfo.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonPropertyInfoCommon.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandleArray.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionEmitMaterializer.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/ReflectionMaterializer.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.SimpleTestClass.cs
src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClassWithObject.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.GenericCollections.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs
src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs [new file with mode: 0644]
src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.cs
src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj

index f2f72cb..dc3eb4a 100644 (file)
   <data name="DeserializeDuplicateKey" xml:space="preserve">
     <value>An item with the same property name '{0}' has already been added.</value>
   </data>
+  <data name="DeserializeTypeNotSupported" xml:space="preserve">
+    <value>Deserialization of type {0} is not supported.</value>
+  </data>
 </root>
\ No newline at end of file
index 99d08f7..14f1ecb 100644 (file)
@@ -49,6 +49,8 @@
     <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\DefaultIEnumerableConstructibleConverter.cs" />
+    <Compile Include="System\Text\Json\Serialization\Converters\DefaultImmutableConverter.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" />
index 75d1f8c..5f78640 100644 (file)
@@ -2,10 +2,37 @@
 // 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.Collections.Generic;
+using System.Diagnostics;
+using System.Reflection;
+using System.Text.Json.Serialization.Converters;
+
 namespace System.Text.Json.Serialization
 {
     internal abstract class ClassMaterializer
     {
         public abstract JsonClassInfo.ConstructorDelegate CreateConstructor(Type classType);
+
+        public abstract object ImmutableCreateRange(Type constructingType, Type elementType);
+
+        protected MethodInfo ImmutableCreateRangeMethod(Type constructingType, Type elementType)
+        {
+            MethodInfo[] constructingTypeMethods = constructingType.GetMethods();
+            MethodInfo createRange = null;
+
+            foreach (MethodInfo method in constructingTypeMethods)
+            {
+                if (method.Name == "CreateRange" && method.GetParameters().Length == 1)
+                {
+                    createRange = method;
+                    break;
+                }
+            }
+
+            Debug.Assert(createRange != null);
+
+            return createRange.MakeGenericMethod(elementType);
+        }
     }
 }
index f48d347..bc2ee86 100644 (file)
@@ -9,8 +9,10 @@ namespace System.Text.Json.Serialization.Converters
 {
     internal sealed class DefaultArrayConverter : JsonEnumerableConverter
     {
-        public override IEnumerable CreateFromList(Type elementType, IList sourceList)
+        public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList, JsonSerializerOptions options)
         {
+            Type elementType = state.Current.GetElementType();
+
             Array array;
 
             if (sourceList.Count > 0 && sourceList[0] is Array probe)
index afddd65..3e8c81f 100644 (file)
@@ -1,4 +1,8 @@
-using System.Collections;
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Collections.Generic;
 using System.Text.Json.Serialization.Policies;
 
@@ -15,10 +19,7 @@ namespace System.Text.Json.Serialization.Converters
 
             foreach (object item in sourceList)
             {
-                if (item is T itemT)
-                {
-                    _list.Add(itemT);
-                }
+                _list.Add((T)item);
             }
         }
 
@@ -81,8 +82,10 @@ namespace System.Text.Json.Serialization.Converters
 
     internal sealed class DefaultEnumerableConverter : JsonEnumerableConverter
     {
-        public override IEnumerable CreateFromList(Type elementType, IList sourceList)
+        public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList, JsonSerializerOptions options)
         {
+            Type elementType = state.Current.GetElementType();
+
             Type t = typeof(JsonEnumerableT<>).MakeGenericType(elementType);
             return (IEnumerable)Activator.CreateInstance(t, sourceList);
         }
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultIEnumerableConstructibleConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultIEnumerableConstructibleConverter.cs
new file mode 100644 (file)
index 0000000..8aa82ed
--- /dev/null
@@ -0,0 +1,43 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Collections.Concurrent;
+using System.Text.Json.Serialization.Policies;
+
+namespace System.Text.Json.Serialization.Converters
+{
+    internal sealed class DefaultIEnumerableConstructibleConverter : JsonEnumerableConverter
+    {
+        public static ConcurrentDictionary<Type, JsonPropertyInfo> s_objectJsonProperties = new ConcurrentDictionary<Type, JsonPropertyInfo>();
+
+        public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList, JsonSerializerOptions options)
+        {
+            Type enumerableType = state.Current.JsonPropertyInfo.RuntimePropertyType;
+            JsonClassInfo elementClassInfo = state.Current.JsonPropertyInfo.ElementClassInfo;
+
+            JsonPropertyInfo propertyInfo;
+            if (elementClassInfo.ClassType == ClassType.Object)
+            {
+                Type objectType = elementClassInfo.Type;
+
+                if (s_objectJsonProperties.ContainsKey(objectType))
+                {
+                    propertyInfo = s_objectJsonProperties[objectType];
+                }
+                else
+                {
+                    propertyInfo = JsonClassInfo.CreateProperty(objectType, objectType, null, typeof(object), options);
+                    s_objectJsonProperties[objectType] = propertyInfo;
+                }
+            }
+            else
+            {
+                propertyInfo = elementClassInfo.GetPolicyProperty();
+            }
+
+            return propertyInfo.CreateIEnumerableConstructibleType(enumerableType, sourceList);
+        }
+    }
+}
diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultImmutableConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/DefaultImmutableConverter.cs
new file mode 100644 (file)
index 0000000..00b77ba
--- /dev/null
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Diagnostics;
+using System.Text.Json.Serialization.Policies;
+
+namespace System.Text.Json.Serialization.Converters
+{
+    // This converter returns enumerables in the System.Collections.Immutable namespace.
+    internal sealed class DefaultImmutableConverter : JsonEnumerableConverter
+    {
+        public const string ImmutableNamespace = "System.Collections.Immutable";
+
+        private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList";
+        private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1";
+        private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1";
+
+        private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack";
+        private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1";
+        private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1";
+
+        private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue";
+        private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1";
+        private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1";
+
+        private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet";
+        private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1";
+
+        private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet";
+        private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1";
+        private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1";
+
+        internal delegate object ImmutableCreateRangeDelegate<T>(IEnumerable<T> items);
+
+        public static ConcurrentDictionary<string, object> CreateRangeDelegates = new ConcurrentDictionary<string, object>();
+
+        private string GetConstructingTypeName(string immutableCollectionTypeName)
+        {
+            switch (immutableCollectionTypeName)
+            {
+                case ImmutableListGenericTypeName:
+                case ImmutableListGenericInterfaceTypeName:
+                    return ImmutableListTypeName;
+                case ImmutableStackGenericTypeName:
+                case ImmutableStackGenericInterfaceTypeName:
+                    return  ImmutableStackTypeName;
+                case ImmutableQueueGenericTypeName:
+                case ImmutableQueueGenericInterfaceTypeName:
+                    return  ImmutableQueueTypeName;
+                case ImmutableSortedSetGenericTypeName:
+                    return  ImmutableSortedSetTypeName;
+                case ImmutableHashSetGenericTypeName:
+                case ImmutableSetGenericInterfaceTypeName:
+                    return  ImmutableHashSetTypeName;
+                default:
+                    // TODO: Refactor exception throw following serialization exception changes. 
+                    throw new NotSupportedException(SR.Format(SR.DeserializeTypeNotSupported, immutableCollectionTypeName));
+            }
+        }
+
+        private string GetDelegateKey(
+            Type immutableCollectionType,
+            Type elementType,
+            out Type underlyingType,
+            out string constructingTypeName)
+        {
+            // Use the generic type definition of the immutable collection to determine an appropriate constructing type,
+            // i.e. a type that we can invoke the `CreateRange<elementType>` method on, which returns an assignable immutable collection.
+            underlyingType = immutableCollectionType.GetGenericTypeDefinition();
+            constructingTypeName = GetConstructingTypeName(underlyingType.FullName);
+
+            return $"{constructingTypeName}:{elementType.FullName}";
+        }
+
+        public void RegisterImmutableCollectionType(Type immutableCollectionType, Type elementType, JsonSerializerOptions options)
+        {
+            // Get a unique identifier for a delegate which will point to the appropiate CreateRange method.
+            string delegateKey = GetDelegateKey(immutableCollectionType, elementType, out Type underlyingType, out string constructingTypeName);
+
+            // Exit if we have registered this immutable collection type.
+            if (CreateRangeDelegates.ContainsKey(delegateKey))
+            {
+                return;
+            }
+
+            // Get the constructing type.
+            Type constructingType = underlyingType.Assembly.GetType(constructingTypeName);
+
+            // Create a delegate which will point to the CreateRange method.
+            object createRangeDelegate = options.ClassMaterializerStrategy.ImmutableCreateRange(constructingType, elementType);
+            Debug.Assert(createRangeDelegate != null);
+
+            // Cache the delegate
+            CreateRangeDelegates.TryAdd(delegateKey, createRangeDelegate);
+        }
+
+        public override IEnumerable CreateFromList(ref ReadStack state, IList sourceList, JsonSerializerOptions options)
+        {
+            Type immutableCollectionType = state.Current.JsonPropertyInfo.RuntimePropertyType;
+            Type elementType = state.Current.GetElementType();
+
+            string delegateKey = GetDelegateKey(immutableCollectionType, elementType, out _, out _);
+            Debug.Assert(CreateRangeDelegates.ContainsKey(delegateKey));
+
+            JsonClassInfo elementClassInfo = state.Current.JsonPropertyInfo.ElementClassInfo;
+
+            JsonPropertyInfo propertyInfo;
+            if (elementClassInfo.ClassType == ClassType.Object)
+            {
+                Type objectType = elementClassInfo.Type;
+
+                if (DefaultIEnumerableConstructibleConverter.s_objectJsonProperties.ContainsKey(objectType))
+                {
+                    propertyInfo = DefaultIEnumerableConstructibleConverter.s_objectJsonProperties[objectType];
+                }
+                else
+                {
+                    propertyInfo = JsonClassInfo.CreateProperty(objectType, objectType, null, typeof(object), options);
+                    DefaultIEnumerableConstructibleConverter.s_objectJsonProperties[objectType] = propertyInfo;
+                }
+            }
+            else
+            {
+                propertyInfo = elementClassInfo.GetPolicyProperty();
+            }
+
+            return propertyInfo.CreateImmutableCollectionFromList(delegateKey, sourceList);
+        }
+    }
+}
index 8eaebc9..05b9ca1 100644 (file)
@@ -52,7 +52,7 @@ namespace System.Text.Json.Serialization
             return jsonInfo;
         }
 
-        internal JsonPropertyInfo CreateProperty(Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
+        internal static JsonPropertyInfo CreateProperty(Type declaredPropertyType, Type runtimePropertyType, PropertyInfo propertyInfo, Type parentClassType, JsonSerializerOptions options)
         {
             Type collectionElementType = null;
             switch (GetClassType(runtimePropertyType))
index dd92cec..3d2d587 100644 (file)
@@ -3,11 +3,12 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections;
+using System.Collections.Generic;
 
 namespace System.Text.Json.Serialization.Policies
 {
     internal abstract class JsonEnumerableConverter
     {
-        public abstract IEnumerable CreateFromList(Type elementType, IList sourceList);
+        public abstract IEnumerable CreateFromList(ref ReadStack state, IList sourceList, JsonSerializerOptions options);
     }
 }
index 3702b01..8c429bc 100644 (file)
@@ -2,8 +2,8 @@
 // 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.Buffers;
 using System.Collections;
+using System.Collections.Generic;
 using System.Diagnostics;
 using System.Reflection;
 using System.Text.Json.Serialization.Converters;
@@ -17,6 +17,8 @@ namespace System.Text.Json.Serialization
         // Cache the converters so they don't get created for every enumerable property.
         private static readonly JsonEnumerableConverter s_jsonArrayConverter = new DefaultArrayConverter();
         private static readonly JsonEnumerableConverter s_jsonEnumerableConverter = new DefaultEnumerableConverter();
+        private static readonly JsonEnumerableConverter s_jsonIEnumerableConstuctibleConverter = new DefaultIEnumerableConstructibleConverter();
+        private static readonly JsonEnumerableConverter s_jsonImmutableConverter = new DefaultImmutableConverter();
 
         public ClassType ClassType;
 
@@ -40,7 +42,6 @@ namespace System.Text.Json.Serialization
 
         public bool IgnoreNullValues { get; private set; }
 
-
         // todo: to minimize hashtable lookups, cache JsonClassInfo:
         //public JsonClassInfo ClassInfo;
 
@@ -201,10 +202,6 @@ namespace System.Text.Json.Serialization
                     {
                         ShouldDeserialize = true;
                     }
-                    //else
-                    //{
-                    //    // todo: future feature that allows non-List types (e.g. from System.Collections.Immutable) to have converters.
-                    //}
                 }
                 //else if (HasSetter)
                 //{
@@ -228,6 +225,22 @@ namespace System.Text.Json.Serialization
                         {
                             EnumerableConverter = s_jsonEnumerableConverter;
                         }
+                        // Else if IList can't be assigned from the property type (we populate and return an IList directly)
+                        // and the type can be constructed with an IEnumerable<T>, then use the
+                        // IEnumerableConstructible converter to create the instance.
+                        else if (!typeof(IList).IsAssignableFrom(RuntimePropertyType) &&
+                            RuntimePropertyType.GetConstructor(new Type[] { typeof(List<>).MakeGenericType(elementType) }) != null)
+                        {
+                            EnumerableConverter = s_jsonIEnumerableConstuctibleConverter;
+                        }
+                        // Else if it's a System.Collections.Immutable type with one generic argument.
+                        else if (RuntimePropertyType.IsGenericType &&
+                            RuntimePropertyType.FullName.StartsWith(DefaultImmutableConverter.ImmutableNamespace) &&
+                            RuntimePropertyType.GetGenericArguments().Length == 1)
+                        {
+                            EnumerableConverter = s_jsonImmutableConverter;
+                            ((DefaultImmutableConverter)EnumerableConverter).RegisterImmutableCollectionType(RuntimePropertyType, elementType, options);
+                        }
                     }
                 }
                 else
@@ -259,6 +272,10 @@ namespace System.Text.Json.Serialization
             return (TAttribute)PropertyInfo?.GetCustomAttribute(typeof(TAttribute), inherit: false);
         }
 
+        public abstract IEnumerable CreateImmutableCollectionFromList(string delegateKey, IList sourceList);
+
+        public abstract IEnumerable CreateIEnumerableConstructibleType(Type enumerableType, IList sourceList);
+
         public abstract IList CreateConverterList();
 
         public abstract Type GetDictionaryConcreteType();
index 50f22bd..708f2d9 100644 (file)
@@ -96,5 +96,31 @@ namespace System.Text.Json.Serialization
         {
             return typeof(Dictionary<string, TRuntimeProperty>);
         }
+
+        // Creates an IEnumerable<TRuntimePropertyType> and populates it with the items in the,
+        // sourceList argument then uses the delegateKey argument to identify the appropriate cached
+        // CreateRange<TRuntimePropertyType> method to create and return the desired immutable collection type.
+        public override IEnumerable CreateImmutableCollectionFromList(string delegateKey, IList sourceList)
+        {
+            Debug.Assert(DefaultImmutableConverter.CreateRangeDelegates.ContainsKey(delegateKey));
+
+            DefaultImmutableConverter.ImmutableCreateRangeDelegate<TRuntimeProperty> createRangeDelegate = (
+                (DefaultImmutableConverter.ImmutableCreateRangeDelegate<TRuntimeProperty>)DefaultImmutableConverter.CreateRangeDelegates[delegateKey]);
+
+            return (IEnumerable)createRangeDelegate.Invoke(CreateGenericIEnumerableFromList(sourceList));
+        }
+
+        public override IEnumerable CreateIEnumerableConstructibleType(Type enumerableType, IList sourceList)
+        {
+            return (IEnumerable)Activator.CreateInstance(enumerableType, CreateGenericIEnumerableFromList(sourceList));
+        }
+
+        private IEnumerable<TRuntimeProperty> CreateGenericIEnumerableFromList(IList sourceList)
+        {
+            foreach (object item in sourceList)
+            {
+                yield return (TRuntimeProperty)item;
+            }
+        }
     }
 }
index a19e02f..b36dbdf 100644 (file)
@@ -106,8 +106,7 @@ namespace System.Text.Json.Serialization
                 JsonEnumerableConverter converter = state.Current.JsonPropertyInfo.EnumerableConverter;
                 Debug.Assert(converter != null);
 
-                Type elementType = state.Current.GetElementType();
-                value = converter.CreateFromList(elementType, (IList)value);
+                value = converter.CreateFromList(ref state, (IList)value, options);
                 setPropertyDirectly = true;
             }
             else if (!popStackOnEnd)
index d6e0efe..be5dec1 100644 (file)
@@ -6,6 +6,7 @@
 using System.Diagnostics;
 using System.Reflection;
 using System.Reflection.Emit;
+using System.Text.Json.Serialization.Converters;
 
 namespace System.Text.Json.Serialization
 {
@@ -34,6 +35,14 @@ namespace System.Text.Json.Serialization
 
             return (JsonClassInfo.ConstructorDelegate)dynamicMethod.CreateDelegate(typeof(JsonClassInfo.ConstructorDelegate));
         }
+
+        public override object ImmutableCreateRange(Type constructingType, Type elementType)
+        {
+            MethodInfo createRange = ImmutableCreateRangeMethod(constructingType, elementType);
+
+            return createRange.CreateDelegate(
+                typeof(DefaultImmutableConverter.ImmutableCreateRangeDelegate<>).MakeGenericType(elementType), null);
+        }
     }
 }
 #endif
index 284affc..5c5c431 100644 (file)
@@ -2,6 +2,10 @@
 // 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.Diagnostics;
+using System.Reflection;
+using System.Text.Json.Serialization.Converters;
+
 namespace System.Text.Json.Serialization
 {
     internal sealed class ReflectionMaterializer : ClassMaterializer
@@ -10,5 +14,13 @@ namespace System.Text.Json.Serialization
         {
             return () => Activator.CreateInstance(type);
         }
+
+        public override object ImmutableCreateRange(Type constructingType, Type elementType)
+        {
+            MethodInfo createRange = ImmutableCreateRangeMethod(constructingType, elementType);
+
+            return createRange.CreateDelegate(
+                typeof(DefaultImmutableConverter.ImmutableCreateRangeDelegate<>).MakeGenericType(elementType), null);
+        }
     }
 }
index 85fb647..29458f2 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Reflection;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -161,5 +163,19 @@ namespace System.Text.Json.Serialization.Tests
             TestClassWithGenericIReadOnlyListT obj = JsonSerializer.Parse<TestClassWithGenericIReadOnlyListT>(TestClassWithGenericIReadOnlyListT.s_data);
             obj.Verify();
         }
+
+        [Fact]
+        public static void ReadClassWithObjectIEnumerableConstructibleTypes()
+        {
+            TestClassWithObjectIEnumerableConstructibleTypes obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableConstructibleTypes>(TestClassWithObjectIEnumerableConstructibleTypes.s_data);
+            obj.Verify();
+        }
+
+        [Fact]
+        public static void ReadClassWithObjectImmutableTypes()
+        {
+            TestClassWithObjectImmutableTypes obj = JsonSerializer.Parse<TestClassWithObjectImmutableTypes>(TestClassWithObjectImmutableTypes.s_data);
+            obj.Verify();
+        }
     }
 }
index d6e0715..2926d4b 100644 (file)
@@ -318,5 +318,51 @@ namespace System.Text.Json.Serialization.Tests
                 obj.Verify();
             }
         }
+
+        [Fact]
+        public static void WriteClassWithObjectIEnumerableConstructibleTypes()
+        {
+            string json;
+
+            {
+                TestClassWithObjectIEnumerableConstructibleTypes obj = new TestClassWithObjectIEnumerableConstructibleTypes();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectIEnumerableConstructibleTypes obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableConstructibleTypes>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectIEnumerableConstructibleTypes obj = JsonSerializer.Parse<TestClassWithObjectIEnumerableConstructibleTypes>(TestClassWithObjectIEnumerableConstructibleTypes.s_data);
+                obj.Verify();
+            }
+        }
+
+        [Fact]
+        public static void WriteClassWithObjectImmutableTypes()
+        {
+            string json;
+
+            {
+                TestClassWithObjectImmutableTypes obj = new TestClassWithObjectImmutableTypes();
+                obj.Initialize();
+                obj.Verify();
+                json = JsonSerializer.ToString(obj);
+            }
+
+            {
+                TestClassWithObjectImmutableTypes obj = JsonSerializer.Parse<TestClassWithObjectImmutableTypes>(json);
+                obj.Verify();
+            }
+
+            {
+                TestClassWithObjectImmutableTypes obj = JsonSerializer.Parse<TestClassWithObjectImmutableTypes>(TestClassWithObjectImmutableTypes.s_data);
+                obj.Verify();
+            }
+        }
     }
 }
index 20b1925..1759d25 100644 (file)
@@ -52,6 +52,11 @@ namespace System.Text.Json.Serialization.Tests
             obj.ICollectionT = null;
             obj.IReadOnlyCollectionT = null;
             obj.IReadOnlyListT = null;
+            obj.StackT = null;
+            obj.QueueT = null;
+            obj.HashSetT = null;
+            obj.LinkedListT = null;
+            obj.SortedSetT = null;
             obj.NullableInt = null;
             obj.NullableIntArray = null;
             obj.Object = null;
@@ -65,6 +70,11 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Contains(@"""ICollectionT"":null", json);
             Assert.Contains(@"""IReadOnlyCollectionT"":null", json);
             Assert.Contains(@"""IReadOnlyListT"":null", json);
+            Assert.Contains(@"""StackT"":null", json);
+            Assert.Contains(@"""QueueT"":null", json);
+            Assert.Contains(@"""HashSetT"":null", json);
+            Assert.Contains(@"""LinkedListT"":null", json);
+            Assert.Contains(@"""SortedSetT"":null", json);
             Assert.Contains(@"""NullableInt"":null", json);
             Assert.Contains(@"""Object"":null", json);
             Assert.Contains(@"""NullableIntArray"":null", json);
index eaa0cd5..238d405 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -68,6 +69,9 @@ namespace System.Text.Json.Serialization.Tests
         public static void ArrayAsRootObject()
         {
             const string ExpectedJson = @"[1,true,{""City"":""MyCity""},null,""foo""]";
+            const string ReversedExpectedJson = @"[""foo"",null,{""City"":""MyCity""},true,1]";
+
+            string[] expectedObjects = { @"""foo""", @"null", @"{""City"":""MyCity""}", @"true", @"1" };
 
             var address = new Address();
             address.Initialize();
@@ -125,6 +129,102 @@ namespace System.Text.Json.Serialization.Tests
 
             json = JsonSerializer.ToString<object>(ireadonlylist);
             Assert.Equal(ExpectedJson, json);
+
+            Stack<object> stack = new Stack<object>(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(stack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(stack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            Queue<object> queue = new Queue<object>(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(queue);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(queue);
+            Assert.Equal(ExpectedJson, json);
+
+            HashSet<object> hashset = new HashSet<object>(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(hashset);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(hashset);
+            Assert.Equal(ExpectedJson, json);
+
+            LinkedList<object> linkedlist = new LinkedList<object>(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(linkedlist);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(linkedlist);
+            Assert.Equal(ExpectedJson, json);
+
+            IImmutableList<object> iimmutablelist = ImmutableList.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(iimmutablelist);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(iimmutablelist);
+            Assert.Equal(ExpectedJson, json);
+
+            IImmutableStack<object> iimmutablestack = ImmutableStack.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(iimmutablestack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(iimmutablestack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            IImmutableQueue<object> iimmutablequeue = ImmutableQueue.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(iimmutablequeue);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(iimmutablequeue);
+            Assert.Equal(ExpectedJson, json);
+
+            IImmutableSet<object> iimmutableset = ImmutableHashSet.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(iimmutableset);
+            foreach (string obj in expectedObjects)
+            {
+                Assert.Contains(obj, json);
+            }
+
+            json = JsonSerializer.ToString<object>(iimmutableset);
+            foreach (string obj in expectedObjects)
+            {
+                Assert.Contains(obj, json);
+            }
+
+            ImmutableHashSet<object> immutablehashset = ImmutableHashSet.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(immutablehashset);
+            foreach (string obj in expectedObjects)
+            {
+                Assert.Contains(obj, json);
+            }
+
+            json = JsonSerializer.ToString<object>(immutablehashset);
+            foreach (string obj in expectedObjects)
+            {
+                Assert.Contains(obj, json);
+            }
+
+            ImmutableList<object> immutablelist = ImmutableList.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(immutablelist);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(immutablelist);
+            Assert.Equal(ExpectedJson, json);
+
+            ImmutableStack<object> immutablestack = ImmutableStack.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(immutablestack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(immutablestack);
+            Assert.Equal(ReversedExpectedJson, json);
+
+            ImmutableQueue<object> immutablequeue = ImmutableQueue.CreateRange(new List<object> { 1, true, address, null, "foo" });
+            json = JsonSerializer.ToString(immutablequeue);
+            Assert.Equal(ExpectedJson, json);
+
+            json = JsonSerializer.ToString<object>(immutablequeue);
+            Assert.Equal(ExpectedJson, json);
         }
 
         [Fact]
@@ -164,6 +264,20 @@ namespace System.Text.Json.Serialization.Tests
                 Assert.Contains(@"""ICollectionT"":[""Hello"",""World""]", json);
                 Assert.Contains(@"""IReadOnlyCollectionT"":[""Hello"",""World""]", json);
                 Assert.Contains(@"""IReadOnlyListT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""StackT"":[""World"",""Hello""]", json);
+                Assert.Contains(@"""QueueT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""HashSetT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""LinkedListT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""SortedSetT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""IImmutableListT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""IImmutableStackT"":[""World"",""Hello""]", json);
+                Assert.Contains(@"""IImmutableQueueT"":[""Hello"",""World""]", json);
+                Assert.True(json.Contains(@"""IImmutableSetT"":[""Hello"",""World""]") || json.Contains(@"""IImmutableSetT"":[""World"",""Hello""]"));
+                Assert.True(json.Contains(@"""ImmutableHashSetT"":[""Hello"",""World""]") || json.Contains(@"""ImmutableHashSetT"":[""World"",""Hello""]"));
+                Assert.Contains(@"""ImmutableListT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""ImmutableStackT"":[""World"",""Hello""]", json);
+                Assert.Contains(@"""ImmutableQueueT"":[""Hello"",""World""]", json);
+                Assert.Contains(@"""ImmutableSortedSetT"":[""Hello"",""World""]", json);
                 Assert.Contains(@"""NullableInt"":42", json);
                 Assert.Contains(@"""Object"":{}", json);
                 Assert.Contains(@"""NullableIntArray"":[null,42,null]", json);
index f97e14c..23708f6 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -115,6 +116,20 @@ namespace System.Text.Json.Serialization.Tests
         public object /*ICollection<string>*/ ICollectionT { get; set; }
         public object /*IReadOnlyCollection<string>*/ IReadOnlyCollectionT { get; set; }
         public object /*IReadOnlyList<string>*/ IReadOnlyListT { get; set; }
+        public object /*Stack<string>*/ StackT { get; set; }
+        public object /*Queue<string>*/ QueueT { get; set; }
+        public object /*HashSet<string>*/ HashSetT { get; set; }
+        public object /*LinkedList<string>*/ LinkedListT { get; set; }
+        public object /*SortedSet<string>*/ SortedSetT { get; set; }
+        public object /*IImmutableList<string>*/ IImmutableListT { get; set; }
+        public object /*IImmutableStack<string>*/ IImmutableStackT { get; set; }
+        public object /*IImmutableQueue<string>*/ IImmutableQueueT { get; set; }
+        public object /*IImmutableSet<string>*/ IImmutableSetT { get; set; }
+        public object /*ImmutableHashSet<string>*/ ImmutableHashSetT { get; set; }
+        public object /*ImmutableList<string>*/ ImmutableListT { get; set; }
+        public object /*ImmutableStack<string>*/ ImmutableStackT { get; set; }
+        public object /*ImmutableQueue<string>*/ ImmutableQueueT { get; set; }
+        public object /*ImmutableSortedSet<string>*/ ImmutableSortedSetT { get; set; }
         public object /*int?*/ NullableInt { get; set; }
         public object /*object*/ Object { get; set; }
         public object /*int?[]*/ NullableIntArray { get; set; }
@@ -124,40 +139,27 @@ namespace System.Text.Json.Serialization.Tests
             Address = new Address();
             ((Address)Address).Initialize();
 
-            List = new List<string>
-            {
-                "Hello", "World"
-            };
-
-            Array = new string[]
-            {
-                "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"
-            };
+            List = new List<string> { "Hello", "World" };
+            Array = new string[] { "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" };
+            StackT = new Stack<string>(new List<string> { "Hello", "World" });
+            QueueT = new Queue<string>(new List<string> { "Hello", "World" });
+            HashSetT = new HashSet<string>(new List<string> { "Hello", "World" });
+            LinkedListT = new LinkedList<string>(new List<string> { "Hello", "World" });
+            SortedSetT = new SortedSet<string>(new List<string> { "Hello", "World" });
+            IImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello", "World" });
+            IImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello", "World" });
+            IImmutableQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello", "World" });
+            IImmutableSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello", "World" });
+            ImmutableHashSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello", "World" });
+            ImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello", "World" });
+            ImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello", "World" });
+            ImmutableQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello", "World" });
+            ImmutableSortedSetT = ImmutableSortedSet.CreateRange(new List<string> { "Hello", "World" });
 
             NullableInt = new int?(42);
             Object = new object();
index 8edbc63..f5b090f 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Linq;
 using Xunit;
 
@@ -57,6 +58,20 @@ namespace System.Text.Json.Serialization.Tests
         public Dictionary<string, string> MyStringToStringDict { get; set; }
         public IDictionary<string, string> MyStringToStringIDict { get; set; }
         public IReadOnlyDictionary<string, string> MyStringToStringIReadOnlyDict { get; set; }
+        public Stack<string> MyStringStackT { get; set; }
+        public Queue<string> MyStringQueueT { get; set; }
+        public HashSet<string> MyStringHashSetT { get; set; }
+        public LinkedList<string> MyStringLinkedListT { get; set; }
+        public SortedSet<string> MyStringSortedSetT { get; set; }
+        public IImmutableList<string> MyStringIImmutableListT { get; set; }
+        public IImmutableStack<string> MyStringIImmutableStackT { get; set; }
+        public IImmutableQueue<string> MyStringIImmutableQueueT { get; set; }
+        public IImmutableSet<string> MyStringIImmutableSetT { get; set; }
+        public ImmutableHashSet<string> MyStringImmutableHashSetT { get; set; }
+        public ImmutableList<string> MyStringImmutableListT { get; set; }
+        public ImmutableStack<string> MyStringImmutableStackT { get; set; }
+        public ImmutableQueue<string> MyStringImmutablQueueT { get; set; }
+        public ImmutableSortedSet<string> MyStringImmutableSortedSetT { get; set; }
         public List<string> MyListOfNullString { get; set; }
 
         public static readonly string s_json = $"{{{s_partialJsonProperties},{s_partialJsonArrays}}}";
@@ -110,6 +125,20 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyStringICollectionT"" : [""Hello""]," +
                 @"""MyStringIReadOnlyCollectionT"" : [""Hello""]," +
                 @"""MyStringIReadOnlyListT"" : [""Hello""]," +
+                @"""MyStringStackT"" : [""Hello"", ""World""]," +
+                @"""MyStringQueueT"" : [""Hello"", ""World""]," +
+                @"""MyStringHashSetT"" : [""Hello""]," +
+                @"""MyStringLinkedListT"" : [""Hello""]," +
+                @"""MyStringSortedSetT"" : [""Hello""]," +
+                @"""MyStringIImmutableListT"" : [""Hello""]," +
+                @"""MyStringIImmutableStackT"" : [""Hello""]," +
+                @"""MyStringIImmutableQueueT"" : [""Hello""]," +
+                @"""MyStringIImmutableSetT"" : [""Hello""]," +
+                @"""MyStringImmutableHashSetT"" : [""Hello""]," +
+                @"""MyStringImmutableListT"" : [""Hello""]," +
+                @"""MyStringImmutableStackT"" : [""Hello""]," +
+                @"""MyStringImmutablQueueT"" : [""Hello""]," +
+                @"""MyStringImmutableSortedSetT"" : [""Hello""]," +
                 @"""MyListOfNullString"" : [null]";
 
         public static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
@@ -164,6 +193,23 @@ namespace System.Text.Json.Serialization.Tests
             MyStringToStringDict = new Dictionary<string, string> { { "key", "value" } };
             MyStringToStringIDict = new Dictionary<string, string> { { "key", "value" } };
             MyStringToStringIReadOnlyDict = new Dictionary<string, string> { { "key", "value" } };
+
+            MyStringStackT = new Stack<string>(new List<string>() { "Hello", "World" } );
+            MyStringQueueT = new Queue<string>(new List<string>() { "Hello", "World" });
+            MyStringHashSetT = new HashSet<string>(new List<string>() { "Hello" });
+            MyStringLinkedListT = new LinkedList<string>(new List<string>() { "Hello" });
+            MyStringSortedSetT = new SortedSet<string>(new List<string>() { "Hello" });
+
+            MyStringIImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableHashSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello" });
+            MyStringImmutablQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableSortedSetT = ImmutableSortedSet.CreateRange(new List<string> { "Hello" });
+
             MyListOfNullString = new List<string> { null };
         }
 
@@ -217,6 +263,33 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal("value", MyStringToStringDict["key"]);
             Assert.Equal("value", MyStringToStringIDict["key"]);
             Assert.Equal("value", MyStringToStringIReadOnlyDict["key"]);
+
+            Assert.Equal(2, MyStringStackT.Count);
+            Assert.True(MyStringStackT.Contains("Hello"));
+            Assert.True(MyStringStackT.Contains("World"));
+
+            string[] expectedQueue = { "Hello", "World" };
+            int i = 0;
+            foreach (string item in MyStringQueueT)
+            {
+                Assert.Equal(expectedQueue[i], item);
+                i++;
+            }
+
+            Assert.Equal("Hello", MyStringHashSetT.First());
+            Assert.Equal("Hello", MyStringLinkedListT.First());
+            Assert.Equal("Hello", MyStringSortedSetT.First());
+
+            Assert.Equal("Hello", MyStringIImmutableListT[0]);
+            Assert.Equal("Hello", MyStringIImmutableStackT.First());
+            Assert.Equal("Hello", MyStringIImmutableQueueT.First());
+            Assert.Equal("Hello", MyStringIImmutableSetT.First());
+            Assert.Equal("Hello", MyStringImmutableHashSetT.First());
+            Assert.Equal("Hello", MyStringImmutableListT[0]);
+            Assert.Equal("Hello", MyStringImmutableStackT.First());
+            Assert.Equal("Hello", MyStringImmutablQueueT.First());
+            Assert.Equal("Hello", MyStringImmutableSortedSetT.First());
+
             Assert.Null(MyListOfNullString[0]);
         }
     }
index 042b395..6ae0511 100644 (file)
@@ -3,6 +3,8 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Linq;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -35,6 +37,20 @@ namespace System.Text.Json.Serialization.Tests
         public object MyStringToStringDict { get; set; }
         public object MyStringToStringIDict { get; set; }
         public object MyStringToStringIReadOnlyDict { get; set; }
+        public object MyStringStackT { get; set; }
+        public object MyStringQueueT { get; set; }
+        public object MyStringHashSetT { get; set; }
+        public object MyStringLinkedListT { get; set; }
+        public object MyStringSortedSetT { get; set; }
+        public object MyStringIImmutableListT { get; set; }
+        public object MyStringIImmutableStackT { get; set; }
+        public object MyStringIImmutableQueueT { get; set; }
+        public object MyStringIImmutableSetT { get; set; }
+        public object MyStringImmutableHashSetT { get; set; }
+        public object MyStringImmutableListT { get; set; }
+        public object MyStringImmutableStackT { get; set; }
+        public object MyStringImmutablQueueT { get; set; }
+        public object MyStringImmutableSortedSetT { get; set; }
 
         public new static readonly string s_json =
                 @"{" +
@@ -81,6 +97,20 @@ namespace System.Text.Json.Serialization.Tests
                 @"""MyStringToStringDict"" : {""key"" : ""value""}," +
                 @"""MyStringToStringIDict"" : {""key"" : ""value""}," +
                 @"""MyStringToStringIReadOnlyDict"" : {""key"" : ""value""}" +
+                @"""MyStringStackT"" : [""Hello"", ""World""]," +
+                @"""MyStringQueueT"" : [""Hello"", ""World""]," +
+                @"""MyStringHashSetT"" : [""Hello""]," +
+                @"""MyStringLinkedListT"" : [""Hello""]," +
+                @"""MyStringSortedSetT"" : [""Hello""]," +
+                @"""MyStringIImmutableListT"" : [""Hello""]," +
+                @"""MyStringIImmutableStackT"" : [""Hello""]," +
+                @"""MyStringIImmutableQueueT"" : [""Hello""]," +
+                @"""MyStringIImmutableSetT"" : [""Hello""]," +
+                @"""MyStringImmutableHashSetT"" : [""Hello""]," +
+                @"""MyStringImmutableListT"" : [""Hello""]," +
+                @"""MyStringImmutableStackT"" : [""Hello""]," +
+                @"""MyStringImmutablQueueT"" : [""Hello""]," +
+                @"""MyStringImmutableSortedSetT"" : [""Hello""]" +
                 @"}";
 
         public new static readonly byte[] s_data = Encoding.UTF8.GetBytes(s_json);
@@ -117,6 +147,22 @@ namespace System.Text.Json.Serialization.Tests
             MyStringToStringDict = new Dictionary<string, string> { { "key", "value" } };
             MyStringToStringIDict = new Dictionary<string, string> { { "key", "value" } };
             MyStringToStringIReadOnlyDict = new Dictionary<string, string> { { "key", "value" } };
+
+            MyStringStackT = new Stack<string>(new List<string>() { "Hello", "World" });
+            MyStringQueueT = new Queue<string>(new List<string>() { "Hello", "World" });
+            MyStringHashSetT = new HashSet<string>(new List<string>() { "Hello" });
+            MyStringLinkedListT = new LinkedList<string>(new List<string>() { "Hello" });
+            MyStringSortedSetT = new SortedSet<string>(new List<string>() { "Hello" });
+
+            MyStringIImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello" });
+            MyStringIImmutableSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableHashSetT = ImmutableHashSet.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableListT = ImmutableList.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableStackT = ImmutableStack.CreateRange(new List<string> { "Hello" });
+            MyStringImmutablQueueT = ImmutableQueue.CreateRange(new List<string> { "Hello" });
+            MyStringImmutableSortedSetT = ImmutableSortedSet.CreateRange(new List<string> { "Hello" });
         }
 
         public override void Verify()
@@ -140,6 +186,43 @@ 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]);
+
+            Assert.Equal("value", ((Dictionary<string, string>)MyStringToStringDict)["key"]);
+            Assert.Equal("value", ((IDictionary<string, string>)MyStringToStringIDict)["key"]);
+            Assert.Equal("value", ((IReadOnlyDictionary<string, string>)MyStringToStringIReadOnlyDict)["key"]);
+
+            Assert.Equal(2, ((Stack<string>)MyStringStackT).Count);
+            Assert.True(((Stack<string>)MyStringStackT).Contains("Hello"));
+            Assert.True(((Stack<string>)MyStringStackT).Contains("World"));
+
+            string[] expectedQueue = { "Hello", "World" };
+            int i = 0;
+            foreach (string item in ((Queue<string>)MyStringQueueT))
+            {
+                Assert.Equal(expectedQueue[i], item);
+                i++;
+            }
+
+            Assert.Equal("Hello", ((HashSet<string>)MyStringHashSetT).First());
+            Assert.Equal("Hello", ((LinkedList<string>)MyStringLinkedListT).First());
+            Assert.Equal("Hello", ((SortedSet<string>)MyStringSortedSetT).First());
+
+            Assert.Equal("Hello", ((IImmutableList<string>)MyStringIImmutableListT)[0]);
+            Assert.Equal("Hello", ((IImmutableStack<string>)MyStringIImmutableStackT).First());
+            Assert.Equal("Hello", ((IImmutableQueue<string>)MyStringIImmutableQueueT).First());
+            Assert.Equal("Hello", ((IImmutableSet<string>)MyStringIImmutableSetT).First());
+            Assert.Equal("Hello", ((ImmutableHashSet<string>)MyStringImmutableHashSetT).First());
+            Assert.Equal("Hello", ((ImmutableList<string>)MyStringImmutableListT)[0]);
+            Assert.Equal("Hello", ((ImmutableStack<string>)MyStringImmutableStackT).First());
+            Assert.Equal("Hello", ((ImmutableQueue<string>)MyStringImmutablQueueT).First());
+            Assert.Equal("Hello", ((ImmutableSortedSet<string>)MyStringImmutableSortedSetT).First());
         }
     }
 }
index 380fbab..22e7eac 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using System.Linq;
 using Xunit;
 
@@ -768,6 +769,295 @@ namespace System.Text.Json.Serialization.Tests
         }
     }
 
+    public class TestClassWithObjectIEnumerableConstructibleTypes : ITestClass
+    {
+        public Stack<SimpleTestClass> MyStack { get; set; }
+        public Queue<SimpleTestClass> MyQueue { get; set; }
+        public HashSet<SimpleTestClass> MyHashSet { get; set; }
+        public LinkedList<SimpleTestClass> MyLinkedList { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyStack"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyQueue"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyHashSet"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyLinkedList"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            MyStack = new Stack<SimpleTestClass>();
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyStack.Push(obj);
+            }
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyStack.Push(obj);
+            }
+
+            MyQueue = new Queue<SimpleTestClass>();
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyQueue.Enqueue(obj);
+            }
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyQueue.Enqueue(obj);
+            }
+
+            MyHashSet = new HashSet<SimpleTestClass>();
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyHashSet.Add(obj);
+            }
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyHashSet.Add(obj);
+            }
+
+            MyLinkedList = new LinkedList<SimpleTestClass>();
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyLinkedList.AddLast(obj);
+            }
+            {
+                SimpleTestClass obj = new SimpleTestClass();
+                obj.Initialize();
+                MyLinkedList.AddLast(obj);
+            }
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyStack.Count);
+            foreach (SimpleTestClass data in MyStack)
+            {
+                data.Verify();
+            }
+
+            Assert.Equal(2, MyQueue.Count);
+            foreach (SimpleTestClass data in MyQueue)
+            {
+                data.Verify();
+            }
+
+            Assert.Equal(2, MyHashSet.Count);
+            foreach (SimpleTestClass data in MyHashSet)
+            {
+                data.Verify();
+            }
+
+            Assert.Equal(2, MyLinkedList.Count);
+            foreach (SimpleTestClass data in MyLinkedList)
+            {
+                data.Verify();
+            }
+        }
+    }
+
+    public class TestClassWithObjectImmutableTypes : ITestClass
+    {
+        public IImmutableList<SimpleTestClass> MyIImmutableList { get; set; }
+        public IImmutableStack<SimpleTestClass> MyIImmutableStack { get; set; }
+        public IImmutableQueue<SimpleTestClass> MyIImmutableQueue { get; set; }
+        public IImmutableSet<SimpleTestClass> MyIImmutableSet { get; set; }
+        public ImmutableHashSet<SimpleTestClass> MyImmutableHashSet { get; set; }
+        public ImmutableList<SimpleTestClass> MyImmutableList { get; set; }
+        public ImmutableStack<SimpleTestClass> MyImmutableStack { get; set; }
+        public ImmutableQueue<SimpleTestClass> MyImmutableQueue { get; set; }
+
+        public static readonly byte[] s_data = Encoding.UTF8.GetBytes(
+            @"{" +
+                @"""MyIImmutableList"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyIImmutableStack"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyIImmutableQueue"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyIImmutableSet"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyImmutableHashSet"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyImmutableList"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyImmutableStack"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]," +
+                @"""MyImmutableQueue"":[" +
+                    SimpleTestClass.s_json + "," +
+                    SimpleTestClass.s_json +
+                @"]" +
+            @"}");
+
+        public void Initialize()
+        {
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyIImmutableList = ImmutableList.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyIImmutableStack = ImmutableStack.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyIImmutableQueue = ImmutableQueue.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyIImmutableSet = ImmutableHashSet.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyImmutableHashSet = ImmutableHashSet.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyImmutableList = ImmutableList.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyImmutableStack = ImmutableStack.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+            {
+                SimpleTestClass obj1 = new SimpleTestClass();
+                obj1.Initialize();
+
+                SimpleTestClass obj2 = new SimpleTestClass();
+                obj2.Initialize();
+
+                MyImmutableQueue = ImmutableQueue.CreateRange(new List<SimpleTestClass> { obj1, obj2 });
+            }
+        }
+
+        public void Verify()
+        {
+            Assert.Equal(2, MyIImmutableList.Count);
+            foreach (SimpleTestClass data in MyIImmutableList)
+            {
+                data.Verify();
+            }
+
+            int i = 0;
+            foreach (SimpleTestClass data in MyIImmutableStack)
+            {
+                data.Verify();
+                i++;
+            }
+            Assert.Equal(2, i);
+
+            i = 0;
+            foreach (SimpleTestClass data in MyIImmutableQueue)
+            {
+                data.Verify();
+                i++;
+            }
+            Assert.Equal(2, i);
+
+            Assert.Equal(2, MyIImmutableSet.Count);
+            foreach (SimpleTestClass data in MyIImmutableSet)
+            {
+                data.Verify();
+            }
+
+            Assert.Equal(2, MyImmutableHashSet.Count);
+            foreach (SimpleTestClass data in MyImmutableHashSet)
+            {
+                data.Verify();
+            }
+
+            Assert.Equal(2, MyImmutableList.Count);
+            foreach (SimpleTestClass data in MyImmutableList)
+            {
+                data.Verify();
+            }
+
+            i = 0;
+            foreach (SimpleTestClass data in MyImmutableStack)
+            {
+                data.Verify();
+                i++;
+            }
+            Assert.Equal(2, i);
+
+            i = 0;
+            foreach (SimpleTestClass data in MyImmutableQueue)
+            {
+                data.Verify();
+                i++;
+            }
+            Assert.Equal(2, i);
+        }
+    }
+
     public class SimpleDerivedTestClass : SimpleTestClass
     {
     }
index 8e585d7..ebf962f 100644 (file)
@@ -34,6 +34,9 @@ namespace System.Text.Json.Serialization.Tests
                 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 };
+                yield return new object[] { typeof(TestClassWithStringToPrimitiveDictionary), TestClassWithStringToPrimitiveDictionary.s_data };
+                yield return new object[] { typeof(TestClassWithObjectIEnumerableConstructibleTypes), TestClassWithObjectIEnumerableConstructibleTypes.s_data };
+                yield return new object[] { typeof(TestClassWithObjectImmutableTypes), TestClassWithObjectImmutableTypes.s_data };
                 yield return new object[] { typeof(JsonElementTests.JsonElementClass), JsonElementTests.JsonElementClass.s_data };
                 yield return new object[] { typeof(JsonElementTests.JsonElementArrayClass), JsonElementTests.JsonElementArrayClass.s_data };
                 yield return new object[] { typeof(ClassWithComplexObjects), ClassWithComplexObjects.s_data };
@@ -65,6 +68,9 @@ namespace System.Text.Json.Serialization.Tests
                 yield return new object[] { new TestClassWithGenericICollectionT() };
                 yield return new object[] { new TestClassWithGenericIReadOnlyCollectionT() };
                 yield return new object[] { new TestClassWithGenericIReadOnlyListT() };
+                yield return new object[] { new TestClassWithStringToPrimitiveDictionary() };
+                yield return new object[] { new TestClassWithObjectIEnumerableConstructibleTypes() };
+                yield return new object[] { new TestClassWithObjectImmutableTypes() };
                 yield return new object[] { new JsonElementTests.JsonElementClass() };
                 yield return new object[] { new JsonElementTests.JsonElementArrayClass() };
                 yield return new object[] { new ClassWithComplexObjects() };
diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.GenericCollections.cs
new file mode 100644 (file)
index 0000000..ca26eeb
--- /dev/null
@@ -0,0 +1,631 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Generic;
+using System.Linq;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public static partial class ValueTests
+    {
+        [Fact]
+        public static void ReadListOfList()
+        {
+            List<List<int>> result = JsonSerializer.Parse<List<List<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+
+            Assert.Equal(1, result[0][0]);
+            Assert.Equal(2, result[0][1]);
+            Assert.Equal(3, result[1][0]);
+            Assert.Equal(4, result[1][1]);
+        }
+
+        [Fact]
+        public static void ReadListOfArray()
+        {
+            List<int[]> result = JsonSerializer.Parse<List<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+
+            Assert.Equal(1, result[0][0]);
+            Assert.Equal(2, result[0][1]);
+            Assert.Equal(3, result[1][0]);
+            Assert.Equal(4, result[1][1]);
+        }
+
+        [Fact]
+        public static void ReadArrayOfList()
+        {
+            List<int>[] result = JsonSerializer.Parse<List<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+
+            Assert.Equal(1, result[0][0]);
+            Assert.Equal(2, result[0][1]);
+            Assert.Equal(3, result[1][0]);
+            Assert.Equal(4, result[1][1]);
+        }
+
+        [Fact]
+        public static void ReadPrimitiveList()
+        {
+            List<int> i = JsonSerializer.Parse<List<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            Assert.Equal(1, i[0]);
+            Assert.Equal(2, i[1]);
+
+            i = JsonSerializer.Parse<List<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, i.Count);
+        }
+
+        [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);
+            }
+
+            result = JsonSerializer.Parse<IEnumerable<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [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);
+            }
+
+            result = JsonSerializer.Parse<IList<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [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);
+            }
+
+            result = JsonSerializer.Parse<ICollection<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [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);
+            }
+
+            result = JsonSerializer.Parse<IReadOnlyCollection<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [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);
+            }
+
+            result = JsonSerializer.Parse<IReadOnlyList<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void StackTOfStackT()
+        {
+            Stack<Stack<int>> result = JsonSerializer.Parse<Stack<Stack<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 4;
+
+            foreach (Stack<int> st in result)
+            {
+                foreach (int i in st)
+                {
+                    Assert.Equal(expected--, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadStackTOfArray()
+        {
+            Stack<int[]> result = JsonSerializer.Parse<Stack<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 3;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+
+                expected = 1;
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfStackT()
+        {
+            Stack<int>[] result = JsonSerializer.Parse<Stack<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 2;
+
+            foreach (Stack<int> st in result)
+            {
+                foreach (int i in st)
+                {
+                    Assert.Equal(expected--, i);
+                }
+
+                expected = 4;
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveStackT()
+        {
+            Stack<int> result = JsonSerializer.Parse<Stack<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 2;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected--, i);
+            }
+
+            result = JsonSerializer.Parse<Stack<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadQueueTOfQueueT()
+        {
+            Queue<Queue<int>> result = JsonSerializer.Parse<Queue<Queue<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (Queue<int> q in result)
+            {
+                foreach (int i in q)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadQueueTOfArray()
+        {
+            Queue<int[]> result = JsonSerializer.Parse<Queue<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 ReadArrayOfIQueueT()
+        {
+            Queue<int>[] result = JsonSerializer.Parse<Queue<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (Queue<int> q in result)
+            {
+                foreach (int i in q)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveQueueT()
+        {
+            Queue<int> result = JsonSerializer.Parse<Queue<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+            result = JsonSerializer.Parse<Queue<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+
+        }
+
+        [Fact]
+        public static void ReadHashSetTOfHashSetT()
+        {
+            HashSet<HashSet<int>> result = JsonSerializer.Parse<HashSet<HashSet<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (HashSet<int> hs in result)
+            {
+                foreach (int i in hs)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadHashSetTOfArray()
+        {
+            HashSet<int[]> result = JsonSerializer.Parse<HashSet<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 ReadArrayOfIHashSetT()
+        {
+            HashSet<int>[] result = JsonSerializer.Parse<HashSet<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (HashSet<int> hs in result)
+            {
+                foreach (int i in hs)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveHashSetT()
+        {
+            HashSet<int> result = JsonSerializer.Parse<HashSet<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<HashSet<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadLinkedListTOfLinkedListT()
+        {
+            LinkedList<LinkedList<int>> result = JsonSerializer.Parse<LinkedList<LinkedList<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (LinkedList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadLinkedListTOfArray()
+        {
+            LinkedList<int[]> result = JsonSerializer.Parse<LinkedList<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 ReadArrayOfILinkedListT()
+        {
+            LinkedList<int>[] result = JsonSerializer.Parse<LinkedList<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (LinkedList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveLinkedListT()
+        {
+            LinkedList<int> result = JsonSerializer.Parse<LinkedList<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<LinkedList<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadArrayOfISortedSetT()
+        {
+            SortedSet<int>[] result = JsonSerializer.Parse<SortedSet<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (SortedSet<int> s in result)
+            {
+                foreach (int i in s)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveSortedSetT()
+        {
+            SortedSet<int> result = JsonSerializer.Parse<SortedSet<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<SortedSet<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+    }
+}
diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.ImmutableCollections.cs
new file mode 100644 (file)
index 0000000..c1b923b
--- /dev/null
@@ -0,0 +1,548 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Generic;
+using System.Collections.Immutable;
+using System.Linq;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public static partial class ValueTests
+    {
+        [Fact]
+        public static void ReadIImmutableListTOfIImmutableListT()
+        {
+            IImmutableList<IImmutableList<int>> result = JsonSerializer.Parse<IImmutableList<IImmutableList<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IImmutableList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIImmutableListTOfArray()
+        {
+            IImmutableList<int[]> result = JsonSerializer.Parse<IImmutableList<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 ReadArrayOfIIImmutableListT()
+        {
+            IImmutableList<int>[] result = JsonSerializer.Parse<IImmutableList<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IImmutableList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIImmutableListT()
+        {
+            IImmutableList<int> result = JsonSerializer.Parse<IImmutableList<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<IImmutableList<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadIImmutableStackTOfIImmutableStackT()
+        {
+            IImmutableStack<IImmutableStack<int>> result = JsonSerializer.Parse<IImmutableStack<IImmutableStack<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 4;
+
+            foreach (IImmutableStack<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected--, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIImmutableStackTOfArray()
+        {
+            IImmutableStack<int[]> result = JsonSerializer.Parse<IImmutableStack<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 3;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+
+                expected = 1;
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIIImmutableStackT()
+        {
+            IImmutableStack<int>[] result = JsonSerializer.Parse<IImmutableStack<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 2;
+
+            foreach (IImmutableStack<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected--, i);
+                }
+
+                expected = 4;
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIImmutableStackT()
+        {
+            IImmutableStack<int> result = JsonSerializer.Parse<IImmutableStack<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 2;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected--, i);
+            }
+
+            result = JsonSerializer.Parse<IImmutableStack<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadIImmutableQueueTOfIImmutableQueueT()
+        {
+            IImmutableQueue<IImmutableQueue<int>> result = JsonSerializer.Parse<IImmutableQueue<IImmutableQueue<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IImmutableQueue<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadIImmutableQueueTOfArray()
+        {
+            IImmutableQueue<int[]> result = JsonSerializer.Parse<IImmutableQueue<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 ReadArrayOfIIImmutableQueueT()
+        {
+            IImmutableQueue<int>[] result = JsonSerializer.Parse<IImmutableQueue<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (IImmutableQueue<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIImmutableQueueT()
+        {
+            IImmutableQueue<int> result = JsonSerializer.Parse<IImmutableQueue<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<IImmutableQueue<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadIImmutableSetTOfIImmutableSetT()
+        {
+            IImmutableSet<IImmutableSet<int>> result = JsonSerializer.Parse<IImmutableSet<IImmutableSet<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (IImmutableSet<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadIImmutableSetTOfArray()
+        {
+            IImmutableSet<int[]> result = JsonSerializer.Parse<IImmutableSet<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadArrayOfIIImmutableSetT()
+        {
+            IImmutableSet<int>[] result = JsonSerializer.Parse<IImmutableSet<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (IImmutableSet<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadPrimitiveIImmutableSetT()
+        {
+            IImmutableSet<int> result = JsonSerializer.Parse<IImmutableSet<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            List<int> expected = new List<int> { 1, 2 };
+
+            foreach (int i in result)
+            {
+                expected.Remove(i);
+            }
+
+            Assert.Equal(0, expected.Count);
+
+            result = JsonSerializer.Parse<IImmutableSet<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadImmutableHashSetTOfImmutableHashSetT()
+        {
+            ImmutableHashSet<ImmutableHashSet<int>> result = JsonSerializer.Parse<ImmutableHashSet<ImmutableHashSet<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (ImmutableHashSet<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadImmutableHashSetTOfArray()
+        {
+            ImmutableHashSet<int[]> result = JsonSerializer.Parse<ImmutableHashSet<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadArrayOfIImmutableHashSetT()
+        {
+            ImmutableHashSet<int>[] result = JsonSerializer.Parse<ImmutableHashSet<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            List<int> expected = new List<int> { 1, 2, 3, 4 };
+
+            foreach (ImmutableHashSet<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    expected.Remove(i);
+                }
+            }
+
+            Assert.Equal(0, expected.Count);
+        }
+
+        [Fact]
+        public static void ReadPrimitiveImmutableHashSetT()
+        {
+            ImmutableHashSet<int> result = JsonSerializer.Parse<ImmutableHashSet<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            List<int> expected = new List<int> { 1, 2 };
+
+            foreach (int i in result)
+            {
+                expected.Remove(i);
+            }
+
+            Assert.Equal(0, expected.Count);
+
+            result = JsonSerializer.Parse<ImmutableHashSet<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadImmutableListTOfImmutableListT()
+        {
+            ImmutableList<ImmutableList<int>> result = JsonSerializer.Parse<ImmutableList<ImmutableList<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ImmutableList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadImmutableListTOfArray()
+        {
+            ImmutableList<int[]> result = JsonSerializer.Parse<ImmutableList<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 ReadArrayOfIImmutableListT()
+        {
+            ImmutableList<int>[] result = JsonSerializer.Parse<ImmutableList<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ImmutableList<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveImmutableListT()
+        {
+            ImmutableList<int> result = JsonSerializer.Parse<ImmutableList<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<ImmutableList<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadImmutableStackTOfImmutableStackT()
+        {
+            ImmutableStack<ImmutableStack<int>> result = JsonSerializer.Parse<ImmutableStack<ImmutableStack<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 4;
+
+            foreach (ImmutableStack<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected--, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadImmutableStackTOfArray()
+        {
+            ImmutableStack<int[]> result = JsonSerializer.Parse<ImmutableStack<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 3;
+
+            foreach (int[] arr in result)
+            {
+                foreach (int i in arr)
+                {
+                    Assert.Equal(expected++, i);
+                }
+
+                expected = 1;
+            }
+        }
+
+        [Fact]
+        public static void ReadArrayOfIImmutableStackT()
+        {
+            ImmutableStack<int>[] result = JsonSerializer.Parse<ImmutableStack<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 2;
+
+            foreach (ImmutableStack<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected--, i);
+                }
+
+                expected = 4;
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveImmutableStackT()
+        {
+            ImmutableStack<int> result = JsonSerializer.Parse<ImmutableStack<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 2;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected--, i);
+            }
+
+            result = JsonSerializer.Parse<ImmutableStack<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadImmutableQueueTOfImmutableQueueT()
+        {
+            ImmutableQueue<ImmutableQueue<int>> result = JsonSerializer.Parse<ImmutableQueue<ImmutableQueue<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ImmutableQueue<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadImmutableQueueTOfArray()
+        {
+            ImmutableQueue<int[]> result = JsonSerializer.Parse<ImmutableQueue<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 ReadArrayOfIImmutableQueueT()
+        {
+            ImmutableQueue<int>[] result = JsonSerializer.Parse<ImmutableQueue<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ImmutableQueue<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveImmutableQueueT()
+        {
+            ImmutableQueue<int> result = JsonSerializer.Parse<ImmutableQueue<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<ImmutableQueue<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+
+        [Fact]
+        public static void ReadArrayOfIImmutableSortedSetT()
+        {
+            ImmutableSortedSet<int>[] result = JsonSerializer.Parse<ImmutableSortedSet<int>[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
+            int expected = 1;
+
+            foreach (ImmutableSortedSet<int> l in result)
+            {
+                foreach (int i in l)
+                {
+                    Assert.Equal(expected++, i);
+                }
+            }
+        }
+
+        [Fact]
+        public static void ReadPrimitiveImmutableSortedSetT()
+        {
+            ImmutableSortedSet<int> result = JsonSerializer.Parse<ImmutableSortedSet<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
+            int expected = 1;
+
+            foreach (int i in result)
+            {
+                Assert.Equal(expected++, i);
+            }
+
+            result = JsonSerializer.Parse<ImmutableSortedSet<int>>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, result.Count());
+        }
+    }
+}
index 1fdd0b0..45c9a33 100644 (file)
@@ -49,6 +49,9 @@ namespace System.Text.Json.Serialization.Tests
             int[] i = JsonSerializer.Parse<int[]>(Encoding.UTF8.GetBytes(@"[1,2]"));
             Assert.Equal(1, i[0]);
             Assert.Equal(2, i[1]);
+
+            i = JsonSerializer.Parse<int[]>(Encoding.UTF8.GetBytes(@"[]"));
+            Assert.Equal(0, i.Length);
         }
 
         [Fact]
@@ -274,332 +277,6 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(4, i[1][1]);
         }
 
-        [Fact]
-        public static void ReadListOfList()
-        {
-            List<List<int>> result = JsonSerializer.Parse<List<List<int>>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
-
-            Assert.Equal(1, result[0][0]);
-            Assert.Equal(2, result[0][1]);
-            Assert.Equal(3, result[1][0]);
-            Assert.Equal(4, result[1][1]);
-        }
-
-        [Fact]
-        public static void ReadListOfArray()
-        {
-            List<int[]> result = JsonSerializer.Parse<List<int[]>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
-
-            Assert.Equal(1, result[0][0]);
-            Assert.Equal(2, result[0][1]);
-            Assert.Equal(3, result[1][0]);
-            Assert.Equal(4, result[1][1]);
-        }
-
-        [Fact]
-        public static void ReadArrayOfList()
-        {
-            List<int>[] result = JsonSerializer.Parse<List<int>[]> (Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]"));
-
-            Assert.Equal(1, result[0][0]);
-            Assert.Equal(2, result[0][1]);
-            Assert.Equal(3, result[1][0]);
-            Assert.Equal(4, result[1][1]);
-        }
-
-        [Fact]
-        public static void ReadPrimitiveList()
-        {
-            List<int> i = JsonSerializer.Parse<List<int>>(Encoding.UTF8.GetBytes(@"[1,2]"));
-            Assert.Equal(1, i[0]);
-            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; }
diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.GenericCollections.cs
new file mode 100644 (file)
index 0000000..8128e44
--- /dev/null
@@ -0,0 +1,492 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Generic;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public static partial class ValueTests
+    {
+        [Fact]
+        public static void WriteListOfList()
+        {
+            var 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 WriteListOfArray()
+        {
+            var 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 WriteArrayOfList()
+        {
+            var 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 WritePrimitiveList()
+        {
+            var input = new List<int> { 1, 2 };
+
+            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);
+        }
+
+        [Fact]
+        public static void WriteStackTOfStackT()
+        {
+            Stack<Stack<int>> input = new Stack<Stack<int>>(new List<Stack<int>>
+            {
+                new Stack<int>(new List<int>() { 1, 2 }),
+                new Stack<int>(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[4,3],[2,1]]", json);
+        }
+
+        [Fact]
+        public static void WriteStackTOfArray()
+        {
+            Stack<int[]> input = new Stack<int[]>(new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[3,4],[1,2]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfStackT()
+        {
+            Stack<int>[] input = new Stack<int>[2];
+            input[0] = new Stack<int>(new List<int> { 1, 2 });
+            input[1] = new Stack<int>(new List<int> { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[2,1],[4,3]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveStackT()
+        {
+            Stack<int> input = new Stack<int>(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[2,1]", json);
+        }
+
+        [Fact]
+        public static void WriteQueueTOfQueueT()
+        {
+            Queue<Queue<int>> input = new Queue<Queue<int>>(new List<Queue<int>>
+            {
+                new Queue<int>(new List<int>() { 1, 2 }),
+                new Queue<int>(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteQueueTOfArray()
+        {
+            Queue<int[]> input = new Queue<int[]>(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 WriteArrayOfQueueT()
+        {
+            Queue<int>[] input = new Queue<int>[2];
+            input[0] = new Queue<int>(new List<int> { 1, 2 });
+            input[1] = new Queue<int>(new List<int> { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveQueueT()
+        {
+            Queue<int> input = new Queue<int>(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteHashSetTOfHashSetT()
+        {
+            HashSet<HashSet<int>> input = new HashSet<HashSet<int>>(new List<HashSet<int>>
+            {
+                new HashSet<int>(new List<int>() { 1, 2 }),
+                new HashSet<int>(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteHashSetTOfArray()
+        {
+            HashSet<int[]> input = new HashSet<int[]>(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 WriteArrayOfHashSetT()
+        {
+            HashSet<int>[] input = new HashSet<int>[2];
+            input[0] = new HashSet<int>(new List<int> { 1, 2 });
+            input[1] = new HashSet<int>(new List<int> { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveHashSetT()
+        {
+            HashSet<int> input = new HashSet<int>(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteLinkedListTOfLinkedListT()
+        {
+            LinkedList<LinkedList<int>> input = new LinkedList<LinkedList<int>>(new List<LinkedList<int>>
+            {
+                new LinkedList<int>(new List<int>() { 1, 2 }),
+                new LinkedList<int>(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteLinkedListTOfArray()
+        {
+            LinkedList<int[]> input = new LinkedList<int[]>(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 WriteArrayOfLinkedListT()
+        {
+            LinkedList<int>[] input = new LinkedList<int>[2];
+            input[0] = new LinkedList<int>(new List<int> { 1, 2 });
+            input[1] = new LinkedList<int>(new List<int> { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveLinkedListT()
+        {
+            LinkedList<int> input = new LinkedList<int>(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfSortedSetT()
+        {
+            SortedSet<int>[] input = new SortedSet<int>[2];
+            input[0] = new SortedSet<int>(new List<int> { 1, 2 });
+            input[1] = new SortedSet<int>(new List<int> { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveSortedSetT()
+        {
+            SortedSet<int> input = new SortedSet<int>(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+    }
+}
diff --git a/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs b/src/libraries/System.Text.Json/tests/Serialization/Value.WriteTests.ImmutableCollections.cs
new file mode 100644 (file)
index 0000000..9ecbd84
--- /dev/null
@@ -0,0 +1,397 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// 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.Generic;
+using System.Collections.Immutable;
+using Xunit;
+
+namespace System.Text.Json.Serialization.Tests
+{
+    public static partial class ValueTests
+    {
+        [Fact]
+        public static void WriteIImmutableListTOfIImmutableListT()
+        {
+            IImmutableList<IImmutableList<int>> input = ImmutableList.CreateRange(new List<IImmutableList<int>>{
+                ImmutableList.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableList.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableListTOfArray()
+        {
+            IImmutableList<int[]> input = ImmutableList.CreateRange(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 WriteArrayOfIImmutableListT()
+        {
+            IImmutableList<int>[] input = new IImmutableList<int>[2];
+            input[0] = ImmutableList.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableList.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIImmutableListT()
+        {
+            IImmutableList<int> input = ImmutableList.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableStackTOfIImmutableStackT()
+        {
+            IImmutableStack<IImmutableStack<int>> input = ImmutableStack.CreateRange(new List<IImmutableStack<int>>{
+                ImmutableStack.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableStack.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[4,3],[2,1]]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableStackTOfArray()
+        {
+            IImmutableStack<int[]> input = ImmutableStack.CreateRange(new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[3,4],[1,2]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfIImmutableStackT()
+        {
+            IImmutableStack<int>[] input = new IImmutableStack<int>[2];
+            input[0] = ImmutableStack.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableStack.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[2,1],[4,3]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIImmutableStackT()
+        {
+            IImmutableStack<int> input = ImmutableStack.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[2,1]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableQueueTOfIImmutableQueueT()
+        {
+            IImmutableQueue<IImmutableQueue<int>> input = ImmutableQueue.CreateRange(new List<IImmutableQueue<int>>{
+                ImmutableQueue.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableQueue.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableQueueTOfArray()
+        {
+            IImmutableQueue<int[]> input = ImmutableQueue.CreateRange(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 WriteArrayOfIImmutableQueueT()
+        {
+            IImmutableQueue<int>[] input = new IImmutableQueue<int>[2];
+            input[0] = ImmutableQueue.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableQueue.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIImmutableQueueT()
+        {
+            IImmutableQueue<int> input = ImmutableQueue.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteIImmutableSetTOfIImmutableSetT()
+        {
+            IImmutableSet<IImmutableSet<int>> input = ImmutableHashSet.CreateRange(new List<IImmutableSet<int>>{
+                ImmutableHashSet.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableHashSet.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.True(json.Contains("[1,2]"));
+            Assert.True(json.Contains("[3,4]"));
+        }
+
+        [Fact]
+        public static void WriteIImmutableSetTOfArray()
+        {
+            IImmutableSet<int[]> input = ImmutableHashSet.CreateRange(new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.True(json.Contains("[1,2]"));
+            Assert.True(json.Contains("[3,4]"));
+        }
+
+        [Fact]
+        public static void WriteArrayOfIImmutableSetT()
+        {
+            IImmutableSet<int>[] input = new IImmutableSet<int>[2];
+            input[0] = ImmutableHashSet.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableHashSet.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveIImmutableSetT()
+        {
+            IImmutableSet<int> input = ImmutableHashSet.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableHashSetTOfImmutableHashSetT()
+        {
+            ImmutableHashSet<ImmutableHashSet<int>> input = ImmutableHashSet.CreateRange(new List<ImmutableHashSet<int>>{
+                ImmutableHashSet.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableHashSet.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.True(json.Contains("[1,2]"));
+            Assert.True(json.Contains("[3,4]"));
+        }
+
+        [Fact]
+        public static void WriteImmutableHashSetTOfArray()
+        {
+            ImmutableHashSet<int[]> input = ImmutableHashSet.CreateRange(new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.True(json.Contains("[1,2]"));
+            Assert.True(json.Contains("[3,4]"));
+        }
+
+        [Fact]
+        public static void WriteArrayOfImmutableHashSetT()
+        {
+            ImmutableHashSet<int>[] input = new ImmutableHashSet<int>[2];
+            input[0] = ImmutableHashSet.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableHashSet.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveImmutableHashSetT()
+        {
+            ImmutableHashSet<int> input = ImmutableHashSet.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableListTOfImmutableListT()
+        {
+            ImmutableList<ImmutableList<int>> input = ImmutableList.CreateRange(new List<ImmutableList<int>>{
+                ImmutableList.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableList.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableListTOfArray()
+        {
+            ImmutableList<int[]> input = ImmutableList.CreateRange(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 WriteArrayOfImmutableListT()
+        {
+            ImmutableList<int>[] input = new ImmutableList<int>[2];
+            input[0] = ImmutableList.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableList.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveImmutableListT()
+        {
+            ImmutableList<int> input = ImmutableList.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableStackTOfImmutableStackT()
+        {
+            ImmutableStack<ImmutableStack<int>> input = ImmutableStack.CreateRange(new List<ImmutableStack<int>>{
+                ImmutableStack.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableStack.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[4,3],[2,1]]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableStackTOfArray()
+        {
+            ImmutableStack<int[]> input = ImmutableStack.CreateRange(new List<int[]>
+            {
+                new int[] { 1, 2 },
+                new int[] { 3, 4 }
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[3,4],[1,2]]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfImmutableStackT()
+        {
+            ImmutableStack<int>[] input = new ImmutableStack<int>[2];
+            input[0] = ImmutableStack.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableStack.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[2,1],[4,3]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveImmutableStackT()
+        {
+            ImmutableStack<int> input = ImmutableStack.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[2,1]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableQueueTOfImmutableQueueT()
+        {
+            ImmutableQueue<ImmutableQueue<int>> input = ImmutableQueue.CreateRange(new List<ImmutableQueue<int>>{
+                ImmutableQueue.CreateRange(new List<int>() { 1, 2 }),
+                ImmutableQueue.CreateRange(new List<int>() { 3, 4 })
+            });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WriteImmutableQueueTOfArray()
+        {
+            ImmutableQueue<int[]> input = ImmutableQueue.CreateRange(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 WriteArrayOfImmutableQueueT()
+        {
+            ImmutableQueue<int>[] input = new ImmutableQueue<int>[2];
+            input[0] = ImmutableQueue.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableQueue.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveImmutableQueueT()
+        {
+            ImmutableQueue<int> input = ImmutableQueue.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+
+        [Fact]
+        public static void WriteArrayOfImmutableSortedSetT()
+        {
+            ImmutableSortedSet<int>[] input = new ImmutableSortedSet<int>[2];
+            input[0] = ImmutableSortedSet.CreateRange(new List<int>() { 1, 2 });
+            input[1] = ImmutableSortedSet.CreateRange(new List<int>() { 3, 4 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[[1,2],[3,4]]", json);
+        }
+
+        [Fact]
+        public static void WritePrimitiveImmutableSortedSetT()
+        {
+            ImmutableSortedSet<int> input = ImmutableSortedSet.CreateRange(new List<int> { 1, 2 });
+
+            string json = JsonSerializer.ToString(input);
+            Assert.Equal("[1,2]", json);
+        }
+    }
+}
index 8a6c960..17b845b 100644 (file)
@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information.
 
 using System.Collections.Generic;
+using System.Collections.Immutable;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -114,281 +115,5 @@ namespace System.Text.Json.Serialization.Tests
             string json = JsonSerializer.ToString(input);
             Assert.Equal("[[1,2],[3,4]]", json);
         }
-
-        [Fact]
-        public static void WriteListOfList()
-        {
-            var 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 WriteListOfArray()
-        {
-            var 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 WriteArrayOfList()
-        {
-            var 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 WritePrimitiveList()
-        {
-            var input = new List<int> { 1, 2 };
-
-            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);
-        }
     }
 }
index 1183e02..fb067fa 100644 (file)
     <Compile Include="Serialization\TestClasses.SimpleTestClassWithSimpleObject.cs" />
     <Compile Include="Serialization\TestData.cs" />
     <Compile Include="Serialization\Value.ReadTests.cs" />
+    <Compile Include="Serialization\Value.ReadTests.GenericCollections.cs" />
+    <Compile Include="Serialization\Value.ReadTests.ImmutableCollections.cs" />
     <Compile Include="Serialization\Value.WriteTests.cs" />
+    <Compile Include="Serialization\Value.WriteTests.GenericCollections.cs" />
+    <Compile Include="Serialization\Value.WriteTests.ImmutableCollections.cs" />
     <Compile Include="TestCaseType.cs" />
     <Compile Include="TestClasses.ClassWithComplexObjects.cs" />
     <Compile Include="Utf8JsonReaderTests.cs" />