From 6a30849a3bc48938cafaff0a513c142bc756c862 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Mon, 12 Jul 2021 14:58:45 -0700 Subject: [PATCH 1/3] Support more collections in STJ source generator --- .../Common/ReflectionExtensions.cs | 129 ++++ .../System.Text.Json/gen/CollectionType.cs | 26 +- .../gen/JsonSourceGenerator.Emitter.cs | 135 ++-- .../gen/JsonSourceGenerator.Parser.cs | 183 ++++- .../gen/TypeGenerationSpec.cs | 2 + .../System.Text.Json/ref/System.Text.Json.cs | 14 + .../ref/System.Text.Json.csproj | 2 + .../Collection/IEnumerableConverterFactory.cs | 1 + .../IEnumerableConverterFactoryHelpers.cs | 85 +-- ...mmutableDictionaryOfTKeyTValueConverter.cs | 25 +- .../ImmutableEnumerableOfTConverter.cs | 20 +- .../Object/KeyValuePairConverter.cs | 2 +- .../Text/Json/Serialization/JsonConverter.cs | 4 +- .../JsonMetadataServices.Collections.cs | 403 +++++++++++ .../Serialization/Metadata/JsonTypeInfo.cs | 12 + .../Metadata/JsonTypeInfoInternalOfT.cs | 10 +- .../CollectionTests.AsyncEnumerable.cs | 70 +- .../CollectionTests.Concurrent.cs | 70 ++ .../CollectionTests.Dictionary.KeyPolicy.cs | 91 +-- ...CollectionTests.Dictionary.NonStringKey.cs | 0 .../CollectionTests.Dictionary.cs | 449 ++++++------ .../CollectionTests.Generic.Read.cs | 405 +++++------ .../CollectionTests.Generic.Write.cs | 313 ++++----- .../CollectionTests.Immutable.Read.cs | 637 ++++++++++++++++++ .../CollectionTests.Immutable.Write.cs | 193 +++--- .../CollectionTests.KeyValuePair.cs | 133 ++-- .../CollectionTests.NonGeneric.Read.cs | 173 ++--- .../CollectionTests.NonGeneric.Write.cs | 147 ++-- .../CollectionTests.ObjectModel.Read.cs | 53 ++ .../CollectionTests.ObjectModel.Write.cs | 19 +- .../CollectionTests.Specialized.Read.cs | 52 ++ .../CollectionTests.Specialized.Write.cs | 38 ++ .../Common/CollectionTests/CollectionTests.cs | 11 + .../Common/JsonSerializerWrapperForStream.cs | 22 + .../tests/Common/JsonTestHelper.cs | 17 + .../tests/Common/SerializerTests.cs | 5 +- .../tests/Common/TestClasses/TestClasses.cs | 16 + .../Serialization/CollectionTests.cs | 43 ++ .../Serialization/PropertyVisibilityTests.cs | 3 +- ...em.Text.Json.SourceGeneration.Tests.csproj | 21 +- .../System.Text.Json.Tests/JsonTestHelper.cs | 5 - .../Serialization/CollectionTests.cs | 10 + .../CollectionTests.Concurrent.Write.cs | 29 - .../CollectionTests.Concurrent.cs | 51 -- .../CollectionTests.Immutable.Read.cs | 636 ----------------- .../CollectionTests.ObjectModel.Read.cs | 52 -- .../CollectionTests.Specialized.Read.cs | 51 -- .../CollectionTests.Specialized.Write.cs | 37 - ...m.cs => JsonSerializerWrapperForStream.cs} | 17 +- .../JsonSerializerWrapperForString_Dynamic.cs | 32 - .../Serialization/PropertyNameTests.cs | 16 - .../Serialization/PropertyVisibilityTests.cs | 4 +- .../Stream.DeserializeAsyncEnumerable.cs | 2 +- .../Serialization/StreamTests.cs | 8 +- .../System.Text.Json.Tests.csproj | 39 +- 55 files changed, 2899 insertions(+), 2124 deletions(-) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.AsyncEnumerable.cs (78%) create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Concurrent.cs rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs (73%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs (100%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Dictionary.cs (70%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Generic.Read.cs (55%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Generic.Write.cs (69%) create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Read.cs rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.Immutable.Write.cs (64%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.KeyValuePair.cs (68%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.NonGeneric.Read.cs (59%) rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.NonGeneric.Write.cs (64%) create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Read.cs rename src/libraries/System.Text.Json/tests/{System.Text.Json.Tests/Serialization => Common}/CollectionTests/CollectionTests.ObjectModel.Write.cs (51%) create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Read.cs create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Write.cs create mode 100644 src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.cs create mode 100644 src/libraries/System.Text.Json/tests/Common/JsonSerializerWrapperForStream.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs rename src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/{JsonSerializationWrapperForStream.cs => JsonSerializerWrapperForStream.cs} (77%) delete mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForString_Dynamic.cs diff --git a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs index 5d9ef545b8d44..fe05c0c848d2a 100644 --- a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs +++ b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs @@ -3,11 +3,140 @@ using System.Diagnostics; using System.Reflection; +#if !BUILDING_SOURCE_GENERATOR +using System.Diagnostics.CodeAnalysis; +#endif namespace System.Text.Json.Reflection { internal static partial class ReflectionExtensions { + // Immutable collection types. + public const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1"; + public const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1"; + public const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1"; + public const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1"; + public const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1"; + public const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1"; + public const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1"; + public const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1"; + public const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1"; + public const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1"; + public const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2"; + public const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2"; + public const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2"; + + public static Type? GetCompatibleGenericBaseClass(this Type type, Type baseType, Type? objectType = null) + { + Debug.Assert(baseType.IsGenericType); + Debug.Assert(!baseType.IsInterface); + Debug.Assert(baseType == baseType.GetGenericTypeDefinition()); + + // Work around not being able to use typeof(object) directly during compile-time src gen type analysis. + objectType ??= typeof(object); + + Type? baseTypeToCheck = type; + + while (baseTypeToCheck != null && baseTypeToCheck != typeof(object)) + { + if (baseTypeToCheck.IsGenericType) + { + Type genericTypeToCheck = baseTypeToCheck.GetGenericTypeDefinition(); + if (genericTypeToCheck == baseType) + { + return baseTypeToCheck; + } + } + + baseTypeToCheck = baseTypeToCheck.BaseType; + } + + return null; + } + +#if !BUILDING_SOURCE_GENERATOR + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", + Justification = "The 'interfaceType' must exist and so trimmer kept it. In which case " + + "It also kept it on any type which implements it. The below call to GetInterfaces " + + "may return fewer results when trimmed but it will return the 'interfaceType' " + + "if the type implemented it, even after trimming.")] +#endif + public static Type? GetCompatibleGenericInterface(this Type type, Type interfaceType) + { + Debug.Assert(interfaceType.IsGenericType); + Debug.Assert(interfaceType.IsInterface); + Debug.Assert(interfaceType == interfaceType.GetGenericTypeDefinition()); + + Type interfaceToCheck = type; + + if (interfaceToCheck.IsGenericType) + { + interfaceToCheck = interfaceToCheck.GetGenericTypeDefinition(); + } + + if (interfaceToCheck == interfaceType) + { + return type; + } + + foreach (Type typeToCheck in type.GetInterfaces()) + { + if (typeToCheck.IsGenericType) + { + Type genericInterfaceToCheck = typeToCheck.GetGenericTypeDefinition(); + if (genericInterfaceToCheck == interfaceType) + { + return typeToCheck; + } + } + } + + return null; + } + + public static bool IsImmutableDictionaryType(this Type type) + { + if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) + { + return false; + } + + switch (type.GetGenericTypeDefinition().FullName) + { + case ImmutableDictionaryGenericTypeName: + case ImmutableDictionaryGenericInterfaceTypeName: + case ImmutableSortedDictionaryGenericTypeName: + return true; + default: + return false; + } + } + + public static bool IsImmutableEnumerableType(this Type type) + { + if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) + { + return false; + } + + switch (type.GetGenericTypeDefinition().FullName) + { + case ImmutableArrayGenericTypeName: + case ImmutableListGenericTypeName: + case ImmutableListGenericInterfaceTypeName: + case ImmutableStackGenericTypeName: + case ImmutableStackGenericInterfaceTypeName: + case ImmutableQueueGenericTypeName: + case ImmutableQueueGenericInterfaceTypeName: + case ImmutableSortedSetGenericTypeName: + case ImmutableHashSetGenericTypeName: + case ImmutableSetGenericInterfaceTypeName: + return true; + default: + return false; + } + } + public static bool IsVirtual(this PropertyInfo? propertyInfo) { Debug.Assert(propertyInfo != null); diff --git a/src/libraries/System.Text.Json/gen/CollectionType.cs b/src/libraries/System.Text.Json/gen/CollectionType.cs index 6f736698f47b8..274fb7f8d0103 100644 --- a/src/libraries/System.Text.Json/gen/CollectionType.cs +++ b/src/libraries/System.Text.Json/gen/CollectionType.cs @@ -9,11 +9,25 @@ namespace System.Text.Json.SourceGeneration { internal enum CollectionType { - NotApplicable = 0, - Array = 1, - List = 2, - IEnumerable = 3, - IList = 4, - Dictionary = 5 + NotApplicable, + Array, + List, + IEnumerable, + IList, + GenericIList, + ISet, + GenericICollection, + GenericStack, + GenericQueue, + ConcurrentStack, + ConcurrentQueue, + GenericIEnumerable, + StackOrQueue, + ImmutableCollection, + IDictionary, + Dictionary, + ImmutableDictionary, + GenericIDictionary, + IReadOnlyDictionary } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index cbab663971eed..09634fd1c0cb0 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -333,7 +333,7 @@ private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec) // Key metadata TypeGenerationSpec? collectionKeyTypeMetadata = typeGenerationSpec.CollectionKeyTypeMetadata; - Debug.Assert(!(typeGenerationSpec.CollectionType == CollectionType.Dictionary && collectionKeyTypeMetadata == null)); + Debug.Assert(!(typeGenerationSpec.ClassType == ClassType.Dictionary && collectionKeyTypeMetadata == null)); string? keyTypeCompilableName = collectionKeyTypeMetadata?.TypeRef; string? keyTypeReadableName = collectionKeyTypeMetadata?.TypeInfoPropertyName; @@ -361,11 +361,8 @@ private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec) string numberHandlingArg = $"{GetNumberHandlingAsStr(typeGenerationSpec.NumberHandling)}"; - string serializeMethodName = $"{typeFriendlyName}{SerializeMethodNameSuffix}"; string serializeFuncNamedArg; - CollectionType collectionType = typeGenerationSpec.CollectionType; - string? serializeFuncSource; if (!typeGenerationSpec.GenerateSerializationLogic) { @@ -374,82 +371,114 @@ private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec) } else { - bool canBeNull = typeGenerationSpec.CanBeNull; - - switch (collectionType) - { - case CollectionType.Array: - serializeFuncSource = GenerateFastPathFuncForEnumerable(typeCompilableName, serializeMethodName, canBeNull, isArray: true, collectionValueTypeMetadata); - break; - case CollectionType.List: - serializeFuncSource = GenerateFastPathFuncForEnumerable(typeCompilableName, serializeMethodName, canBeNull, isArray: false, collectionValueTypeMetadata); - break; - case CollectionType.Dictionary: - serializeFuncSource = GenerateFastPathFuncForDictionary(typeCompilableName, serializeMethodName, canBeNull, collectionKeyTypeMetadata, collectionValueTypeMetadata); - break; - default: - serializeFuncSource = null; - break; - } + serializeFuncSource = typeGenerationSpec.ClassType == ClassType.Enumerable + ? GenerateFastPathFuncForEnumerable(typeGenerationSpec) + : GenerateFastPathFuncForDictionary(typeGenerationSpec); - serializeFuncNamedArg = $"serializeFunc: {serializeMethodName}"; + serializeFuncNamedArg = $"serializeFunc: {typeGenerationSpec.SerializeMethodName}"; } - string collectionTypeInfoValue = collectionType switch + //string collectionTypeInfoValue = typeGenerationSpec.CollectionType switch + //{ + // CollectionType.Array => $"{JsonMetadataServicesTypeRef}.CreateArrayInfo<{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", + // CollectionType.List => $"{JsonMetadataServicesTypeRef}.CreateListInfo<{typeCompilableName}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {ListTypeRef}<{valueTypeCompilableName}>(), {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", + // CollectionType.Dictionary => $"{JsonMetadataServicesTypeRef}.CreateDictionaryInfo<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", + // _ => throw new NotSupportedException() + //}; + + + CollectionType collectionType = typeGenerationSpec.CollectionType; + string collectionTypeInfoValue; + + switch (collectionType) { - CollectionType.Array => $"{JsonMetadataServicesTypeRef}.CreateArrayInfo<{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - CollectionType.List => $"{JsonMetadataServicesTypeRef}.CreateListInfo<{typeCompilableName}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {ListTypeRef}<{valueTypeCompilableName}>(), {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - CollectionType.Dictionary => $"{JsonMetadataServicesTypeRef}.CreateDictionaryInfo<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - _ => throw new NotSupportedException() - }; + case CollectionType.IDictionary: + case CollectionType.Dictionary: + case CollectionType.GenericIDictionary: + case CollectionType.IReadOnlyDictionary: + collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + break; + case CollectionType.ImmutableDictionary: + collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg}, )"; + break; + default: + collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + break; + } string metadataInitSource = @$"_{typeFriendlyName} = {collectionTypeInfoValue};"; return GenerateForType(typeGenerationSpec, metadataInitSource, serializeFuncSource); } - private string GenerateFastPathFuncForEnumerable(string typeInfoRef, string serializeMethodName, bool canBeNull, bool isArray, TypeGenerationSpec valueTypeGenerationSpec) + private enum EnumerableIterationType + { + ForEach, + Length, + Count + } + + private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerationSpec) { + TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata; + string? writerMethodToCall = GetWriterMethod(valueTypeGenerationSpec.Type); - string valueToWrite = $"{ValueVarName}[i]"; - string lengthPropName = isArray ? "Length" : "Count"; + + string iterationLogic; + string valueToWrite; - string elementSerializationLogic; - if (writerMethodToCall != null) + switch (typeGenerationSpec.CollectionType) { - elementSerializationLogic = $"{writerMethodToCall}Value({valueToWrite});"; - } - else - { - elementSerializationLogic = GetSerializeLogicForNonPrimitiveType(valueTypeGenerationSpec.TypeInfoPropertyName, valueToWrite, valueTypeGenerationSpec.GenerateSerializationLogic); - } + case CollectionType.Array: + iterationLogic = $"for (int i = 0; i < {ValueVarName}.Length; i++)"; + valueToWrite = $"{ValueVarName}[i]"; + break; + case CollectionType.GenericICollection: + case CollectionType.GenericIList: + case CollectionType.List: + case CollectionType.IList: + iterationLogic = $"for (int i = 0; i < {ValueVarName}.Count; i++)"; + valueToWrite = $"{ValueVarName}[i]"; + break; + default: + const string elementVarName = "element"; + iterationLogic = $"foreach ({valueTypeGenerationSpec.TypeRef} {elementVarName} in {ValueVarName})"; + valueToWrite = $"{ValueVarName}[i]"; + break; + }; + + string elementSerializationLogic = writerMethodToCall == null + ? GetSerializeLogicForNonPrimitiveType(valueTypeGenerationSpec.TypeInfoPropertyName, valueToWrite, valueTypeGenerationSpec.GenerateSerializationLogic) + : $"{writerMethodToCall}Value({valueToWrite});"; string serializationLogic = $@"{WriterVarName}.WriteStartArray(); - for (int i = 0; i < {ValueVarName}.{lengthPropName}; i++) + {iterationLogic} {{ {elementSerializationLogic} }} {WriterVarName}.WriteEndArray();"; - return GenerateFastPathFuncForType(serializeMethodName, typeInfoRef, serializationLogic, canBeNull); + return GenerateFastPathFuncForType( + typeGenerationSpec.SerializeMethodName, + typeGenerationSpec.TypeRef, + serializationLogic, + typeGenerationSpec.CanBeNull); } - private string GenerateFastPathFuncForDictionary( - string typeInfoRef, - string serializeMethodName, - bool canBeNull, - TypeGenerationSpec keyTypeGenerationSpec, - TypeGenerationSpec valueTypeGenerationSpec) + private string GenerateFastPathFuncForDictionary(TypeGenerationSpec typeGenerationSpec) { - const string pairVarName = "pair"; - string keyToWrite = $"{pairVarName}.Key"; - string valueToWrite = $"{pairVarName}.Value"; + TypeGenerationSpec keyTypeGenerationSpec = typeGenerationSpec.CollectionKeyTypeMetadata; + TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata; string? writerMethodToCall = GetWriterMethod(valueTypeGenerationSpec.Type); string elementSerializationLogic; + const string pairVarName = "pair"; + string keyToWrite = $"{pairVarName}.Key"; + string valueToWrite = $"{pairVarName}.Value"; + if (writerMethodToCall != null) { elementSerializationLogic = $"{writerMethodToCall}({keyToWrite}, {valueToWrite});"; @@ -469,7 +498,11 @@ private string GenerateFastPathFuncForDictionary( {WriterVarName}.WriteEndObject();"; - return GenerateFastPathFuncForType(serializeMethodName, typeInfoRef, serializationLogic, canBeNull); + return GenerateFastPathFuncForType( + typeGenerationSpec.SerializeMethodName, + typeGenerationSpec.TypeRef, + serializationLogic, + typeGenerationSpec.CanBeNull); } private string GenerateForObject(TypeGenerationSpec typeMetadata) diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 727d80c6b1084..9849814e5eb9b 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -40,9 +40,23 @@ private sealed class Parser private readonly MetadataLoadContextInternal _metadataLoadContext; - private readonly Type _ienumerableType; private readonly Type _listOfTType; private readonly Type _dictionaryType; + private readonly Type _idictionaryOfTKeyTValueType; + private readonly Type _ireadonlyDictionaryType; + private readonly Type _ilistOfTType; + private readonly Type _isetType; + private readonly Type _icollectionOfTType; + private readonly Type _stackOfTType; + private readonly Type _queueOfTType; + private readonly Type _concurrentStackType; + private readonly Type _concurrentQueueType; + private readonly Type _ienumerableOfTType; + private readonly Type _idictionaryType; + private readonly Type _ilistType; + private readonly Type _stackType; + private readonly Type _queueType; + private readonly Type _ienumerableType; private readonly Type _booleanType; private readonly Type _byteArrayType; @@ -51,6 +65,7 @@ private sealed class Parser private readonly Type _dateTimeOffsetType; private readonly Type _guidType; private readonly Type _nullableOfTType; + private readonly Type _objectType; private readonly Type _stringType; private readonly Type _uriType; private readonly Type _versionType; @@ -81,9 +96,23 @@ public Parser(in GeneratorExecutionContext executionContext) _executionContext = executionContext; _metadataLoadContext = new MetadataLoadContextInternal(executionContext.Compilation); - _ienumerableType = _metadataLoadContext.Resolve(typeof(IEnumerable)); _listOfTType = _metadataLoadContext.Resolve(typeof(List<>)); _dictionaryType = _metadataLoadContext.Resolve(typeof(Dictionary<,>)); + _idictionaryOfTKeyTValueType = _metadataLoadContext.Resolve(typeof(IDictionary<,>)); + _ireadonlyDictionaryType = _metadataLoadContext.Resolve(typeof(IReadOnlyDictionary<,>)); + _ilistOfTType = _metadataLoadContext.Resolve(typeof(IList<>)); + _isetType = _metadataLoadContext.Resolve(typeof(ISet<>)); + _icollectionOfTType = _metadataLoadContext.Resolve(typeof(ICollection<>)); + _stackOfTType = _metadataLoadContext.Resolve(typeof(Stack<>)); + _queueOfTType = _metadataLoadContext.Resolve(typeof(Queue<>)); + _concurrentStackType = _metadataLoadContext.Resolve(typeof(Stack<>)); + _concurrentQueueType = _metadataLoadContext.Resolve(typeof(Queue<>)); + _ienumerableOfTType = _metadataLoadContext.Resolve(typeof(IEnumerable<>)); + _idictionaryType = _metadataLoadContext.Resolve(typeof(IDictionary)); + _ilistType = _metadataLoadContext.Resolve(typeof(IList)); + _stackType = _metadataLoadContext.Resolve(typeof(Stack)); + _queueType = _metadataLoadContext.Resolve(typeof(Queue)); + _ienumerableType = _metadataLoadContext.Resolve(typeof(IEnumerable)); _booleanType = _metadataLoadContext.Resolve(typeof(bool)); _byteArrayType = _metadataLoadContext.Resolve(typeof(byte[])); @@ -92,6 +121,7 @@ public Parser(in GeneratorExecutionContext executionContext) _dateTimeOffsetType = _metadataLoadContext.Resolve(typeof(DateTimeOffset)); _guidType = _metadataLoadContext.Resolve(typeof(Guid)); _nullableOfTType = _metadataLoadContext.Resolve(typeof(Nullable<>)); + _objectType = _metadataLoadContext.Resolve(typeof(object)); _stringType = _metadataLoadContext.Resolve(typeof(string)); _uriType = _metadataLoadContext.Resolve(typeof(Uri)); _versionType = _metadataLoadContext.Resolve(typeof(Version)); @@ -526,6 +556,10 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener } } + if (type.Name.StartsWith("Concurrent")) + { + } + if (foundDesignTimeCustomConverter) { classType = converterInstatiationLogic != null @@ -549,7 +583,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener } else if (_ienumerableType.IsAssignableFrom(type)) { - // Only T[], List, and Dictionary are supported. + Type actualTypeToConvert; if (type.IsArray) { @@ -557,32 +591,126 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener collectionType = CollectionType.Array; collectionValueType = type.GetElementType(); } - else if (!type.IsGenericType) + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _listOfTType)) != null) { - classType = ClassType.TypeUnsupportedBySourceGen; + classType = ClassType.Enumerable; + collectionType = CollectionType.List; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } - else + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _dictionaryType)) != null) { - Type genericTypeDef = type.GetGenericTypeDefinition(); - Type[] genericTypeArgs = type.GetGenericArguments(); + classType = ClassType.Dictionary; + collectionType = CollectionType.Dictionary; - if (genericTypeDef == _listOfTType) - { - classType = ClassType.Enumerable; - collectionType = CollectionType.List; - collectionValueType = genericTypeArgs[0]; - } - else if (genericTypeDef == _dictionaryType) - { - classType = ClassType.Dictionary; - collectionType = CollectionType.Dictionary; - collectionKeyType = genericTypeArgs[0]; - collectionValueType = genericTypeArgs[1]; - } - else - { - classType = ClassType.TypeUnsupportedBySourceGen; - } + Type[] genericArgs = actualTypeToConvert.GetGenericArguments(); + collectionKeyType = genericArgs[0]; + collectionValueType = genericArgs[1]; + } + else if (type.IsImmutableDictionaryType()) + { + classType = ClassType.Dictionary; + collectionType = CollectionType.ImmutableDictionary; + + Type[] genericArgs = type.GetGenericArguments(); + collectionKeyType = genericArgs[0]; + collectionValueType = genericArgs[1]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_idictionaryOfTKeyTValueType)) != null) + { + classType = ClassType.Dictionary; + collectionType = CollectionType.GenericIDictionary; + + Type[] genericArgs = actualTypeToConvert.GetGenericArguments(); + collectionKeyType = genericArgs[0]; + collectionValueType = genericArgs[1]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_ireadonlyDictionaryType)) != null) + { + classType = ClassType.Dictionary; + collectionType = CollectionType.IReadOnlyDictionary; + + Type[] genericArgs = actualTypeToConvert.GetGenericArguments(); + collectionKeyType = genericArgs[0]; + collectionValueType = genericArgs[1]; + } + else if (type.IsImmutableEnumerableType()) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.ImmutableCollection; + collectionValueType = type.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_ilistOfTType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.GenericIList; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_isetType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.ISet; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_icollectionOfTType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.GenericICollection; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _stackOfTType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.GenericStack; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _queueOfTType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.GenericQueue; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _concurrentStackType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.ConcurrentStack; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _concurrentQueueType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.ConcurrentQueue; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_ienumerableOfTType)) != null) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.GenericIEnumerable; + collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; + } + else if (_idictionaryType.IsAssignableFrom(type)) + { + classType = ClassType.Dictionary; + collectionType = CollectionType.IDictionary; + collectionKeyType = _stringType; + collectionValueType = _objectType; + } + else if (typeof(IList).IsAssignableFrom(type)) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.IList; + collectionValueType = _objectType; + } + else if (_stackType.IsAssignableFrom(type) || _queueType.IsAssignableFrom(type)) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.StackOrQueue; + collectionValueType = _objectType; + } + else + { + classType = ClassType.Enumerable; + collectionType = CollectionType.IEnumerable; + collectionValueType = _objectType; } } else @@ -667,6 +795,9 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener return typeMetadata; } + private Type GetCompatibleGenericBaseClass(Type type, Type baseType) + => type.GetCompatibleGenericBaseClass(baseType, _objectType); + private void CacheMember( PropertyGenerationSpec propGenSpec, ref List propGenSpecList, @@ -936,7 +1067,7 @@ private void PopulateKnownTypes() _knownTypes.Add(_dateTimeType); _knownTypes.Add(_dateTimeOffsetType); _knownTypes.Add(_guidType); - _knownTypes.Add(_metadataLoadContext.Resolve(typeof(object))); + _knownTypes.Add(_objectType); _knownTypes.Add(_stringType); // System.Private.Uri may not be loaded in input compilation. diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index 865134823f9a3..d11598d971b30 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -57,6 +57,8 @@ internal class TypeGenerationSpec public string? ConverterInstantiationLogic { get; private set; } + public string SerializeMethodName => $"{TypeInfoPropertyName}Serialize"; + public void Initialize( JsonSourceGenerationMode generationMode, string typeRef, diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index 97e39311a09e7..aa2073d843d83 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -934,10 +934,24 @@ public static partial class JsonMetadataServices public static System.Text.Json.Serialization.JsonConverter UriConverter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter VersionConverter { get { throw null; } } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateArrayInfo(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) { throw null; } + public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentQueueOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentQueue { throw null; } + public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentStackOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentStack { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo keyInfo, System.Text.Json.Serialization.Metadata.JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Dictionary where TKey : notnull { throw null; } + public static JsonTypeInfo CreateICollectionOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ICollection { throw null; } + public static JsonTypeInfo CreateIDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, JsonTypeInfo objectInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IDictionary { throw null; } + public static JsonTypeInfo CreateIEnumerableInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IEnumerable { throw null; } + public static JsonTypeInfo CreateIEnumerableOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IEnumerable { throw null; } + public static JsonTypeInfo CreateIListOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IList { throw null; } + public static JsonTypeInfo CreateImmutableDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc, System.Func>, TCollection> createRangeFunc) where TCollection : System.Collections.Generic.IReadOnlyDictionary where TKey : notnull { throw null; } + public static JsonTypeInfo CreateImmutableEnumerableInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc, System.Func, TCollection> createRangeFunc) where TCollection : System.Collections.Generic.IEnumerable { throw null; } + public static JsonTypeInfo CreateIReadOnlyDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Dictionary where TKey : notnull { throw null; } + public static JsonTypeInfo CreateISetInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ISet { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateListInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.List { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateObjectInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Func? propInitFunc, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where T : notnull { throw null; } public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo(System.Text.Json.JsonSerializerOptions options, bool isProperty, bool isPublic, bool isVirtual, System.Type declaringType, System.Text.Json.Serialization.Metadata.JsonTypeInfo propertyTypeInfo, System.Text.Json.Serialization.JsonConverter? converter, System.Func? getter, System.Action? setter, System.Text.Json.Serialization.JsonIgnoreCondition? ignoreCondition, bool hasJsonInclude, System.Text.Json.Serialization.JsonNumberHandling? numberHandling, string propertyName, string? jsonPropertyName) { throw null; } + public static JsonTypeInfo CreateQueueOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Queue { throw null; } + public static JsonTypeInfo CreateStackOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Stack { throw null; } + public static JsonTypeInfo CreateStackOrQueueInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IEnumerable { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateValueInfo(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.JsonConverter converter) { throw null; } public static System.Text.Json.Serialization.JsonConverter GetEnumConverter(System.Text.Json.JsonSerializerOptions options) where T : struct { throw null; } public static System.Text.Json.Serialization.JsonConverter GetNullableConverter(System.Text.Json.Serialization.Metadata.JsonTypeInfo underlyingTypeInfo) where T : struct { throw null; } diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj index f015d29c355e6..5244502eb33a5 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.csproj +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.csproj @@ -13,11 +13,13 @@ + + diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs index d90b9c1d0c83e..ca1e09228b106 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactory.cs @@ -7,6 +7,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Text.Json.Reflection; namespace System.Text.Json.Serialization.Converters { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs index 819de1fec2037..a63fef10cd96a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; +using System.Text.Json.Reflection; using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization @@ -14,21 +15,6 @@ internal static class IEnumerableConverterFactoryHelpers // any netstandard2.0 consumers don't need to reference System.Collections.Immutable. // So instead, implement a "weak reference" by using strings to check for Immutable types. - // Immutable collection types. - private const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1"; - private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1"; - private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1"; - private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1"; - private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1"; - private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1"; - private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1"; - private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1"; - private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1"; - private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1"; - private const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2"; - private const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2"; - private const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2"; - // Immutable collection builder types. private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray"; private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList"; @@ -107,49 +93,6 @@ internal static class IEnumerableConverterFactoryHelpers return null; } - public static bool IsImmutableDictionaryType(this Type type) - { - if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) - { - return false; - } - - switch (type.GetGenericTypeDefinition().FullName) - { - case ImmutableDictionaryGenericTypeName: - case ImmutableDictionaryGenericInterfaceTypeName: - case ImmutableSortedDictionaryGenericTypeName: - return true; - default: - return false; - } - } - - public static bool IsImmutableEnumerableType(this Type type) - { - if (!type.IsGenericType|| !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) - { - return false; - } - - switch (type.GetGenericTypeDefinition().FullName) - { - case ImmutableArrayGenericTypeName: - case ImmutableListGenericTypeName: - case ImmutableListGenericInterfaceTypeName: - case ImmutableStackGenericTypeName: - case ImmutableStackGenericInterfaceTypeName: - case ImmutableQueueGenericTypeName: - case ImmutableQueueGenericInterfaceTypeName: - case ImmutableSortedSetGenericTypeName: - case ImmutableHashSetGenericTypeName: - case ImmutableSetGenericInterfaceTypeName: - return true; - default: - return false; - } - } - [RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)] public static MethodInfo GetImmutableEnumerableCreateRangeMethod(this Type type, Type elementType) { @@ -209,26 +152,26 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, switch (underlyingType.FullName) { - case ImmutableArrayGenericTypeName: + case ReflectionExtensions.ImmutableArrayGenericTypeName: constructingTypeName = ImmutableArrayTypeName; break; - case ImmutableListGenericTypeName: - case ImmutableListGenericInterfaceTypeName: + case ReflectionExtensions.ImmutableListGenericTypeName: + case ReflectionExtensions.ImmutableListGenericInterfaceTypeName: constructingTypeName = ImmutableListTypeName; break; - case ImmutableStackGenericTypeName: - case ImmutableStackGenericInterfaceTypeName: + case ReflectionExtensions.ImmutableStackGenericTypeName: + case ReflectionExtensions.ImmutableStackGenericInterfaceTypeName: constructingTypeName = ImmutableStackTypeName; break; - case ImmutableQueueGenericTypeName: - case ImmutableQueueGenericInterfaceTypeName: + case ReflectionExtensions.ImmutableQueueGenericTypeName: + case ReflectionExtensions.ImmutableQueueGenericInterfaceTypeName: constructingTypeName = ImmutableQueueTypeName; break; - case ImmutableSortedSetGenericTypeName: + case ReflectionExtensions.ImmutableSortedSetGenericTypeName: constructingTypeName = ImmutableSortedSetTypeName; break; - case ImmutableHashSetGenericTypeName: - case ImmutableSetGenericInterfaceTypeName: + case ReflectionExtensions.ImmutableHashSetGenericTypeName: + case ReflectionExtensions.ImmutableSetGenericInterfaceTypeName: constructingTypeName = ImmutableHashSetTypeName; break; default: @@ -253,11 +196,11 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, switch (underlyingType.FullName) { - case ImmutableDictionaryGenericTypeName: - case ImmutableDictionaryGenericInterfaceTypeName: + case ReflectionExtensions.ImmutableDictionaryGenericTypeName: + case ReflectionExtensions.ImmutableDictionaryGenericInterfaceTypeName: constructingTypeName = ImmutableDictionaryTypeName; break; - case ImmutableSortedDictionaryGenericTypeName: + case ReflectionExtensions.ImmutableSortedDictionaryGenericTypeName: constructingTypeName = ImmutableSortedDictionaryTypeName; break; default: diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs index 7923890979b39..4abff2ad3743a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization.Metadata; @@ -24,24 +25,18 @@ protected override void Add(TKey key, in TValue value, JsonSerializerOptions opt internal override bool CanHaveIdMetadata => false; + internal override bool IsImmutableCollectionConverter => true; + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { state.Current.ReturnValue = new Dictionary(); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "The ctor is marked RequiresUnreferencedCode.")] protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { - JsonTypeInfo typeInfo = state.Current.JsonTypeInfo; - - Func>, TCollection>? creator = (Func>, TCollection>?)typeInfo.CreateObjectWithArgs; - if (creator == null) - { - creator = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate(); - typeInfo.CreateObjectWithArgs = creator; - } - + Func>, TCollection>? creator = + (Func>, TCollection>?)state.Current.JsonTypeInfo.CreateObjectWithArgs; + Debug.Assert(creator != null); state.Current.ReturnValue = creator((Dictionary)state.Current.ReturnValue!); } @@ -95,5 +90,13 @@ protected internal override bool OnWriteResume(Utf8JsonWriter writer, TCollectio enumerator.Dispose(); return true; } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The ctor is marked RequiresUnreferencedCode.")] + internal override void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) + { + Debug.Assert(jsonTypeInfo != null); + jsonTypeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateImmutableDictionaryCreateRangeDelegate(); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs index d65807bf25c61..37a9dbcc292be 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Text.Json.Serialization.Metadata; @@ -23,24 +24,19 @@ protected override void Add(in TElement value, ref ReadStack state) internal override bool CanHaveIdMetadata => false; + internal override bool IsImmutableCollectionConverter => true; + protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { state.Current.ReturnValue = new List(); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", - Justification = "The ctor is marked RequiresUnreferencedCode.")] protected override void ConvertCollection(ref ReadStack state, JsonSerializerOptions options) { JsonTypeInfo typeInfo = state.Current.JsonTypeInfo; Func, TCollection>? creator = (Func, TCollection>?)typeInfo.CreateObjectWithArgs; - if (creator == null) - { - creator = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate(); - typeInfo.CreateObjectWithArgs = creator; - } - + Debug.Assert(creator != null); state.Current.ReturnValue = creator((List)state.Current.ReturnValue!); } @@ -81,5 +77,13 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, enumerator.Dispose(); return true; } + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode", + Justification = "The ctor is marked RequiresUnreferencedCode.")] + internal override void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) + { + Debug.Assert(jsonTypeInfo != null); + jsonTypeInfo.CreateObjectWithArgs = options.MemberAccessorStrategy.CreateImmutableEnumerableCreateRangeDelegate(); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/KeyValuePairConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/KeyValuePairConverter.cs index 016702cf6cb60..f769427e0b696 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/KeyValuePairConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Object/KeyValuePairConverter.cs @@ -23,7 +23,7 @@ internal sealed class KeyValuePairConverter : private static readonly ConstructorInfo s_constructorInfo = typeof(KeyValuePair).GetConstructor(new[] { typeof(TKey), typeof(TValue) })!; - internal override void Initialize(JsonSerializerOptions options) + internal override void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) { JsonNamingPolicy? namingPolicy = options.PropertyNamingPolicy; if (namingPolicy == null) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs index f324f672c915f..e62f97cc7bcc9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs @@ -114,7 +114,9 @@ internal bool ShouldFlush(Utf8JsonWriter writer, ref WriteStack state) internal ConstructorInfo? ConstructorInfo { get; set; } - internal virtual void Initialize(JsonSerializerOptions options) { } + internal virtual bool IsImmutableCollectionConverter { get; } + + internal virtual void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) { } /// /// Creates the instance and assigns it to state.Current.ReturnValue. diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs index e0f846ddaf25c..23ebb13a16792 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs @@ -1,6 +1,8 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Text.Json.Serialization.Converters; @@ -90,5 +92,406 @@ public static JsonTypeInfo CreateDictionaryInfo + /// Creates metadata for and + /// types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the key type. + /// The generic definition of the value type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the key type. + /// A instance representing the value type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// A method to create an immutable dictionary instance. + /// +#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved + public static JsonTypeInfo CreateImmutableDictionaryInfo( + JsonSerializerOptions options, + Func createObjectFunc, + JsonTypeInfo keyInfo, + JsonTypeInfo valueInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc, + Func>, TCollection> createRangeFunc) + where TCollection : IReadOnlyDictionary + where TKey : notnull + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ImmutableDictionaryOfTKeyTValueConverter(), + keyInfo, + valueInfo, + numberHandling, + serializeFunc, + typeof(TKey), + typeof(TValue), + createRangeFunc ?? throw new ArgumentNullException(nameof(createRangeFunc))); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the key type. + /// The generic definition of the value type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the key type. + /// A instance representing the value type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIReadOnlyDictionaryInfo( + JsonSerializerOptions options, + Func createObjectFunc, + JsonTypeInfo keyInfo, + JsonTypeInfo valueInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : Dictionary + where TKey : notnull + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IReadOnlyDictionaryOfTKeyTValueConverter(), + keyInfo, + valueInfo, + numberHandling, + serializeFunc, + typeof(TKey), + typeof(TValue)); + +#pragma warning disable CS1574 // XML comment has cref attribute that could not be resolved + /// + /// Creates metadata for non-dictionary immutable collection types. + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// A method to create an immutable dictionary instance. + /// +#pragma warning restore CS1574 // XML comment has cref attribute that could not be resolved + public static JsonTypeInfo CreateImmutableEnumerableInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc, + Func, TCollection> createRangeFunc) + where TCollection : IEnumerable + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ImmutableEnumerableOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement), + createRangeFunc ?? throw new ArgumentNullException(nameof(createRangeFunc))); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIListOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IList + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IListOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateISetInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : ISet + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ISetOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateICollectionOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : ICollection + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ICollectionOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateStackOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : Stack + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new StackOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateQueueOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : Queue + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new QueueOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateConcurrentStackOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : ConcurrentStack + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ConcurrentStackOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateConcurrentQueueOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : ConcurrentQueue + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new ConcurrentQueueOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the element type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIEnumerableOfTInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IEnumerable + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IEnumerableOfTConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(TElement)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing instances. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIDictionaryInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo objectInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IDictionary + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IDictionaryConverter(), + keyInfo: objectInfo, + valueInfo: objectInfo, + numberHandling, + serializeFunc, + typeof(object), + typeof(object)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateStackOrQueueInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IEnumerable + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IEnumerableWithAddMethodConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(object)); + + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIEnumerableInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo elementInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IEnumerable + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IEnumerableWithAddMethodConverter(), + elementInfo, + numberHandling, + serializeFunc, + typeof(object)); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs index 077de6d05372d..7f3057b2c73e1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs @@ -305,6 +305,12 @@ internal JsonTypeInfo(Type type, JsonConverter converter, Type runtimeType, Json { ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); + + if (converter.IsImmutableCollectionConverter) + { + // Initialize a func to create immutable enumerable instances. + converter.Initialize(Options, this); + } } break; case ConverterStrategy.Dictionary: @@ -312,6 +318,12 @@ internal JsonTypeInfo(Type type, JsonConverter converter, Type runtimeType, Json KeyType = converter.KeyType; ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); + + if (converter.IsImmutableCollectionConverter) + { + // Initialize a func to create immutable dictionary instances. + converter.Initialize(Options, this); + } } break; case ConverterStrategy.Value: diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs index b016ef98757db..c61a504691b2e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs @@ -58,7 +58,9 @@ public JsonTypeInfoInternal( JsonTypeInfo? elementInfo, JsonNumberHandling numberHandling, Action? serializeFunc, - Type elementType) : base(typeof(T), options, ConverterStrategy.Enumerable) + Type elementType, + object? createObjectWithArgs = null) + : base(typeof(T), options, ConverterStrategy.Enumerable) { JsonConverter converter = new JsonMetadataServicesConverter(converterCreator, ConverterStrategy.Enumerable, keyType: null, elementType); @@ -67,6 +69,7 @@ public JsonTypeInfoInternal( NumberHandling = numberHandling; PropertyInfoForTypeInfo = JsonMetadataServices.CreateJsonPropertyInfoForClassInfo(typeof(T), this, converter, options); Serialize = serializeFunc; + CreateObjectWithArgs = createObjectWithArgs; SetCreateObjectFunc(createObjectFunc); } @@ -82,7 +85,9 @@ public JsonTypeInfoInternal( JsonNumberHandling numberHandling, Action? serializeFunc, Type keyType, - Type elementType) : base(typeof(T), options, ConverterStrategy.Dictionary) + Type elementType, + object? createObjectWithArgs = null) + : base(typeof(T), options, ConverterStrategy.Dictionary) { JsonConverter converter = new JsonMetadataServicesConverter(converterCreator, ConverterStrategy.Dictionary, keyType, elementType); @@ -94,6 +99,7 @@ public JsonTypeInfoInternal( NumberHandling = numberHandling; PropertyInfoForTypeInfo = JsonMetadataServices.CreateJsonPropertyInfoForClassInfo(typeof(T), this, converter, options); Serialize = serializeFunc; + CreateObjectWithArgs = createObjectWithArgs; SetCreateObjectFunc(createObjectFunc); } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.AsyncEnumerable.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.AsyncEnumerable.cs similarity index 78% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.AsyncEnumerable.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.AsyncEnumerable.cs index 05520dcf9c241..9e57524697cc7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.AsyncEnumerable.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.AsyncEnumerable.cs @@ -9,24 +9,25 @@ using System.Threading.Tasks; using Xunit; -namespace System.Text.Json.Tests.Serialization +namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests +#if !BUILDING_SOURCE_GENERATOR_TESTS + public abstract partial class CollectionTests { [Theory] [MemberData(nameof(GetAsyncEnumerableSources))] - public static async Task WriteRootLevelAsyncEnumerable(IEnumerable source, int delayInterval, int bufferSize) + public async Task WriteRootLevelAsyncEnumerable(IEnumerable source, int delayInterval, int bufferSize) { JsonSerializerOptions options = new JsonSerializerOptions { DefaultBufferSize = bufferSize }; - string expectedJson = JsonSerializer.Serialize(source); + string expectedJson = await JsonSerializerWrapperForString.SerializeWrapper(source); using var stream = new Utf8MemoryStream(); var asyncEnumerable = new MockedAsyncEnumerable(source, delayInterval); - await JsonSerializer.SerializeAsync(stream, asyncEnumerable, options); + await JsonSerializerWrapperForStream.SerializeWrapper(stream, asyncEnumerable, options); JsonTestHelper.AssertJsonEqual(expectedJson, stream.ToString()); Assert.Equal(1, asyncEnumerable.TotalCreatedEnumerators); @@ -35,18 +36,18 @@ public static async Task WriteRootLevelAsyncEnumerable(IEnumerable(IEnumerable source, int delayInterval, int bufferSize) + public async Task WriteNestedAsyncEnumerable(IEnumerable source, int delayInterval, int bufferSize) { JsonSerializerOptions options = new JsonSerializerOptions { DefaultBufferSize = bufferSize }; - string expectedJson = JsonSerializer.Serialize(new { Data = source }); + string expectedJson = await JsonSerializerWrapperForString.SerializeWrapper(new { Data = source }); using var stream = new Utf8MemoryStream(); var asyncEnumerable = new MockedAsyncEnumerable(source, delayInterval); - await JsonSerializer.SerializeAsync(stream, new { Data = asyncEnumerable }, options); + await JsonSerializerWrapperForStream.SerializeWrapper(stream, new { Data = asyncEnumerable }, options); JsonTestHelper.AssertJsonEqual(expectedJson, stream.ToString()); Assert.Equal(1, asyncEnumerable.TotalCreatedEnumerators); @@ -55,18 +56,18 @@ public static async Task WriteNestedAsyncEnumerable(IEnumerable(IEnumerable source, int delayInterval, int bufferSize) + public async Task WriteNestedAsyncEnumerable_DTO(IEnumerable source, int delayInterval, int bufferSize) { JsonSerializerOptions options = new JsonSerializerOptions { DefaultBufferSize = bufferSize }; - string expectedJson = JsonSerializer.Serialize(new { Data = source }); + string expectedJson = await JsonSerializerWrapperForString.SerializeWrapper(new { Data = source }); using var stream = new Utf8MemoryStream(); var asyncEnumerable = new MockedAsyncEnumerable(source, delayInterval); - await JsonSerializer.SerializeAsync(stream, new AsyncEnumerableDto { Data = asyncEnumerable }, options); + await JsonSerializerWrapperForStream.SerializeWrapper(stream, new AsyncEnumerableDto { Data = asyncEnumerable }, options); JsonTestHelper.AssertJsonEqual(expectedJson, stream.ToString()); Assert.Equal(1, asyncEnumerable.TotalCreatedEnumerators); @@ -74,7 +75,7 @@ public static async Task WriteNestedAsyncEnumerable_DTO(IEnumerable( source: Enumerable.Range(1, 100), @@ -97,18 +98,18 @@ public class AsyncEnumerableDto [Theory] [MemberData(nameof(GetAsyncEnumerableSources))] - public static async Task WriteSequentialNestedAsyncEnumerables(IEnumerable source, int delayInterval, int bufferSize) + public async Task WriteSequentialNestedAsyncEnumerables(IEnumerable source, int delayInterval, int bufferSize) { JsonSerializerOptions options = new JsonSerializerOptions { DefaultBufferSize = bufferSize }; - string expectedJson = JsonSerializer.Serialize(new { Data1 = source, Data2 = source }); + string expectedJson = await JsonSerializerWrapperForString.SerializeWrapper(new { Data1 = source, Data2 = source }); using var stream = new Utf8MemoryStream(); var asyncEnumerable = new MockedAsyncEnumerable(source, delayInterval); - await JsonSerializer.SerializeAsync(stream, new { Data1 = asyncEnumerable, Data2 = asyncEnumerable }, options); + await JsonSerializerWrapperForStream.SerializeWrapper(stream, new { Data1 = asyncEnumerable, Data2 = asyncEnumerable }, options); JsonTestHelper.AssertJsonEqual(expectedJson, stream.ToString()); Assert.Equal(2, asyncEnumerable.TotalCreatedEnumerators); @@ -117,7 +118,7 @@ public static async Task WriteSequentialNestedAsyncEnumerables(IEnumer [Theory] [MemberData(nameof(GetAsyncEnumerableSources))] - public static async Task WriteAsyncEnumerableOfAsyncEnumerables(IEnumerable source, int delayInterval, int bufferSize) + public async Task WriteAsyncEnumerableOfAsyncEnumerables(IEnumerable source, int delayInterval, int bufferSize) { JsonSerializerOptions options = new JsonSerializerOptions { @@ -125,7 +126,7 @@ public static async Task WriteAsyncEnumerableOfAsyncEnumerables(IEnume }; const int OuterEnumerableCount = 5; - string expectedJson = JsonSerializer.Serialize(Enumerable.Repeat(source, OuterEnumerableCount)); + string expectedJson = await JsonSerializerWrapperForString.SerializeWrapper(Enumerable.Repeat(source, OuterEnumerableCount)); var innerAsyncEnumerable = new MockedAsyncEnumerable(source, delayInterval); var outerAsyncEnumerable = @@ -133,7 +134,7 @@ public static async Task WriteAsyncEnumerableOfAsyncEnumerables(IEnume Enumerable.Repeat(innerAsyncEnumerable, OuterEnumerableCount), delayInterval); using var stream = new Utf8MemoryStream(); - await JsonSerializer.SerializeAsync(stream, outerAsyncEnumerable, options); + await JsonSerializerWrapperForStream.SerializeWrapper(stream, outerAsyncEnumerable, options); JsonTestHelper.AssertJsonEqual(expectedJson, stream.ToString()); Assert.Equal(1, outerAsyncEnumerable.TotalCreatedEnumerators); @@ -143,26 +144,26 @@ public static async Task WriteAsyncEnumerableOfAsyncEnumerables(IEnume } [Fact] - public static void WriteRootLevelAsyncEnumerableSync_ThrowsNotSupportedException() + public async Task WriteRootLevelAsyncEnumerableSync_ThrowsNotSupportedException() { IAsyncEnumerable asyncEnumerable = new MockedAsyncEnumerable(Enumerable.Range(1, 10)); - Assert.Throws(() => JsonSerializer.Serialize(asyncEnumerable)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(asyncEnumerable)); } [Fact] - public static void WriteNestedAsyncEnumerableSync_ThrowsNotSupportedException() + public async Task WriteNestedAsyncEnumerableSync_ThrowsNotSupportedException() { IAsyncEnumerable asyncEnumerable = new MockedAsyncEnumerable(Enumerable.Range(1, 10)); - Assert.Throws(() => JsonSerializer.Serialize(new { Data = asyncEnumerable })); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(new { Data = asyncEnumerable })); } [Fact] - public static async Task WriteAsyncEnumerable_ElementSerializationThrows_ShouldDisposeEnumerator() + public async Task WriteAsyncEnumerable_ElementSerializationThrows_ShouldDisposeEnumerator() { using var stream = new Utf8MemoryStream(); var asyncEnumerable = new MockedAsyncEnumerable>(Enumerable.Repeat(ThrowingEnumerable(), 2)); - await Assert.ThrowsAsync(() => JsonSerializer.SerializeAsync(stream, new { Data = asyncEnumerable })); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForStream.SerializeWrapper(stream, new { Data = asyncEnumerable })); Assert.Equal(1, asyncEnumerable.TotalCreatedEnumerators); Assert.Equal(1, asyncEnumerable.TotalDisposedEnumerators); @@ -174,7 +175,7 @@ static IEnumerable ThrowingEnumerable() } [Fact] - public static async Task ReadRootLevelAsyncEnumerable() + public async Task ReadRootLevelAsyncEnumerable() { var utf8Stream = new Utf8MemoryStream("[0,1,2,3,4]"); @@ -183,7 +184,7 @@ public static async Task ReadRootLevelAsyncEnumerable() } [Fact] - public static async Task ReadNestedAsyncEnumerable() + public async Task ReadNestedAsyncEnumerable() { var utf8Stream = new Utf8MemoryStream(@"{ ""Data"" : [0,1,2,3,4] }"); @@ -192,7 +193,7 @@ public static async Task ReadNestedAsyncEnumerable() } [Fact] - public static async Task ReadAsyncEnumerableOfAsyncEnumerables() + public async Task ReadAsyncEnumerableOfAsyncEnumerables() { var utf8Stream = new Utf8MemoryStream("[[0,1,2,3,4], []]"); @@ -205,7 +206,7 @@ public static async Task ReadAsyncEnumerableOfAsyncEnumerables() } [Fact] - public static async Task ReadRootLevelAsyncEnumerableDerivative_ThrowsNotSupportedException() + public async Task ReadRootLevelAsyncEnumerableDerivative_ThrowsNotSupportedException() { var utf8Stream = new Utf8MemoryStream("[0,1,2,3,4]"); await Assert.ThrowsAsync(async () => await JsonSerializer.DeserializeAsync>(utf8Stream)); @@ -224,16 +225,6 @@ public static IEnumerable GetAsyncEnumerableSources() static object[] WrapArgs(IEnumerable source, int delayInterval, int bufferSize) => new object[]{ source, delayInterval, bufferSize }; } - private static async Task> ToListAsync(this IAsyncEnumerable source) - { - var list = new List(); - await foreach (T item in source) - { - list.Add(item); - } - return list; - } - private class MockedAsyncEnumerable : IAsyncEnumerable, IEnumerable { private readonly IEnumerable _source; @@ -314,7 +305,8 @@ public Utf8MemoryStream(string text) : base(Encoding.UTF8.GetBytes(text)) { } - public override string ToString() => Encoding.UTF8.GetString(ToArray()); + public override string ToString () => Encoding.UTF8.GetString(ToArray()); } } +#endif } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Concurrent.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Concurrent.cs new file mode 100644 index 0000000000000..2b4f2026f077a --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Concurrent.cs @@ -0,0 +1,70 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests + { + [Fact] + public async Task Read_ConcurrentCollection() + { + ConcurrentDictionary cd = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""key"":""value""}"); + Assert.Equal(1, cd.Count); + Assert.Equal("value", cd["key"]); + + ConcurrentQueue qc = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[""1""]"); + Assert.Equal(1, qc.Count); + bool found = qc.TryPeek(out string val); + Assert.True(found); + Assert.Equal("1", val); + + ConcurrentStack qs = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[""1""]"); + Assert.Equal(1, qs.Count); + found = qs.TryPeek(out val); + Assert.True(found); + Assert.Equal("1", val); + } + + [Theory] + [InlineData(typeof(BlockingCollection), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. + [InlineData(typeof(ConcurrentBag), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. + public async Task Read_ConcurrentCollection_Throws(Type type, string json) + { + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + + [Theory] + [InlineData(typeof(GenericConcurrentQueuePrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentQueueInternalConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentStackPrivateConstructor), @"[""1""]")] + [InlineData(typeof(GenericConcurrentStackInternalConstructor), @"[""1""]")] + public async Task Read_ConcurrentCollection_NoPublicConstructor_Throws(Type type, string json) + { + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); + Assert.Contains(type.ToString(), ex.Message); + } + + [Fact] + public async Task Write_ConcurrentCollection() + { + Assert.Equal(@"[""1""]", await JsonSerializerWrapperForString.SerializeWrapper(new BlockingCollection { "1" })); + + Assert.Equal(@"[""1""]", await JsonSerializerWrapperForString.SerializeWrapper(new ConcurrentBag { "1" })); + + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new ConcurrentDictionary { ["key"] = "value" })); + + ConcurrentQueue qc = new ConcurrentQueue(); + qc.Enqueue("1"); + Assert.Equal(@"[""1""]", await JsonSerializerWrapperForString.SerializeWrapper(qc)); + + ConcurrentStack qs = new ConcurrentStack(); + qs.Push("1"); + Assert.Equal(@"[""1""]", await JsonSerializerWrapperForString.SerializeWrapper(qs)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs similarity index 73% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs index d2ea8ea547809..64b5cd5b9666b 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs @@ -2,14 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static class DictionaryKeyPolicyTests + public abstract partial class CollectionTests { [Fact] - public static void CamelCaseDeserialize() + public async Task CamelCaseDeserialize() { var options = new JsonSerializerOptions { @@ -19,7 +20,7 @@ public static void CamelCaseDeserialize() const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; // Without key policy, deserialize keys as they are. - Dictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); + Dictionary[] obj = await JsonSerializerWrapperForString.DeserializeWrapper[]>(JsonString); Assert.Equal(2, obj.Length); @@ -32,7 +33,7 @@ public static void CamelCaseDeserialize() Assert.Equal(4, obj[1]["Key2"]); // Ensure we ignore key policy and deserialize keys as they are. - obj = JsonSerializer.Deserialize[]>(JsonString, options); + obj = await JsonSerializerWrapperForString.DeserializeWrapper[]>(JsonString, options); Assert.Equal(2, obj.Length); @@ -46,7 +47,7 @@ public static void CamelCaseDeserialize() } [Fact] - public static void IgnoreKeyPolicyForExtensionData() + public async Task IgnoreKeyPolicyForExtensionData() { var options = new JsonSerializerOptions { @@ -54,12 +55,12 @@ public static void IgnoreKeyPolicyForExtensionData() }; // Ensure we ignore key policy for extension data and deserialize keys as they are. - ClassWithExtensionData myClass = JsonSerializer.Deserialize(@"{""Key1"":1, ""Key2"":2}", options); + ClassWithExtensionData myClass = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""Key1"":1, ""Key2"":2}", options); Assert.Equal(1, (myClass.ExtensionData["Key1"]).GetInt32()); Assert.Equal(2, (myClass.ExtensionData["Key2"]).GetInt32()); // Ensure we ignore key policy for extension data and serialize keys as they are. - Assert.Equal(@"{""Key1"":1,""Key2"":2}", JsonSerializer.Serialize(myClass, options)); + Assert.Equal(@"{""Key1"":1,""Key2"":2}", await JsonSerializerWrapperForString.SerializeWrapper(myClass, options)); } public class ClassWithExtensionData @@ -69,7 +70,7 @@ public class ClassWithExtensionData } [Fact] - public static void CamelCaseSerialize() + public async Task CamelCaseSerialize() { var options = new JsonSerializerOptions() { @@ -86,16 +87,16 @@ public static void CamelCaseSerialize() const string JsonCamel = @"[{""key1"":1,""key2"":2},{""key1"":3,""key2"":4}]"; // Without key policy option, serialize keys as they are. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(Json, json); // With key policy option, serialize keys with camel casing. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal(JsonCamel, json); } [Fact] - public static void CamelCaseSerialize_Null_Values() + public async Task CamelCaseSerialize_Null_Values() { var options = new JsonSerializerOptions() { @@ -111,16 +112,16 @@ public static void CamelCaseSerialize_Null_Values() const string JsonCamel = @"[{""key1"":null,""key2"":null}]"; // Without key policy option, serialize keys as they are. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(Json, json); // With key policy option, serialize keys with camel casing. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal(JsonCamel, json); } [Fact] - public static void CamelCaseSerialize_Null_Nullable_Values() + public async Task CamelCaseSerialize_Null_Nullable_Values() { var options = new JsonSerializerOptions() { @@ -136,16 +137,16 @@ public static void CamelCaseSerialize_Null_Nullable_Values() const string JsonCamel = @"[{""key1"":null,""key2"":null}]"; // Without key policy option, serialize keys as they are. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(Json, json); // With key policy option, serialize keys with camel casing. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal(JsonCamel, json); } [Fact] - public static void CustomNameDeserialize() + public async Task CustomNameDeserialize() { var options = new JsonSerializerOptions { @@ -154,16 +155,16 @@ public static void CustomNameDeserialize() // Without key policy, deserialize keys as they are. - Dictionary obj = JsonSerializer.Deserialize>(@"{""myint"":1}"); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""myint"":1}"); Assert.Equal(1, obj["myint"]); // Ensure we ignore key policy and deserialize keys as they are. - obj = JsonSerializer.Deserialize>(@"{""myint"":1}", options); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""myint"":1}", options); Assert.Equal(1, obj["myint"]); } [Fact] - public static void CustomNameSerialize() + public async Task CustomNameSerialize() { var options = new JsonSerializerOptions { @@ -176,16 +177,16 @@ public static void CustomNameSerialize() const string JsonCustomKey = @"{""MYINT1"":1,""MYINT2"":2}"; // Without key policy option, serialize keys as they are. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(Json, json); // With key policy option, serialize keys honoring the custom key policy. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal(JsonCustomKey, json); } [Fact] - public static void NullNamePolicy() + public async Task NullNamePolicy() { var options = new JsonSerializerOptions { @@ -193,17 +194,17 @@ public static void NullNamePolicy() }; // A naming policy that returns null is not allowed. - Assert.Throws(() => JsonSerializer.Serialize(new Dictionary { { "onlyKey", 1 } }, options)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(new Dictionary { { "onlyKey", 1 } }, options)); // We don't use policy on deserialize, so we populate dictionary. - Dictionary obj = JsonSerializer.Deserialize>(@"{""onlyKey"": 1}", options); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""onlyKey"": 1}", options); Assert.Equal(1, obj.Count); Assert.Equal(1, obj["onlyKey"]); } [Fact] - public static void CustomNameSerialize_NullableValue() + public async Task CustomNameSerialize_NullableValue() { var options = new JsonSerializerOptions { @@ -216,16 +217,16 @@ public static void CustomNameSerialize_NullableValue() const string JsonCustomKey = @"{""MYINT1"":1,""MYINT2"":2}"; // Without key policy option, serialize keys as they are. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(Json, json); // With key policy option, serialize keys honoring the custom key policy. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal(JsonCustomKey, json); } [Fact] - public static void NullNamePolicy_NullableValue() + public async Task NullNamePolicy_NullableValue() { var options = new JsonSerializerOptions { @@ -233,17 +234,17 @@ public static void NullNamePolicy_NullableValue() }; // A naming policy that returns null is not allowed. - Assert.Throws(() => JsonSerializer.Serialize(new Dictionary { { "onlyKey", 1 } }, options)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(new Dictionary { { "onlyKey", 1 } }, options)); // We don't use policy on deserialize, so we populate dictionary. - Dictionary obj = JsonSerializer.Deserialize>(@"{""onlyKey"": 1}", options); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""onlyKey"": 1}", options); Assert.Equal(1, obj.Count); Assert.Equal(1, obj["onlyKey"]); } [Fact] - public static void KeyConflict_Serialize_WriteAll() + public async Task KeyConflict_Serialize_WriteAll() { var options = new JsonSerializerOptions { @@ -252,14 +253,14 @@ public static void KeyConflict_Serialize_WriteAll() // The camel case policy resolves two keys to the same output key. Dictionary obj = new Dictionary { { "myInt", 1 }, { "MyInt", 2 } }; - string json = JsonSerializer.Serialize(obj, options); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); // Check that we write all. Assert.Equal(@"{""myInt"":1,""myInt"":2}", json); } [Fact] - public static void CamelCaseSerialize_ApplyDictionaryKeyPolicy() + public async Task CamelCaseSerialize_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""keyDict"":{""keyString"":""text"",""keyNumber"":1000,""keyBool"":true},""keyList"":[1,2,3]}"; var options = new JsonSerializerOptions @@ -276,7 +277,7 @@ public static void CamelCaseSerialize_ApplyDictionaryKeyPolicy() }; obj["KeyList"] = new List() { 1, 2, 3 }; - var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + var json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); @@ -285,7 +286,7 @@ public static void CamelCaseSerialize_ApplyDictionaryKeyPolicy() } [Fact] - public static void SerializationWithJsonExtensionDataAttribute_IgoneDictionaryKeyPolicy() + public async Task SerializationWithJsonExtensionDataAttribute_IgoneDictionaryKeyPolicy() { var expectedJson = @"{""KeyInt"":1000,""KeyString"":""text"",""KeyBool"":true,""KeyObject"":{},""KeyList"":[],""KeyDictionary"":{}}"; var obj = new ClassWithExtensionDataProperty(); @@ -298,7 +299,7 @@ public static void SerializationWithJsonExtensionDataAttribute_IgoneDictionaryKe { "KeyList", new List() }, { "KeyDictionary", new Dictionary() } }; - string json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); @@ -312,14 +313,14 @@ private class ClassWithExtensionDataProperty } [Fact] - public static void CamelCaseSerialize_ForTypedDictionary_ApplyDictionaryKeyPolicy() + public async Task CamelCaseSerialize_ForTypedDictionary_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""keyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}"; var obj = new Dictionary() { { "KeyDict", CreateCustomObject() } }; - var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + var json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); @@ -341,7 +342,7 @@ private static CustomClass CreateCustomObject() } [Fact] - public static void CamelCaseSerialize_ForNestedTypedDictionary_ApplyDictionaryKeyPolicy() + public async Task CamelCaseSerialize_ForNestedTypedDictionary_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""keyDict"":{""nestedKeyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}"; var options = new JsonSerializerOptions @@ -352,7 +353,7 @@ public static void CamelCaseSerialize_ForNestedTypedDictionary_ApplyDictionaryKe { "KeyDict", new Dictionary() {{ "NestedKeyDict", CreateCustomObject() }} }}; - var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + var json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); @@ -366,14 +367,14 @@ private class TestClassWithDictionary } [Fact] - public static void CamelCaseSerialize_ForClassWithDictionaryProperty_ApplyDictionaryKeyPolicy() + public async Task CamelCaseSerialize_ForClassWithDictionaryProperty_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""Data"":{""keyObj"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}"; var obj = new TestClassWithDictionary(); obj.Data = new Dictionary { {"KeyObj", CreateCustomObject() } }; - var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + var json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); @@ -381,7 +382,7 @@ public static void CamelCaseSerialize_ForClassWithDictionaryProperty_ApplyDictio } [Fact] - public static void CamelCaseSerialize_ForKeyValuePairWithDictionaryValue_ApplyDictionaryKeyPolicy() + public async Task CamelCaseSerialize_ForKeyValuePairWithDictionaryValue_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""Key"":""KeyPair"",""Value"":{""keyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}"; var options = new JsonSerializerOptions @@ -392,7 +393,7 @@ public static void CamelCaseSerialize_ForKeyValuePairWithDictionaryValue_ApplyDi ("KeyPair", new Dictionary { {"KeyDict", CreateCustomObject() } }); - var json = JsonSerializer.Serialize(obj, new JsonSerializerOptions() + var json = await JsonSerializerWrapperForString.SerializeWrapper(obj, new JsonSerializerOptions() { DictionaryKeyPolicy = JsonNamingPolicy.CamelCase }); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs similarity index 100% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.NonStringKey.cs diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs similarity index 70% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs index b878829bf07dc..fe04a9b625c5e 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Dictionary.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs @@ -7,24 +7,25 @@ using System.Collections.Immutable; using System.Collections.Specialized; using System.Text.Encodings.Web; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class DictionaryTests + public abstract partial class CollectionTests { [Fact] - public static void DictionaryOfString() + public async Task DictionaryOfString() { const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; { - IDictionary obj = JsonSerializer.Deserialize(JsonString); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -32,11 +33,11 @@ public static void DictionaryOfString() } { - Dictionary obj = JsonSerializer.Deserialize>(JsonString); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -44,11 +45,11 @@ public static void DictionaryOfString() } { - SortedDictionary obj = JsonSerializer.Deserialize>(JsonString); + SortedDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -56,11 +57,11 @@ public static void DictionaryOfString() } { - IDictionary obj = JsonSerializer.Deserialize>(JsonString); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -68,11 +69,11 @@ public static void DictionaryOfString() } { - IReadOnlyDictionary obj = JsonSerializer.Deserialize>(JsonString); + IReadOnlyDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -80,11 +81,11 @@ public static void DictionaryOfString() } { - ImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); + ImmutableDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); json = JsonSerializer.Serialize(obj); @@ -92,11 +93,11 @@ public static void DictionaryOfString() } { - IImmutableDictionary obj = JsonSerializer.Deserialize>(JsonString); + IImmutableDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); json = JsonSerializer.Serialize(obj); @@ -104,11 +105,11 @@ public static void DictionaryOfString() } { - ImmutableSortedDictionary obj = JsonSerializer.Deserialize>(JsonString); + ImmutableSortedDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json); json = JsonSerializer.Serialize(obj); @@ -116,11 +117,11 @@ public static void DictionaryOfString() } { - Hashtable obj = JsonSerializer.Deserialize(JsonString); + Hashtable obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); json = JsonSerializer.Serialize(obj); @@ -128,11 +129,11 @@ public static void DictionaryOfString() } { - SortedList obj = JsonSerializer.Deserialize(JsonString); + SortedList obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -141,17 +142,17 @@ public static void DictionaryOfString() } [Fact] - public static void ImplementsDictionary_DictionaryOfString() + public async Task ImplementsDictionary_DictionaryOfString() { const string JsonString = @"{""Hello"":""World"",""Hello2"":""World2""}"; const string ReorderedJsonString = @"{""Hello2"":""World2"",""Hello"":""World""}"; { - WrapperForIDictionary obj = JsonSerializer.Deserialize(JsonString); + WrapperForIDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -159,11 +160,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - StringToStringDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); + StringToStringDictionaryWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -171,11 +172,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - StringToStringSortedDictionaryWrapper obj = JsonSerializer.Deserialize(JsonString); + StringToStringSortedDictionaryWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -183,11 +184,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - GenericIDictionaryWrapper obj = JsonSerializer.Deserialize>(JsonString); + GenericIDictionaryWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -195,14 +196,14 @@ public static void ImplementsDictionary_DictionaryOfString() } { - Assert.Throws(() => JsonSerializer.Deserialize>(JsonString)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString)); GenericIReadOnlyDictionaryWrapper obj = new GenericIReadOnlyDictionaryWrapper(new Dictionary() { { "Hello", "World" }, { "Hello2", "World2" }, }); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -210,7 +211,7 @@ public static void ImplementsDictionary_DictionaryOfString() } { - Assert.Throws(() => JsonSerializer.Deserialize(JsonString)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(JsonString)); StringToStringIImmutableDictionaryWrapper obj = new StringToStringIImmutableDictionaryWrapper(new Dictionary() { @@ -218,7 +219,7 @@ public static void ImplementsDictionary_DictionaryOfString() { "Hello2", "World2" }, }); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); json = JsonSerializer.Serialize(obj); @@ -226,11 +227,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - HashtableWrapper obj = JsonSerializer.Deserialize(JsonString); + HashtableWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); json = JsonSerializer.Serialize(obj); @@ -238,11 +239,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - SortedListWrapper obj = JsonSerializer.Deserialize(JsonString); + SortedListWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal("World", ((JsonElement)obj["Hello"]).GetString()); Assert.Equal("World2", ((JsonElement)obj["Hello2"]).GetString()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -250,11 +251,11 @@ public static void ImplementsDictionary_DictionaryOfString() } { - GenericStructIDictionaryWrapper obj = JsonSerializer.Deserialize>(JsonString); + GenericStructIDictionaryWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal("World", obj["Hello"]); Assert.Equal("World2", obj["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -262,12 +263,12 @@ public static void ImplementsDictionary_DictionaryOfString() } { - GenericStructIDictionaryWrapper? obj = JsonSerializer.Deserialize?>(JsonString); + GenericStructIDictionaryWrapper? obj = await JsonSerializerWrapperForString.DeserializeWrapper?>(JsonString); Assert.True(obj.HasValue); Assert.Equal("World", obj.Value["Hello"]); Assert.Equal("World2", obj.Value["Hello2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -275,54 +276,54 @@ public static void ImplementsDictionary_DictionaryOfString() } { - GenericStructIDictionaryWrapper? obj = JsonSerializer.Deserialize?>("null"); + GenericStructIDictionaryWrapper? obj = await JsonSerializerWrapperForString.DeserializeWrapper?>("null"); Assert.False(obj.HasValue); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal("null", json); } { GenericStructIDictionaryWrapper obj = default; - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal("{}", json); } { StructWrapperForIDictionary obj = default; - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal("{}", json); } } [Fact] - public static void DictionaryOfObject() + public async Task DictionaryOfObject() { { - Dictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key1"":1}"); Assert.Equal(1, obj.Count); JsonElement element = (JsonElement)obj["Key1"]; Assert.Equal(JsonValueKind.Number, element.ValueKind); Assert.Equal(1, element.GetInt32()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(@"{""Key1"":1}", json); } { - IDictionary obj = JsonSerializer.Deserialize>(@"{""Key1"":1}"); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key1"":1}"); Assert.Equal(1, obj.Count); JsonElement element = (JsonElement)obj["Key1"]; Assert.Equal(JsonValueKind.Number, element.ValueKind); Assert.Equal(1, element.GetInt32()); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(@"{""Key1"":1}", json); } } [Fact] - public static void ImplementsIDictionaryOfObject() + public async Task ImplementsIDictionaryOfObject() { var input = new GenericIDictionaryWrapper(new Dictionary { @@ -330,17 +331,17 @@ public static void ImplementsIDictionaryOfObject() { "Age", 32 } }); - string json = JsonSerializer.Serialize(input, typeof(IDictionary)); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input, typeof(IDictionary)); Assert.Equal(@"{""Name"":""David"",""Age"":32}", json); - IDictionary obj = JsonSerializer.Deserialize>(json); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); Assert.Equal("David", ((JsonElement)obj["Name"]).GetString()); Assert.Equal(32, ((JsonElement)obj["Age"]).GetInt32()); } [Fact] - public static void ImplementsIDictionaryOfString() + public async Task ImplementsIDictionaryOfString() { var input = new GenericIDictionaryWrapper(new Dictionary { @@ -348,25 +349,25 @@ public static void ImplementsIDictionaryOfString() { "Job", "Software Architect" } }); - string json = JsonSerializer.Serialize(input, typeof(IDictionary)); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input, typeof(IDictionary)); Assert.Equal(@"{""Name"":""David"",""Job"":""Software Architect""}", json); - IDictionary obj = JsonSerializer.Deserialize>(json); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); Assert.Equal("David", obj["Name"]); Assert.Equal("Software Architect", obj["Job"]); } [Fact] - public static void PocoWithDictionaryObject() + public async Task PocoWithDictionaryObject() { - PocoDictionary dict = JsonSerializer.Deserialize("{\n\t\"key\" : {\"a\" : \"b\", \"c\" : \"d\"}}"); + PocoDictionary dict = await JsonSerializerWrapperForString.DeserializeWrapper("{\n\t\"key\" : {\"a\" : \"b\", \"c\" : \"d\"}}"); Assert.Equal("b", dict.key["a"]); Assert.Equal("d", dict.key["c"]); } [Fact] - public static void DictionaryOfObject_NonPrimitiveTypes() + public async Task DictionaryOfObject_NonPrimitiveTypes() { // https://github.com/dotnet/runtime/issues/29504 Dictionary dictionary = new Dictionary @@ -374,22 +375,22 @@ public static void DictionaryOfObject_NonPrimitiveTypes() ["key"] = new Poco { Id = 10 }, }; - string json = JsonSerializer.Serialize(dictionary); + string json = await JsonSerializerWrapperForString.SerializeWrapper(dictionary); Assert.Equal(@"{""key"":{""Id"":10}}", json); - dictionary = JsonSerializer.Deserialize>(json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(1, dictionary.Count); JsonElement element = (JsonElement)dictionary["key"]; Assert.Equal(@"{""Id"":10}", element.ToString()); } [Fact] - public static void DictionaryOfList() + public async Task DictionaryOfList() { const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; { - IDictionary obj = JsonSerializer.Deserialize(JsonString); + IDictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper(JsonString); Assert.Equal(2, obj.Count); @@ -407,12 +408,12 @@ public static void DictionaryOfList() Assert.Equal(expectedNumber++, value.GetInt32()); } - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } { - IDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + IDictionary> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -422,12 +423,12 @@ public static void DictionaryOfList() Assert.Equal(3, obj["Key2"][0]); Assert.Equal(4, obj["Key2"][1]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } { - ImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + ImmutableDictionary> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -437,13 +438,13 @@ public static void DictionaryOfList() Assert.Equal(3, obj["Key2"][0]); Assert.Equal(4, obj["Key2"][1]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; Assert.True(JsonString == json || ReorderedJsonString == json); } { - IImmutableDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + IImmutableDictionary> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -454,17 +455,17 @@ public static void DictionaryOfList() Assert.Equal(4, obj["Key2"][1]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); const string ReorderedJsonString = @"{""Key2"":[3,4],""Key1"":[1,2]}"; Assert.True(JsonString == json || ReorderedJsonString == json); } } [Fact] - public static void DictionaryOfArray() + public async Task DictionaryOfArray() { const string JsonString = @"{""Key1"":[1,2],""Key2"":[3,4]}"; - Dictionary obj = JsonSerializer.Deserialize>(JsonString); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Length); @@ -474,17 +475,17 @@ public static void DictionaryOfArray() Assert.Equal(3, obj["Key2"][0]); Assert.Equal(4, obj["Key2"][1]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } [Fact] - public static void ListOfDictionary() + public async Task ListOfDictionary() { const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; { - List> obj = JsonSerializer.Deserialize>>(JsonString); + List> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj[0].Count); @@ -494,14 +495,14 @@ public static void ListOfDictionary() Assert.Equal(3, obj[1]["Key1"]); Assert.Equal(4, obj[1]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); Assert.Equal(JsonString, json); } { - List> obj = JsonSerializer.Deserialize>>(JsonString); + List> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj[0].Count); @@ -511,7 +512,7 @@ public static void ListOfDictionary() Assert.Equal(3, obj[1]["Key1"]); Assert.Equal(4, obj[1]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -520,12 +521,12 @@ public static void ListOfDictionary() } [Fact] - public static void ArrayOfDictionary() + public async Task ArrayOfDictionary() { const string JsonString = @"[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}]"; { - Dictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); + Dictionary[] obj = await JsonSerializerWrapperForString.DeserializeWrapper[]>(JsonString); Assert.Equal(2, obj.Length); Assert.Equal(2, obj[0].Count); @@ -535,7 +536,7 @@ public static void ArrayOfDictionary() Assert.Equal(3, obj[1]["Key1"]); Assert.Equal(4, obj[1]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -543,7 +544,7 @@ public static void ArrayOfDictionary() } { - ImmutableSortedDictionary[] obj = JsonSerializer.Deserialize[]>(JsonString); + ImmutableSortedDictionary[] obj = await JsonSerializerWrapperForString.DeserializeWrapper[]>(JsonString); Assert.Equal(2, obj.Length); Assert.Equal(2, obj[0].Count); @@ -553,7 +554,7 @@ public static void ArrayOfDictionary() Assert.Equal(3, obj[1]["Key1"]); Assert.Equal(4, obj[1]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -562,12 +563,12 @@ public static void ArrayOfDictionary() } [Fact] - public static void DictionaryOfDictionary() + public async Task DictionaryOfDictionary() { const string JsonString = @"{""Key1"":{""Key1a"":1,""Key1b"":2},""Key2"":{""Key2a"":3,""Key2b"":4}}"; { - Dictionary> obj = JsonSerializer.Deserialize>>(JsonString); + Dictionary> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -577,7 +578,7 @@ public static void DictionaryOfDictionary() Assert.Equal(3, obj["Key2"]["Key2a"]); Assert.Equal(4, obj["Key2"]["Key2b"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -585,7 +586,7 @@ public static void DictionaryOfDictionary() } { - ImmutableSortedDictionary> obj = JsonSerializer.Deserialize>>(JsonString); + ImmutableSortedDictionary> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -595,7 +596,7 @@ public static void DictionaryOfDictionary() Assert.Equal(3, obj["Key2"]["Key2a"]); Assert.Equal(4, obj["Key2"]["Key2b"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); json = JsonSerializer.Serialize(obj); @@ -604,10 +605,10 @@ public static void DictionaryOfDictionary() } [Fact] - public static void DictionaryOfDictionaryOfDictionary() + public async Task DictionaryOfDictionaryOfDictionary() { const string JsonString = @"{""Key1"":{""Key1"":{""Key1"":1,""Key2"":2},""Key2"":{""Key1"":3,""Key2"":4}},""Key2"":{""Key1"":{""Key1"":5,""Key2"":6},""Key2"":{""Key1"":7,""Key2"":8}}}"; - Dictionary>> obj = JsonSerializer.Deserialize>>>(JsonString); + Dictionary>> obj = await JsonSerializerWrapperForString.DeserializeWrapper>>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Count); @@ -628,7 +629,7 @@ public static void DictionaryOfDictionaryOfDictionary() Assert.Equal(7, obj["Key2"]["Key2"]["Key1"]); Assert.Equal(8, obj["Key2"]["Key2"]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); // Verify that typeof(object) doesn't interfere. @@ -637,10 +638,10 @@ public static void DictionaryOfDictionaryOfDictionary() } [Fact] - public static void DictionaryOfArrayOfDictionary() + public async Task DictionaryOfArrayOfDictionary() { const string JsonString = @"{""Key1"":[{""Key1"":1,""Key2"":2},{""Key1"":3,""Key2"":4}],""Key2"":[{""Key1"":5,""Key2"":6},{""Key1"":7,""Key2"":8}]}"; - Dictionary[]> obj = JsonSerializer.Deserialize[]>>(JsonString); + Dictionary[]> obj = await JsonSerializerWrapperForString.DeserializeWrapper[]>>(JsonString); Assert.Equal(2, obj.Count); Assert.Equal(2, obj["Key1"].Length); @@ -661,7 +662,7 @@ public static void DictionaryOfArrayOfDictionary() Assert.Equal(7, obj["Key2"][1]["Key1"]); Assert.Equal(8, obj["Key2"][1]["Key2"]); - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); // Verify that typeof(object) doesn't interfere. @@ -787,32 +788,32 @@ public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerO } [Fact] - public static void NestedDictionariesRoundtrip() + public async Task NestedDictionariesRoundtrip() { JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new MyFactory()); foreach ((Type dictionaryType, string testJson) in NestedDictionaryTypeData()) { - object dict = JsonSerializer.Deserialize(testJson, dictionaryType, options); - Assert.Equal(testJson, JsonSerializer.Serialize(dict, options)); + object dict = await JsonSerializerWrapperForString.DeserializeWrapper(testJson, dictionaryType, options); + Assert.Equal(testJson, await JsonSerializerWrapperForString.SerializeWrapper(dict, options)); } } [Fact] - public static void DictionaryOfClasses() + public async Task DictionaryOfClasses() { { IDictionary obj; { string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.Count); if (obj["Key1"] is JsonElement element) { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + SimpleTestClass result = await JsonSerializerWrapperForString.DeserializeWrapper(element.GetRawText()); result.Verify(); } else @@ -825,13 +826,13 @@ public static void DictionaryOfClasses() { // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize(json); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); + obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.Count); if (obj["Key1"] is JsonElement element) { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + SimpleTestClass result = await JsonSerializerWrapperForString.DeserializeWrapper(element.GetRawText()); result.Verify(); } else @@ -843,12 +844,12 @@ public static void DictionaryOfClasses() { string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.Count); if (obj["Key1"] is JsonElement element) { - SimpleTestClass result = JsonSerializer.Deserialize(element.GetRawText()); + SimpleTestClass result = await JsonSerializerWrapperForString.DeserializeWrapper(element.GetRawText()); result.Verify(); } else @@ -864,7 +865,7 @@ public static void DictionaryOfClasses() { string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize>(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -873,8 +874,8 @@ public static void DictionaryOfClasses() { // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -882,7 +883,7 @@ public static void DictionaryOfClasses() { string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -894,7 +895,7 @@ public static void DictionaryOfClasses() { string json = @"{""Key1"":" + SimpleTestClass.s_json + @",""Key2"":" + SimpleTestClass.s_json + "}"; - obj = JsonSerializer.Deserialize>(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -903,8 +904,8 @@ public static void DictionaryOfClasses() { // We can't compare against the json string above because property ordering is not deterministic (based on reflection order) // so just round-trip the json and compare. - string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -912,7 +913,7 @@ public static void DictionaryOfClasses() { string json = JsonSerializer.Serialize(obj); - obj = JsonSerializer.Deserialize>(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); obj["Key2"].Verify(); @@ -921,7 +922,7 @@ public static void DictionaryOfClasses() } [Fact] - public static void UnicodePropertyNames() + public async Task UnicodePropertyNames() { var options = new JsonSerializerOptions(); options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; @@ -929,20 +930,20 @@ public static void UnicodePropertyNames() { Dictionary obj; - obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}"); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""A\u0467"":1}"); Assert.Equal(1, obj["A\u0467"]); // Specifying encoder on options does not impact deserialize. - obj = JsonSerializer.Deserialize>(@"{""A\u0467"":1}", options); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""A\u0467"":1}", options); Assert.Equal(1, obj["A\u0467"]); string json; // Verify the name is escaped after serialize. - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(@"{""A\u0467"":1}", json); // Verify with encoder. - json = JsonSerializer.Serialize(obj, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj, options); Assert.Equal("{\"A\u0467\":1}", json); } @@ -952,11 +953,11 @@ public static void UnicodePropertyNames() string longPropertyName = new string('\u0467', charsInProperty); - Dictionary obj = JsonSerializer.Deserialize>($"{{\"{longPropertyName}\":1}}"); + Dictionary obj = await JsonSerializerWrapperForString.DeserializeWrapper>($"{{\"{longPropertyName}\":1}}"); Assert.Equal(1, obj[longPropertyName]); // Verify the name is escaped after serialize. - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); // Duplicate the unicode character 'charsInProperty' times. string longPropertyNameEscaped = new StringBuilder().Insert(0, @"\u0467", charsInProperty).ToString(); @@ -965,106 +966,106 @@ public static void UnicodePropertyNames() Assert.Equal(expectedJson, json); // Verify the name is unescaped after deserialize. - obj = JsonSerializer.Deserialize>(json); + obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(1, obj[longPropertyName]); } } [Fact] - public static void CustomEscapingOnPropertyNameAndValue() + public async Task CustomEscapingOnPropertyNameAndValue() { var dict = new Dictionary(); dict.Add("A\u046701", "Value\u0467"); // Baseline with no escaping. - var json = JsonSerializer.Serialize(dict); + var json = await JsonSerializerWrapperForString.SerializeWrapper(dict); Assert.Equal("{\"A\\u046701\":\"Value\\u0467\"}", json); // Enable escaping. var options = new JsonSerializerOptions(); options.Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping; - json = JsonSerializer.Serialize(dict, options); + json = await JsonSerializerWrapperForString.SerializeWrapper(dict, options); Assert.Equal("{\"A\u046701\":\"Value\u0467\"}", json); } [Fact] - public static void ObjectToStringFail() + public async Task ObjectToStringFail() { // Baseline string json = @"{""MyDictionary"":{""Key"":""Value""}}"; JsonSerializer.Deserialize>(json); - Assert.Throws(() => JsonSerializer.Deserialize>(json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json)); } [Fact] - public static void ObjectToJsonElement() + public async Task ObjectToJsonElement() { string json = @"{""MyDictionary"":{""Key"":""Value""}}"; - Dictionary result = JsonSerializer.Deserialize>(json); + Dictionary result = await JsonSerializerWrapperForString.DeserializeWrapper>(json); JsonElement element = result["MyDictionary"]; Assert.Equal(JsonValueKind.Object, element.ValueKind); Assert.Equal("Value", element.GetProperty("Key").GetString()); } [Fact] - public static void Hashtable() + public async Task Hashtable() { const string Json = @"{""Key"":""Value""}"; IDictionary ht = new Hashtable(); ht.Add("Key", "Value"); - string json = JsonSerializer.Serialize(ht); + string json = await JsonSerializerWrapperForString.SerializeWrapper(ht); Assert.Equal(Json, json); - ht = JsonSerializer.Deserialize(json); + ht = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.IsType(ht["Key"]); Assert.Equal("Value", ((JsonElement)ht["Key"]).GetString()); // Verify round-tripped JSON. - json = JsonSerializer.Serialize(ht); + json = await JsonSerializerWrapperForString.SerializeWrapper(ht); Assert.Equal(Json, json); } [Fact] - public static void DeserializeDictionaryWithDuplicateKeys() + public async Task DeserializeDictionaryWithDuplicateKeys() { // Non-generic IDictionary case. - IDictionary iDictionary = JsonSerializer.Deserialize(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + IDictionary iDictionary = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); Assert.Equal("NewValue", iDictionary["Hello"].ToString()); // Generic IDictionary case. - IDictionary iNonGenericDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + IDictionary iNonGenericDictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); Assert.Equal("NewValue", iNonGenericDictionary["Hello"]); - IDictionary iNonGenericObjectDictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + IDictionary iNonGenericObjectDictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); Assert.Equal("NewValue", iNonGenericObjectDictionary["Hello"].ToString()); // Strongly-typed IDictionary<,> case. - Dictionary dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); + Dictionary dictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Hello"":""World"", ""Hello"":""NewValue""}"); Assert.Equal("NewValue", dictionary["Hello"]); - dictionary = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""myKey"" : ""myValue"", ""Hello"":""NewValue""}"); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Hello"":""World"", ""myKey"" : ""myValue"", ""Hello"":""NewValue""}"); Assert.Equal("NewValue", dictionary["Hello"]); // Weakly-typed IDictionary case. - Dictionary dictionaryObject = JsonSerializer.Deserialize>(@"{""Hello"":""World"", ""Hello"": null}"); + Dictionary dictionaryObject = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Hello"":""World"", ""Hello"": null}"); Assert.Null(dictionaryObject["Hello"]); } [Fact] - public static void DeserializeDictionaryWithDuplicateProperties() + public async Task DeserializeDictionaryWithDuplicateProperties() { - PocoDuplicate foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""BoolProperty"": true}"); + PocoDuplicate foo = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""BoolProperty"": false, ""BoolProperty"": true}"); Assert.True(foo.BoolProperty); - foo = JsonSerializer.Deserialize(@"{""BoolProperty"": false, ""IntProperty"" : 1, ""BoolProperty"": true , ""IntProperty"" : 2}"); + foo = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""BoolProperty"": false, ""IntProperty"" : 1, ""BoolProperty"": true , ""IntProperty"" : 2}"); Assert.True(foo.BoolProperty); Assert.Equal(2, foo.IntProperty); - foo = JsonSerializer.Deserialize(@"{""DictProperty"" : {""a"" : ""b"", ""c"" : ""d""},""DictProperty"" : {""b"" : ""b"", ""c"" : ""e""}}"); + foo = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""DictProperty"" : {""a"" : ""b"", ""c"" : ""d""},""DictProperty"" : {""b"" : ""b"", ""c"" : ""e""}}"); Assert.Equal(2, foo.DictProperty.Count); // We don't concat. Assert.Equal("e", foo.DictProperty["c"]); } @@ -1088,20 +1089,20 @@ public ClassWithPopulatedDictionaryAndNoSetter() } [Fact] - public static void ClassWithNoSetterAndDictionary() + public async Task ClassWithNoSetterAndDictionary() { // We don't attempt to deserialize into dictionaries without a setter. string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); + ClassWithPopulatedDictionaryAndNoSetter obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(1, obj.MyDictionary.Count); } [Fact] - public static void ClassWithNoSetterAndImmutableDictionary() + public async Task ClassWithNoSetterAndImmutableDictionary() { // We don't attempt to deserialize into dictionaries without a setter. string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndNoSetter obj = JsonSerializer.Deserialize(json); + ClassWithPopulatedDictionaryAndNoSetter obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(1, obj.MyImmutableDictionary.Count); } @@ -1184,10 +1185,10 @@ public class ClassWithIgnoredImmutableDictionary [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":[1,2,3]}, ""Parsed3"":{""Key"":2}}")] [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":{}}, ""Parsed3"":{""Key"":2}}")] [InlineData(@"{""Parsed1"":{""Key"":1},""Skipped2"":{""Key"":null}, ""Parsed3"":{""Key"":2}}")] - public static void IgnoreDictionaryProperty(string json) + public async Task IgnoreDictionaryProperty(string json) { // Verify deserialization - ClassWithIgnoredDictionary2 obj = JsonSerializer.Deserialize(json); + ClassWithIgnoredDictionary2 obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(1, obj.Parsed1.Count); Assert.Equal(1, obj.Parsed1["Key"]); Assert.Null(obj.Skipped2); @@ -1195,8 +1196,8 @@ public static void IgnoreDictionaryProperty(string json) Assert.Equal(2, obj.Parsed3["Key"]); // Round-trip and verify. - string jsonRoundTripped = JsonSerializer.Serialize(obj); - ClassWithIgnoredDictionary2 objRoundTripped = JsonSerializer.Deserialize(jsonRoundTripped); + string jsonRoundTripped = await JsonSerializerWrapperForString.SerializeWrapper(obj); + ClassWithIgnoredDictionary2 objRoundTripped = await JsonSerializerWrapperForString.DeserializeWrapper(jsonRoundTripped); Assert.Equal(1, objRoundTripped.Parsed1.Count); Assert.Equal(1, objRoundTripped.Parsed1["Key"]); Assert.Null(objRoundTripped.Skipped2); @@ -1205,25 +1206,25 @@ public static void IgnoreDictionaryProperty(string json) } [Fact] - public static void IgnoreDictionaryPropertyWithDifferentOrdering() + public async Task IgnoreDictionaryPropertyWithDifferentOrdering() { // Verify all combinations of 3 properties with at least one ignore. - VerifyIgnore(false, false, true); - VerifyIgnore(false, true, false); - VerifyIgnore(false, true, true); - VerifyIgnore(true, false, false); - VerifyIgnore(true, false, true); - VerifyIgnore(true, true, false); - VerifyIgnore(true, true, true); + await VerifyIgnore(false, false, true); + await VerifyIgnore(false, true, false); + await VerifyIgnore(false, true, true); + await VerifyIgnore(true, false, false); + await VerifyIgnore(true, false, true); + await VerifyIgnore(true, true, false); + await VerifyIgnore(true, true, true); // Verify single case for IDictionary, [Ignore] and ImmutableDictionary. // Also specify addMissing to add additional skipped JSON that does not have a corresponding property. - VerifyIgnore(false, true, false, addMissing: true); - VerifyIgnore(false, true, false, addMissing: true); - VerifyIgnore(false, true, false, addMissing: true); + await VerifyIgnore(false, true, false, addMissing: true); + await VerifyIgnore(false, true, false, addMissing: true); + await VerifyIgnore(false, true, false, addMissing: true); } - private static void VerifyIgnore(bool skip1, bool skip2, bool skip3, bool addMissing = false) + private async Task VerifyIgnore(bool skip1, bool skip2, bool skip3, bool addMissing = false) { static IDictionary GetProperty(T objectToVerify, string propertyName) { @@ -1307,13 +1308,13 @@ void Verify(T objectToVerify) // Deserialize and verify. string jsonString = json.ToString(); - T obj = JsonSerializer.Deserialize(jsonString); + T obj = await JsonSerializerWrapperForString.DeserializeWrapper(jsonString); Verify(obj); // Round-trip and verify. // Any skipped properties due to lack of a setter will now be "null" when serialized instead of "{}". - string jsonStringRoundTripped = JsonSerializer.Serialize(obj); - T objRoundTripped = JsonSerializer.Deserialize(jsonStringRoundTripped); + string jsonStringRoundTripped = await JsonSerializerWrapperForString.SerializeWrapper(obj); + T objRoundTripped = await JsonSerializerWrapperForString.DeserializeWrapper(jsonStringRoundTripped); Verify(objRoundTripped); } @@ -1329,45 +1330,45 @@ public ClassWithPopulatedDictionaryAndSetter() } [Fact] - public static void ClassWithPopulatedDictionary() + public async Task ClassWithPopulatedDictionary() { // We replace the contents. string json = @"{""MyDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); + ClassWithPopulatedDictionaryAndSetter obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.MyDictionary.Count); } [Fact] - public static void ClassWithPopulatedImmutableDictionary() + public async Task ClassWithPopulatedImmutableDictionary() { // We replace the contents. string json = @"{""MyImmutableDictionary"":{""Key1"":""Value1"", ""Key2"":""Value2""}}"; - ClassWithPopulatedDictionaryAndSetter obj = JsonSerializer.Deserialize(json); + ClassWithPopulatedDictionaryAndSetter obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.MyImmutableDictionary.Count); } [Fact] - public static void DictionaryNotSupported() + public async Task DictionaryNotSupported() { string json = @"{""MyDictionary"":{""Key"":""Value""}}"; - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); // The exception contains the type. Assert.Contains(typeof(Dictionary).ToString(), ex.Message); } [Fact] - public static void DictionaryNotSupportedButIgnored() + public async Task DictionaryNotSupportedButIgnored() { string json = @"{""MyDictionary"":{""Key"":1}}"; - ClassWithNotSupportedDictionaryButIgnored obj = JsonSerializer.Deserialize(json); + ClassWithNotSupportedDictionaryButIgnored obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Null(obj.MyDictionary); } // https://github.com/dotnet/runtime/issues/29933 [Fact] - public static void Serialize_IDictionaryOfPoco() + public async Task Serialize_IDictionaryOfPoco() { // Arrange var value = new AllSingleUpperPropertiesParent() @@ -1386,7 +1387,7 @@ public static void Serialize_IDictionaryOfPoco() } }; - var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + var actual = await JsonSerializerWrapperForString.SerializeWrapper(value, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); // Assert Assert.NotNull(actual); @@ -1395,12 +1396,12 @@ public static void Serialize_IDictionaryOfPoco() // https://github.com/dotnet/runtime/issues/29933 [Fact] - public static void Deserialize_IDictionaryOfPoco() + public async Task Deserialize_IDictionaryOfPoco() { // Arrange string json = "{\"child\":{\"1\":{\"a\":\"1\",\"b\":\"\",\"c\":[],\"d\":[],\"e\":null,\"f\":[],\"g\":null,\"h\":null,\"i\":null,\"j\":null,\"k\":[]}}}"; - var actual = JsonSerializer.Deserialize(json, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); + var actual = await JsonSerializerWrapperForString.DeserializeWrapper(json, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase }); // Assert Assert.NotNull(actual); @@ -1412,7 +1413,7 @@ public static void Deserialize_IDictionaryOfPoco() // https://github.com/dotnet/runtime/issues/29893 [Fact] - public static void ShouldHandleNullInDictionaries_Serialize() + public async Task ShouldHandleNullInDictionaries_Serialize() { var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() { @@ -1420,16 +1421,16 @@ public static void ShouldHandleNullInDictionaries_Serialize() Child = new ClassWithDictionaryOfString() }; - var actual = JsonSerializer.Serialize(value); + var actual = await JsonSerializerWrapperForString.SerializeWrapper(value); Assert.Equal("{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}", actual); } // https://github.com/dotnet/runtime/issues/29893 [Fact] - public static void ShouldHandleNullInDictionaries_Deserialize() + public async Task ShouldHandleNullInDictionaries_Deserialize() { var json = "{\"Test\":\"value1\",\"Dict\":null,\"Child\":{\"Test\":null,\"Dict\":null}}"; - ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); + ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", actual.Test); Assert.Null(actual.Dict); @@ -1440,7 +1441,7 @@ public static void ShouldHandleNullInDictionaries_Deserialize() // https://github.com/dotnet/runtime/issues/29893 [Fact] - public static void ShouldHandleNullInDictionaries_Serialize_IgnoreNullValues() + public async Task ShouldHandleNullInDictionaries_Serialize_IgnoreNullValues() { var value = new ClassWithDictionaryOfString_ChildWithDictionaryOfString() { @@ -1448,16 +1449,16 @@ public static void ShouldHandleNullInDictionaries_Serialize_IgnoreNullValues() Child = new ClassWithDictionaryOfString() }; - var actual = JsonSerializer.Serialize(value, new JsonSerializerOptions { IgnoreNullValues = true }); + var actual = await JsonSerializerWrapperForString.SerializeWrapper(value, new JsonSerializerOptions { IgnoreNullValues = true }); Assert.Equal("{\"Test\":\"value1\",\"Child\":{}}", actual); } // https://github.com/dotnet/runtime/issues/29893 [Fact] - public static void ShouldHandleNullInDictionaries_Deserialize_IgnoreNullValues() + public async Task ShouldHandleNullInDictionaries_Deserialize_IgnoreNullValues() { var json = "{\"Test\":\"value1\",\"Child\":{}}"; - ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = JsonSerializer.Deserialize(json); + ClassWithDictionaryOfString_ChildWithDictionaryOfString actual = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", actual.Test); Assert.Null(actual.Dict); @@ -1468,14 +1469,14 @@ public static void ShouldHandleNullInDictionaries_Deserialize_IgnoreNullValues() // https://github.com/dotnet/runtime/issues/29888 [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Serialize() + public async Task DictionaryWithNullShouldPreserveOrder_Serialize() { var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() { Test = "value1" }; - var actual = JsonSerializer.Serialize(dictionaryFirst); + var actual = await JsonSerializerWrapperForString.SerializeWrapper(dictionaryFirst); Assert.Equal("{\"Dict\":null,\"Test\":\"value1\"}", actual); var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() @@ -1483,22 +1484,22 @@ public static void DictionaryWithNullShouldPreserveOrder_Serialize() Test = "value1" }; - actual = JsonSerializer.Serialize(dictionaryLast); + actual = await JsonSerializerWrapperForString.SerializeWrapper(dictionaryLast); Assert.Equal("{\"Test\":\"value1\",\"Dict\":null}", actual); } // https://github.com/dotnet/runtime/issues/29888 [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Deserialize() + public async Task DictionaryWithNullShouldPreserveOrder_Deserialize() { var json = "{\"Dict\":null,\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); + ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", dictionaryFirst.Test); Assert.Null(dictionaryFirst.Dict); json = "{\"Test\":\"value1\",\"Dict\":null}"; - ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); + ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", dictionaryLast.Test); Assert.Null(dictionaryLast.Dict); @@ -1506,14 +1507,14 @@ public static void DictionaryWithNullShouldPreserveOrder_Deserialize() // https://github.com/dotnet/runtime/issues/29888 [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Serialize_IgnoreNullValues() + public async Task DictionaryWithNullShouldPreserveOrder_Serialize_IgnoreNullValues() { var dictionaryFirst = new ClassWithDictionaryAndProperty_DictionaryFirst() { Test = "value1" }; - var actual = JsonSerializer.Serialize(dictionaryFirst, new JsonSerializerOptions { IgnoreNullValues = true }); + var actual = await JsonSerializerWrapperForString.SerializeWrapper(dictionaryFirst, new JsonSerializerOptions { IgnoreNullValues = true }); Assert.Equal("{\"Test\":\"value1\"}", actual); var dictionaryLast = new ClassWithDictionaryAndProperty_DictionaryLast() @@ -1521,29 +1522,29 @@ public static void DictionaryWithNullShouldPreserveOrder_Serialize_IgnoreNullVal Test = "value1" }; - actual = JsonSerializer.Serialize(dictionaryLast, new JsonSerializerOptions { IgnoreNullValues = true }); + actual = await JsonSerializerWrapperForString.SerializeWrapper(dictionaryLast, new JsonSerializerOptions { IgnoreNullValues = true }); Assert.Equal("{\"Test\":\"value1\"}", actual); } // https://github.com/dotnet/runtime/issues/29888 [Fact] - public static void DictionaryWithNullShouldPreserveOrder_Deserialize_IgnoreNullValues() + public async Task DictionaryWithNullShouldPreserveOrder_Deserialize_IgnoreNullValues() { var json = "{\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = JsonSerializer.Deserialize(json); + ClassWithDictionaryAndProperty_DictionaryFirst dictionaryFirst = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", dictionaryFirst.Test); Assert.Null(dictionaryFirst.Dict); json = "{\"Test\":\"value1\"}"; - ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = JsonSerializer.Deserialize(json); + ClassWithDictionaryAndProperty_DictionaryLast dictionaryLast = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("value1", dictionaryLast.Test); Assert.Null(dictionaryLast.Dict); } [Fact] - public static void NullDictionaryValuesShouldDeserializeAsNull() + public async Task NullDictionaryValuesShouldDeserializeAsNull() { const string json = @"{" + @@ -1564,7 +1565,7 @@ public static void NullDictionaryValuesShouldDeserializeAsNull() @"}" + @"}"; - SimpleClassWithDictionaries obj = JsonSerializer.Deserialize(json); + SimpleClassWithDictionaries obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Null(obj.StringVals["key"]); Assert.Null(obj.ObjectVals["key"]); Assert.Null(obj.StringDictVals["key"]); @@ -1726,32 +1727,32 @@ public bool TryGetValue(string key, out TValue value) } [Fact] - public static void DictionaryOfTOnlyWithStringTValueAsInt() + public async Task DictionaryOfTOnlyWithStringTValueAsInt() { const string Json = @"{""One"":1,""Two"":2}"; DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; - dictionary = JsonSerializer.Deserialize>(Json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(Json); Assert.Equal(1, dictionary["One"]); Assert.Equal(2, dictionary["Two"]); - string json = JsonSerializer.Serialize(dictionary); + string json = await JsonSerializerWrapperForString.SerializeWrapper(dictionary); Assert.Equal(Json, json); } [Fact] - public static void DictionaryOfTOnlyWithStringTValueAsPoco() + public async Task DictionaryOfTOnlyWithStringTValueAsPoco() { const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; DictionaryThatOnlyImplementsIDictionaryOfStringTValue dictionary; - dictionary = JsonSerializer.Deserialize>(Json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper>(Json); Assert.Equal(1, dictionary["One"].Id); Assert.Equal(2, dictionary["Two"].Id); - string json = JsonSerializer.Serialize(dictionary); + string json = await JsonSerializerWrapperForString.SerializeWrapper(dictionary); Assert.Equal(Json, json); } @@ -1760,17 +1761,17 @@ public class DictionaryThatOnlyImplementsIDictionaryOfStringPoco : DictionaryTha } [Fact] - public static void DictionaryOfTOnlyWithStringPoco() + public async Task DictionaryOfTOnlyWithStringPoco() { const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; DictionaryThatOnlyImplementsIDictionaryOfStringPoco dictionary; - dictionary = JsonSerializer.Deserialize(Json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper(Json); Assert.Equal(1, dictionary["One"].Id); Assert.Equal(2, dictionary["Two"].Id); - string json = JsonSerializer.Serialize(dictionary); + string json = await JsonSerializerWrapperForString.SerializeWrapper(dictionary); Assert.Equal(Json, json); } @@ -1854,27 +1855,27 @@ public void CopyTo(Array array, int index) } [Fact] - public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithInt() + public async Task VerifyDictionaryThatHasIncomatibleEnumeratorWithInt() { const string Json = @"{""One"":1,""Two"":2}"; DictionaryThatHasIncompatibleEnumerator dictionary; - dictionary = JsonSerializer.Deserialize(Json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper(Json); Assert.Equal(1, ((JsonElement)dictionary["One"]).GetInt32()); Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetInt32()); - Assert.Throws(() => JsonSerializer.Serialize(dictionary)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(dictionary)); } [Fact] - public static void VerifyDictionaryThatHasIncomatibleEnumeratorWithPoco() + public async Task VerifyDictionaryThatHasIncomatibleEnumeratorWithPoco() { const string Json = @"{""One"":{""Id"":1},""Two"":{""Id"":2}}"; DictionaryThatHasIncompatibleEnumerator dictionary; - dictionary = JsonSerializer.Deserialize(Json); + dictionary = await JsonSerializerWrapperForString.DeserializeWrapper(Json); Assert.Equal(1, ((JsonElement)dictionary["One"]).GetProperty("Id").GetInt32()); Assert.Equal(2, ((JsonElement)dictionary["Two"]).GetProperty("Id").GetInt32()); - Assert.Throws(() => JsonSerializer.Serialize(dictionary)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(dictionary)); } private class ClassWithoutParameterlessCtor @@ -1896,14 +1897,14 @@ private ClassWithPrivateParameterlessConstructor() { } } [Fact] - public static void DictionaryWith_ObjectWithNoParameterlessCtor_AsValue_Throws() + public async Task DictionaryWith_ObjectWithNoParameterlessCtor_AsValue_Throws() { - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""key"":{}}")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""key"":{}}")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""key"":{}}")); } [Fact] - public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works() + public async Task DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works() { var noParameterless = new Dictionary() { @@ -1913,7 +1914,7 @@ public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works( } }; - string json = JsonSerializer.Serialize(noParameterless); + string json = await JsonSerializerWrapperForString.SerializeWrapper(noParameterless); Assert.Equal("{\"key\":{\"Name\":\"parameterless\"}}", json); var onlyInternal = new Dictionary() @@ -1924,7 +1925,7 @@ public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works( } }; - json = JsonSerializer.Serialize(onlyInternal); + json = await JsonSerializerWrapperForString.SerializeWrapper(onlyInternal); Assert.Equal("{\"key\":{\"Name\":\"internal\"}}", json); var onlyPrivate = new Dictionary() @@ -1932,7 +1933,7 @@ public static void DictionaryWith_ObjectWithNoParameterlessCtor_Serialize_Works( ["key"] = null }; - json = JsonSerializer.Serialize(onlyPrivate); + json = await JsonSerializerWrapperForString.SerializeWrapper(onlyPrivate); Assert.Equal("{\"key\":null}", json); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs similarity index 55% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs index c5b865860ef5e..1d5733dde3a83 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Read.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs @@ -3,23 +3,24 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void ReadListOfList() + public async Task ReadListOfList() { - List> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[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]); - GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); Assert.Equal("1", result2[0][0]); Assert.Equal("2", result2[0][1]); @@ -28,16 +29,16 @@ public static void ReadListOfList() } [Fact] - public static void ReadListOfArray() + public async Task ReadListOfArray() { - List result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[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]); - GenericListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); Assert.Equal("1", result2[0][0]); Assert.Equal("2", result2[0][1]); @@ -46,16 +47,16 @@ public static void ReadListOfArray() } [Fact] - public static void ReadArrayOfList() + public async Task ReadArrayOfList() { - List[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + List[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[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]); - StringListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + StringListWrapper[] result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]"); Assert.Equal("1", result2[0][0]); Assert.Equal("2", result2[0][1]); Assert.Equal("3", result2[1][0]); @@ -63,27 +64,27 @@ public static void ReadArrayOfList() } [Fact] - public static void ReadSimpleList() + public async Task ReadSimpleList() { - List i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + List i = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); Assert.Equal(1, i[0]); Assert.Equal(2, i[1]); - i = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + i = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, i.Count); - StringListWrapper i2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + StringListWrapper i2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]"); Assert.Equal("1", i2[0]); Assert.Equal("2", i2[1]); - i2 = JsonSerializer.Deserialize(@"[]"); + i2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); Assert.Equal(0, i2.Count); } [Fact] - public static void ReadGenericIEnumerableOfGenericIEnumerable() + public async Task ReadGenericIEnumerableOfGenericIEnumerable() { - IEnumerable> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IEnumerable ie in result) @@ -95,13 +96,13 @@ public static void ReadGenericIEnumerableOfGenericIEnumerable() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadIEnumerableTOfArray() + public async Task ReadIEnumerableTOfArray() { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -113,13 +114,13 @@ public static void ReadIEnumerableTOfArray() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3, 4]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3, 4]]")); } [Fact] - public static void ReadArrayOfIEnumerableT() + public async Task ReadArrayOfIEnumerableT() { - IEnumerable[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IEnumerable arr in result) @@ -131,13 +132,13 @@ public static void ReadArrayOfIEnumerableT() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadSimpleGenericIEnumerable() + public async Task ReadSimpleGenericIEnumerable() { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + IEnumerable result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -145,18 +146,18 @@ public static void ReadSimpleGenericIEnumerable() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); // There is no way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[]")); } [Fact] - public static void ReadIListTOfIListT() + public async Task ReadIListTOfIListT() { - IList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IList ie in result) @@ -167,7 +168,7 @@ public static void ReadIListTOfIListT() } } - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericIListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringIListWrapper il in result2) @@ -180,9 +181,9 @@ public static void ReadIListTOfIListT() } [Fact] - public static void ReadGenericIListOfArray() + public async Task ReadGenericIListOfArray() { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -193,7 +194,7 @@ public static void ReadGenericIListOfArray() } } - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericIListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (string[] arr in result2) @@ -206,9 +207,9 @@ public static void ReadGenericIListOfArray() } [Fact] - public static void ReadArrayOfIListT() + public async Task ReadArrayOfIListT() { - IList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IList arr in result) @@ -219,7 +220,7 @@ public static void ReadArrayOfIListT() } } - StringIListWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + StringIListWrapper[] result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringIListWrapper il in result2) @@ -232,9 +233,9 @@ public static void ReadArrayOfIListT() } [Fact] - public static void ReadSimpleGenericIList() + public async Task ReadSimpleGenericIList() { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + IList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -242,10 +243,10 @@ public static void ReadSimpleGenericIList() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); - StringIListWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + StringIListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]"); expected = 1; foreach (string str in result2) @@ -253,15 +254,15 @@ public static void ReadSimpleGenericIList() Assert.Equal($"{expected++}", str); } - result2 = JsonSerializer.Deserialize(@"[]"); + result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); Assert.Equal(0, result2.Count()); } [Fact] - public static void ReadGenericStructIList() + public async Task ReadGenericStructIList() { string json = "[10,20,30]"; - var wrapper = JsonSerializer.Deserialize>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(3, wrapper.Count); Assert.Equal(10, wrapper[0]); Assert.Equal(20, wrapper[1]); @@ -269,10 +270,10 @@ public static void ReadGenericStructIList() } [Fact] - public static void ReadNullableGenericStructIList() + public async Task ReadNullableGenericStructIList() { string json = "[10,20,30]"; - var wrapper = JsonSerializer.Deserialize?>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>(json); Assert.True(wrapper.HasValue); Assert.Equal(3, wrapper.Value.Count); Assert.Equal(10, wrapper.Value[0]); @@ -281,17 +282,17 @@ public static void ReadNullableGenericStructIList() } [Fact] - public static void ReadNullableGenericStructIListWithNullJson() + public async Task ReadNullableGenericStructIListWithNullJson() { - var wrapper = JsonSerializer.Deserialize?>("null"); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>("null"); Assert.False(wrapper.HasValue); } [Fact] - public static void ReadGenericStructICollection() + public async Task ReadGenericStructICollection() { string json = "[10,20,30]"; - var wrapper = JsonSerializer.Deserialize>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(3, wrapper.Count); Assert.Equal(10, wrapper.ElementAt(0)); Assert.Equal(20, wrapper.ElementAt(1)); @@ -299,10 +300,10 @@ public static void ReadGenericStructICollection() } [Fact] - public static void ReadNullableGenericStructICollection() + public async Task ReadNullableGenericStructICollection() { string json = "[10,20,30]"; - var wrapper = JsonSerializer.Deserialize?>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>(json); Assert.True(wrapper.HasValue); Assert.Equal(3, wrapper.Value.Count); Assert.Equal(10, wrapper.Value.ElementAt(0)); @@ -311,16 +312,16 @@ public static void ReadNullableGenericStructICollection() } [Fact] - public static void ReadNullableGenericStructICollectionWithNullJson() + public async Task ReadNullableGenericStructICollectionWithNullJson() { - var wrapper = JsonSerializer.Deserialize?>("null"); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>("null"); Assert.False(wrapper.HasValue); } [Fact] - public static void ReadGenericICollectionOfGenericICollection() + public async Task ReadGenericICollectionOfGenericICollection() { - ICollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (ICollection ie in result) @@ -345,9 +346,9 @@ public static void ReadGenericICollectionOfGenericICollection() } [Fact] - public static void ReadGenericICollectionOfArray() + public async Task ReadGenericICollectionOfArray() { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -358,7 +359,7 @@ public static void ReadGenericICollectionOfArray() } } - GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericICollectionWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (string[] arr in result2) @@ -371,9 +372,9 @@ public static void ReadGenericICollectionOfArray() } [Fact] - public static void ReadArrayOfGenericICollection() + public async Task ReadArrayOfGenericICollection() { - ICollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (ICollection arr in result) @@ -386,9 +387,9 @@ public static void ReadArrayOfGenericICollection() } [Fact] - public static void ReadSimpleGenericICollection() + public async Task ReadSimpleGenericICollection() { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + ICollection result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -396,10 +397,10 @@ public static void ReadSimpleGenericICollection() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); - GenericICollectionWrapper result2 = JsonSerializer.Deserialize>(@"[""1"",""2""]"); + GenericICollectionWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[""1"",""2""]"); expected = 1; foreach (string str in result2) @@ -407,14 +408,14 @@ public static void ReadSimpleGenericICollection() Assert.Equal($"{expected++}", str); } - result2 = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result2.Count()); } [Fact] - public static void ReadGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() + public async Task ReadGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() { - IReadOnlyCollection> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyCollection> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IReadOnlyCollection ie in result) @@ -426,14 +427,14 @@ public static void ReadGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() } // There's no way to populate this collection. - Assert.Throws( - () => JsonSerializer.Deserialize>>(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync( + async () => await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadGenericIReadOnlyCollectionOfArray() + public async Task ReadGenericIReadOnlyCollectionOfArray() { - IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyCollection result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -444,13 +445,13 @@ public static void ReadGenericIReadOnlyCollectionOfArray() } } - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]")); } [Fact] - public static void ReadArrayOfIReadOnlyCollectionT() + public async Task ReadArrayOfIReadOnlyCollectionT() { - IReadOnlyCollection[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyCollection[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IReadOnlyCollection arr in result) @@ -462,13 +463,13 @@ public static void ReadArrayOfIReadOnlyCollectionT() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize[]>(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadGenericSimpleIReadOnlyCollection() + public async Task ReadGenericSimpleIReadOnlyCollection() { - IReadOnlyCollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + IReadOnlyCollection result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -476,17 +477,17 @@ public static void ReadGenericSimpleIReadOnlyCollection() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[""1"",""2""]")); } [Fact] - public static void ReadGenericIReadOnlyListOfGenericIReadOnlyList() + public async Task ReadGenericIReadOnlyListOfGenericIReadOnlyList() { - IReadOnlyList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyList> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IReadOnlyList ie in result) @@ -497,13 +498,13 @@ public static void ReadGenericIReadOnlyListOfGenericIReadOnlyList() } } - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadGenericIReadOnlyListOfArray() + public async Task ReadGenericIReadOnlyListOfArray() { - IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -515,13 +516,13 @@ public static void ReadGenericIReadOnlyListOfArray() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadArrayOfGenericIReadOnlyList() + public async Task ReadArrayOfGenericIReadOnlyList() { - IReadOnlyList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IReadOnlyList[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IReadOnlyList arr in result) @@ -533,13 +534,13 @@ public static void ReadArrayOfGenericIReadOnlyList() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]")); } [Fact] - public static void ReadSimpleGenericIReadOnlyList() + public async Task ReadSimpleGenericIReadOnlyList() { - IReadOnlyList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + IReadOnlyList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -547,17 +548,17 @@ public static void ReadSimpleGenericIReadOnlyList() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); } [Fact] - public static void ReadGenericISetOfGenericISet() + public async Task ReadGenericISetOfGenericISet() { - ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ISet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); if (result.First().Contains(1)) { @@ -570,7 +571,7 @@ public static void ReadGenericISetOfGenericISet() Assert.Equal(new HashSet { 1, 2 }, result.Last()); } - GenericISetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericISetWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); if (result2.First().Contains("1")) { @@ -585,10 +586,10 @@ public static void ReadGenericISetOfGenericISet() } [Fact] - public static void ReadGenericStructISet() + public async Task ReadGenericStructISet() { string json = "[10, 20, 30]"; - var wrapper = JsonSerializer.Deserialize>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(3, wrapper.Count); Assert.Equal(10, wrapper.ElementAt(0)); Assert.Equal(20, wrapper.ElementAt(1)); @@ -596,10 +597,10 @@ public static void ReadGenericStructISet() } [Fact] - public static void ReadNullableGenericStructISet() + public async Task ReadNullableGenericStructISet() { string json = "[10, 20, 30]"; - var wrapper = JsonSerializer.Deserialize?>(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>(json); Assert.True(wrapper.HasValue); Assert.Equal(3, wrapper.Value.Count); Assert.Equal(10, wrapper.Value.ElementAt(0)); @@ -608,17 +609,17 @@ public static void ReadNullableGenericStructISet() } [Fact] - public static void ReadNullableGenericStructISetWithNullJson() + public async Task ReadNullableGenericStructISetWithNullJson() { - var wrapper = JsonSerializer.Deserialize?>("null"); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper?>("null"); Assert.False(wrapper.HasValue); } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/50721", typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltWithAggressiveTrimming), nameof(PlatformDetection.IsBrowser))] - public static void ReadISetTOfHashSetT() + public async Task ReadISetTOfHashSetT() { - ISet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ISet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); if (result.First().Contains(1)) { @@ -633,9 +634,9 @@ public static void ReadISetTOfHashSetT() } [Fact] - public static void ReadHashSetTOfISetT() + public async Task ReadHashSetTOfISetT() { - HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + HashSet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); if (result.First().Contains(1)) { @@ -650,9 +651,9 @@ public static void ReadHashSetTOfISetT() } [Fact] - public static void ReadISetTOfArray() + public async Task ReadISetTOfArray() { - ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ISet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); if (result.First().Contains(1)) { @@ -667,29 +668,29 @@ public static void ReadISetTOfArray() } [Fact] - public static void ReadArrayOfISetT() + public async Task ReadArrayOfISetT() { - ISet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ISet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); Assert.Equal(new HashSet { 1, 2 }, result.First()); Assert.Equal(new HashSet { 3, 4 }, result.Last()); } [Fact] - public static void ReadSimpleISetT() + public async Task ReadSimpleISetT() { - ISet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + ISet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); Assert.Equal(new HashSet { 1, 2 }, result); - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); } [Fact] - public static void StackTOfStackT() + public async Task StackTOfStackT() { - Stack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 4; foreach (Stack st in result) @@ -700,7 +701,7 @@ public static void StackTOfStackT() } } - GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericStackWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 4; foreach (StringStackWrapper st in result2) @@ -713,9 +714,9 @@ public static void StackTOfStackT() } [Fact] - public static void ReadGenericStackOfArray() + public async Task ReadGenericStackOfArray() { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 3; foreach (int[] arr in result) @@ -728,7 +729,7 @@ public static void ReadGenericStackOfArray() expected = 1; } - GenericStackWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericStackWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 3; foreach (string[] arr in result2) @@ -743,9 +744,9 @@ public static void ReadGenericStackOfArray() } [Fact] - public static void ReadArrayOfGenericStack() + public async Task ReadArrayOfGenericStack() { - Stack[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 2; foreach (Stack st in result) @@ -758,7 +759,7 @@ public static void ReadArrayOfGenericStack() expected = 4; } - StringStackWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + StringStackWrapper[] result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]"); expected = 2; foreach (StringStackWrapper st in result2) @@ -773,9 +774,9 @@ public static void ReadArrayOfGenericStack() } [Fact] - public static void ReadSimpleGenericStack() + public async Task ReadSimpleGenericStack() { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + Stack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 2; foreach (int i in result) @@ -783,10 +784,10 @@ public static void ReadSimpleGenericStack() Assert.Equal(expected--, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); - StringStackWrapper result2 = JsonSerializer.Deserialize(@"[""1"",""2""]"); + StringStackWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]"); expected = 2; foreach (string str in result2) @@ -794,14 +795,14 @@ public static void ReadSimpleGenericStack() Assert.Equal($"{expected--}", str); } - result2 = JsonSerializer.Deserialize(@"[]"); + result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); Assert.Equal(0, result2.Count()); } [Fact] - public static void ReadQueueTOfQueueT() + public async Task ReadQueueTOfQueueT() { - Queue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (Queue q in result) @@ -812,7 +813,7 @@ public static void ReadQueueTOfQueueT() } } - GenericQueueWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericQueueWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringQueueWrapper q in result2) @@ -825,9 +826,9 @@ public static void ReadQueueTOfQueueT() } [Fact] - public static void ReadQueueTOfArray() + public async Task ReadQueueTOfArray() { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -840,9 +841,9 @@ public static void ReadQueueTOfArray() } [Fact] - public static void ReadArrayOfIQueueT() + public async Task ReadArrayOfIQueueT() { - Queue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (Queue q in result) @@ -855,24 +856,24 @@ public static void ReadArrayOfIQueueT() } [Fact] - public static void ReadSimpleQueueT() + public async Task ReadSimpleQueueT() { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + Queue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) { Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); } [Fact] - public static void ReadHashSetTOfHashSetT() + public async Task ReadHashSetTOfHashSetT() { - HashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + HashSet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (HashSet hs in result) @@ -883,7 +884,7 @@ public static void ReadHashSetTOfHashSetT() } } - GenericHashSetWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericHashSetWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringHashSetWrapper hs in result2) @@ -896,9 +897,9 @@ public static void ReadHashSetTOfHashSetT() } [Fact] - public static void ReadHashSetTOfArray() + public async Task ReadHashSetTOfArray() { - HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + HashSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -911,9 +912,9 @@ public static void ReadHashSetTOfArray() } [Fact] - public static void ReadArrayOfIHashSetT() + public async Task ReadArrayOfIHashSetT() { - HashSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + HashSet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (HashSet hs in result) @@ -926,9 +927,9 @@ public static void ReadArrayOfIHashSetT() } [Fact] - public static void ReadSimpleHashSetT() + public async Task ReadSimpleHashSetT() { - HashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + HashSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -936,14 +937,14 @@ public static void ReadSimpleHashSetT() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); } [Fact] - public static void ReadGenericLinkedListOfGenericLinkedList() + public async Task ReadGenericLinkedListOfGenericLinkedList() { - LinkedList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + LinkedList> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); int expected = 1; foreach (LinkedList l in result) @@ -954,7 +955,7 @@ public static void ReadGenericLinkedListOfGenericLinkedList() } } - GenericLinkedListWrapper result2 = JsonSerializer.Deserialize>(@"[[""1"",""2""],[""3"",""4""]]"); + GenericLinkedListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringLinkedListWrapper l in result2) @@ -967,9 +968,9 @@ public static void ReadGenericLinkedListOfGenericLinkedList() } [Fact] - public static void ReadLinkedListTOfArray() + public async Task ReadLinkedListTOfArray() { - LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + LinkedList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (int[] arr in result) @@ -982,9 +983,9 @@ public static void ReadLinkedListTOfArray() } [Fact] - public static void ReadArrayOfILinkedListT() + public async Task ReadArrayOfILinkedListT() { - LinkedList[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + LinkedList[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (LinkedList l in result) @@ -997,9 +998,9 @@ public static void ReadArrayOfILinkedListT() } [Fact] - public static void ReadSimpleLinkedListT() + public async Task ReadSimpleLinkedListT() { - LinkedList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + LinkedList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -1007,14 +1008,14 @@ public static void ReadSimpleLinkedListT() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); } [Fact] - public static void ReadArrayOfSortedSetT() + public async Task ReadArrayOfSortedSetT() { - SortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + SortedSet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); int expected = 1; foreach (SortedSet s in result) @@ -1025,7 +1026,7 @@ public static void ReadArrayOfSortedSetT() } } - StringSortedSetWrapper[] result2 = JsonSerializer.Deserialize(@"[[""1"",""2""],[""3"",""4""]]"); + StringSortedSetWrapper[] result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[""1"",""2""],[""3"",""4""]]"); expected = 1; foreach (StringSortedSetWrapper s in result2) @@ -1038,9 +1039,9 @@ public static void ReadArrayOfSortedSetT() } [Fact] - public static void ReadSimpleSortedSetT() + public async Task ReadSimpleSortedSetT() { - SortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); + SortedSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); int expected = 1; foreach (int i in result) @@ -1048,31 +1049,31 @@ public static void ReadSimpleSortedSetT() Assert.Equal(expected++, i); } - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); Assert.Equal(0, result.Count()); } [Fact] - public static void ReadClass_WithGenericStructCollectionWrapper_NullJson_Throws() + public async Task ReadClass_WithGenericStructCollectionWrapper_NullJson_Throws() { - Assert.Throws(() => JsonSerializer.Deserialize(@"{ ""List"": null }")); - Assert.Throws(() => JsonSerializer.Deserialize(@"{ ""Collection"": null }")); - Assert.Throws(() => JsonSerializer.Deserialize(@"{ ""Dictionary"": null }")); - Assert.Throws(() => JsonSerializer.Deserialize(@"{ ""Set"": null }")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{ ""List"": null }")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{ ""Collection"": null }")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{ ""Dictionary"": null }")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{ ""Set"": null }")); } [Fact] - public static void ReadSimpleTestClass_GenericStructCollectionWrappers() + public async Task ReadSimpleTestClass_GenericStructCollectionWrappers() { - SimpleTestClassWithGenericStructCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithGenericStructCollectionWrappers.s_json); + SimpleTestClassWithGenericStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithGenericStructCollectionWrappers.s_json); obj.Verify(); } [Fact] - public static void ReadSimpleTestStruct_NullableGenericStructCollectionWrappers() + public async Task ReadSimpleTestStruct_NullableGenericStructCollectionWrappers() { { - SimpleTestStructWithNullableGenericStructCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestStructWithNullableGenericStructCollectionWrappers.s_json); + SimpleTestStructWithNullableGenericStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestStructWithNullableGenericStructCollectionWrappers.s_json); obj.Verify(); } @@ -1084,7 +1085,7 @@ public static void ReadSimpleTestStruct_NullableGenericStructCollectionWrappers( @"""Set"" : null," + @"""Dictionary"" : null" + @"}"; - SimpleTestStructWithNullableGenericStructCollectionWrappers obj = JsonSerializer.Deserialize(json); + SimpleTestStructWithNullableGenericStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.False(obj.List.HasValue); Assert.False(obj.Collection.HasValue); Assert.False(obj.Set.HasValue); @@ -1093,17 +1094,17 @@ public static void ReadSimpleTestStruct_NullableGenericStructCollectionWrappers( } [Fact] - public static void ReadSimpleTestClass_GenericCollectionWrappers() + public async Task ReadSimpleTestClass_GenericCollectionWrappers() { - SimpleTestClassWithGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithGenericCollectionWrappers.s_json); + SimpleTestClassWithGenericCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithGenericCollectionWrappers.s_json); obj.Verify(); } [Theory] [MemberData(nameof(ReadSimpleTestClass_GenericWrappers_NoAddMethod))] - public static void ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) + public async Task ReadSimpleTestClass_GenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); Assert.Contains(exceptionMessageType.ToString(), ex.Message); } @@ -1145,22 +1146,22 @@ public static IEnumerable ReadSimpleTestClass_GenericWrappers_NoAddMet [InlineData(typeof(ReadOnlyStringISetWrapper), @"[""1"", ""2""]")] [InlineData(typeof(ReadOnlyWrapperForIDictionary), @"{""Key"":""key"",""Value"":""value""}")] [InlineData(typeof(ReadOnlyStringToStringIDictionaryWrapper), @"{""Key"":""key"",""Value"":""value""}")] - public static void ReadReadOnlyCollections_Throws(Type type, string json) + public async Task ReadReadOnlyCollections_Throws(Type type, string json) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); Assert.Contains(type.ToString(), ex.Message); } [Fact] - public static void Read_HigherOrderCollectionInheritance_Works() + public async Task Read_HigherOrderCollectionInheritance_Works() { const string json = "[\"test\"]"; - Assert.Equal("test", JsonSerializer.Deserialize(json)[0]); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize>(json).First()); - Assert.Equal("test", JsonSerializer.Deserialize(json).First()); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper(json))[0]); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper>(json)).First()); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper(json)).First()); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper>(json)).First()); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper>(json)).First()); + Assert.Equal("test", (await JsonSerializerWrapperForString.DeserializeWrapper(json)).First()); } [Theory] @@ -1184,21 +1185,21 @@ public static void Read_HigherOrderCollectionInheritance_Works() [InlineData(typeof(GenericStackWrapperInternalConstructor), @"[""1""]")] [InlineData(typeof(StringToGenericDictionaryWrapperPrivateConstructor), @"{""Key"":""Value""}")] [InlineData(typeof(StringToGenericDictionaryWrapperInternalConstructor), @"{""Key"":""Value""}")] - public static void Read_Generic_NoPublicConstructor_Throws(Type type, string json) + public async Task Read_Generic_NoPublicConstructor_Throws(Type type, string json) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); Assert.Contains(type.ToString(), ex.Message); } [Fact] - public static void DoesNotCall_CollectionPropertyGetter_EveryTimeElementIsAdded() + public async Task DoesNotCall_CollectionPropertyGetter_EveryTimeElementIsAdded() { var networkList = new List { "Network1", "Network2" }; - string serialized = JsonSerializer.Serialize(new NetworkWrapper { NetworkList = networkList }); + string serialized = await JsonSerializerWrapperForString.SerializeWrapper(new NetworkWrapper { NetworkList = networkList }); Assert.Equal(@"{""NetworkList"":[""Network1"",""Network2""]}", serialized); - NetworkWrapper obj = JsonSerializer.Deserialize(serialized); + NetworkWrapper obj = await JsonSerializerWrapperForString.DeserializeWrapper(serialized); int i = 0; foreach (string network in obj.NetworkList) @@ -1227,14 +1228,14 @@ public IEnumerable NetworkList } [Fact] - public static void CollectionWith_BackingField_CanRoundtrip() + public async Task CollectionWith_BackingField_CanRoundtrip() { string json = "{\"AllowedGrantTypes\":[\"client_credentials\"]}"; - Client obj = JsonSerializer.Deserialize(json); + Client obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("client_credentials", obj.AllowedGrantTypes.First()); - string serialized = JsonSerializer.Serialize(obj); + string serialized = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(json, serialized); } @@ -1251,17 +1252,17 @@ public ICollection AllowedGrantTypes [Theory] [MemberData(nameof(CustomInterfaces_Enumerables))] - public static void CustomInterfacesNotSupported_Enumerables(Type type) + public async Task CustomInterfacesNotSupported_Enumerables(Type type) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize("[]", type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper("[]", type)); Assert.Contains(type.ToString(), ex.ToString()); } [Theory] [MemberData(nameof(CustomInterfaces_Dictionaries))] - public static void CustomInterfacesNotSupported_Dictionaries(Type type) + public async Task CustomInterfacesNotSupported_Dictionaries(Type type) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize("{}", type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper("{}", type)); Assert.Contains(type.ToString(), ex.ToString()); } @@ -1278,10 +1279,10 @@ public static IEnumerable CustomInterfaces_Dictionaries() } [Fact] - public static void IReadOnlyDictionary_NotSupportedKey() + public async Task IReadOnlyDictionary_NotSupportedKey() { - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""http://foo"":1}")); - Assert.Throws(() => JsonSerializer.Serialize(new GenericIReadOnlyDictionaryWrapper(new Dictionary { { new Uri("http://foo"), 1 } }))); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""http://foo"":1}")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(new GenericIReadOnlyDictionaryWrapper(new Dictionary { { new Uri("http://foo"), 1 } }))); } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Write.cs similarity index 69% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Write.cs index e6963f2ca07a3..33015af00e893 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Generic.Write.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Write.cs @@ -3,14 +3,15 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void WriteListOfList() + public async Task WriteListOfList() { var input = new List> { @@ -18,7 +19,7 @@ public static void WriteListOfList() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); var input2 = new GenericListWrapper @@ -27,12 +28,12 @@ public static void WriteListOfList() new StringListWrapper() { "3", "4" } }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteListOfArray() + public async Task WriteListOfArray() { var input = new List { @@ -40,32 +41,32 @@ public static void WriteListOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfList() + public async Task WriteArrayOfList() { var input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveList() + public async Task WritePrimitiveList() { var input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteGenericIEnumerableOfGenericIEnumerable() + public async Task WriteGenericIEnumerableOfGenericIEnumerable() { IEnumerable> input = new List> { @@ -73,7 +74,7 @@ public static void WriteGenericIEnumerableOfGenericIEnumerable() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericIEnumerableWrapper input2 = new GenericIEnumerableWrapper(new List @@ -82,12 +83,12 @@ public static void WriteGenericIEnumerableOfGenericIEnumerable() new StringIEnumerableWrapper(new List { "3", "4" }), }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteIEnumerableTOfArray() + public async Task WriteIEnumerableTOfArray() { IEnumerable input = new List { @@ -95,32 +96,32 @@ public static void WriteIEnumerableTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIEnumerableT() + public async Task WriteArrayOfIEnumerableT() { IEnumerable[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIEnumerableT() + public async Task WritePrimitiveIEnumerableT() { IEnumerable input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteGenericIListOfGenericIList() + public async Task WriteGenericIListOfGenericIList() { IList> input = new List> { @@ -128,7 +129,7 @@ public static void WriteGenericIListOfGenericIList() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericIListWrapper input2 = new GenericIListWrapper @@ -137,12 +138,12 @@ public static void WriteGenericIListOfGenericIList() new StringIListWrapper() { "3", "4" } }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteIListTOfArray() + public async Task WriteIListTOfArray() { IList input = new List { @@ -150,60 +151,60 @@ public static void WriteIListTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIListT() + public async Task WriteArrayOfIListT() { IList[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIListT() + public async Task WritePrimitiveIListT() { IList input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteGenericStructIListWrapperT() + public async Task WriteGenericStructIListWrapperT() { { GenericStructIListWrapper obj = new GenericStructIListWrapper() { 10, 20 }; - Assert.Equal("[10,20]", JsonSerializer.Serialize(obj)); + Assert.Equal("[10,20]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { GenericStructIListWrapper obj = default; - Assert.Equal("[]", JsonSerializer.Serialize(obj)); + Assert.Equal("[]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteGenericStructICollectionWrapperT() + public async Task WriteGenericStructICollectionWrapperT() { { GenericStructICollectionWrapper obj = new GenericStructICollectionWrapper() { 10, 20 }; - Assert.Equal("[10,20]", JsonSerializer.Serialize(obj)); + Assert.Equal("[10,20]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { GenericStructICollectionWrapper obj = default; - Assert.Equal("[]", JsonSerializer.Serialize(obj)); + Assert.Equal("[]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteGenericICollectionOfGenericICollection() + public async Task WriteGenericICollectionOfGenericICollection() { ICollection> input = new List> { @@ -211,7 +212,7 @@ public static void WriteGenericICollectionOfGenericICollection() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericICollectionWrapper> input2 = new GenericICollectionWrapper> @@ -220,12 +221,12 @@ public static void WriteGenericICollectionOfGenericICollection() new GenericICollectionWrapper() { "3", "4" } }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteICollectionTOfArray() + public async Task WriteICollectionTOfArray() { ICollection input = new List { @@ -233,32 +234,32 @@ public static void WriteICollectionTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfICollectionT() + public async Task WriteArrayOfICollectionT() { ICollection[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveICollectionT() + public async Task WritePrimitiveICollectionT() { ICollection input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() + public async Task WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() { IReadOnlyCollection> input = new List> { @@ -266,7 +267,7 @@ public static void WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericIReadOnlyCollectionWrapper> input2 = @@ -276,12 +277,12 @@ public static void WriteGenericIReadOnlyCollectionOfGenericIReadOnlyCollection() new WrapperForIReadOnlyCollectionOfT(new List { "3", "4" }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteIReadOnlyCollectionTOfArray() + public async Task WriteIReadOnlyCollectionTOfArray() { IReadOnlyCollection input = new List { @@ -289,32 +290,32 @@ public static void WriteIReadOnlyCollectionTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIReadOnlyCollectionT() + public async Task WriteArrayOfIReadOnlyCollectionT() { IReadOnlyCollection[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIReadOnlyCollectionT() + public async Task WritePrimitiveIReadOnlyCollectionT() { IReadOnlyCollection input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteIReadOnlyListTOfIReadOnlyListT() + public async Task WriteIReadOnlyListTOfIReadOnlyListT() { IReadOnlyList> input = new List> { @@ -322,7 +323,7 @@ public static void WriteIReadOnlyListTOfIReadOnlyListT() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericIReadOnlyListWrapper input2 = new GenericIReadOnlyListWrapper(new List @@ -331,12 +332,12 @@ public static void WriteIReadOnlyListTOfIReadOnlyListT() new StringIReadOnlyListWrapper(new List { "3", "4" }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteIReadOnlyListTOfArray() + public async Task WriteIReadOnlyListTOfArray() { IReadOnlyList input = new List { @@ -344,47 +345,47 @@ public static void WriteIReadOnlyListTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIReadOnlyListT() + public async Task WriteArrayOfIReadOnlyListT() { IReadOnlyList[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIReadOnlyListT() + public async Task WritePrimitiveIReadOnlyListT() { IReadOnlyList input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void GenericStructISetWrapperT() + public async Task GenericStructISetWrapperT() { { GenericStructISetWrapper obj = new GenericStructISetWrapper() { 10, 20 }; - Assert.Equal("[10,20]", JsonSerializer.Serialize(obj)); + Assert.Equal("[10,20]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { GenericStructISetWrapper obj = default; - Assert.Equal("[]", JsonSerializer.Serialize(obj)); + Assert.Equal("[]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/50721", typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltWithAggressiveTrimming), nameof(PlatformDetection.IsBrowser))] - public static void WriteISetTOfISetT() + public async Task WriteISetTOfISetT() { ISet> input = new HashSet> { @@ -392,10 +393,10 @@ public static void WriteISetTOfISetT() new HashSet() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper>>(json); if (input.First().Contains(1)) { @@ -414,10 +415,10 @@ public static void WriteISetTOfISetT() new StringISetWrapper() { "3", "4" }, }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input2 = JsonSerializer.Deserialize>(json); + input2 = await JsonSerializerWrapperForString.DeserializeWrapper>(json); if (input2.First().Contains("1")) { @@ -433,7 +434,7 @@ public static void WriteISetTOfISetT() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/50721", typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltWithAggressiveTrimming), nameof(PlatformDetection.IsBrowser))] - public static void WriteISetTOfHashSetT() + public async Task WriteISetTOfHashSetT() { ISet> input = new HashSet> { @@ -441,10 +442,10 @@ public static void WriteISetTOfHashSetT() new HashSet() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper>>(json); if (input.First().Contains(1)) { @@ -459,7 +460,7 @@ public static void WriteISetTOfHashSetT() } [Fact] - public static void WriteHashSetTOfISetT() + public async Task WriteHashSetTOfISetT() { HashSet> input = new HashSet> { @@ -467,10 +468,10 @@ public static void WriteHashSetTOfISetT() new HashSet() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper>>(json); if (input.First().Contains(1)) { @@ -485,7 +486,7 @@ public static void WriteHashSetTOfISetT() } [Fact] - public static void WriteISetTOfArray() + public async Task WriteISetTOfArray() { ISet input = new HashSet { @@ -493,37 +494,37 @@ public static void WriteISetTOfArray() new int[] { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] - public static void WriteArrayOfISetT() + public async Task WriteArrayOfISetT() { ISet[] input = new HashSet[2]; input[0] = new HashSet() { 1, 2 }; input[1] = new HashSet() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize[]>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper[]>(json); Assert.Equal(new HashSet { 1, 2 }, input.First()); Assert.Equal(new HashSet { 3, 4 }, input.Last()); } [Fact] - public static void WritePrimitiveISetT() + public async Task WritePrimitiveISetT() { ISet input = new HashSet { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.True(json == "[1,2]" || json == "[2,1]"); } [Fact] - public static void WriteStackTOfStackT() + public async Task WriteStackTOfStackT() { Stack> input = new Stack>(new List> { @@ -531,7 +532,7 @@ public static void WriteStackTOfStackT() new Stack(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[4,3],[2,1]]", json); GenericStackWrapper input2 = new GenericStackWrapper(new List @@ -540,12 +541,12 @@ public static void WriteStackTOfStackT() new StringStackWrapper(new List() { "3", "4" }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""4"",""3""],[""2"",""1""]]", json); } [Fact] - public static void WriteStackTOfArray() + public async Task WriteStackTOfArray() { Stack input = new Stack(new List { @@ -553,32 +554,32 @@ public static void WriteStackTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[3,4],[1,2]]", json); } [Fact] - public static void WriteArrayOfStackT() + public async Task WriteArrayOfStackT() { Stack[] input = new Stack[2]; input[0] = new Stack(new List { 1, 2 }); input[1] = new Stack(new List { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[2,1],[4,3]]", json); } [Fact] - public static void WritePrimitiveStackT() + public async Task WritePrimitiveStackT() { Stack input = new Stack(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[2,1]", json); } [Fact] - public static void WriteQueueTOfQueueT() + public async Task WriteQueueTOfQueueT() { Queue> input = new Queue>(new List> { @@ -586,7 +587,7 @@ public static void WriteQueueTOfQueueT() new Queue(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericQueueWrapper input2 = new GenericQueueWrapper(new List @@ -595,12 +596,12 @@ public static void WriteQueueTOfQueueT() new StringQueueWrapper(new List() { "3", "4" }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteQueueTOfArray() + public async Task WriteQueueTOfArray() { Queue input = new Queue(new List { @@ -608,32 +609,32 @@ public static void WriteQueueTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfQueueT() + public async Task WriteArrayOfQueueT() { Queue[] input = new Queue[2]; input[0] = new Queue(new List { 1, 2 }); input[1] = new Queue(new List { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveQueueT() + public async Task WritePrimitiveQueueT() { Queue input = new Queue(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteHashSetTOfHashSetT() + public async Task WriteHashSetTOfHashSetT() { HashSet> input = new HashSet>(new List> { @@ -641,10 +642,10 @@ public static void WriteHashSetTOfHashSetT() new HashSet(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize>>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper>>(json); if (input.First().Contains(1)) { @@ -663,10 +664,10 @@ public static void WriteHashSetTOfHashSetT() new StringHashSetWrapper(new List() { "3", "4" }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input2 = JsonSerializer.Deserialize>(json); + input2 = await JsonSerializerWrapperForString.DeserializeWrapper>(json); if (input2.First().Contains("1")) { @@ -681,7 +682,7 @@ public static void WriteHashSetTOfHashSetT() } [Fact] - public static void WriteHashSetTOfArray() + public async Task WriteHashSetTOfArray() { HashSet input = new HashSet(new List { @@ -689,38 +690,38 @@ public static void WriteHashSetTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/50721", typeof(PlatformDetection), nameof(PlatformDetection.IsBuiltWithAggressiveTrimming), nameof(PlatformDetection.IsBrowser))] - public static void WriteArrayOfHashSetT() + public async Task WriteArrayOfHashSetT() { HashSet[] input = new HashSet[2]; input[0] = new HashSet(new List { 1, 2 }); input[1] = new HashSet(new List { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); // Because order isn't guaranteed, roundtrip data to ensure write was accurate. - input = JsonSerializer.Deserialize[]>(json); + input = await JsonSerializerWrapperForString.DeserializeWrapper[]>(json); Assert.Equal(new HashSet { 1, 2 }, input.First()); Assert.Equal(new HashSet { 3, 4 }, input.Last()); } [Fact] - public static void WritePrimitiveHashSetT() + public async Task WritePrimitiveHashSetT() { HashSet input = new HashSet(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.True(json == "[1,2]" || json == "[2,1]"); } [Fact] - public static void WriteLinkedListTOfLinkedListT() + public async Task WriteLinkedListTOfLinkedListT() { LinkedList> input = new LinkedList>(new List> { @@ -728,7 +729,7 @@ public static void WriteLinkedListTOfLinkedListT() new LinkedList(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericLinkedListWrapper input2 = new GenericLinkedListWrapper(new List @@ -737,12 +738,12 @@ public static void WriteLinkedListTOfLinkedListT() new StringLinkedListWrapper(new List() { "3", "4" }), }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[[""1"",""2""],[""3"",""4""]]", json); } [Fact] - public static void WriteLinkedListTOfArray() + public async Task WriteLinkedListTOfArray() { LinkedList input = new LinkedList(new List { @@ -750,52 +751,52 @@ public static void WriteLinkedListTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfLinkedListT() + public async Task WriteArrayOfLinkedListT() { LinkedList[] input = new LinkedList[2]; input[0] = new LinkedList(new List { 1, 2 }); input[1] = new LinkedList(new List { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveLinkedListT() + public async Task WritePrimitiveLinkedListT() { LinkedList input = new LinkedList(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteArrayOfSortedSetT() + public async Task WriteArrayOfSortedSetT() { SortedSet[] input = new SortedSet[2]; input[0] = new SortedSet(new List { 1, 2 }); input[1] = new SortedSet(new List { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveSortedSetT() + public async Task WritePrimitiveSortedSetT() { SortedSet input = new SortedSet(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteGenericCollectionWrappers() + public async Task WriteGenericCollectionWrappers() { SimpleTestClassWithGenericCollectionWrappers obj1 = new SimpleTestClassWithGenericCollectionWrappers(); SimpleTestClassWithStringIEnumerableWrapper obj2 = new SimpleTestClassWithStringIEnumerableWrapper(); @@ -809,29 +810,29 @@ public static void WriteGenericCollectionWrappers() obj4.Initialize(); obj5.Initialize(); - Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); + Assert.Equal(SimpleTestClassWithGenericCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); - Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); + Assert.Equal(SimpleTestClassWithStringIEnumerableWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyCollectionWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); + Assert.Equal(SimpleTestClassWithStringIReadOnlyListWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); - Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); + Assert.Equal(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); } [Fact] - public static void WriteSimpleTestClassWithGenericStructCollectionWrappers() + public async Task WriteSimpleTestClassWithGenericStructCollectionWrappers() { { SimpleTestClassWithGenericStructCollectionWrappers obj = new SimpleTestClassWithGenericStructCollectionWrappers(); obj.Initialize(); - Assert.Equal(SimpleTestClassWithGenericStructCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestClassWithGenericStructCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { @@ -849,17 +850,17 @@ public static void WriteSimpleTestClassWithGenericStructCollectionWrappers() @"""Set"" : []," + @"""Dictionary"" : {}" + @"}"; - Assert.Equal(json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteSimpleTestStructWithNullableGenericStructCollectionWrappers() + public async Task WriteSimpleTestStructWithNullableGenericStructCollectionWrappers() { { SimpleTestStructWithNullableGenericStructCollectionWrappers obj = new SimpleTestStructWithNullableGenericStructCollectionWrappers(); obj.Initialize(); - Assert.Equal(SimpleTestStructWithNullableGenericStructCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestStructWithNullableGenericStructCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { @@ -871,87 +872,87 @@ public static void WriteSimpleTestStructWithNullableGenericStructCollectionWrapp @"""Set"" : null," + @"""Dictionary"" : null" + @"}"; - Assert.Equal(json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void ConvertIEnumerableValueTypesThenSerialize() + public async Task ConvertIEnumerableValueTypesThenSerialize() { IEnumerable valueAs = Enumerable.Range(0, 5).Select(x => new ValueA { Value = x }).ToList(); IEnumerable valueBs = valueAs.Select(x => new ValueB { Value = x.Value }); string expectedJson = @"[{""Value"":0},{""Value"":1},{""Value"":2},{""Value"":3},{""Value"":4}]"; - Assert.Equal(expectedJson, JsonSerializer.Serialize>(valueBs)); + Assert.Equal(expectedJson, await JsonSerializerWrapperForString.SerializeWrapper>(valueBs)); } [Fact] - public static void WriteIEnumerableT_DisposesEnumerators() + public async Task WriteIEnumerableT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var items = new RefCountedList(Enumerable.Range(1, count)); - _ = JsonSerializer.Serialize(items.AsEnumerable()); + _ = await JsonSerializerWrapperForString.SerializeWrapper(items.AsEnumerable()); Assert.Equal(0, items.RefCount); } } [Fact] - public static void WriteICollectionT_DisposesEnumerators() + public async Task WriteICollectionT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var items = new RefCountedList(Enumerable.Range(1, count)); - _ = JsonSerializer.Serialize((ICollection)items); + _ = await JsonSerializerWrapperForString.SerializeWrapper((ICollection)items); Assert.Equal(0, items.RefCount); } } [Fact] - public static void WriteIListT_DisposesEnumerators() + public async Task WriteIListT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var items = new RefCountedList(Enumerable.Range(1, count)); - _ = JsonSerializer.Serialize((IList)items); + _ = await JsonSerializerWrapperForString.SerializeWrapper((IList)items); Assert.Equal(0, items.RefCount); } } [Fact] - public static void WriteIDictionaryT_DisposesEnumerators() + public async Task WriteIDictionaryT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var pairs = new RefCountedDictionary(Enumerable.Range(1, count).Select(x => new KeyValuePair(x, x))); - _ = JsonSerializer.Serialize((IDictionary)pairs); + _ = await JsonSerializerWrapperForString.SerializeWrapper((IDictionary)pairs); Assert.Equal(0, pairs.RefCount); } } [Fact] - public static void WriteIReadOnlyDictionaryT_DisposesEnumerators() + public async Task WriteIReadOnlyDictionaryT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var pairs = new RefCountedDictionary(Enumerable.Range(1, count).Select(x => new KeyValuePair(x, x))); - _ = JsonSerializer.Serialize((IReadOnlyDictionary)pairs); + _ = await JsonSerializerWrapperForString.SerializeWrapper((IReadOnlyDictionary)pairs); Assert.Equal(0, pairs.RefCount); } } [Fact] - public static void WriteISetT_DisposesEnumerators() + public async Task WriteISetT_DisposesEnumerators() { for (int count = 0; count < 5; count++) { var items = new RefCountedSet(Enumerable.Range(1, count)); - _ = JsonSerializer.Serialize((ISet)items); + _ = await JsonSerializerWrapperForString.SerializeWrapper((ISet)items); Assert.Equal(0, items.RefCount); } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Read.cs new file mode 100644 index 0000000000000..ca63692b2b287 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Read.cs @@ -0,0 +1,637 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests + { + [Fact] + public async Task ReadImmutableArrayOfImmutableArray() + { + ImmutableArray> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableArray l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadImmutableArrayOfArray() + { + ImmutableArray result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadArrayOfImmutableArray() + { + ImmutableArray[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableArray l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadSimpleImmutableArray() + { + ImmutableArray result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadSimpleClassWithImmutableArray() + { + SimpleTestClassWithImmutableArray obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithImmutableArray.s_json); + obj.Verify(); + } + + [Fact] + public async Task ReadIImmutableListTOfIImmutableListT() + { + IImmutableList> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (IImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadIImmutableListTOfArray() + { + IImmutableList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadArrayOfIIImmutableListT() + { + IImmutableList[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (IImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadPrimitiveIImmutableListT() + { + IImmutableList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[]")); + } + + [Fact] + public async Task ReadIImmutableStackTOfIImmutableStackT() + { + IImmutableStack> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 4; + + foreach (IImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + } + } + + [Fact] + public async Task ReadIImmutableStackTOfArray() + { + IImmutableStack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[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 async Task ReadArrayOfIIImmutableStackT() + { + IImmutableStack[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 2; + + foreach (IImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + + expected = 4; + } + } + + [Fact] + public async Task ReadPrimitiveIImmutableStackT() + { + IImmutableStack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 2; + + foreach (int i in result) + { + Assert.Equal(expected--, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[]")); + } + + [Fact] + public async Task ReadIImmutableQueueTOfIImmutableQueueT() + { + IImmutableQueue> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (IImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadIImmutableQueueTOfArray() + { + IImmutableQueue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadArrayOfIImmutableQueueT() + { + IImmutableQueue[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (IImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadPrimitiveIImmutableQueueT() + { + IImmutableQueue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[]")); + } + + [Fact] + public async Task ReadIImmutableSetTOfIImmutableSetT() + { + IImmutableSet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (IImmutableSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadIImmutableSetTOfArray() + { + IImmutableSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadArrayOfIImmutableSetT() + { + IImmutableSet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (IImmutableSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadPrimitiveIImmutableSetT() + { + IImmutableSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + List expected = new List { 1, 2 }; + + foreach (int i in result) + { + expected.Remove(i); + } + + Assert.Equal(0, expected.Count); + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"",""2""]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[]")); + } + + [Fact] + public async Task ReadImmutableHashSetTOfImmutableHashSetT() + { + ImmutableHashSet> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (ImmutableHashSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadImmutableHashSetTOfArray() + { + ImmutableHashSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadArrayOfIImmutableHashSetT() + { + ImmutableHashSet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + List expected = new List { 1, 2, 3, 4 }; + + foreach (ImmutableHashSet l in result) + { + foreach (int i in l) + { + expected.Remove(i); + } + } + + Assert.Equal(0, expected.Count); + } + + [Fact] + public async Task ReadPrimitiveImmutableHashSetT() + { + ImmutableHashSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + List expected = new List { 1, 2 }; + + foreach (int i in result) + { + expected.Remove(i); + } + + Assert.Equal(0, expected.Count); + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadImmutableListTOfImmutableListT() + { + ImmutableList> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadImmutableListTOfArray() + { + ImmutableList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadArrayOfIImmutableListT() + { + ImmutableList[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableList l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadPrimitiveImmutableListT() + { + ImmutableList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadImmutableStackTOfImmutableStackT() + { + ImmutableStack> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 4; + + foreach (ImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + } + } + + [Fact] + public async Task ReadImmutableStackTOfArray() + { + ImmutableStack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[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 async Task ReadArrayOfIImmutableStackT() + { + ImmutableStack[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 2; + + foreach (ImmutableStack l in result) + { + foreach (int i in l) + { + Assert.Equal(expected--, i); + } + + expected = 4; + } + } + + [Fact] + public async Task ReadPrimitiveImmutableStackT() + { + ImmutableStack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 2; + + foreach (int i in result) + { + Assert.Equal(expected--, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadImmutableQueueTOfImmutableQueueT() + { + ImmutableQueue> result = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadImmutableQueueTOfArray() + { + ImmutableQueue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (int[] arr in result) + { + foreach (int i in arr) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadArrayOfImmutableQueueT() + { + ImmutableQueue[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableQueue l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadPrimitiveImmutableQueueT() + { + ImmutableQueue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadArrayOfIImmutableSortedSetT() + { + ImmutableSortedSet[] result = await JsonSerializerWrapperForString.DeserializeWrapper[]>(@"[[1,2],[3,4]]"); + int expected = 1; + + foreach (ImmutableSortedSet l in result) + { + foreach (int i in l) + { + Assert.Equal(expected++, i); + } + } + } + + [Fact] + public async Task ReadPrimitiveImmutableSortedSetT() + { + ImmutableSortedSet result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[1,2]"); + int expected = 1; + + foreach (int i in result) + { + Assert.Equal(expected++, i); + } + + result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[]"); + Assert.Equal(0, result.Count()); + } + + [Fact] + public async Task ReadSimpleTestClass_ImmutableCollectionWrappers_Throws() + { + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithIImmutableDictionaryWrapper.s_json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithImmutableListWrapper.s_json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithImmutableStackWrapper.s_json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithImmutableQueueWrapper.s_json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithImmutableSetWrapper.s_json)); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Write.cs similarity index 64% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Write.cs index c994d45de7f54..3f7295f7bb88d 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Write.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Immutable.Write.cs @@ -3,26 +3,27 @@ using System.Collections.Generic; using System.Collections.Immutable; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void WriteImmutableArrayOfImmutableArray() + public async Task WriteImmutableArrayOfImmutableArray() { ImmutableArray> input = ImmutableArray.CreateRange(new List>{ ImmutableArray.CreateRange(new List() { 1, 2 }), ImmutableArray.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteImmutableArrayOfArray() + public async Task WriteImmutableArrayOfArray() { ImmutableArray input = ImmutableArray.CreateRange(new List { @@ -30,44 +31,44 @@ public static void WriteImmutableArrayOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfImmutableArray() + public async Task WriteArrayOfImmutableArray() { ImmutableArray[] input = new ImmutableArray[2]; input[0] = ImmutableArray.CreateRange(new List() { 1, 2 }); input[1] = ImmutableArray.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteSimpleImmutableArray() + public async Task WriteSimpleImmutableArray() { ImmutableArray input = ImmutableArray.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteIImmutableListTOfIImmutableListT() + public async Task WriteIImmutableListTOfIImmutableListT() { IImmutableList> input = ImmutableList.CreateRange(new List>{ ImmutableList.CreateRange(new List() { 1, 2 }), ImmutableList.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteIImmutableListTOfArray() + public async Task WriteIImmutableListTOfArray() { IImmutableList input = ImmutableList.CreateRange(new List { @@ -75,67 +76,67 @@ public static void WriteIImmutableListTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteSimpleClassWithImmutableArray() + public async Task WriteSimpleClassWithImmutableArray() { SimpleTestClassWithImmutableArray obj = new SimpleTestClassWithImmutableArray(); obj.Initialize(); - Assert.Equal(SimpleTestClassWithImmutableArray.s_json, JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestClassWithImmutableArray.s_json, await JsonSerializerWrapperForString.SerializeWrapper(obj)); } [Fact] - public static void WriteSimpleClassWithObjectImmutableArray() + public async Task WriteSimpleClassWithObjectImmutableArray() { SimpleTestClassWithObjectImmutableArray obj = new SimpleTestClassWithObjectImmutableArray(); obj.Initialize(); - Assert.Equal(SimpleTestClassWithObjectImmutableArray.s_json, JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestClassWithObjectImmutableArray.s_json, await JsonSerializerWrapperForString.SerializeWrapper(obj)); } [Fact] - public static void WriteArrayOfIImmutableListT() + public async Task WriteArrayOfIImmutableListT() { IImmutableList[] input = new IImmutableList[2]; input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIImmutableListT() + public async Task WritePrimitiveIImmutableListT() { IImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); StringIImmutableListWrapper input2 = new StringIImmutableListWrapper(new List { "1", "2" }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[""1"",""2""]", json); } [Fact] - public static void WriteIImmutableStackTOfIImmutableStackT() + public async Task WriteIImmutableStackTOfIImmutableStackT() { IImmutableStack> input = ImmutableStack.CreateRange(new List>{ ImmutableStack.CreateRange(new List() { 1, 2 }), ImmutableStack.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[4,3],[2,1]]", json); } [Fact] - public static void WriteIImmutableStackTOfArray() + public async Task WriteIImmutableStackTOfArray() { IImmutableStack input = ImmutableStack.CreateRange(new List { @@ -143,49 +144,49 @@ public static void WriteIImmutableStackTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[3,4],[1,2]]", json); } [Fact] - public static void WriteArrayOfIImmutableStackT() + public async Task WriteArrayOfIImmutableStackT() { IImmutableStack[] input = new IImmutableStack[2]; input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[2,1],[4,3]]", json); } [Fact] - public static void WritePrimitiveIImmutableStackT() + public async Task WritePrimitiveIImmutableStackT() { IImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[2,1]", json); StringIImmutableStackWrapper input2 = new StringIImmutableStackWrapper(new List { "1", "2" }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[""2"",""1""]", json); } [Fact] - public static void WriteIImmutableQueueTOfIImmutableQueueT() + public async Task WriteIImmutableQueueTOfIImmutableQueueT() { IImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ ImmutableQueue.CreateRange(new List() { 1, 2 }), ImmutableQueue.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteIImmutableQueueTOfArray() + public async Task WriteIImmutableQueueTOfArray() { IImmutableQueue input = ImmutableQueue.CreateRange(new List { @@ -193,50 +194,50 @@ public static void WriteIImmutableQueueTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIImmutableQueueT() + public async Task WriteArrayOfIImmutableQueueT() { IImmutableQueue[] input = new IImmutableQueue[2]; input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIImmutableQueueT() + public async Task WritePrimitiveIImmutableQueueT() { IImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); StringIImmutableQueueWrapper input2 = new StringIImmutableQueueWrapper(new List { "1", "2" }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal(@"[""1"",""2""]", json); } [Fact] - public static void WriteIImmutableSetTOfIImmutableSetT() + public async Task WriteIImmutableSetTOfIImmutableSetT() { IImmutableSet> input = ImmutableHashSet.CreateRange(new List>{ ImmutableHashSet.CreateRange(new List() { 1, 2 }), ImmutableHashSet.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] - public static void WriteIImmutableSetTOfArray() + public async Task WriteIImmutableSetTOfArray() { IImmutableSet input = ImmutableHashSet.CreateRange(new List { @@ -244,51 +245,51 @@ public static void WriteIImmutableSetTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] - public static void WriteArrayOfIImmutableSetT() + public async Task WriteArrayOfIImmutableSetT() { IImmutableSet[] input = new IImmutableSet[2]; input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIImmutableSetT() + public async Task WritePrimitiveIImmutableSetT() { IImmutableSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); StringIImmutableSetWrapper input2 = new StringIImmutableSetWrapper(new List { "1", "2" }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.True(json == @"[""1"",""2""]" || json == @"[""2"",""1""]"); } [Fact] - public static void WriteImmutableHashSetTOfImmutableHashSetT() + public async Task WriteImmutableHashSetTOfImmutableHashSetT() { ImmutableHashSet> input = ImmutableHashSet.CreateRange(new List>{ ImmutableHashSet.CreateRange(new List() { 1, 2 }), ImmutableHashSet.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] - public static void WriteImmutableHashSetTOfArray() + public async Task WriteImmutableHashSetTOfArray() { ImmutableHashSet input = ImmutableHashSet.CreateRange(new List { @@ -296,45 +297,45 @@ public static void WriteImmutableHashSetTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Contains("[1,2]", json); Assert.Contains("[3,4]", json); } [Fact] - public static void WriteArrayOfImmutableHashSetT() + public async Task WriteArrayOfImmutableHashSetT() { ImmutableHashSet[] input = new ImmutableHashSet[2]; input[0] = ImmutableHashSet.CreateRange(new List() { 1, 2 }); input[1] = ImmutableHashSet.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveImmutableHashSetT() + public async Task WritePrimitiveImmutableHashSetT() { ImmutableHashSet input = ImmutableHashSet.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteImmutableListTOfImmutableListT() + public async Task WriteImmutableListTOfImmutableListT() { ImmutableList> input = ImmutableList.CreateRange(new List>{ ImmutableList.CreateRange(new List() { 1, 2 }), ImmutableList.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteImmutableListTOfArray() + public async Task WriteImmutableListTOfArray() { ImmutableList input = ImmutableList.CreateRange(new List { @@ -342,44 +343,44 @@ public static void WriteImmutableListTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfImmutableListT() + public async Task WriteArrayOfImmutableListT() { ImmutableList[] input = new ImmutableList[2]; input[0] = ImmutableList.CreateRange(new List() { 1, 2 }); input[1] = ImmutableList.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveImmutableListT() + public async Task WritePrimitiveImmutableListT() { ImmutableList input = ImmutableList.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteImmutableStackTOfImmutableStackT() + public async Task WriteImmutableStackTOfImmutableStackT() { ImmutableStack> input = ImmutableStack.CreateRange(new List>{ ImmutableStack.CreateRange(new List() { 1, 2 }), ImmutableStack.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[4,3],[2,1]]", json); } [Fact] - public static void WriteImmutableStackTOfArray() + public async Task WriteImmutableStackTOfArray() { ImmutableStack input = ImmutableStack.CreateRange(new List { @@ -387,44 +388,44 @@ public static void WriteImmutableStackTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[3,4],[1,2]]", json); } [Fact] - public static void WriteArrayOfImmutableStackT() + public async Task WriteArrayOfImmutableStackT() { ImmutableStack[] input = new ImmutableStack[2]; input[0] = ImmutableStack.CreateRange(new List() { 1, 2 }); input[1] = ImmutableStack.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[2,1],[4,3]]", json); } [Fact] - public static void WritePrimitiveImmutableStackT() + public async Task WritePrimitiveImmutableStackT() { ImmutableStack input = ImmutableStack.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[2,1]", json); } [Fact] - public static void WriteImmutableQueueTOfImmutableQueueT() + public async Task WriteImmutableQueueTOfImmutableQueueT() { ImmutableQueue> input = ImmutableQueue.CreateRange(new List>{ ImmutableQueue.CreateRange(new List() { 1, 2 }), ImmutableQueue.CreateRange(new List() { 3, 4 }) }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteImmutableQueueTOfArray() + public async Task WriteImmutableQueueTOfArray() { ImmutableQueue input = ImmutableQueue.CreateRange(new List { @@ -432,52 +433,52 @@ public static void WriteImmutableQueueTOfArray() new int[] { 3, 4 } }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfImmutableQueueT() + public async Task WriteArrayOfImmutableQueueT() { ImmutableQueue[] input = new ImmutableQueue[2]; input[0] = ImmutableQueue.CreateRange(new List() { 1, 2 }); input[1] = ImmutableQueue.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveImmutableQueueT() + public async Task WritePrimitiveImmutableQueueT() { ImmutableQueue input = ImmutableQueue.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteArrayOfImmutableSortedSetT() + public async Task WriteArrayOfImmutableSortedSetT() { ImmutableSortedSet[] input = new ImmutableSortedSet[2]; input[0] = ImmutableSortedSet.CreateRange(new List() { 1, 2 }); input[1] = ImmutableSortedSet.CreateRange(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveImmutableSortedSetT() + public async Task WritePrimitiveImmutableSortedSetT() { ImmutableSortedSet input = ImmutableSortedSet.CreateRange(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteImmutableCollectionWrappers() + public async Task WriteImmutableCollectionWrappers() { SimpleTestClassWithIImmutableDictionaryWrapper obj1 = new SimpleTestClassWithIImmutableDictionaryWrapper(); SimpleTestClassWithImmutableListWrapper obj2 = new SimpleTestClassWithImmutableListWrapper(); @@ -491,20 +492,20 @@ public static void WriteImmutableCollectionWrappers() obj4.Initialize(); obj5.Initialize(); - Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); + Assert.Equal(SimpleTestClassWithIImmutableDictionaryWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); - Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); + Assert.Equal(SimpleTestClassWithImmutableListWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); - Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); + Assert.Equal(SimpleTestClassWithImmutableStackWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); - Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); + Assert.Equal(SimpleTestClassWithImmutableQueueWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); - Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); + Assert.Equal(SimpleTestClassWithImmutableSetWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.KeyValuePair.cs similarity index 68% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.KeyValuePair.cs index c016b5caaf2cb..2fec3ce973839 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.KeyValuePair.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.KeyValuePair.cs @@ -3,29 +3,31 @@ using System.Collections.Generic; using System.Text.Encodings.Web; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests +#if !BUILDING_SOURCE_GENERATOR_TESTS + public abstract partial class CollectionTests { [Fact] - public static void ReadSimpleKeyValuePairFail() + public async Task ReadSimpleKeyValuePairFail() { // Invalid form: no Value - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": 123}")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"": 123}")); // Invalid form: extra property - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Value"": 123, ""Value2"": 456}")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"": ""Key"", ""Value"": 123, ""Value2"": 456}")); // Invalid form: does not contain both Key and Value properties - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""Key"": ""Key"", ""Val"": 123")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"": ""Key"", ""Val"": 123")); } [Fact] - public static void ReadListOfKeyValuePair() + public async Task ReadListOfKeyValuePair() { - List> input = JsonSerializer.Deserialize>>(@"[{""Key"": ""123"", ""Value"": 123},{""Key"": ""456"", ""Value"": 456}]"); + List> input = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"[{""Key"": ""123"", ""Value"": 123},{""Key"": ""456"", ""Value"": 456}]"); Assert.Equal(2, input.Count); Assert.Equal("123", input[0].Key); @@ -35,9 +37,9 @@ public static void ReadListOfKeyValuePair() } [Fact] - public static void ReadKeyValuePairOfList() + public async Task ReadKeyValuePairOfList() { - KeyValuePair> input = JsonSerializer.Deserialize>>(@"{""Key"":""Key"", ""Value"":[1, 2, 3]}"); + KeyValuePair> input = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"{""Key"":""Key"", ""Value"":[1, 2, 3]}"); Assert.Equal("Key", input.Key); Assert.Equal(3, input.Value.Count); @@ -51,9 +53,9 @@ public static void ReadKeyValuePairOfList() [InlineData(@"{""Key"":""Key"", ""Value"":{""Value"":2, ""Key"":1}}")] [InlineData(@"{""Value"":{""Key"":1, ""Value"":2}, ""Key"":""Key""}")] [InlineData(@"{""Value"":{""Value"":2, ""Key"":1}, ""Key"":""Key""}")] - public static void ReadKeyValuePairOfKeyValuePair(string json) + public async Task ReadKeyValuePairOfKeyValuePair(string json) { - KeyValuePair> input = JsonSerializer.Deserialize>>(json); + KeyValuePair> input = await JsonSerializerWrapperForString.DeserializeWrapper>>(json); Assert.Equal("Key", input.Key); Assert.Equal(1, input.Value.Key); @@ -61,42 +63,42 @@ public static void ReadKeyValuePairOfKeyValuePair(string json) } [Fact] - public static void ReadKeyValuePairWithNullValues() + public async Task ReadKeyValuePairWithNullValues() { { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"":""key"",""Value"":null}"); Assert.Equal("key", kvp.Key); Assert.Null(kvp.Value); } { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"":""key"",""Value"":null}"); Assert.Equal("key", kvp.Key); Assert.Null(kvp.Value); } { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":""key"",""Value"":null}"); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"":""key"",""Value"":null}"); Assert.Equal("key", kvp.Key); Assert.Null(kvp.Value); } { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + KeyValuePair> kvp = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); Assert.Equal("key", kvp.Key); Assert.Equal("key", kvp.Value.Key); Assert.Null(kvp.Value.Value); } { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + KeyValuePair> kvp = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); Assert.Equal("key", kvp.Key); Assert.Equal("key", kvp.Value.Key); Assert.Null(kvp.Value.Value); } { - KeyValuePair> kvp = JsonSerializer.Deserialize>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); + KeyValuePair> kvp = await JsonSerializerWrapperForString.DeserializeWrapper>>(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}"); Assert.Equal("key", kvp.Key); Assert.Equal("key", kvp.Value.Key); Assert.Null(kvp.Value.Value); @@ -104,7 +106,7 @@ public static void ReadKeyValuePairWithNullValues() } [Fact] - public static void ReadClassWithNullKeyValuePairValues() + public async Task ReadClassWithNullKeyValuePairValues() { string json = @"{" + @@ -142,7 +144,7 @@ public static void ReadClassWithNullKeyValuePairValues() @"}" + @"}" + @"}"; - SimpleClassWithKeyValuePairs obj = JsonSerializer.Deserialize(json); + SimpleClassWithKeyValuePairs obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("key", obj.KvpWStrVal.Key); Assert.Equal("key", obj.KvpWObjVal.Key); @@ -163,24 +165,24 @@ public static void ReadClassWithNullKeyValuePairValues() } [Fact] - public static void Kvp_NullKeyIsFine() + public async Task Kvp_NullKeyIsFine() { - KeyValuePair kvp = JsonSerializer.Deserialize>(@"{""Key"":null,""Value"":null}"); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""Key"":null,""Value"":null}"); Assert.Null(kvp.Key); Assert.Null(kvp.Value); } [Fact] - public static void WritePrimitiveKeyValuePair() + public async Task WritePrimitiveKeyValuePair() { KeyValuePair input = new KeyValuePair("Key", 123); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal(@"{""Key"":""Key"",""Value"":123}", json); } [Fact] - public static void WriteListOfKeyValuePair() + public async Task WriteListOfKeyValuePair() { List> input = new List> { @@ -188,65 +190,65 @@ public static void WriteListOfKeyValuePair() new KeyValuePair("456", 456) }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal(@"[{""Key"":""123"",""Value"":123},{""Key"":""456"",""Value"":456}]", json); } [Fact] - public static void WriteKeyValuePairOfList() + public async Task WriteKeyValuePairOfList() { KeyValuePair> input = new KeyValuePair>("Key", new List { 1, 2, 3 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal(@"{""Key"":""Key"",""Value"":[1,2,3]}", json); } [Fact] - public static void WriteKeyValuePairOfKeyValuePair() + public async Task WriteKeyValuePairOfKeyValuePair() { KeyValuePair> input = new KeyValuePair>( "Key", new KeyValuePair("Key", 1)); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal(@"{""Key"":""Key"",""Value"":{""Key"":""Key"",""Value"":1}}", json); } [Fact] - public static void WriteKeyValuePairWithNullValues() + public async Task WriteKeyValuePairWithNullValues() { { KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } { KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } { KeyValuePair kvp = new KeyValuePair("key", null); - Assert.Equal(@"{""Key"":""key"",""Value"":null}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":null}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } { KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } { KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } { KeyValuePair> kvp = new KeyValuePair>("key", new KeyValuePair("key", null)); - Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", JsonSerializer.Serialize(kvp)); + Assert.Equal(@"{""Key"":""key"",""Value"":{""Key"":""key"",""Value"":null}}", await JsonSerializerWrapperForString.SerializeWrapper(kvp)); } } [Fact] - public static void WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject() + public async Task WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject() { var value = new SimpleClassWithKeyValuePairs() { @@ -258,10 +260,10 @@ public static void WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject KvpWClassKvpVal = new KeyValuePair>("key", new KeyValuePair("key", null)), }; - string result = JsonSerializer.Serialize(value); + string result = await JsonSerializerWrapperForString.SerializeWrapper(value); // Roundtrip to ensure serialize was correct. - value = JsonSerializer.Deserialize(result); + value = await JsonSerializerWrapperForString.DeserializeWrapper(result); Assert.Equal("key", value.KvpWStrVal.Key); Assert.Equal("key", value.KvpWObjVal.Key); Assert.Equal("key", value.KvpWClassVal.Key); @@ -281,7 +283,7 @@ public static void WriteClassWithNullKeyValuePairValues_NullWrittenAsEmptyObject } [Fact] - public static void HonorNamingPolicy() + public async Task HonorNamingPolicy() { var kvp = new KeyValuePair("Hello, World!", 1); @@ -290,22 +292,22 @@ public static void HonorNamingPolicy() PropertyNamingPolicy = new LeadingUnderscorePolicy() }; - string serialized = JsonSerializer.Serialize(kvp, options); + string serialized = await JsonSerializerWrapperForString.SerializeWrapper(kvp, options); // We know serializer writes the key first. Assert.Equal(@"{""_Key"":""Hello, World!"",""_Value"":1}", serialized); - kvp = JsonSerializer.Deserialize>(serialized, options); + kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(serialized, options); Assert.Equal("Hello, World!", kvp.Key); Assert.Equal(1, kvp.Value); } [Fact] - public static void HonorNamingPolicy_CaseInsensitive() + public async Task HonorNamingPolicy_CaseInsensitive() { const string json = @"{""key"":""Hello, World!"",""value"":1}"; // Baseline - with case-sensitive matching, the payload doesn't have mapping properties. - Assert.Throws(() => JsonSerializer.Deserialize>(json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json)); // Test - with case-insensitivity on, we have property matches. var options = new JsonSerializerOptions @@ -313,13 +315,13 @@ public static void HonorNamingPolicy_CaseInsensitive() PropertyNameCaseInsensitive = true }; - KeyValuePair kvp = JsonSerializer.Deserialize>(json, options); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(json, options); Assert.Equal("Hello, World!", kvp.Key); Assert.Equal(1, kvp.Value); } [Fact] - public static void HonorCLRProperties() + public async Task HonorCLRProperties() { var options = new JsonSerializerOptions { @@ -330,13 +332,13 @@ public static void HonorCLRProperties() // "Key" and "Value" are special cased to accomodate content serialized with previous // versions of the serializer (.NET Core 3.x/System.Text.Json 4.7.x). string json = @"{""Key"":""Hello, World!"",""Value"":1}"; - KeyValuePair kvp = JsonSerializer.Deserialize>(json, options); + KeyValuePair kvp = await JsonSerializerWrapperForString.DeserializeWrapper>(json, options); Assert.Equal("Hello, World!", kvp.Key); Assert.Equal(1, kvp.Value); // "Key" and "Value" matching is case sensitive. json = @"{""key"":""Hello, World!"",""value"":1}"; - Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json, options)); // "Key" and "Value" matching is case sensitive, even when case insensitivity is on. // Case sensitivity only applies to the result of converting the CLR property names @@ -347,7 +349,7 @@ public static void HonorCLRProperties() PropertyNameCaseInsensitive = true }; - Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json, options)); } private class LeadingUnderscorePolicy : JsonNamingPolicy @@ -356,7 +358,7 @@ private class LeadingUnderscorePolicy : JsonNamingPolicy } [Fact] - public static void HonorCustomEncoder() + public async Task HonorCustomEncoder() { var kvp = new KeyValuePair(1, 2); @@ -368,7 +370,7 @@ public static void HonorCustomEncoder() PropertyNamingPolicy = namingPolicy, }; - Assert.Equal(@"{""Key\u003C"":1,""Value\u003C"":2}", JsonSerializer.Serialize(kvp, options)); + Assert.Equal(@"{""Key\u003C"":1,""Value\u003C"":2}", await JsonSerializerWrapperForString.SerializeWrapper(kvp, options)); // Test - serializer honors custom encoder. options = new JsonSerializerOptions @@ -377,7 +379,7 @@ public static void HonorCustomEncoder() Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; - Assert.Equal(@"{""Key<"":1,""Value<"":2}", JsonSerializer.Serialize(kvp, options)); + Assert.Equal(@"{""Key<"":1,""Value<"":2}", await JsonSerializerWrapperForString.SerializeWrapper(kvp, options)); } private class TrailingAngleBracketPolicy : JsonNamingPolicy @@ -388,18 +390,18 @@ private class TrailingAngleBracketPolicy : JsonNamingPolicy [Theory] [InlineData(typeof(KeyNameNullPolicy), "Key")] [InlineData(typeof(ValueNameNullPolicy), "Value")] - public static void InvalidPropertyNameFail(Type policyType, string offendingProperty) + public async Task InvalidPropertyNameFail(Type policyType, string offendingProperty) { var options = new JsonSerializerOptions { PropertyNamingPolicy = (JsonNamingPolicy)Activator.CreateInstance(policyType) }; - InvalidOperationException ex = Assert.Throws(() => JsonSerializer.Deserialize>("", options)); + InvalidOperationException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>("", options)); string exAsStr = ex.ToString(); Assert.Contains(offendingProperty, exAsStr); - Assert.Throws(() => JsonSerializer.Serialize(new KeyValuePair("", ""), options)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(new KeyValuePair("", ""), options)); } private class KeyNameNullPolicy : JsonNamingPolicy @@ -432,9 +434,9 @@ private class ValueNameNullPolicy : JsonNamingPolicy [InlineData(@"{""Value"":1,""Value"":1}")] [InlineData(@"{""Value"":1,null:1}")] [InlineData(@"{""Value"":1,""Value"":2}")] - public static void InvalidJsonFail(string json) + public async Task InvalidJsonFail(string json) { - Assert.Throws(() => JsonSerializer.Deserialize>(json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json)); } [Theory] @@ -445,34 +447,35 @@ public static void InvalidJsonFail(string json) [InlineData(@"{""Extra"":3,""Key"":1,""Value"":2}", "$.Extra")] [InlineData(@"{""Key"":1,""Extra"":3,""Value"":2}", "$.Extra")] [InlineData(@"{""Key"":1,""Value"":2,""Extra"":3}", "$.Extra")] - public static void JsonPathIsAccurate(string json, string expectedPath) + public async Task JsonPathIsAccurate(string json, string expectedPath) { - JsonException ex = Assert.Throws(() => JsonSerializer.Deserialize>(json)); + JsonException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json)); Assert.Contains(expectedPath, ex.ToString()); var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - ex = Assert.Throws(() => JsonSerializer.Deserialize>(json)); + ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json)); Assert.Contains(expectedPath, ex.ToString()); } [Theory] [InlineData(@"{""kEy"":""1"",""vAlUe"":2}", "$.kEy")] [InlineData(@"{""kEy"":1,""vAlUe"":""2""}", "$.vAlUe")] - public static void JsonPathIsAccurate_CaseInsensitive(string json, string expectedPath) + public async Task JsonPathIsAccurate_CaseInsensitive(string json, string expectedPath) { var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - JsonException ex = Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + JsonException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json, options)); Assert.Contains(expectedPath, ex.ToString()); } [Theory] [InlineData(@"{""_Key"":""1"",""_Value"":2}", "$._Key")] [InlineData(@"{""_Key"":1,""_Value"":""2""}", "$._Value")] - public static void JsonPathIsAccurate_PropertyNamingPolicy(string json, string expectedPath) + public async Task JsonPathIsAccurate_PropertyNamingPolicy(string json, string expectedPath) { var options = new JsonSerializerOptions { PropertyNamingPolicy = new LeadingUnderscorePolicy() }; - JsonException ex = Assert.Throws(() => JsonSerializer.Deserialize>(json, options)); + JsonException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(json, options)); Assert.Contains(expectedPath, ex.ToString()); } } +#endif } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Read.cs similarity index 59% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Read.cs index 1f32ab0b80fe7..4187cefde1a01 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Read.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Read.cs @@ -3,16 +3,17 @@ using System.Collections; using System.Collections.Generic; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void ReadGenericIEnumerableOfIEnumerable() + public async Task ReadGenericIEnumerableOfIEnumerable() { - IEnumerable result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IEnumerable ie in result) @@ -24,13 +25,13 @@ public static void ReadGenericIEnumerableOfIEnumerable() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]")); } [Fact] - public static void ReadIEnumerableOfArray() + public async Task ReadIEnumerableOfArray() { - IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (JsonElement arr in result) @@ -43,9 +44,9 @@ public static void ReadIEnumerableOfArray() } [Fact] - public static void ReadArrayOfIEnumerable() + public async Task ReadArrayOfIEnumerable() { - IEnumerable[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IEnumerable[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (IEnumerable arr in result) @@ -58,9 +59,9 @@ public static void ReadArrayOfIEnumerable() } [Fact] - public static void ReadPrimitiveIEnumerable() + public async Task ReadPrimitiveIEnumerable() { - IEnumerable result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + IEnumerable result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 1; foreach (JsonElement i in result) @@ -68,7 +69,7 @@ public static void ReadPrimitiveIEnumerable() Assert.Equal(expected++, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -80,9 +81,9 @@ public static void ReadPrimitiveIEnumerable() } [Fact] - public static void ReadGenericIListOfIList() + public async Task ReadGenericIListOfIList() { - IList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (IList list in result) @@ -93,7 +94,7 @@ public static void ReadGenericIListOfIList() } } - GenericIListWrapper result2 = JsonSerializer.Deserialize>(@"[[1,2],[3,4]]"); + GenericIListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); expected = 1; foreach (WrapperForIList list in result2) @@ -106,9 +107,9 @@ public static void ReadGenericIListOfIList() } [Fact] - public static void ReadIListOfArray() + public async Task ReadIListOfArray() { - IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (JsonElement arr in result) @@ -121,9 +122,9 @@ public static void ReadIListOfArray() } [Fact] - public static void ReadArrayOfIList() + public async Task ReadArrayOfIList() { - IList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + IList[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (IList arr in result) @@ -136,20 +137,20 @@ public static void ReadArrayOfIList() } [Fact] - public static void ReadStructIList() + public async Task ReadStructIList() { string json = @"[""a"",20]"; - var wrapper = JsonSerializer.Deserialize(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, wrapper.Count); Assert.Equal("a", ((JsonElement)wrapper[0]).GetString()); Assert.Equal(20, ((JsonElement)wrapper[1]).GetInt32()); } [Fact] - public static void ReadNullableStructIList() + public async Task ReadNullableStructIList() { string json = @"[""a"",20]"; - var wrapper = JsonSerializer.Deserialize(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.True(wrapper.HasValue); Assert.Equal(2, wrapper.Value.Count); Assert.Equal("a", ((JsonElement)wrapper.Value[0]).GetString()); @@ -157,54 +158,54 @@ public static void ReadNullableStructIList() } [Fact] - public static void ReadNullableStructIListWithNullJson() + public async Task ReadNullableStructIListWithNullJson() { - var wrapper = JsonSerializer.Deserialize("null"); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper("null"); Assert.False(wrapper.HasValue); } [Fact] - public static void ReadClassWithStructIListWrapper_NullJson_Throws() + public async Task ReadClassWithStructIListWrapper_NullJson_Throws() { string json = @"{ ""List"" : null }"; - Assert.Throws(() => JsonSerializer.Deserialize(json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); } [Fact] - public static void ReadStructIDictionary() + public async Task ReadStructIDictionary() { string json = @"{""Key"":""Value""}"; - var wrapper = JsonSerializer.Deserialize(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal("Value", wrapper["Key"].ToString()); } [Fact] - public static void ReadNullableStructIDictionary() + public async Task ReadNullableStructIDictionary() { string json = @"{""Key"":""Value""}"; - var wrapper = JsonSerializer.Deserialize(json); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.True(wrapper.HasValue); Assert.Equal("Value", wrapper.Value["Key"].ToString()); } [Fact] - public static void ReadNullableStructIDictionaryWithNullJson() + public async Task ReadNullableStructIDictionaryWithNullJson() { - var wrapper = JsonSerializer.Deserialize("null"); + var wrapper = await JsonSerializerWrapperForString.DeserializeWrapper("null"); Assert.False(wrapper.HasValue); } [Fact] - public static void ReadClassWithStructIDictionaryWrapper_NullJson_Throws() + public async Task ReadClassWithStructIDictionaryWrapper_NullJson_Throws() { string json = @"{ ""Dictionary"" : null }"; - Assert.Throws(() => JsonSerializer.Deserialize(json)); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json)); } [Fact] - public static void ReadPrimitiveIList() + public async Task ReadPrimitiveIList() { - IList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + IList result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 1; foreach (JsonElement i in result) @@ -212,7 +213,7 @@ public static void ReadPrimitiveIList() Assert.Equal(expected++, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -222,7 +223,7 @@ public static void ReadPrimitiveIList() } Assert.Equal(0, count); - WrapperForIList result2 = JsonSerializer.Deserialize(@"[1,2]"); + WrapperForIList result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); expected = 1; foreach (JsonElement i in result2) @@ -232,9 +233,9 @@ public static void ReadPrimitiveIList() } [Fact] - public static void ReadGenericICollectionOfICollection() + public async Task ReadGenericICollectionOfICollection() { - ICollection result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (ICollection ie in result) @@ -246,13 +247,13 @@ public static void ReadGenericICollectionOfICollection() } // No way to populate this collection. - Assert.Throws(() => JsonSerializer.Deserialize>(@"[[1,2],[3,4]]")); + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]")); } [Fact] - public static void ReadICollectionOfArray() + public async Task ReadICollectionOfArray() { - ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (JsonElement arr in result) @@ -265,9 +266,9 @@ public static void ReadICollectionOfArray() } [Fact] - public static void ReadArrayOfICollection() + public async Task ReadArrayOfICollection() { - ICollection[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ICollection[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (ICollection arr in result) @@ -280,9 +281,9 @@ public static void ReadArrayOfICollection() } [Fact] - public static void ReadPrimitiveICollection() + public async Task ReadPrimitiveICollection() { - ICollection result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + ICollection result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 1; foreach (JsonElement i in result) @@ -290,7 +291,7 @@ public static void ReadPrimitiveICollection() Assert.Equal(expected++, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -302,9 +303,9 @@ public static void ReadPrimitiveICollection() } [Fact] - public static void ReadGenericStackOfStack() + public async Task ReadGenericStackOfStack() { - Stack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 4; foreach (Stack stack in result) @@ -317,9 +318,9 @@ public static void ReadGenericStackOfStack() } [Fact] - public static void ReadStackOfArray() + public async Task ReadStackOfArray() { - Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 3; foreach (JsonElement arr in result) @@ -333,9 +334,9 @@ public static void ReadStackOfArray() } [Fact] - public static void ReadArrayOfStack() + public async Task ReadArrayOfStack() { - Stack[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Stack[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 2; foreach (Stack arr in result) @@ -349,9 +350,9 @@ public static void ReadArrayOfStack() } [Fact] - public static void ReadPrimitiveStack() + public async Task ReadPrimitiveStack() { - Stack result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + Stack result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 2; foreach (JsonElement i in result) @@ -359,7 +360,7 @@ public static void ReadPrimitiveStack() Assert.Equal(expected--, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -379,9 +380,9 @@ public static void ReadPrimitiveStack() } [Fact] - public static void ReadGenericQueueOfQueue() + public async Task ReadGenericQueueOfQueue() { - Queue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue result = await JsonSerializerWrapperForString.DeserializeWrapper>(@"[[1,2],[3,4]]"); int expected = 1; foreach (Queue ie in result) @@ -394,9 +395,9 @@ public static void ReadGenericQueueOfQueue() } [Fact] - public static void ReadQueueOfArray() + public async Task ReadQueueOfArray() { - Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (JsonElement arr in result) @@ -409,9 +410,9 @@ public static void ReadQueueOfArray() } [Fact] - public static void ReadArrayOfQueue() + public async Task ReadArrayOfQueue() { - Queue[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + Queue[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (Queue arr in result) @@ -424,9 +425,9 @@ public static void ReadArrayOfQueue() } [Fact] - public static void ReadPrimitiveQueue() + public async Task ReadPrimitiveQueue() { - Queue result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + Queue result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 1; foreach (JsonElement i in result) @@ -434,7 +435,7 @@ public static void ReadPrimitiveQueue() Assert.Equal(expected++, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -444,7 +445,7 @@ public static void ReadPrimitiveQueue() } Assert.Equal(0, count); - QueueWrapper wrapper = JsonSerializer.Deserialize(@"[1,2]"); + QueueWrapper wrapper = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); expected = 1; foreach (JsonElement i in wrapper) @@ -454,9 +455,9 @@ public static void ReadPrimitiveQueue() } [Fact] - public static void ReadArrayListOfArray() + public async Task ReadArrayListOfArray() { - ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ArrayList result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (JsonElement arr in result) @@ -467,7 +468,7 @@ public static void ReadArrayListOfArray() } } - ArrayListWrapper result2 = JsonSerializer.Deserialize(@"[[1,2],[3,4]]"); + ArrayListWrapper result2 = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); expected = 1; foreach (JsonElement arr in result2) @@ -480,9 +481,9 @@ public static void ReadArrayListOfArray() } [Fact] - public static void ReadArrayOfArrayList() + public async Task ReadArrayOfArrayList() { - ArrayList[] result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); + ArrayList[] result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[[1,2],[3,4]]"); int expected = 1; foreach (ArrayList arr in result) @@ -495,9 +496,9 @@ public static void ReadArrayOfArrayList() } [Fact] - public static void ReadPrimitiveArrayList() + public async Task ReadPrimitiveArrayList() { - ArrayList result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[1,2]")); + ArrayList result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[1,2]"); int expected = 1; foreach (JsonElement i in result) @@ -505,7 +506,7 @@ public static void ReadPrimitiveArrayList() Assert.Equal(expected++, i.GetInt32()); } - result = JsonSerializer.Deserialize(Encoding.UTF8.GetBytes(@"[]")); + result = await JsonSerializerWrapperForString.DeserializeWrapper(@"[]"); int count = 0; IEnumerator e = result.GetEnumerator(); @@ -517,24 +518,24 @@ public static void ReadPrimitiveArrayList() } [Fact] - public static void ReadSimpleTestClass_NonGenericCollectionWrappers() + public async Task ReadSimpleTestClass_NonGenericCollectionWrappers() { - SimpleTestClassWithNonGenericCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithNonGenericCollectionWrappers.s_json); + SimpleTestClassWithNonGenericCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithNonGenericCollectionWrappers.s_json); obj.Verify(); } [Fact] - public static void ReadSimpleTestClass_StructCollectionWrappers() + public async Task ReadSimpleTestClass_StructCollectionWrappers() { - SimpleTestClassWithStructCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestClassWithStructCollectionWrappers.s_json); + SimpleTestClassWithStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestClassWithStructCollectionWrappers.s_json); obj.Verify(); } [Fact] - public static void ReadSimpleTestStruct_NullableStructCollectionWrappers() + public async Task ReadSimpleTestStruct_NullableStructCollectionWrappers() { { - SimpleTestStructWithNullableStructCollectionWrappers obj = JsonSerializer.Deserialize(SimpleTestStructWithNullableStructCollectionWrappers.s_json); + SimpleTestStructWithNullableStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(SimpleTestStructWithNullableStructCollectionWrappers.s_json); obj.Verify(); } @@ -545,7 +546,7 @@ public static void ReadSimpleTestStruct_NullableStructCollectionWrappers() @"""Dictionary"" : null" + @"}"; - SimpleTestStructWithNullableStructCollectionWrappers obj = JsonSerializer.Deserialize(json); + SimpleTestStructWithNullableStructCollectionWrappers obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.False(obj.List.HasValue); Assert.False(obj.Dictionary.HasValue); } @@ -553,9 +554,9 @@ public static void ReadSimpleTestStruct_NullableStructCollectionWrappers() [Theory] [MemberData(nameof(ReadSimpleTestClass_NonGenericWrappers_NoAddMethod))] - public static void ReadSimpleTestClass_NonGenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) + public async Task ReadSimpleTestClass_NonGenericWrappers_NoAddMethod_Throws(Type type, string json, Type exceptionMessageType) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); Assert.Contains(exceptionMessageType.ToString(), ex.Message); } @@ -587,9 +588,9 @@ public static IEnumerable ReadSimpleTestClass_NonGenericWrappers_NoAdd [InlineData(typeof(WrapperForIListInternalConstructor), @"[""1""]")] [InlineData(typeof(WrapperForIDictionaryPrivateConstructor), @"{""Key"":""Value""}")] [InlineData(typeof(WrapperForIDictionaryInternalConstructor), @"{""Key"":""Value""}")] - public static void Read_NonGeneric_NoPublicConstructor_Throws(Type type, string json) + public async Task Read_NonGeneric_NoPublicConstructor_Throws(Type type, string json) { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); + NotSupportedException ex = await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(json, type)); Assert.Contains(type.ToString(), ex.Message); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Write.cs similarity index 64% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Write.cs index f626437f4baf9..4c4fd353047f3 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.NonGeneric.Write.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.NonGeneric.Write.cs @@ -3,14 +3,15 @@ using System.Collections; using System.Collections.Generic; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void WriteIEnumerableOfIEnumerable() + public async Task WriteIEnumerableOfIEnumerable() { IEnumerable input = new List> { @@ -18,7 +19,7 @@ public static void WriteIEnumerableOfIEnumerable() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); WrapperForIEnumerable input2 = new WrapperForIEnumerable(new List @@ -27,12 +28,12 @@ public static void WriteIEnumerableOfIEnumerable() new List() { 3, 4 }, }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteGenericIEnumerableOfIEnumerable() + public async Task WriteGenericIEnumerableOfIEnumerable() { IEnumerable input = new List { @@ -40,46 +41,46 @@ public static void WriteGenericIEnumerableOfIEnumerable() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIEnumerable() + public async Task WriteArrayOfIEnumerable() { IEnumerable[] input = new IEnumerable[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIEnumerable() + public async Task WritePrimitiveIEnumerable() { IEnumerable input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteStructWrapperForIList() + public async Task WriteStructWrapperForIList() { { StructWrapperForIList obj = new StructWrapperForIList() { 1, "Hello" }; - Assert.Equal(@"[1,""Hello""]", JsonSerializer.Serialize(obj)); + Assert.Equal(@"[1,""Hello""]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { StructWrapperForIList obj = default; - Assert.Equal("[]", JsonSerializer.Serialize(obj)); + Assert.Equal("[]", await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteIListOfIList() + public async Task WriteIListOfIList() { IList input = new List { @@ -87,7 +88,7 @@ public static void WriteIListOfIList() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); WrapperForIList input2 = new WrapperForIList @@ -96,12 +97,12 @@ public static void WriteIListOfIList() new List() { 3, 4 }, }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteIListGenericOfIList() + public async Task WriteIListGenericOfIList() { IList input = new List { @@ -109,32 +110,32 @@ public static void WriteIListGenericOfIList() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfIList() + public async Task WriteArrayOfIList() { IList[] input = new IList[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveIList() + public async Task WritePrimitiveIList() { IList input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteICollectionOfICollection() + public async Task WriteICollectionOfICollection() { ICollection input = new List { @@ -142,12 +143,12 @@ public static void WriteICollectionOfICollection() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteGenericICollectionOfICollection() + public async Task WriteGenericICollectionOfICollection() { ICollection input = new List { @@ -155,7 +156,7 @@ public static void WriteGenericICollectionOfICollection() new List() { 3, 4 } }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericICollectionWrapper input2 = new GenericICollectionWrapper @@ -164,130 +165,130 @@ public static void WriteGenericICollectionOfICollection() new WrapperForICollection(new List { 3, 4 }), }; - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfICollection() + public async Task WriteArrayOfICollection() { ICollection[] input = new List[2]; input[0] = new List() { 1, 2 }; input[1] = new List() { 3, 4 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveICollection() + public async Task WritePrimitiveICollection() { ICollection input = new List { 1, 2 }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteStackOfStack() + public async Task WriteStackOfStack() { Stack input = new Stack(); input.Push(new Stack(new List() { 1, 2 })); input.Push(new Stack(new List() { 3, 4 })); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[4,3],[2,1]]", json); } [Fact] - public static void WriteGenericStackOfStack() + public async Task WriteGenericStackOfStack() { Stack input = new Stack(); input.Push(new Stack(new List() { 1, 2 })); input.Push(new Stack(new List() { 3, 4 })); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[4,3],[2,1]]", json); GenericStackWrapper input2 = new GenericStackWrapper(); input2.Push(new StackWrapper(new List { 1, 2 })); input2.Push(new StackWrapper(new List { 3, 4 })); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[4,3],[2,1]]", json); } [Fact] - public static void WriteArrayOfStack() + public async Task WriteArrayOfStack() { Stack[] input = new Stack[2]; input[0] = new Stack(new List() { 1, 2 }); input[1] = new Stack(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[2,1],[4,3]]", json); } [Fact] - public static void WritePrimitiveStack() + public async Task WritePrimitiveStack() { Stack input = new Stack( new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[2,1]", json); } [Fact] - public static void WriteQueueOfQueue() + public async Task WriteQueueOfQueue() { Queue input = new Queue(); input.Enqueue(new Queue(new List() { 1, 2 })); input.Enqueue(new Queue(new List() { 3, 4 })); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteGenericQueueOfQueue() + public async Task WriteGenericQueueOfQueue() { Queue input = new Queue(); input.Enqueue(new Queue(new List() { 1, 2 })); input.Enqueue(new Queue(new List() { 3, 4 })); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); GenericQueueWrapper input2 = new GenericQueueWrapper(); input2.Enqueue(new QueueWrapper(new List() { 1, 2 })); input2.Enqueue(new QueueWrapper(new List() { 3, 4 })); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfQueue() + public async Task WriteArrayOfQueue() { Queue[] input = new Queue[2]; input[0] = new Queue(new List() { 1, 2 }); input[1] = new Queue(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveQueue() + public async Task WritePrimitiveQueue() { Queue input = new Queue(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteArrayListOfArrayList() + public async Task WriteArrayListOfArrayList() { ArrayList input = new ArrayList { @@ -295,7 +296,7 @@ public static void WriteArrayListOfArrayList() new ArrayList(new List() { 3, 4 }) }; - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); ArrayListWrapper input2 = new ArrayListWrapper(new List @@ -304,37 +305,37 @@ public static void WriteArrayListOfArrayList() new ArrayListWrapper(new List() { 3, 4 }) }); - json = JsonSerializer.Serialize(input2); + json = await JsonSerializerWrapperForString.SerializeWrapper(input2); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WriteArrayOfArrayList() + public async Task WriteArrayOfArrayList() { ArrayList[] input = new ArrayList[2]; input[0] = new ArrayList(new List() { 1, 2 }); input[1] = new ArrayList(new List() { 3, 4 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[[1,2],[3,4]]", json); } [Fact] - public static void WritePrimitiveArrayList() + public async Task WritePrimitiveArrayList() { ArrayList input = new ArrayList(new List { 1, 2 }); - string json = JsonSerializer.Serialize(input); + string json = await JsonSerializerWrapperForString.SerializeWrapper(input); Assert.Equal("[1,2]", json); } [Fact] - public static void WriteSimpleTestStructWithNullableStructCollectionWrappers() + public async Task WriteSimpleTestStructWithNullableStructCollectionWrappers() { { SimpleTestStructWithNullableStructCollectionWrappers obj = new SimpleTestStructWithNullableStructCollectionWrappers(); obj.Initialize(); - Assert.Equal(SimpleTestStructWithNullableStructCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestStructWithNullableStructCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { @@ -344,17 +345,17 @@ public static void WriteSimpleTestStructWithNullableStructCollectionWrappers() @"""List"" : null," + @"""Dictionary"" : null" + @"}"; - Assert.Equal(json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteSimpleTestClassWithStructCollectionWrappers() + public async Task WriteSimpleTestClassWithStructCollectionWrappers() { { SimpleTestClassWithStructCollectionWrappers obj = new SimpleTestClassWithStructCollectionWrappers(); obj.Initialize(); - Assert.Equal(SimpleTestClassWithStructCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(SimpleTestClassWithStructCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } { @@ -368,12 +369,12 @@ public static void WriteSimpleTestClassWithStructCollectionWrappers() @"""List"" : []," + @"""Dictionary"" : {}" + @"}"; - Assert.Equal(json.StripWhitespace(), JsonSerializer.Serialize(obj)); + Assert.Equal(json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj)); } } [Fact] - public static void WriteNonGenericCollectionWrappers() + public async Task WriteNonGenericCollectionWrappers() { SimpleTestClassWithNonGenericCollectionWrappers obj1 = new SimpleTestClassWithNonGenericCollectionWrappers(); SimpleTestClassWithIEnumerableWrapper obj2 = new SimpleTestClassWithIEnumerableWrapper(); @@ -387,20 +388,20 @@ public static void WriteNonGenericCollectionWrappers() obj4.Initialize(); obj5.Initialize(); - Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); - Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), JsonSerializer.Serialize(obj1)); + Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); + Assert.Equal(SimpleTestClassWithNonGenericCollectionWrappers.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj1)); - Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); - Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj2)); + Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); + Assert.Equal(SimpleTestClassWithIEnumerableWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj2)); - Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); - Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj3)); + Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); + Assert.Equal(SimpleTestClassWithICollectionWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj3)); - Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); - Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj4)); + Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); + Assert.Equal(SimpleTestClassWithStackWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj4)); - Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); - Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), JsonSerializer.Serialize(obj5)); + Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); + Assert.Equal(SimpleTestClassWithQueueWrapper.s_json.StripWhitespace(), await JsonSerializerWrapperForString.SerializeWrapper(obj5)); } } } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Read.cs new file mode 100644 index 0000000000000..2fc8575f76f41 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Read.cs @@ -0,0 +1,53 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.ObjectModel; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests + { + [Fact] + public async Task Read_ObjectModelCollection() + { + Collection c = await JsonSerializerWrapperForString.DeserializeWrapper>("[true,false]"); + Assert.Equal(2, c.Count); + Assert.True(c[0]); + Assert.False(c[1]); + + // Regression test for https://github.com/dotnet/runtime/issues/30686. + ObservableCollection oc = await JsonSerializerWrapperForString.DeserializeWrapper>("[true,false]"); + Assert.Equal(2, oc.Count); + Assert.True(oc[0]); + Assert.False(oc[1]); + + SimpleKeyedCollection kc = await JsonSerializerWrapperForString.DeserializeWrapper("[true]"); + Assert.Equal(1, kc.Count); + Assert.True(kc[0]); + } + + [Fact] + public async Task Read_ObjectModelCollection_Throws() + { + // No default constructor. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>("[true,false]")); + // No default constructor. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>("[true,false]")); + // No default constructor. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>(@"{""true"":false}")); + + // Abstract types can't be instantiated. This means there's no default constructor, so the type is not supported for deserialization. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper>("[true]")); + } + + public class SimpleKeyedCollection : KeyedCollection + { + protected override string GetKeyForItem(bool item) + { + return item.ToString(); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Write.cs similarity index 51% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs rename to src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Write.cs index ab2e231fcb5a8..f9c0e6834de38 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Write.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.ObjectModel.Write.cs @@ -3,33 +3,34 @@ using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json.Serialization.Tests { - public static partial class CollectionTests + public abstract partial class CollectionTests { [Fact] - public static void Write_ObjectModelCollection() + public async Task Write_ObjectModelCollection() { Collection c = new Collection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(c)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper(c)); ObservableCollection oc = new ObservableCollection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(oc)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper(oc)); SimpleKeyedCollection kc = new SimpleKeyedCollection() { true, false }; - Assert.Equal("[true,false]", JsonSerializer.Serialize(kc)); - Assert.Equal("[true,false]", JsonSerializer.Serialize>(kc)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper(kc)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper>(kc)); ReadOnlyCollection roc = new ReadOnlyCollection(new List { true, false }); - Assert.Equal("[true,false]", JsonSerializer.Serialize(roc)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper(roc)); ReadOnlyObservableCollection rooc = new ReadOnlyObservableCollection(oc); - Assert.Equal("[true,false]", JsonSerializer.Serialize(rooc)); + Assert.Equal("[true,false]", await JsonSerializerWrapperForString.SerializeWrapper(rooc)); ReadOnlyDictionary rod = new ReadOnlyDictionary(new Dictionary { ["true"] = false }); - Assert.Equal(@"{""true"":false}", JsonSerializer.Serialize(rod)); + Assert.Equal(@"{""true"":false}", await JsonSerializerWrapperForString.SerializeWrapper(rod)); } } } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Read.cs new file mode 100644 index 0000000000000..22bb9b2067040 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Read.cs @@ -0,0 +1,52 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests + { + [Fact] + public async Task Read_SpecializedCollection() + { + BitVector32 bv32 = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""Data"":4}"); + // Data property is skipped because it doesn't have a setter. + Assert.Equal(0, bv32.Data); + + HybridDictionary hd = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""key"":""value""}"); + Assert.Equal(1, hd.Count); + Assert.Equal("value", ((JsonElement)hd["key"]).GetString()); + + IOrderedDictionary iod = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""key"":""value""}"); + Assert.Equal(1, iod.Count); + Assert.Equal("value", ((JsonElement)iod["key"]).GetString()); + + ListDictionary ld = await JsonSerializerWrapperForString.DeserializeWrapper(@"{""key"":""value""}"); + Assert.Equal(1, ld.Count); + Assert.Equal("value", ((JsonElement)ld["key"]).GetString()); + } + + [Fact] + public async Task Read_SpecializedCollection_Throws() + { + // Add method for this collection only accepts strings, even though it only implements IList which usually + // indicates that the element type is typeof(object). + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""1"", ""2""]")); + + // Not supported. Not IList, and we don't detect the add method for this collection. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[{""Key"": ""key"",""Value"":""value""}]")); + + // Int key is not allowed. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{1:""value""}")); + + // Runtime type in this case is IOrderedDictionary (we don't replace with concrete type), which we can't instantiate. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"{""first"":""John"",""second"":""Jane"",""third"":""Jet""}")); + + // Not supported. Not IList, and we don't detect the add method for this collection. + await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.DeserializeWrapper(@"[""NameValueCollection""]")); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Write.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Write.cs new file mode 100644 index 0000000000000..084777e4167cb --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Specialized.Write.cs @@ -0,0 +1,38 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Specialized; +using System.Threading.Tasks; +using Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests + { + [Fact] + public async Task Write_SpecializedCollection() + { + Assert.Equal(@"{""Data"":4}", await JsonSerializerWrapperForString.SerializeWrapper(new BitVector32(4))); + Assert.Equal(@"{""Data"":4}", await JsonSerializerWrapperForString.SerializeWrapper(new BitVector32(4))); + + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new HybridDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new HybridDictionary { ["key"] = "value" })); + + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new OrderedDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new OrderedDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new OrderedDictionary { ["key"] = "value" })); + + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new ListDictionary { ["key"] = "value" })); + Assert.Equal(@"{""key"":""value""}", await JsonSerializerWrapperForString.SerializeWrapper(new ListDictionary { ["key"] = "value" })); + + Assert.Equal(@"[""1"",""2""]", await JsonSerializerWrapperForString.SerializeWrapper(new StringCollection { "1", "2" })); + Assert.Equal(@"[""1"",""2""]", await JsonSerializerWrapperForString.SerializeWrapper(new StringCollection { "1", "2" })); + + Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", await JsonSerializerWrapperForString.SerializeWrapper(new StringDictionary { ["key"] = "value" })); + Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", await JsonSerializerWrapperForString.SerializeWrapper(new StringDictionary { ["key"] = "value" })); + + // Element type returned by .GetEnumerator for this type is string, specifically the key. + Assert.Equal(@"[""key""]", await JsonSerializerWrapperForString.SerializeWrapper(new NameValueCollection { ["key"] = "value" })); + } + } +} diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.cs new file mode 100644 index 0000000000000..82ac3b7eb10e4 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.cs @@ -0,0 +1,11 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Text.Json.Serialization.Tests +{ + public abstract partial class CollectionTests : SerializerTests + { + public CollectionTests(JsonSerializerWrapperForString stringSerializerWrapper, JsonSerializerWrapperForStream streamSerializerWrapper) + : base(stringSerializerWrapper, streamSerializerWrapper) { } + } +} diff --git a/src/libraries/System.Text.Json/tests/Common/JsonSerializerWrapperForStream.cs b/src/libraries/System.Text.Json/tests/Common/JsonSerializerWrapperForStream.cs new file mode 100644 index 0000000000000..d3e9994c6e77c --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Common/JsonSerializerWrapperForStream.cs @@ -0,0 +1,22 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.IO; +using System.Text.Json.Serialization.Metadata; +using System.Threading.Tasks; + +namespace System.Text.Json.Serialization.Tests +{ + /// + /// Base class for wrapping Stream-based JsonSerializer methods which allows tests to run under different configurations. + /// + public abstract partial class JsonSerializerWrapperForStream + { + protected internal abstract Task SerializeWrapper(Stream stream, T value, JsonSerializerOptions options = null); + protected internal abstract Task SerializeWrapper(Stream stream, object value, Type inputType, JsonSerializerOptions options = null); + protected internal abstract Task SerializeWrapper(Stream stream, T value, JsonTypeInfo jsonTypeInfo); + protected internal abstract Task DeserializeWrapper(Stream utf8Json, JsonSerializerOptions options = null); + protected internal abstract Task DeserializeWrapper(Stream utf8Json, Type returnType, JsonSerializerOptions options = null); + protected internal abstract Task DeserializeWrapper(Stream utf8Json, JsonTypeInfo jsonTypeInfo); + } +} diff --git a/src/libraries/System.Text.Json/tests/Common/JsonTestHelper.cs b/src/libraries/System.Text.Json/tests/Common/JsonTestHelper.cs index 8d53fc3c56318..528ac2903e405 100644 --- a/src/libraries/System.Text.Json/tests/Common/JsonTestHelper.cs +++ b/src/libraries/System.Text.Json/tests/Common/JsonTestHelper.cs @@ -3,6 +3,8 @@ using System.Collections.Generic; using System.Diagnostics; +using System.Text.RegularExpressions; +using System.Threading.Tasks; using Xunit; namespace System.Text.Json @@ -67,5 +69,20 @@ private static void AssertJsonEqual(JsonElement expected, JsonElement actual) break; } } + + public static async Task> ToListAsync(this IAsyncEnumerable source) + { + var list = new List(); + await foreach (T item in source) + { + list.Add(item); + } + return list; + } + + private static readonly Regex s_stripWhitespace = new Regex(@"\s+", RegexOptions.Compiled); + + public static string StripWhitespace(this string value) + => s_stripWhitespace.Replace(value, string.Empty); } } diff --git a/src/libraries/System.Text.Json/tests/Common/SerializerTests.cs b/src/libraries/System.Text.Json/tests/Common/SerializerTests.cs index c7198b1e30691..e1536add900ae 100644 --- a/src/libraries/System.Text.Json/tests/Common/SerializerTests.cs +++ b/src/libraries/System.Text.Json/tests/Common/SerializerTests.cs @@ -7,6 +7,9 @@ public abstract class SerializerTests { protected JsonSerializerWrapperForString JsonSerializerWrapperForString { get; } - protected SerializerTests(JsonSerializerWrapperForString serializerWrapper) => JsonSerializerWrapperForString = serializerWrapper; + protected JsonSerializerWrapperForStream JsonSerializerWrapperForStream { get; } + + protected SerializerTests(JsonSerializerWrapperForString stringSerializerWrapper, JsonSerializerWrapperForStream? streamSerializerWrapper = null) + => (JsonSerializerWrapperForString, JsonSerializerWrapperForStream) = (stringSerializerWrapper, streamSerializerWrapper); } } diff --git a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs index a725199441227..9f423cfedb057 100644 --- a/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Common/TestClasses/TestClasses.cs @@ -1967,4 +1967,20 @@ public class Poco { public int Id { get; set; } } + + public class UppercaseNamingPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + return name.ToUpperInvariant(); + } + } + + public class NullNamingPolicy : JsonNamingPolicy + { + public override string ConvertName(string name) + { + return null; + } + } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs new file mode 100644 index 0000000000000..1a3822f4dfc26 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs @@ -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. + +using System.Collections.Concurrent; +using System.Text.Json.Serialization; +using System.Text.Json.Serialization.Tests; + +namespace System.Text.Json.SourceGeneration.Tests +{ + public partial class CollectionTests_Metadata : CollectionTests + { + public CollectionTests_Metadata() + : this(new JsonSerializerWrapperForString_SourceGen(CollectionTestsContext_Metadata.Default, (options) => new CollectionTestsContext_Metadata(options))) + { + } + + protected CollectionTests_Metadata(Serialization.Tests.JsonSerializerWrapperForString serializerWrapper) + : base(serializerWrapper) + { + } + + [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] + [JsonSerializable(typeof(ConcurrentDictionary))] + //[JsonSerializable(typeof())] + //[JsonSerializable(typeof())] + //[JsonSerializable(typeof())] + internal sealed partial class CollectionTestsContext_Metadata : JsonSerializerContext + { + } + } + + //public partial class CollectionTests_Default : CollectionTests_Metadata + //{ + // public CollectionTests_Default() + // : base(new JsonSerializerWrapperForString_SourceGen(CollectionTestsContext_Default.Default, (options) => new CollectionTestsContext_Default(options))) + // { + // } + + // internal sealed partial class CollectionTestsContext_Default : JsonSerializerContext + // { + // } + //} +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index 6ebb90f030c6b..884108a0f18d5 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -16,7 +16,7 @@ public PropertyVisibilityTests_Metadata() { } - protected PropertyVisibilityTests_Metadata(JsonSerializerWrapperForString serializerWrapper) + protected PropertyVisibilityTests_Metadata(Serialization.Tests.JsonSerializerWrapperForString serializerWrapper) : base(serializerWrapper) { } @@ -259,7 +259,6 @@ internal sealed partial class PropertyVisibilityTestsContext_Metadata : JsonSeri } public partial class PropertyVisibilityTests_Default : PropertyVisibilityTests_Metadata - //public partial class PropertyVisibilityTests_Default : PropertyVisibilityTests { public PropertyVisibilityTests_Default() : base(new JsonSerializerWrapperForString_SourceGen(PropertyVisibilityTestsContext_Default.Default, (options) => new PropertyVisibilityTestsContext_Default(options))) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj index 2520aa52a8b17..a50b259aacbc9 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj @@ -1,4 +1,4 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true @@ -15,6 +15,24 @@ + + + + + + + + + + + + + + + + + + @@ -39,6 +57,7 @@ + diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonTestHelper.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonTestHelper.cs index 269469a874839..d30e62a6b7a45 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonTestHelper.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonTestHelper.cs @@ -801,11 +801,6 @@ public static void AssertThrows( } } - private static readonly Regex s_stripWhitespace = new Regex(@"\s+", RegexOptions.Compiled); - - public static string StripWhitespace(this string value) - => s_stripWhitespace.Replace(value, string.Empty); - #if NET6_0_OR_GREATER // This is needed due to the fact that git might normalize line endings when checking-out files public static string NormalizeLineEndings(this string value) => value.ReplaceLineEndings(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests.cs new file mode 100644 index 0000000000000..d0a10baf3624e --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests.cs @@ -0,0 +1,10 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Text.Json.Serialization.Tests +{ + public sealed partial class CollectionTestsDynamic : CollectionTests + { + public CollectionTestsDynamic() : base(JsonSerializerWrapperForString.StringSerializer, JsonSerializerWrapperForStream.AsyncStreamSerializer) { } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs deleted file mode 100644 index 0cb162bdc7302..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.Write.cs +++ /dev/null @@ -1,29 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void Write_ConcurrentCollection() - { - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new BlockingCollection { "1" })); - - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(new ConcurrentBag { "1" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ConcurrentDictionary { ["key"] = "value" })); - - ConcurrentQueue qc = new ConcurrentQueue(); - qc.Enqueue("1"); - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qc)); - - ConcurrentStack qs = new ConcurrentStack(); - qs.Push("1"); - Assert.Equal(@"[""1""]", JsonSerializer.Serialize(qs)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs deleted file mode 100644 index 2a737f3c2d67f..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Concurrent.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Concurrent; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void Read_ConcurrentCollection() - { - ConcurrentDictionary cd = JsonSerializer.Deserialize>(@"{""key"":""value""}"); - Assert.Equal(1, cd.Count); - Assert.Equal("value", cd["key"]); - - ConcurrentQueue qc = JsonSerializer.Deserialize>(@"[""1""]"); - Assert.Equal(1, qc.Count); - bool found = qc.TryPeek(out string val); - Assert.True(found); - Assert.Equal("1", val); - - ConcurrentStack qs = JsonSerializer.Deserialize>(@"[""1""]"); - Assert.Equal(1, qs.Count); - found = qs.TryPeek(out val); - Assert.True(found); - Assert.Equal("1", val); - } - - [Theory] - [InlineData(typeof(BlockingCollection), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. - [InlineData(typeof(ConcurrentBag), @"[""1""]")] // Not supported. Not IList, and we don't detect the add method for this collection. - public static void Read_ConcurrentCollection_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - - [Theory] - [InlineData(typeof(GenericConcurrentQueuePrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentQueueInternalConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentStackPrivateConstructor), @"[""1""]")] - [InlineData(typeof(GenericConcurrentStackInternalConstructor), @"[""1""]")] - public static void Read_ConcurrentCollection_NoPublicConstructor_Throws(Type type, string json) - { - NotSupportedException ex = Assert.Throws(() => JsonSerializer.Deserialize(json, type)); - Assert.Contains(type.ToString(), ex.Message); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs deleted file mode 100644 index 09b656206b751..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Immutable.Read.cs +++ /dev/null @@ -1,636 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; -using System.Collections.Immutable; -using System.Linq; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void ReadImmutableArrayOfImmutableArray() - { - ImmutableArray> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableArray l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableArrayOfArray() - { - ImmutableArray result = JsonSerializer.Deserialize>(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 ReadArrayOfImmutableArray() - { - ImmutableArray[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableArray l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadSimpleImmutableArray() - { - ImmutableArray result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadSimpleClassWithImmutableArray() - { - SimpleTestClassWithImmutableArray obj = JsonSerializer.Deserialize(SimpleTestClassWithImmutableArray.s_json); - obj.Verify(); - } - - [Fact] - public static void ReadIImmutableListTOfIImmutableListT() - { - IImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadIImmutableListTOfArray() - { - IImmutableList result = JsonSerializer.Deserialize>(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[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveIImmutableListT() - { - IImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableStackTOfIImmutableStackT() - { - IImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (IImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - } - } - - [Fact] - public static void ReadIImmutableStackTOfArray() - { - IImmutableStack result = JsonSerializer.Deserialize>(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[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (IImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - - expected = 4; - } - } - - [Fact] - public static void ReadPrimitiveIImmutableStackT() - { - IImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (int i in result) - { - Assert.Equal(expected--, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableQueueTOfIImmutableQueueT() - { - IImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadIImmutableQueueTOfArray() - { - IImmutableQueue result = JsonSerializer.Deserialize>(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() - { - IImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (IImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveIImmutableQueueT() - { - IImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadIImmutableSetTOfIImmutableSetT() - { - IImmutableSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (IImmutableSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadIImmutableSetTOfArray() - { - IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 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 ReadArrayOfIImmutableSetT() - { - IImmutableSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (IImmutableSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadPrimitiveIImmutableSetT() - { - IImmutableSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - List expected = new List { 1, 2 }; - - foreach (int i in result) - { - expected.Remove(i); - } - - Assert.Equal(0, expected.Count); - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"",""2""]")); - Assert.Throws(() => JsonSerializer.Deserialize(@"[]")); - } - - [Fact] - public static void ReadImmutableHashSetTOfImmutableHashSetT() - { - ImmutableHashSet> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (ImmutableHashSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadImmutableHashSetTOfArray() - { - ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 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[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - List expected = new List { 1, 2, 3, 4 }; - - foreach (ImmutableHashSet l in result) - { - foreach (int i in l) - { - expected.Remove(i); - } - } - - Assert.Equal(0, expected.Count); - } - - [Fact] - public static void ReadPrimitiveImmutableHashSetT() - { - ImmutableHashSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - List expected = new List { 1, 2 }; - - foreach (int i in result) - { - expected.Remove(i); - } - - Assert.Equal(0, expected.Count); - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableListTOfImmutableListT() - { - ImmutableList> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableListTOfArray() - { - ImmutableList result = JsonSerializer.Deserialize>(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[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableList l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableListT() - { - ImmutableList result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableStackTOfImmutableStackT() - { - ImmutableStack> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 4; - - foreach (ImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - } - } - - [Fact] - public static void ReadImmutableStackTOfArray() - { - ImmutableStack result = JsonSerializer.Deserialize>(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[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 2; - - foreach (ImmutableStack l in result) - { - foreach (int i in l) - { - Assert.Equal(expected--, i); - } - - expected = 4; - } - } - - [Fact] - public static void ReadPrimitiveImmutableStackT() - { - ImmutableStack result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 2; - - foreach (int i in result) - { - Assert.Equal(expected--, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadImmutableQueueTOfImmutableQueueT() - { - ImmutableQueue> result = JsonSerializer.Deserialize>>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadImmutableQueueTOfArray() - { - ImmutableQueue result = JsonSerializer.Deserialize>(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 ReadArrayOfImmutableQueueT() - { - ImmutableQueue[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableQueue l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableQueueT() - { - ImmutableQueue result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadArrayOfIImmutableSortedSetT() - { - ImmutableSortedSet[] result = JsonSerializer.Deserialize[]>(Encoding.UTF8.GetBytes(@"[[1,2],[3,4]]")); - int expected = 1; - - foreach (ImmutableSortedSet l in result) - { - foreach (int i in l) - { - Assert.Equal(expected++, i); - } - } - } - - [Fact] - public static void ReadPrimitiveImmutableSortedSetT() - { - ImmutableSortedSet result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[1,2]")); - int expected = 1; - - foreach (int i in result) - { - Assert.Equal(expected++, i); - } - - result = JsonSerializer.Deserialize>(Encoding.UTF8.GetBytes(@"[]")); - Assert.Equal(0, result.Count()); - } - - [Fact] - public static void ReadSimpleTestClass_ImmutableCollectionWrappers_Throws() - { - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithIImmutableDictionaryWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableListWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableStackWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableQueueWrapper.s_json)); - Assert.Throws(() => JsonSerializer.Deserialize(SimpleTestClassWithImmutableSetWrapper.s_json)); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs deleted file mode 100644 index a89c84af28eff..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.ObjectModel.Read.cs +++ /dev/null @@ -1,52 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.ObjectModel; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void Read_ObjectModelCollection() - { - Collection c = JsonSerializer.Deserialize>("[true,false]"); - Assert.Equal(2, c.Count); - Assert.True(c[0]); - Assert.False(c[1]); - - // Regression test for https://github.com/dotnet/runtime/issues/30686. - ObservableCollection oc = JsonSerializer.Deserialize>("[true,false]"); - Assert.Equal(2, oc.Count); - Assert.True(oc[0]); - Assert.False(oc[1]); - - SimpleKeyedCollection kc = JsonSerializer.Deserialize("[true]"); - Assert.Equal(1, kc.Count); - Assert.True(kc[0]); - } - - [Fact] - public static void Read_ObjectModelCollection_Throws() - { - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>("[true,false]")); - // No default constructor. - Assert.Throws(() => JsonSerializer.Deserialize>(@"{""true"":false}")); - - // Abstract types can't be instantiated. This means there's no default constructor, so the type is not supported for deserialization. - Assert.Throws(() => JsonSerializer.Deserialize>("[true]")); - } - - public class SimpleKeyedCollection : KeyedCollection - { - protected override string GetKeyForItem(bool item) - { - return item.ToString(); - } - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs deleted file mode 100644 index d4566de70ed9a..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Read.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Specialized; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void Read_SpecializedCollection() - { - BitVector32 bv32 = JsonSerializer.Deserialize(@"{""Data"":4}"); - // Data property is skipped because it doesn't have a setter. - Assert.Equal(0, bv32.Data); - - HybridDictionary hd = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, hd.Count); - Assert.Equal("value", ((JsonElement)hd["key"]).GetString()); - - IOrderedDictionary iod = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, iod.Count); - Assert.Equal("value", ((JsonElement)iod["key"]).GetString()); - - ListDictionary ld = JsonSerializer.Deserialize(@"{""key"":""value""}"); - Assert.Equal(1, ld.Count); - Assert.Equal("value", ((JsonElement)ld["key"]).GetString()); - } - - [Fact] - public static void Read_SpecializedCollection_Throws() - { - // Add method for this collection only accepts strings, even though it only implements IList which usually - // indicates that the element type is typeof(object). - Assert.Throws(() => JsonSerializer.Deserialize(@"[""1"", ""2""]")); - - // Not supported. Not IList, and we don't detect the add method for this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[{""Key"": ""key"",""Value"":""value""}]")); - - // Int key is not allowed. - Assert.Throws(() => JsonSerializer.Deserialize(@"{1:""value""}")); - - // Runtime type in this case is IOrderedDictionary (we don't replace with concrete type), which we can't instantiate. - Assert.Throws(() => JsonSerializer.Deserialize(@"{""first"":""John"",""second"":""Jane"",""third"":""Jet""}")); - - // Not supported. Not IList, and we don't detect the add method for this collection. - Assert.Throws(() => JsonSerializer.Deserialize(@"[""NameValueCollection""]")); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs deleted file mode 100644 index 0bc21811e65cc..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/CollectionTests/CollectionTests.Specialized.Write.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Specialized; -using Xunit; - -namespace System.Text.Json.Serialization.Tests -{ - public static partial class CollectionTests - { - [Fact] - public static void Write_SpecializedCollection() - { - Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); - Assert.Equal(@"{""Data"":4}", JsonSerializer.Serialize(new BitVector32(4))); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new HybridDictionary { ["key"] = "value" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new OrderedDictionary { ["key"] = "value" })); - - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); - Assert.Equal(@"{""key"":""value""}", JsonSerializer.Serialize(new ListDictionary { ["key"] = "value" })); - - Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); - Assert.Equal(@"[""1"",""2""]", JsonSerializer.Serialize(new StringCollection { "1", "2" })); - - Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); - Assert.Equal(@"[{""Key"":""key"",""Value"":""value""}]", JsonSerializer.Serialize(new StringDictionary { ["key"] = "value" })); - - // Element type returned by .GetEnumerator for this type is string, specifically the key. - Assert.Equal(@"[""key""]", JsonSerializer.Serialize(new NameValueCollection { ["key"] = "value" })); - } - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializationWrapperForStream.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForStream.cs similarity index 77% rename from src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializationWrapperForStream.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForStream.cs index 365bf23a1d2d3..2856ad4eac985 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializationWrapperForStream.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForStream.cs @@ -10,19 +10,12 @@ namespace System.Text.Json.Serialization.Tests /// /// Base class for wrapping Stream-based JsonSerializer methods which allows tests to run under different configurations. /// - public abstract class JsonSerializationWrapperForStream + public abstract partial class JsonSerializerWrapperForStream { - public static JsonSerializationWrapperForStream AsyncStreamSerializer => new AsyncStreamSerializerWrapper(); - public static JsonSerializationWrapperForStream SyncStreamSerializer => new SyncStreamSerializerWrapper(); + public static JsonSerializerWrapperForStream AsyncStreamSerializer => new AsyncStreamSerializerWrapper(); + public static JsonSerializerWrapperForStream SyncStreamSerializer => new SyncStreamSerializerWrapper(); - protected internal abstract Task SerializeWrapper(Stream stream, T value, JsonSerializerOptions options = null); - protected internal abstract Task SerializeWrapper(Stream stream, object value, Type inputType, JsonSerializerOptions options = null); - protected internal abstract Task SerializeWrapper(Stream stream, T value, JsonTypeInfo jsonTypeInfo); - protected internal abstract Task DeserializeWrapper(Stream utf8Json, JsonSerializerOptions options = null); - protected internal abstract Task DeserializeWrapper(Stream utf8Json, Type returnType, JsonSerializerOptions options = null); - protected internal abstract Task DeserializeWrapper(Stream utf8Json, JsonTypeInfo jsonTypeInfo); - - private class AsyncStreamSerializerWrapper : JsonSerializationWrapperForStream + private class AsyncStreamSerializerWrapper : JsonSerializerWrapperForStream { protected internal override async Task SerializeWrapper(Stream utf8Json, T value, JsonSerializerOptions options = null) { @@ -55,7 +48,7 @@ protected internal override async Task DeserializeWrapper(Stream utf8Json, } } - private class SyncStreamSerializerWrapper : JsonSerializationWrapperForStream + private class SyncStreamSerializerWrapper : JsonSerializerWrapperForStream { protected internal override Task SerializeWrapper(Stream stream, T value, JsonSerializerOptions options = null) { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForString_Dynamic.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForString_Dynamic.cs deleted file mode 100644 index aaee9f03d81cc..0000000000000 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonSerializerWrapperForString_Dynamic.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Text.Json.Serialization.Metadata; -using System.Threading.Tasks; - -namespace System.Text.Json.Serialization.Tests -{ - internal sealed class JsonSerializerWrapperForString_Dynamic - : JsonSerializerWrapperForString - { - protected internal override Task DeserializeWrapper(string json, JsonSerializerOptions options = null) - => Task.FromResult(JsonSerializer.Deserialize(json, options)); - - protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerOptions options = null) - => Task.FromResult(JsonSerializer.Deserialize(json, type, options)); - - protected internal override Task DeserializeWrapper(string json, JsonTypeInfo jsonTypeInfo) => throw new NotImplementedException(); - - protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) => throw new NotImplementedException(); - - protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerOptions options = null) - => Task.FromResult(JsonSerializer.Serialize(value, inputType, options)); - - protected internal override Task SerializeWrapper(T value, JsonSerializerOptions options = null) - => Task.FromResult(JsonSerializer.Serialize(value, options)); - - protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) => throw new NotImplementedException(); - - protected internal override Task SerializeWrapper(T value, JsonTypeInfo jsonTypeInfo) => throw new NotImplementedException(); - } -} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyNameTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyNameTests.cs index 8a6535c4ee0e3..33f4f5f2bb5fc 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyNameTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyNameTests.cs @@ -576,22 +576,6 @@ public class ObjectPropertyNamesDifferentByCaseOnly_TestClass public int MyObject { get; set; } } - public class UppercaseNamingPolicy : JsonNamingPolicy - { - public override string ConvertName(string name) - { - return name.ToUpperInvariant(); - } - } - - public class NullNamingPolicy : JsonNamingPolicy - { - public override string ConvertName(string name) - { - return null; - } - } - public class EmptyClassWithExtensionProperty { [JsonExtensionData] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyVisibilityTests.cs index 85a36e92b9b1e..71b8830410c10 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/PropertyVisibilityTests.cs @@ -1,12 +1,10 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -using Xunit; - namespace System.Text.Json.Serialization.Tests { public sealed partial class PropertyVisibilityTestsDynamic : PropertyVisibilityTests { - public PropertyVisibilityTestsDynamic() : base(new JsonSerializerWrapperForString_Dynamic()) { } + public PropertyVisibilityTestsDynamic() : base(JsonSerializerWrapperForString.StringSerializer) { } } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.DeserializeAsyncEnumerable.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.DeserializeAsyncEnumerable.cs index 5f458dbb14792..7d448fa7a5086 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.DeserializeAsyncEnumerable.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.DeserializeAsyncEnumerable.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; using Xunit; -using Utf8MemoryStream = System.Text.Json.Tests.Serialization.CollectionTests.Utf8MemoryStream; +using Utf8MemoryStream = System.Text.Json.Serialization.Tests.CollectionTests.Utf8MemoryStream; namespace System.Text.Json.Serialization.Tests { diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/StreamTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/StreamTests.cs index fc85e180dfe23..858ececfe4957 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/StreamTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/StreamTests.cs @@ -5,12 +5,12 @@ namespace System.Text.Json.Serialization.Tests { public sealed class StreamTests_Async : StreamTests { - public StreamTests_Async() : base(JsonSerializationWrapperForStream.AsyncStreamSerializer) { } + public StreamTests_Async() : base(JsonSerializerWrapperForStream.AsyncStreamSerializer) { } } public sealed class StreamTests_Sync : StreamTests { - public StreamTests_Sync() : base(JsonSerializationWrapperForStream.SyncStreamSerializer) { } + public StreamTests_Sync() : base(JsonSerializerWrapperForStream.SyncStreamSerializer) { } } public abstract partial class StreamTests @@ -18,9 +18,9 @@ public abstract partial class StreamTests /// /// Wrapper for JsonSerializer's Serialize() and Deserialize() methods. /// - private JsonSerializationWrapperForStream Serializer { get; } + private JsonSerializerWrapperForStream Serializer { get; } - public StreamTests(JsonSerializationWrapperForStream serializer) + public StreamTests(JsonSerializerWrapperForStream serializer) { Serializer = serializer; } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj index 9e117638ddb80..d3feb54ba0455 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/System.Text.Json.Tests.csproj @@ -16,6 +16,24 @@ + + + + + + + + + + + + + + + + + + @@ -77,23 +95,7 @@ - - - - - - - - - - - - - - - - - + @@ -139,9 +141,8 @@ - + - From b0f2019d87ff07c5970e982beb5819258fcbc8ad Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Tue, 13 Jul 2021 10:53:02 -0700 Subject: [PATCH 2/3] Fix tests --- .../Common/ReflectionExtensions.cs | 131 +++- .../System.Text.Json/gen/CollectionType.cs | 27 +- .../gen/ContextGenerationSpec.cs | 4 +- .../gen/JsonSourceGenerator.Emitter.cs | 95 ++- .../gen/JsonSourceGenerator.Parser.cs | 217 +++--- .../Reflection/CustomAttributeDataWrapper.cs | 10 +- .../Reflection/MetadataLoadContextInternal.cs | 30 +- .../gen/Reflection/TypeExtensions.cs | 74 +- .../gen/Reflection/TypeWrapper.cs | 80 +- .../gen/TypeGenerationSpec.cs | 72 +- .../System.Text.Json/ref/System.Text.Json.cs | 23 +- .../IAsyncEnumerableConverterFactory.cs | 4 +- .../IEnumerableConverterFactoryHelpers.cs | 145 +--- .../IEnumerableWithAddMethodConverter.cs | 22 +- ...mmutableDictionaryOfTKeyTValueConverter.cs | 5 +- .../ImmutableEnumerableOfTConverter.cs | 5 +- .../Text/Json/Serialization/JsonConverter.cs | 2 +- .../JsonSerializer.Read.HandlePropertyName.cs | 1 + .../Serialization/JsonSerializerContext.cs | 1 + .../JsonMetadataServices.Collections.cs | 97 ++- .../JsonMetadataServices.Converters.cs | 2 +- .../Serialization/Metadata/JsonTypeInfo.cs | 6 +- .../Metadata/JsonTypeInfoInternalOfT.cs | 4 +- .../CollectionTests.Dictionary.KeyPolicy.cs | 13 +- .../CollectionTests.Dictionary.cs | 80 +- .../CollectionTests.Generic.Read.cs | 2 +- .../JsonSerializerContextTests.cs | 42 + .../RealWorldContextTests.cs | 38 - .../Serialization/CollectionTests.cs | 729 +++++++++++++++++- ..._SourceGen.cs => JsonSerializerWrapper.cs} | 32 +- .../Serialization/PropertyVisibilityTests.cs | 4 +- .../SerializationLogicTests.cs | 4 +- ...em.Text.Json.SourceGeneration.Tests.csproj | 5 +- .../TestClasses.cs | 2 + .../Serialization/Stream.Collections.cs | 1 - 35 files changed, 1514 insertions(+), 495 deletions(-) rename src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/{JsonSerializerWrapperForString_SourceGen.cs => JsonSerializerWrapper.cs} (70%) diff --git a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs index fe05c0c848d2a..623aa48fceeba 100644 --- a/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs +++ b/src/libraries/System.Text.Json/Common/ReflectionExtensions.cs @@ -12,21 +12,37 @@ namespace System.Text.Json.Reflection internal static partial class ReflectionExtensions { // Immutable collection types. - public const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1"; - public const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1"; - public const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1"; - public const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1"; - public const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1"; - public const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1"; - public const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1"; - public const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1"; - public const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1"; - public const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1"; - public const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2"; - public const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2"; - public const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2"; - - public static Type? GetCompatibleGenericBaseClass(this Type type, Type baseType, Type? objectType = null) + private const string ImmutableArrayGenericTypeName = "System.Collections.Immutable.ImmutableArray`1"; + private const string ImmutableListGenericTypeName = "System.Collections.Immutable.ImmutableList`1"; + private const string ImmutableListGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableList`1"; + private const string ImmutableStackGenericTypeName = "System.Collections.Immutable.ImmutableStack`1"; + private const string ImmutableStackGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableStack`1"; + private const string ImmutableQueueGenericTypeName = "System.Collections.Immutable.ImmutableQueue`1"; + private const string ImmutableQueueGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableQueue`1"; + private const string ImmutableSortedSetGenericTypeName = "System.Collections.Immutable.ImmutableSortedSet`1"; + private const string ImmutableHashSetGenericTypeName = "System.Collections.Immutable.ImmutableHashSet`1"; + private const string ImmutableSetGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableSet`1"; + private const string ImmutableDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableDictionary`2"; + private const string ImmutableDictionaryGenericInterfaceTypeName = "System.Collections.Immutable.IImmutableDictionary`2"; + private const string ImmutableSortedDictionaryGenericTypeName = "System.Collections.Immutable.ImmutableSortedDictionary`2"; + + // Immutable collection builder types. + private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray"; + private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList"; + private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack"; + private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue"; + private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet"; + private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet"; + private const string ImmutableDictionaryTypeName = "System.Collections.Immutable.ImmutableDictionary"; + private const string ImmutableSortedDictionaryTypeName = "System.Collections.Immutable.ImmutableSortedDictionary"; + + public const string CreateRangeMethodName = "CreateRange"; + + public static Type? GetCompatibleGenericBaseClass( + this Type type, + Type baseType, + Type? objectType = null, + bool sourceGenType = false) { Debug.Assert(baseType.IsGenericType); Debug.Assert(!baseType.IsInterface); @@ -42,7 +58,8 @@ internal static partial class ReflectionExtensions if (baseTypeToCheck.IsGenericType) { Type genericTypeToCheck = baseTypeToCheck.GetGenericTypeDefinition(); - if (genericTypeToCheck == baseType) + if (genericTypeToCheck == baseType || + (sourceGenType && (OpenGenericTypesHaveSamePrefix(baseType, genericTypeToCheck)))) { return baseTypeToCheck; } @@ -94,14 +111,14 @@ internal static partial class ReflectionExtensions return null; } - public static bool IsImmutableDictionaryType(this Type type) + public static bool IsImmutableDictionaryType(this Type type, bool sourceGenType = false) { - if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) + if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable", StringComparison.Ordinal)) { return false; } - switch (type.GetGenericTypeDefinition().FullName) + switch (GetBaseNameFromGenericType(type, sourceGenType)) { case ImmutableDictionaryGenericTypeName: case ImmutableDictionaryGenericInterfaceTypeName: @@ -112,14 +129,14 @@ public static bool IsImmutableDictionaryType(this Type type) } } - public static bool IsImmutableEnumerableType(this Type type) + public static bool IsImmutableEnumerableType(this Type type, bool sourceGenType = false) { - if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable,", StringComparison.Ordinal)) + if (!type.IsGenericType || !type.Assembly.FullName!.StartsWith("System.Collections.Immutable", StringComparison.Ordinal)) { return false; } - switch (type.GetGenericTypeDefinition().FullName) + switch (GetBaseNameFromGenericType(type, sourceGenType)) { case ImmutableArrayGenericTypeName: case ImmutableListGenericTypeName: @@ -137,6 +154,76 @@ public static bool IsImmutableEnumerableType(this Type type) } } + public static string? GetImmutableDictionaryConstructingTypeName(this Type type, bool sourceGenType = false) + { + Debug.Assert(type.IsImmutableDictionaryType(sourceGenType)); + + // 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` method on, which returns the desired immutable collection. + switch (GetBaseNameFromGenericType(type, sourceGenType)) + { + case ImmutableDictionaryGenericTypeName: + case ImmutableDictionaryGenericInterfaceTypeName: + return ImmutableDictionaryTypeName; + case ImmutableSortedDictionaryGenericTypeName: + return ImmutableSortedDictionaryTypeName; + default: + // We verified that the type is an immutable collection, so the + // generic definition is one of the above. + return null; + } + } + + public static string? GetImmutableEnumerableConstructingTypeName(this Type type, bool sourceGenType = false) + { + Debug.Assert(type.IsImmutableEnumerableType(sourceGenType)); + + // 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` method on, which returns the desired immutable collection. + switch (GetBaseNameFromGenericType(type, sourceGenType)) + { + case ImmutableArrayGenericTypeName: + return ImmutableArrayTypeName; + 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: + // We verified that the type is an immutable collection, so the + // generic definition is one of the above. + return null; + } + } + + private static bool OpenGenericTypesHaveSamePrefix(Type t1, Type t2) + => t1.FullName == GetBaseNameFromGenericTypeDef(t2); + + private static string GetBaseNameFromGenericType(Type genericType, bool sourceGenType) + { + Type genericTypeDef = genericType.GetGenericTypeDefinition(); + return sourceGenType ? GetBaseNameFromGenericTypeDef(genericTypeDef) : genericTypeDef.FullName!; + } + + private static string GetBaseNameFromGenericTypeDef(Type genericTypeDef) + { + Debug.Assert(genericTypeDef.IsGenericType); + string fullName = genericTypeDef.FullName!; + int length = fullName.IndexOf("`") + 2; + return fullName.Substring(0, length); + } + public static bool IsVirtual(this PropertyInfo? propertyInfo) { Debug.Assert(propertyInfo != null); diff --git a/src/libraries/System.Text.Json/gen/CollectionType.cs b/src/libraries/System.Text.Json/gen/CollectionType.cs index 274fb7f8d0103..26e5bca1e6e6b 100644 --- a/src/libraries/System.Text.Json/gen/CollectionType.cs +++ b/src/libraries/System.Text.Json/gen/CollectionType.cs @@ -10,24 +10,27 @@ namespace System.Text.Json.SourceGeneration internal enum CollectionType { NotApplicable, + // Dictionary types + IDictionary, + Dictionary, + ImmutableDictionary, + IDictionaryOfTKeyTValue, + IReadOnlyDictionary, + // Non-dictionary types Array, List, IEnumerable, IList, - GenericIList, + IListOfT, ISet, - GenericICollection, - GenericStack, - GenericQueue, + ICollectionOfT, + StackOfT, + QueueOfT, ConcurrentStack, ConcurrentQueue, - GenericIEnumerable, - StackOrQueue, - ImmutableCollection, - IDictionary, - Dictionary, - ImmutableDictionary, - GenericIDictionary, - IReadOnlyDictionary + IEnumerableOfT, + Stack, + Queue, + ImmutableEnumerable } } diff --git a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs index 8020f798086e9..1339e4b9d167b 100644 --- a/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/ContextGenerationSpec.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Text.Json.Serialization; using System.Text.Json.Reflection; +using System.Diagnostics; namespace System.Text.Json.SourceGeneration { @@ -11,6 +12,7 @@ namespace System.Text.Json.SourceGeneration /// Represents the set of input types and options needed to provide an /// implementation for a user-provided JsonSerializerContext-derived type. /// + [DebuggerDisplay("ContextTypeRef={ContextTypeRef}")] internal sealed class ContextGenerationSpec { public JsonSourceGenerationOptionsAttribute GenerationOptions { get; init; } @@ -34,6 +36,6 @@ internal sealed class ContextGenerationSpec /// public HashSet RuntimePropertyNames { get; } = new(); - public string ContextTypeRef => $"global::{ContextType.GetUniqueCompilableTypeName()}"; + public string ContextTypeRef => ContextType.GetCompilableName(); } } diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs index 09634fd1c0cb0..fe8447e1309a8 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Emitter.cs @@ -328,9 +328,6 @@ private string GenerateForEnum(TypeGenerationSpec typeMetadata) private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec) { - string typeCompilableName = typeGenerationSpec.TypeRef; - string typeFriendlyName = typeGenerationSpec.TypeInfoPropertyName; - // Key metadata TypeGenerationSpec? collectionKeyTypeMetadata = typeGenerationSpec.CollectionKeyTypeMetadata; Debug.Assert(!(typeGenerationSpec.ClassType == ClassType.Dictionary && collectionKeyTypeMetadata == null)); @@ -375,54 +372,80 @@ private string GenerateForCollection(TypeGenerationSpec typeGenerationSpec) ? GenerateFastPathFuncForEnumerable(typeGenerationSpec) : GenerateFastPathFuncForDictionary(typeGenerationSpec); - serializeFuncNamedArg = $"serializeFunc: {typeGenerationSpec.SerializeMethodName}"; + serializeFuncNamedArg = $"serializeFunc: {typeGenerationSpec.FastPathSerializeMethodName}"; } - //string collectionTypeInfoValue = typeGenerationSpec.CollectionType switch - //{ - // CollectionType.Array => $"{JsonMetadataServicesTypeRef}.CreateArrayInfo<{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - // CollectionType.List => $"{JsonMetadataServicesTypeRef}.CreateListInfo<{typeCompilableName}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {ListTypeRef}<{valueTypeCompilableName}>(), {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - // CollectionType.Dictionary => $"{JsonMetadataServicesTypeRef}.CreateDictionaryInfo<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})", - // _ => throw new NotSupportedException() - //}; + CollectionType collectionType = typeGenerationSpec.CollectionType; + string typeRef = typeGenerationSpec.TypeRef; + string createObjectFuncArg = typeGenerationSpec.ConstructionStrategy == ObjectConstructionStrategy.ParameterlessConstructor + ? $"createObjectFunc: () => new {typeRef}()" + : "createObjectFunc: null"; + + string collectionInfoCreationPrefix = collectionType switch + { + CollectionType.IListOfT => $"{JsonMetadataServicesTypeRef}.CreateIListInfo<", + CollectionType.ICollectionOfT => $"{JsonMetadataServicesTypeRef}.CreateICollectionInfo<", + CollectionType.StackOfT => $"{JsonMetadataServicesTypeRef}.CreateStackInfo<", + CollectionType.QueueOfT => $"{JsonMetadataServicesTypeRef}.CreateQueueInfo<", + CollectionType.Stack => $"{JsonMetadataServicesTypeRef}.CreateStackOrQueueInfo<", + CollectionType.Queue => $"{JsonMetadataServicesTypeRef}.CreateStackOrQueueInfo<", + CollectionType.IEnumerableOfT => $"{JsonMetadataServicesTypeRef}.CreateIEnumerableInfo<", + CollectionType.IDictionaryOfTKeyTValue => $"{JsonMetadataServicesTypeRef}.CreateIDictionaryInfo<", + _ => $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<" + }; + + string dictInfoCreationPrefix = $"{collectionInfoCreationPrefix}{typeRef}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, {createObjectFuncArg}, {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg}"; + string enumerableInfoCreationPrefix = $"{collectionInfoCreationPrefix}{typeRef}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, {createObjectFuncArg}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg}"; + string immutableCollectionCreationSuffix = $"createRangeFunc: {typeGenerationSpec.ImmutableCollectionBuilderName}"; - CollectionType collectionType = typeGenerationSpec.CollectionType; string collectionTypeInfoValue; switch (collectionType) { + case CollectionType.Array: + collectionTypeInfoValue = $"{collectionInfoCreationPrefix}{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + break; + case CollectionType.IEnumerable: + case CollectionType.IList: + collectionTypeInfoValue = $"{collectionInfoCreationPrefix}{typeRef}>({OptionsInstanceVariableName}, {createObjectFuncArg}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + break; + case CollectionType.Stack: + case CollectionType.Queue: + string addMethod = collectionType == CollectionType.Stack ? "Push" : "Enqueue"; + string addFuncNamedArg = $"addFunc: (collection, {ValueVarName}) => collection.{addMethod}({ValueVarName})"; + collectionTypeInfoValue = $"{collectionInfoCreationPrefix}{typeRef}>({OptionsInstanceVariableName}, {createObjectFuncArg}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg}, {addFuncNamedArg})"; + break; + case CollectionType.ImmutableEnumerable: + collectionTypeInfoValue = $"{enumerableInfoCreationPrefix}, {immutableCollectionCreationSuffix})"; + break; case CollectionType.IDictionary: + collectionTypeInfoValue = $"{collectionInfoCreationPrefix}{typeRef}>({OptionsInstanceVariableName}, {createObjectFuncArg}, {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + break; case CollectionType.Dictionary: - case CollectionType.GenericIDictionary: + case CollectionType.IDictionaryOfTKeyTValue: case CollectionType.IReadOnlyDictionary: - collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + collectionTypeInfoValue = $"{dictInfoCreationPrefix})"; break; case CollectionType.ImmutableDictionary: - collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{typeCompilableName}, {keyTypeCompilableName!}, {valueTypeCompilableName}>({OptionsInstanceVariableName}, () => new {DictionaryTypeRef}<{keyTypeCompilableName}, {valueTypeCompilableName}>(), {keyTypeMetadataPropertyName!}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg}, )"; + collectionTypeInfoValue = $"{dictInfoCreationPrefix}, {immutableCollectionCreationSuffix})"; break; default: - collectionTypeInfoValue = $"{JsonMetadataServicesTypeRef}.Create{collectionType}Info<{valueTypeCompilableName}>({OptionsInstanceVariableName}, {valueTypeMetadataPropertyName}, {numberHandlingArg}, {serializeFuncNamedArg})"; + collectionTypeInfoValue = $"{enumerableInfoCreationPrefix})"; break; } - string metadataInitSource = @$"_{typeFriendlyName} = {collectionTypeInfoValue};"; + string metadataInitSource = @$"_{typeGenerationSpec.TypeInfoPropertyName} = {collectionTypeInfoValue};"; return GenerateForType(typeGenerationSpec, metadataInitSource, serializeFuncSource); } - private enum EnumerableIterationType - { - ForEach, - Length, - Count - } - private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerationSpec) { TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata; - string? writerMethodToCall = GetWriterMethod(valueTypeGenerationSpec.Type); + Type elementType = valueTypeGenerationSpec.Type; + string? writerMethodToCall = GetWriterMethod(elementType); string iterationLogic; string valueToWrite; @@ -433,8 +456,7 @@ private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerati iterationLogic = $"for (int i = 0; i < {ValueVarName}.Length; i++)"; valueToWrite = $"{ValueVarName}[i]"; break; - case CollectionType.GenericICollection: - case CollectionType.GenericIList: + case CollectionType.IListOfT: case CollectionType.List: case CollectionType.IList: iterationLogic = $"for (int i = 0; i < {ValueVarName}.Count; i++)"; @@ -443,10 +465,15 @@ private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerati default: const string elementVarName = "element"; iterationLogic = $"foreach ({valueTypeGenerationSpec.TypeRef} {elementVarName} in {ValueVarName})"; - valueToWrite = $"{ValueVarName}[i]"; + valueToWrite = elementVarName; break; }; + if (elementType == _generationSpec.CharType) + { + valueToWrite = $"{valueToWrite}.ToString()"; + } + string elementSerializationLogic = writerMethodToCall == null ? GetSerializeLogicForNonPrimitiveType(valueTypeGenerationSpec.TypeInfoPropertyName, valueToWrite, valueTypeGenerationSpec.GenerateSerializationLogic) : $"{writerMethodToCall}Value({valueToWrite});"; @@ -461,7 +488,7 @@ private string GenerateFastPathFuncForEnumerable(TypeGenerationSpec typeGenerati {WriterVarName}.WriteEndArray();"; return GenerateFastPathFuncForType( - typeGenerationSpec.SerializeMethodName, + typeGenerationSpec.FastPathSerializeMethodName, typeGenerationSpec.TypeRef, serializationLogic, typeGenerationSpec.CanBeNull); @@ -472,13 +499,19 @@ private string GenerateFastPathFuncForDictionary(TypeGenerationSpec typeGenerati TypeGenerationSpec keyTypeGenerationSpec = typeGenerationSpec.CollectionKeyTypeMetadata; TypeGenerationSpec valueTypeGenerationSpec = typeGenerationSpec.CollectionValueTypeMetadata; - string? writerMethodToCall = GetWriterMethod(valueTypeGenerationSpec.Type); + Type elementType = valueTypeGenerationSpec.Type; + string? writerMethodToCall = GetWriterMethod(elementType); string elementSerializationLogic; const string pairVarName = "pair"; string keyToWrite = $"{pairVarName}.Key"; string valueToWrite = $"{pairVarName}.Value"; + if (elementType == _generationSpec.CharType) + { + valueToWrite = $"{valueToWrite}.ToString()"; + } + if (writerMethodToCall != null) { elementSerializationLogic = $"{writerMethodToCall}({keyToWrite}, {valueToWrite});"; @@ -499,7 +532,7 @@ private string GenerateFastPathFuncForDictionary(TypeGenerationSpec typeGenerati {WriterVarName}.WriteEndObject();"; return GenerateFastPathFuncForType( - typeGenerationSpec.SerializeMethodName, + typeGenerationSpec.FastPathSerializeMethodName, typeGenerationSpec.TypeRef, serializationLogic, typeGenerationSpec.CanBeNull); diff --git a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs index 9849814e5eb9b..2290738c51aa3 100644 --- a/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs +++ b/src/libraries/System.Text.Json/gen/JsonSourceGenerator.Parser.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; @@ -21,57 +22,53 @@ public sealed partial class JsonSourceGenerator private sealed class Parser { private const string SystemTextJsonNamespace = "System.Text.Json"; - private const string JsonConverterAttributeFullName = "System.Text.Json.Serialization.JsonConverterAttribute"; - + private const string JsonElementFullName = "System.Text.Json.JsonElement"; private const string JsonIgnoreAttributeFullName = "System.Text.Json.Serialization.JsonIgnoreAttribute"; - private const string JsonIgnoreConditionFullName = "System.Text.Json.Serialization.JsonIgnoreCondition"; - private const string JsonIncludeAttributeFullName = "System.Text.Json.Serialization.JsonIncludeAttribute"; - private const string JsonNumberHandlingAttributeFullName = "System.Text.Json.Serialization.JsonNumberHandlingAttribute"; - private const string JsonPropertyNameAttributeFullName = "System.Text.Json.Serialization.JsonPropertyNameAttribute"; private const string JsonPropertyOrderAttributeFullName = "System.Text.Json.Serialization.JsonPropertyOrderAttribute"; private readonly GeneratorExecutionContext _executionContext; - private readonly MetadataLoadContextInternal _metadataLoadContext; - private readonly Type _listOfTType; - private readonly Type _dictionaryType; - private readonly Type _idictionaryOfTKeyTValueType; - private readonly Type _ireadonlyDictionaryType; private readonly Type _ilistOfTType; - private readonly Type _isetType; private readonly Type _icollectionOfTType; - private readonly Type _stackOfTType; - private readonly Type _queueOfTType; - private readonly Type _concurrentStackType; - private readonly Type _concurrentQueueType; - private readonly Type _ienumerableOfTType; - private readonly Type _idictionaryType; - private readonly Type _ilistType; - private readonly Type _stackType; - private readonly Type _queueType; private readonly Type _ienumerableType; + private readonly Type _ienumerableOfTType; + + private readonly Type? _listOfTType; + private readonly Type? _dictionaryType; + private readonly Type? _idictionaryOfTKeyTValueType; + private readonly Type? _ireadonlyDictionaryType; + private readonly Type? _isetType; + private readonly Type? _stackOfTType; + private readonly Type? _queueOfTType; + private readonly Type? _concurrentStackType; + private readonly Type? _concurrentQueueType; + private readonly Type? _idictionaryType; + private readonly Type? _ilistType; + private readonly Type? _stackType; + private readonly Type? _queueType; private readonly Type _booleanType; - private readonly Type _byteArrayType; private readonly Type _charType; private readonly Type _dateTimeType; - private readonly Type _dateTimeOffsetType; - private readonly Type _guidType; private readonly Type _nullableOfTType; private readonly Type _objectType; private readonly Type _stringType; - private readonly Type _uriType; - private readonly Type _versionType; - private readonly HashSet _numberTypes = new(); + private readonly Type? _dateTimeOffsetType; + private readonly Type? _byteArrayType; + private readonly Type? _guidType; + private readonly Type? _uriType; + private readonly Type? _versionType; + private readonly Type? _jsonElementType; + private readonly HashSet _numberTypes = new(); private readonly HashSet _knownTypes = new(); /// @@ -96,35 +93,38 @@ public Parser(in GeneratorExecutionContext executionContext) _executionContext = executionContext; _metadataLoadContext = new MetadataLoadContextInternal(executionContext.Compilation); - _listOfTType = _metadataLoadContext.Resolve(typeof(List<>)); - _dictionaryType = _metadataLoadContext.Resolve(typeof(Dictionary<,>)); - _idictionaryOfTKeyTValueType = _metadataLoadContext.Resolve(typeof(IDictionary<,>)); - _ireadonlyDictionaryType = _metadataLoadContext.Resolve(typeof(IReadOnlyDictionary<,>)); - _ilistOfTType = _metadataLoadContext.Resolve(typeof(IList<>)); - _isetType = _metadataLoadContext.Resolve(typeof(ISet<>)); - _icollectionOfTType = _metadataLoadContext.Resolve(typeof(ICollection<>)); - _stackOfTType = _metadataLoadContext.Resolve(typeof(Stack<>)); - _queueOfTType = _metadataLoadContext.Resolve(typeof(Queue<>)); - _concurrentStackType = _metadataLoadContext.Resolve(typeof(Stack<>)); - _concurrentQueueType = _metadataLoadContext.Resolve(typeof(Queue<>)); - _ienumerableOfTType = _metadataLoadContext.Resolve(typeof(IEnumerable<>)); - _idictionaryType = _metadataLoadContext.Resolve(typeof(IDictionary)); - _ilistType = _metadataLoadContext.Resolve(typeof(IList)); - _stackType = _metadataLoadContext.Resolve(typeof(Stack)); - _queueType = _metadataLoadContext.Resolve(typeof(Queue)); - _ienumerableType = _metadataLoadContext.Resolve(typeof(IEnumerable)); - - _booleanType = _metadataLoadContext.Resolve(typeof(bool)); - _byteArrayType = _metadataLoadContext.Resolve(typeof(byte[])); - _charType = _metadataLoadContext.Resolve(typeof(char)); - _dateTimeType = _metadataLoadContext.Resolve(typeof(DateTime)); - _dateTimeOffsetType = _metadataLoadContext.Resolve(typeof(DateTimeOffset)); - _guidType = _metadataLoadContext.Resolve(typeof(Guid)); - _nullableOfTType = _metadataLoadContext.Resolve(typeof(Nullable<>)); - _objectType = _metadataLoadContext.Resolve(typeof(object)); - _stringType = _metadataLoadContext.Resolve(typeof(string)); - _uriType = _metadataLoadContext.Resolve(typeof(Uri)); - _versionType = _metadataLoadContext.Resolve(typeof(Version)); + _ilistOfTType = ResolveType(SpecialType.System_Collections_Generic_IList_T); + _icollectionOfTType = ResolveType(SpecialType.System_Collections_Generic_ICollection_T); + _ienumerableOfTType = ResolveType(SpecialType.System_Collections_Generic_IEnumerable_T); + _ienumerableType = ResolveType(SpecialType.System_Collections_IEnumerable); + + _listOfTType = ResolveType(typeof(List<>).FullName!); + _dictionaryType = ResolveType(typeof(Dictionary<,>).FullName!); + _idictionaryOfTKeyTValueType = ResolveType(typeof(IDictionary<,>).FullName!); + _ireadonlyDictionaryType = ResolveType(typeof(IReadOnlyDictionary<,>).FullName!); + _isetType = ResolveType(typeof(ISet<>).FullName!); + _stackOfTType = ResolveType(typeof(Stack<>).FullName!); + _queueOfTType = ResolveType(typeof(Queue<>).FullName!); + _concurrentStackType = ResolveType(typeof(ConcurrentStack<>).FullName!); + _concurrentQueueType = ResolveType(typeof(ConcurrentQueue<>).FullName!); + _idictionaryType = ResolveType(typeof(IDictionary).FullName!); + _ilistType = ResolveType(typeof(IList).FullName!); + _stackType = ResolveType(typeof(Stack).FullName!); + _queueType = ResolveType(typeof(Queue).FullName!); + + _booleanType = ResolveType(SpecialType.System_Boolean); + _charType = ResolveType(SpecialType.System_Char); + _dateTimeType = ResolveType(SpecialType.System_DateTime); + _nullableOfTType = ResolveType(SpecialType.System_Nullable_T); + _objectType = ResolveType(SpecialType.System_Object); + _stringType = ResolveType(SpecialType.System_String); + + _dateTimeOffsetType = ResolveType(typeof(DateTimeOffset).FullName!); + _byteArrayType = ResolveType(typeof(byte[]).FullName!); + _guidType = ResolveType(typeof(Guid).FullName!); + _uriType = ResolveType(typeof(Uri).FullName!); + _versionType = ResolveType(typeof(Version).FullName!); + _jsonElementType = ResolveType(JsonElementFullName); PopulateKnownTypes(); } @@ -529,13 +529,11 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener Type? collectionValueType = null; TypeGenerationSpec? nullableUnderlyingTypeGenSpec = null; List? propGenSpecList = null; - CollectionType collectionType = CollectionType.NotApplicable; ObjectConstructionStrategy constructionStrategy = default; + CollectionType collectionType = CollectionType.NotApplicable; JsonNumberHandling? numberHandling = null; - bool foundDesignTimeCustomConverter = false; string? converterInstatiationLogic = null; - bool implementsIJsonOnSerialized = false; bool implementsIJsonOnSerializing = false; @@ -556,8 +554,13 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener } } - if (type.Name.StartsWith("Concurrent")) + if (type.Name.StartsWith("StackWrapper")) + { + } + + if (type.GetConstructor(Type.EmptyTypes) != null && !type.IsAbstract && !type.IsInterface) { + constructionStrategy = ObjectConstructionStrategy.ParameterlessConstructor; } if (foundDesignTimeCustomConverter) @@ -587,7 +590,9 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener if (type.IsArray) { - classType = ClassType.Enumerable; + classType = type.GetArrayRank() > 1 + ? ClassType.TypeUnsupportedBySourceGen // Multi-dimentional arrays are not supported in STJ. + : ClassType.Enumerable; collectionType = CollectionType.Array; collectionValueType = type.GetElementType(); } @@ -606,7 +611,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener collectionKeyType = genericArgs[0]; collectionValueType = genericArgs[1]; } - else if (type.IsImmutableDictionaryType()) + else if (type.IsImmutableDictionaryType(sourceGenType: true)) { classType = ClassType.Dictionary; collectionType = CollectionType.ImmutableDictionary; @@ -618,7 +623,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_idictionaryOfTKeyTValueType)) != null) { classType = ClassType.Dictionary; - collectionType = CollectionType.GenericIDictionary; + collectionType = CollectionType.IDictionaryOfTKeyTValue; Type[] genericArgs = actualTypeToConvert.GetGenericArguments(); collectionKeyType = genericArgs[0]; @@ -633,16 +638,16 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener collectionKeyType = genericArgs[0]; collectionValueType = genericArgs[1]; } - else if (type.IsImmutableEnumerableType()) + else if (type.IsImmutableEnumerableType(sourceGenType: true)) { classType = ClassType.Enumerable; - collectionType = CollectionType.ImmutableCollection; + collectionType = CollectionType.ImmutableEnumerable; collectionValueType = type.GetGenericArguments()[0]; } else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_ilistOfTType)) != null) { classType = ClassType.Enumerable; - collectionType = CollectionType.GenericIList; + collectionType = CollectionType.IListOfT; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_isetType)) != null) @@ -654,28 +659,28 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_icollectionOfTType)) != null) { classType = ClassType.Enumerable; - collectionType = CollectionType.GenericICollection; + collectionType = CollectionType.ICollectionOfT; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _stackOfTType)) != null) { classType = ClassType.Enumerable; - collectionType = CollectionType.GenericStack; + collectionType = CollectionType.StackOfT; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _queueOfTType)) != null) { classType = ClassType.Enumerable; - collectionType = CollectionType.GenericQueue; + collectionType = CollectionType.QueueOfT; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } - else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _concurrentStackType)) != null) + else if ((actualTypeToConvert = type.GetCompatibleGenericBaseClass(_concurrentStackType, _objectType, sourceGenType: true)) != null) { classType = ClassType.Enumerable; collectionType = CollectionType.ConcurrentStack; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } - else if ((actualTypeToConvert = GetCompatibleGenericBaseClass(type, _concurrentQueueType)) != null) + else if ((actualTypeToConvert = type.GetCompatibleGenericBaseClass(_concurrentQueueType, _objectType, sourceGenType: true)) != null) { classType = ClassType.Enumerable; collectionType = CollectionType.ConcurrentQueue; @@ -684,7 +689,7 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener else if ((actualTypeToConvert = type.GetCompatibleGenericInterface(_ienumerableOfTType)) != null) { classType = ClassType.Enumerable; - collectionType = CollectionType.GenericIEnumerable; + collectionType = CollectionType.IEnumerableOfT; collectionValueType = actualTypeToConvert.GetGenericArguments()[0]; } else if (_idictionaryType.IsAssignableFrom(type)) @@ -694,16 +699,22 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener collectionKeyType = _stringType; collectionValueType = _objectType; } - else if (typeof(IList).IsAssignableFrom(type)) + else if (_ilistType.IsAssignableFrom(type)) { classType = ClassType.Enumerable; collectionType = CollectionType.IList; collectionValueType = _objectType; } - else if (_stackType.IsAssignableFrom(type) || _queueType.IsAssignableFrom(type)) + else if (_stackType.IsAssignableFrom(type)) { classType = ClassType.Enumerable; - collectionType = CollectionType.StackOrQueue; + collectionType = CollectionType.Stack; + collectionValueType = _objectType; + } + else if (_queueType.IsAssignableFrom(type)) + { + classType = ClassType.Enumerable; + collectionType = CollectionType.Queue; collectionValueType = _objectType; } else @@ -717,13 +728,8 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener { classType = ClassType.Object; - if (type.GetConstructor(Type.EmptyTypes) != null && !type.IsAbstract && !type.IsInterface) - { - constructionStrategy = ObjectConstructionStrategy.ParameterlessConstructor; - } - // GetInterface() is currently not implemented, so we use GetInterfaces(). - IEnumerable interfaces = type.GetInterfaces().Select(interfaceType => interfaceType.FullName); + IEnumerable interfaces = type.GetInterfaces().Select(interfaceType => interfaceType.FullName!); implementsIJsonOnSerialized = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializedFullName) != null; implementsIJsonOnSerializing = interfaces.FirstOrDefault(interfaceName => interfaceName == IJsonOnSerializingFullName) != null; @@ -776,11 +782,8 @@ private TypeGenerationSpec GetOrAddTypeGenerationSpec(Type type, JsonSourceGener typeMetadata.Initialize( generationMode, - typeRef: type.GetUniqueCompilableTypeName(), - typeInfoPropertyName: type.GetFriendlyTypeName(), type, classType, - isValueType: type.IsValueType, numberHandling, propGenSpecList, collectionType, @@ -991,7 +994,7 @@ private PropertyGenerationSpec GetPropertyGenerationSpec(MemberInfo memberInfo, Order = order, HasJsonInclude = hasJsonInclude, TypeGenerationSpec = GetOrAddTypeGenerationSpec(memberCLRType, generationMode), - DeclaringTypeRef = $"global::{memberInfo.DeclaringType.GetUniqueCompilableTypeName()}", + DeclaringTypeRef = memberInfo.DeclaringType.GetCompilableName(), ConverterInstantiationLogic = converterInstantiationLogic }; } @@ -1014,7 +1017,7 @@ private static bool PropertyAccessorCanBeReferenced(MethodInfo? accessor) return null; } - return $"new {converterType.GetUniqueCompilableTypeName()}()"; + return $"new {converterType.GetCompilableName()}()"; } private static string DetermineRuntimePropName(string clrPropName, string? jsonPropName, JsonKnownNamingPolicy namingPolicy) @@ -1040,23 +1043,22 @@ private static string DetermineRuntimePropName(string clrPropName, string? jsonP private void PopulateNumberTypes() { Debug.Assert(_numberTypes != null); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(byte))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(decimal))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(double))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(short))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(sbyte))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(int))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(long))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(float))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(ushort))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(uint))); - _numberTypes.Add(_metadataLoadContext.Resolve(typeof(ulong))); + _numberTypes.Add(ResolveType(SpecialType.System_Byte)); + _numberTypes.Add(ResolveType(SpecialType.System_Decimal)); + _numberTypes.Add(ResolveType(SpecialType.System_Double)); + _numberTypes.Add(ResolveType(SpecialType.System_Int16)); + _numberTypes.Add(ResolveType(SpecialType.System_SByte)); + _numberTypes.Add(ResolveType(SpecialType.System_Int32)); + _numberTypes.Add(ResolveType(SpecialType.System_Int64)); + _numberTypes.Add(ResolveType(SpecialType.System_Single)); + _numberTypes.Add(ResolveType(SpecialType.System_UInt64)); + _numberTypes.Add(ResolveType(SpecialType.System_UInt32)); + _numberTypes.Add(ResolveType(SpecialType.System_UInt64)); } private void PopulateKnownTypes() { PopulateNumberTypes(); - Debug.Assert(_knownTypes != null); Debug.Assert(_numberTypes != null); @@ -1069,14 +1071,21 @@ private void PopulateKnownTypes() _knownTypes.Add(_guidType); _knownTypes.Add(_objectType); _knownTypes.Add(_stringType); + _knownTypes.Add(_uriType); + _knownTypes.Add(_versionType); + _knownTypes.Add(_jsonElementType); + } - // System.Private.Uri may not be loaded in input compilation. - if (_uriType != null) - { - _knownTypes.Add(_uriType); - } + private Type ResolveType(string fullyQualifiedMetadataName) + { + INamedTypeSymbol? typeSymbol = _executionContext.Compilation.GetTypeByMetadataName(fullyQualifiedMetadataName); + return typeSymbol.AsType(_metadataLoadContext); + } - _knownTypes.Add(_metadataLoadContext.Resolve(typeof(Version))); + private Type ResolveType(SpecialType specialType) + { + INamedTypeSymbol? typeSymbol = _executionContext.Compilation.GetSpecialType(specialType); + return typeSymbol.AsType(_metadataLoadContext); } } } diff --git a/src/libraries/System.Text.Json/gen/Reflection/CustomAttributeDataWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/CustomAttributeDataWrapper.cs index e518212ce65b0..58354168b719f 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/CustomAttributeDataWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/CustomAttributeDataWrapper.cs @@ -25,10 +25,18 @@ public CustomAttributeDataWrapper(AttributeData a, MetadataLoadContextInternal m } var constructorArguments = new List(); + foreach (TypedConstant ca in a.ConstructorArguments) { - constructorArguments.Add(new CustomAttributeTypedArgument(ca.Type.AsType(metadataLoadContext), ca.Value)); + if (ca.Kind == TypedConstantKind.Error) + { + continue; + } + + object value = ca.Kind == TypedConstantKind.Array ? ca.Values : ca.Value; + constructorArguments.Add(new CustomAttributeTypedArgument(ca.Type.AsType(metadataLoadContext), value)); } + Constructor = new ConstructorInfoWrapper(a.AttributeConstructor!, metadataLoadContext); NamedArguments = namedArguments; ConstructorArguments = constructorArguments; diff --git a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs index d12f3f8ed60f8..44107c865011c 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs @@ -43,14 +43,16 @@ public MetadataLoadContextInternal(Compilation compilation) MainAssembly = new AssemblyWrapper(compilation.Assembly, this); } - public Type Resolve() => Resolve(typeof(T)); - public Type? Resolve(Type type) { string assemblyName = type.Assembly.GetName().Name; IAssemblySymbol assemblySymbol; - if (assemblyName == "System.Private.CoreLib" || assemblyName == "mscorlib" || assemblyName == "System.Runtime" || assemblyName == "System.Private.Uri") + if (assemblyName == "System.Private.CoreLib" || + assemblyName == "mscorlib" || + assemblyName == "System.Runtime" || + assemblyName == "System.Private.Uri" || + assemblyName == "System.Collections") { Type resolvedType = ResolveFromAssembly(type, CoreAssembly.Symbol); if (resolvedType != null) @@ -74,12 +76,28 @@ public MetadataLoadContextInternal(Compilation compilation) assemblyName = typeForwardedFrom.GetConstructorArgument(0); } - if (!_assemblies.TryGetValue(new AssemblyName(assemblyName).Name, out assemblySymbol)) + Type? candidate; + + if (_assemblies.TryGetValue(new AssemblyName(assemblyName).Name, out assemblySymbol)) { - return null; + candidate = ResolveFromAssembly(type, assemblySymbol); + if (candidate != null) + { + return type; + } + } + + // Last-ditch fallback: check all of the assemblies. + foreach (IAssemblySymbol assembly in _assemblies.Values) + { + candidate = ResolveFromAssembly(type, assembly); + if (candidate != null) + { + return type; + } } - return ResolveFromAssembly(type, assemblySymbol); + throw new NotSupportedException(); } private Type? ResolveFromAssembly(Type type, IAssemblySymbol assemblySymbol) diff --git a/src/libraries/System.Text.Json/gen/Reflection/TypeExtensions.cs b/src/libraries/System.Text.Json/gen/Reflection/TypeExtensions.cs index 6ad76f42b7b4a..ba20339565cbf 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/TypeExtensions.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/TypeExtensions.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections.Generic; using System.Diagnostics; using System.Linq; @@ -8,34 +9,75 @@ namespace System.Text.Json.Reflection { internal static class TypeExtensions { - public static string GetUniqueCompilableTypeName(this Type type) => GetCompilableTypeName(type, type.FullName); + public static string GetCompilableName(this Type type) + { + if (type.IsArray) + { + return GetCompilableName(type.GetElementType()) + "[]"; + } - public static string GetCompilableTypeName(this Type type) => GetCompilableTypeName(type, type.Name); + string compilableName; - private static string GetCompilableTypeName(Type type, string name) - { if (!type.IsGenericType) { - return name.Replace('+', '.'); + compilableName = type.FullName; } + else + { + StringBuilder sb = new(); - // TODO: Guard upstream against open generics. - Debug.Assert(!type.ContainsGenericParameters); + string fullName = type.FullName; + int backTickIndex = fullName.IndexOf('`'); - int backTickIndex = name.IndexOf('`'); - string baseName = name.Substring(0, backTickIndex).Replace('+', '.'); + string baseName = fullName.Substring(0, backTickIndex); - return $"{baseName}<{string.Join(",", type.GetGenericArguments().Select(arg => GetUniqueCompilableTypeName(arg)))}>"; - } + sb.Append(baseName); - public static string GetFriendlyTypeName(this Type type) - { - return GetFriendlyTypeName(type.GetCompilableTypeName()); + sb.Append("<"); + + Type[] genericArgs = type.GetGenericArguments(); + int genericArgCount = genericArgs.Length; + List genericArgNames = new(genericArgCount); + + for (int i = 0; i < genericArgCount; i++) + { + genericArgNames.Add(GetCompilableName(genericArgs[i])); + } + + sb.Append(string.Join(", ", genericArgNames)); + + sb.Append(">"); + + compilableName = sb.ToString(); + } + + compilableName = compilableName.Replace("+", "."); + return "global::" + compilableName; } - private static string GetFriendlyTypeName(string compilableName) + public static string GetTypeInfoPropertyName(this Type type) { - return compilableName.Replace(".", "").Replace("<", "").Replace(">", "").Replace(",", "").Replace("[]", "Array"); + if (type.IsArray) + { + return GetTypeInfoPropertyName(type.GetElementType()) + "Array"; + } + else if (!type.IsGenericType) + { + return type.Name; + } + + StringBuilder sb = new(); + + string name = ((TypeWrapper)type).SimpleName; + + sb.Append(name); + + foreach (Type genericArg in type.GetGenericArguments()) + { + sb.Append(GetTypeInfoPropertyName(genericArg)); + } + + return sb.ToString(); } public static bool IsNullableValueType(this Type type, Type nullableOfTType, out Type? underlyingType) diff --git a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs index abeed3dfaaf0d..db2c79a949069 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/TypeWrapper.cs @@ -43,9 +43,38 @@ public override string AssemblyQualifiedName { StringBuilder sb = new(); - AssemblyIdentity identity = _typeSymbol.ContainingAssembly.Identity; + AssemblyIdentity identity; - sb.Append(FullName); + if (_arrayTypeSymbol == null) + { + identity = _typeSymbol.ContainingAssembly.Identity; + sb.Append(FullName); + } + else + { + TypeWrapper currentType = this; + int nestCount = 1; + + while (true) + { + currentType = (TypeWrapper)currentType.GetElementType(); + + if (!currentType.IsArray) + { + break; + } + + nestCount++; + } + + identity = currentType._typeSymbol.ContainingAssembly.Identity; + sb.Append(currentType.FullName); + + for (int i = 0; i < nestCount; i++) + { + sb.Append("[]"); + } + } sb.Append(", "); sb.Append(identity.Name); @@ -97,6 +126,10 @@ public override string FullName sb.Append(underlyingType.AssemblyQualifiedName); sb.Append("]]"); } + else if (IsArray) + { + sb.Append(GetElementType().FullName + "[]"); + } else { sb.Append(Name); @@ -110,7 +143,22 @@ public override string FullName { sb.Insert(0, $"{Namespace}."); } + + if (this.IsGenericType && !ContainsGenericParameters) + { + sb.Append("["); + + foreach (Type genericArg in GetGenericArguments()) + { + sb.Append("["); + sb.Append(genericArg.AssemblyQualifiedName); + sb.Append("]"); + } + + sb.Append("]"); + } } + _fullName = sb.ToString(); } @@ -144,6 +192,8 @@ public override string Name } } + public string SimpleName => _typeSymbol.Name; + private Type _enumType; public override bool IsEnum @@ -190,11 +240,21 @@ public override IList GetCustomAttributesData() public override ConstructorInfo[] GetConstructors(BindingFlags bindingAttr) { - var ctors = new List(); + if (_namedTypeSymbol == null) + { + return Array.Empty(); + } + + List ctors = new(); + foreach (IMethodSymbol c in _namedTypeSymbol.Constructors) { - ctors.Add(new ConstructorInfoWrapper(c, _metadataLoadContext)); + if (c.DeclaredAccessibility == Accessibility.Public) + { + ctors.Add(new ConstructorInfoWrapper(c, _metadataLoadContext)); + } } + return ctors.ToArray(); } @@ -268,7 +328,7 @@ public override Type GetInterface(string name, bool ignoreCase) public override Type[] GetInterfaces() { var interfaces = new List(); - foreach (INamedTypeSymbol i in _typeSymbol.Interfaces) + foreach (INamedTypeSymbol i in _typeSymbol.AllInterfaces) { interfaces.Add(i.AsType(_metadataLoadContext)); } @@ -484,6 +544,16 @@ public override bool IsAssignableFrom(Type c) public override int GetHashCode() => _typeSymbol.GetHashCode(); #pragma warning restore RS1024 // Compare symbols correctly + public override int GetArrayRank() + { + if (_arrayTypeSymbol == null) + { + throw new ArgumentException("Must be an array type."); + } + + return _arrayTypeSymbol.Rank; + } + public override bool Equals(object o) { if (o is TypeWrapper tw) diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index d11598d971b30..0fb7b2e37c059 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -57,15 +57,42 @@ internal class TypeGenerationSpec public string? ConverterInstantiationLogic { get; private set; } - public string SerializeMethodName => $"{TypeInfoPropertyName}Serialize"; + public string FastPathSerializeMethodName + { + get + { + Debug.Assert(GenerateSerializationLogic); + return $"{TypeInfoPropertyName}Serialize"; + } + } + + public string? ImmutableCollectionBuilderName + { + get + { + string builderName; + + if (CollectionType == CollectionType.ImmutableDictionary) + { + builderName = Type.GetImmutableDictionaryConstructingTypeName(sourceGenType: true); + } + else if (CollectionType == CollectionType.ImmutableEnumerable) + { + builderName = Type.GetImmutableEnumerableConstructingTypeName(sourceGenType: true); + } + else + { + return null; + } + + return $"global::{builderName}.{ReflectionExtensions.CreateRangeMethodName}"; + } + } public void Initialize( JsonSourceGenerationMode generationMode, - string typeRef, - string typeInfoPropertyName, Type type, ClassType classType, - bool isValueType, JsonNumberHandling? numberHandling, List? propertyGenSpecList, CollectionType collectionType, @@ -78,12 +105,12 @@ public void Initialize( bool implementsIJsonOnSerializing) { GenerationMode = generationMode; - TypeRef = $"global::{typeRef}"; - TypeInfoPropertyName = typeInfoPropertyName; + TypeRef = type.GetCompilableName(); + TypeInfoPropertyName = type.GetTypeInfoPropertyName(); Type = type; ClassType = classType; - IsValueType = isValueType; - CanBeNull = !isValueType || nullableUnderlyingTypeMetadata != null; + IsValueType = type.IsValueType; + CanBeNull = !IsValueType || nullableUnderlyingTypeMetadata != null; NumberHandling = numberHandling; PropertyGenSpecList = propertyGenSpecList; CollectionType = collectionType; @@ -180,20 +207,31 @@ private bool FastPathIsSupported() { if (ClassType == ClassType.Object) { - return true; - } + foreach (PropertyGenerationSpec property in PropertyGenSpecList) + { + if (property.TypeGenerationSpec.Type.IsObjectType()) + { + return false; + } + } - if (CollectionType == CollectionType.Array || CollectionType == CollectionType.List) - { - return !CollectionValueTypeMetadata!.Type.IsObjectType(); + return true; } - if (CollectionType == CollectionType.Dictionary) + switch (CollectionType) { - return CollectionKeyTypeMetadata!.Type.IsStringType() && !CollectionValueTypeMetadata!.Type.IsObjectType(); + case CollectionType.NotApplicable: + return false; + case CollectionType.IDictionary: + case CollectionType.Dictionary: + case CollectionType.ImmutableDictionary: + case CollectionType.IDictionaryOfTKeyTValue: + case CollectionType.IReadOnlyDictionary: + return CollectionKeyTypeMetadata!.Type.IsStringType() && !CollectionValueTypeMetadata!.Type.IsObjectType(); + default: + // Non-dictionary collections + return !CollectionValueTypeMetadata!.Type.IsObjectType(); } - - return false; } private bool GenerationModeIsSpecified(JsonSourceGenerationMode mode) => GenerationMode == JsonSourceGenerationMode.Default || (mode & GenerationMode) != 0; diff --git a/src/libraries/System.Text.Json/ref/System.Text.Json.cs b/src/libraries/System.Text.Json/ref/System.Text.Json.cs index aa2073d843d83..58b6d523aad9a 100644 --- a/src/libraries/System.Text.Json/ref/System.Text.Json.cs +++ b/src/libraries/System.Text.Json/ref/System.Text.Json.cs @@ -919,6 +919,7 @@ public static partial class JsonMetadataServices public static System.Text.Json.Serialization.JsonConverter Int16Converter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter Int32Converter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter Int64Converter { get { throw null; } } + public static System.Text.Json.Serialization.JsonConverter JsonElementConverter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter ObjectConverter { get { throw null; } } [System.CLSCompliantAttribute(false)] public static System.Text.Json.Serialization.JsonConverter SByteConverter { get { throw null; } } @@ -934,24 +935,26 @@ public static partial class JsonMetadataServices public static System.Text.Json.Serialization.JsonConverter UriConverter { get { throw null; } } public static System.Text.Json.Serialization.JsonConverter VersionConverter { get { throw null; } } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateArrayInfo(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) { throw null; } - public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentQueueOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentQueue { throw null; } - public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentStackOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentStack { throw null; } + public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentQueueInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentQueue { throw null; } + public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateConcurrentStackInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Concurrent.ConcurrentStack { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo keyInfo, System.Text.Json.Serialization.Metadata.JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Dictionary where TKey : notnull { throw null; } - public static JsonTypeInfo CreateICollectionOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ICollection { throw null; } - public static JsonTypeInfo CreateIDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, JsonTypeInfo objectInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IDictionary { throw null; } + public static JsonTypeInfo CreateICollectionInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ICollection { throw null; } + public static JsonTypeInfo CreateIDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, JsonTypeInfo stringInfo, JsonTypeInfo objectInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IDictionary { throw null; } + public static JsonTypeInfo CreateIDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IDictionary where TKey : notnull { throw null; } public static JsonTypeInfo CreateIEnumerableInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IEnumerable { throw null; } - public static JsonTypeInfo CreateIEnumerableOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IEnumerable { throw null; } - public static JsonTypeInfo CreateIListOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IList { throw null; } + public static JsonTypeInfo CreateIEnumerableInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IEnumerable { throw null; } + public static JsonTypeInfo CreateIListInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo objectInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IList { throw null; } + public static JsonTypeInfo CreateIListInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IList { throw null; } public static JsonTypeInfo CreateImmutableDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc, System.Func>, TCollection> createRangeFunc) where TCollection : System.Collections.Generic.IReadOnlyDictionary where TKey : notnull { throw null; } public static JsonTypeInfo CreateImmutableEnumerableInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc, System.Func, TCollection> createRangeFunc) where TCollection : System.Collections.Generic.IEnumerable { throw null; } - public static JsonTypeInfo CreateIReadOnlyDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Dictionary where TKey : notnull { throw null; } + public static JsonTypeInfo CreateIReadOnlyDictionaryInfo(System.Text.Json.JsonSerializerOptions options, System.Func createObjectFunc, JsonTypeInfo keyInfo, JsonTypeInfo valueInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.IReadOnlyDictionary where TKey : notnull { throw null; } public static JsonTypeInfo CreateISetInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.ISet { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateListInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.List { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateObjectInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Func? propInitFunc, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where T : notnull { throw null; } public static System.Text.Json.Serialization.Metadata.JsonPropertyInfo CreatePropertyInfo(System.Text.Json.JsonSerializerOptions options, bool isProperty, bool isPublic, bool isVirtual, System.Type declaringType, System.Text.Json.Serialization.Metadata.JsonTypeInfo propertyTypeInfo, System.Text.Json.Serialization.JsonConverter? converter, System.Func? getter, System.Action? setter, System.Text.Json.Serialization.JsonIgnoreCondition? ignoreCondition, bool hasJsonInclude, System.Text.Json.Serialization.JsonNumberHandling? numberHandling, string propertyName, string? jsonPropertyName) { throw null; } - public static JsonTypeInfo CreateQueueOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Queue { throw null; } - public static JsonTypeInfo CreateStackOfTInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Stack { throw null; } - public static JsonTypeInfo CreateStackOrQueueInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.IEnumerable { throw null; } + public static JsonTypeInfo CreateQueueInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Queue { throw null; } + public static JsonTypeInfo CreateStackInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc) where TCollection : System.Collections.Generic.Stack { throw null; } + public static JsonTypeInfo CreateStackOrQueueInfo(System.Text.Json.JsonSerializerOptions options, System.Func? createObjectFunc, System.Text.Json.Serialization.Metadata.JsonTypeInfo elementInfo, System.Text.Json.Serialization.JsonNumberHandling numberHandling, System.Action? serializeFunc, System.Action addFunc) where TCollection : System.Collections.IEnumerable { throw null; } public static System.Text.Json.Serialization.Metadata.JsonTypeInfo CreateValueInfo(System.Text.Json.JsonSerializerOptions options, System.Text.Json.Serialization.JsonConverter converter) { throw null; } public static System.Text.Json.Serialization.JsonConverter GetEnumConverter(System.Text.Json.JsonSerializerOptions options) where T : struct { throw null; } public static System.Text.Json.Serialization.JsonConverter GetNullableConverter(System.Text.Json.Serialization.Metadata.JsonTypeInfo underlyingTypeInfo) where T : struct { throw null; } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IAsyncEnumerableConverterFactory.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IAsyncEnumerableConverterFactory.cs index d9ad1615bb4c2..9de2b8219bf86 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IAsyncEnumerableConverterFactory.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IAsyncEnumerableConverterFactory.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Diagnostics; -using System.Diagnostics.CodeAnalysis; +using System.Text.Json.Reflection; using System.Text.Json.Serialization.Converters; namespace System.Text.Json.Serialization @@ -26,6 +26,6 @@ public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializer } private static Type? GetAsyncEnumerableInterface(Type type) - => IEnumerableConverterFactoryHelpers.GetCompatibleGenericInterface(type, typeof(IAsyncEnumerable<>)); + => type.GetCompatibleGenericInterface(typeof(IAsyncEnumerable<>)); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs index a63fef10cd96a..d015f7f6a838e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableConverterFactoryHelpers.cs @@ -5,7 +5,6 @@ using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Text.Json.Reflection; -using System.Text.Json.Serialization.Metadata; namespace System.Text.Json.Serialization { @@ -15,84 +14,9 @@ internal static class IEnumerableConverterFactoryHelpers // any netstandard2.0 consumers don't need to reference System.Collections.Immutable. // So instead, implement a "weak reference" by using strings to check for Immutable types. - // Immutable collection builder types. - private const string ImmutableArrayTypeName = "System.Collections.Immutable.ImmutableArray"; - private const string ImmutableListTypeName = "System.Collections.Immutable.ImmutableList"; - private const string ImmutableStackTypeName = "System.Collections.Immutable.ImmutableStack"; - private const string ImmutableQueueTypeName = "System.Collections.Immutable.ImmutableQueue"; - private const string ImmutableSortedSetTypeName = "System.Collections.Immutable.ImmutableSortedSet"; - private const string ImmutableHashSetTypeName = "System.Collections.Immutable.ImmutableHashSet"; - private const string ImmutableDictionaryTypeName = "System.Collections.Immutable.ImmutableDictionary"; - private const string ImmutableSortedDictionaryTypeName = "System.Collections.Immutable.ImmutableSortedDictionary"; - - private const string CreateRangeMethodName = "CreateRange"; - // Don't use DynamicDependency attributes to the Immutable Collection types so they can be trimmed in applications that don't use Immutable Collections. internal const string ImmutableConvertersUnreferencedCodeMessage = "System.Collections.Immutable converters use Reflection to find and create Immutable Collection types, which requires unreferenced code."; - internal static Type? GetCompatibleGenericBaseClass(this Type type, Type baseType) - { - Debug.Assert(baseType.IsGenericType); - Debug.Assert(!baseType.IsInterface); - Debug.Assert(baseType == baseType.GetGenericTypeDefinition()); - - Type? baseTypeToCheck = type; - - while (baseTypeToCheck != null && baseTypeToCheck != JsonTypeInfo.ObjectType) - { - if (baseTypeToCheck.IsGenericType) - { - Type genericTypeToCheck = baseTypeToCheck.GetGenericTypeDefinition(); - if (genericTypeToCheck == baseType) - { - return baseTypeToCheck; - } - } - - baseTypeToCheck = baseTypeToCheck.BaseType; - } - - return null; - } - - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2070:UnrecognizedReflectionPattern", - Justification = "The 'interfaceType' must exist and so trimmer kept it. In which case " + - "It also kept it on any type which implements it. The below call to GetInterfaces " + - "may return fewer results when trimmed but it will return the 'interfaceType' " + - "if the type implemented it, even after trimming.")] - internal static Type? GetCompatibleGenericInterface(this Type type, Type interfaceType) - { - Debug.Assert(interfaceType.IsGenericType); - Debug.Assert(interfaceType.IsInterface); - Debug.Assert(interfaceType == interfaceType.GetGenericTypeDefinition()); - - Type interfaceToCheck = type; - - if (interfaceToCheck.IsGenericType) - { - interfaceToCheck = interfaceToCheck.GetGenericTypeDefinition(); - } - - if (interfaceToCheck == interfaceType) - { - return type; - } - - foreach (Type typeToCheck in type.GetInterfaces()) - { - if (typeToCheck.IsGenericType) - { - Type genericInterfaceToCheck = typeToCheck.GetGenericTypeDefinition(); - if (genericInterfaceToCheck == interfaceType) - { - return typeToCheck; - } - } - } - - return null; - } - [RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)] public static MethodInfo GetImmutableEnumerableCreateRangeMethod(this Type type, Type elementType) { @@ -102,7 +26,7 @@ public static MethodInfo GetImmutableEnumerableCreateRangeMethod(this Type type, MethodInfo[] constructingTypeMethods = constructingType.GetMethods(); foreach (MethodInfo method in constructingTypeMethods) { - if (method.Name == CreateRangeMethodName && + if (method.Name == ReflectionExtensions.CreateRangeMethodName && method.GetParameters().Length == 1 && method.IsGenericMethod && method.GetGenericArguments().Length == 1) @@ -125,7 +49,7 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, MethodInfo[] constructingTypeMethods = constructingType.GetMethods(); foreach (MethodInfo method in constructingTypeMethods) { - if (method.Name == CreateRangeMethodName && + if (method.Name == ReflectionExtensions.CreateRangeMethodName && method.GetParameters().Length == 1 && method.IsGenericMethod && method.GetGenericArguments().Length == 2) @@ -144,43 +68,11 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, { Debug.Assert(type.IsImmutableEnumerableType()); - // 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` method on, which returns the desired immutable collection. - Type underlyingType = type.GetGenericTypeDefinition(); - string constructingTypeName; + string? constructingTypeName = type.GetImmutableEnumerableConstructingTypeName(); - switch (underlyingType.FullName) - { - case ReflectionExtensions.ImmutableArrayGenericTypeName: - constructingTypeName = ImmutableArrayTypeName; - break; - case ReflectionExtensions.ImmutableListGenericTypeName: - case ReflectionExtensions.ImmutableListGenericInterfaceTypeName: - constructingTypeName = ImmutableListTypeName; - break; - case ReflectionExtensions.ImmutableStackGenericTypeName: - case ReflectionExtensions.ImmutableStackGenericInterfaceTypeName: - constructingTypeName = ImmutableStackTypeName; - break; - case ReflectionExtensions.ImmutableQueueGenericTypeName: - case ReflectionExtensions.ImmutableQueueGenericInterfaceTypeName: - constructingTypeName = ImmutableQueueTypeName; - break; - case ReflectionExtensions.ImmutableSortedSetGenericTypeName: - constructingTypeName = ImmutableSortedSetTypeName; - break; - case ReflectionExtensions.ImmutableHashSetGenericTypeName: - case ReflectionExtensions.ImmutableSetGenericInterfaceTypeName: - constructingTypeName = ImmutableHashSetTypeName; - break; - default: - // We verified that the type is an immutable collection, so the - // generic definition is one of the above. - return null; - } - - return underlyingType.Assembly.GetType(constructingTypeName); + return constructingTypeName == null + ? null + : type.Assembly.GetType(constructingTypeName); } [RequiresUnreferencedCode(ImmutableConvertersUnreferencedCodeMessage)] @@ -188,28 +80,11 @@ public static MethodInfo GetImmutableDictionaryCreateRangeMethod(this Type type, { Debug.Assert(type.IsImmutableDictionaryType()); - // 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` method on, which returns the desired immutable collection. - Type underlyingType = type.GetGenericTypeDefinition(); - string constructingTypeName; - - switch (underlyingType.FullName) - { - case ReflectionExtensions.ImmutableDictionaryGenericTypeName: - case ReflectionExtensions.ImmutableDictionaryGenericInterfaceTypeName: - constructingTypeName = ImmutableDictionaryTypeName; - break; - case ReflectionExtensions.ImmutableSortedDictionaryGenericTypeName: - constructingTypeName = ImmutableSortedDictionaryTypeName; - break; - default: - // We verified that the type is an immutable collection, so the - // generic definition is one of the above. - return null; - } + string? constructingTypeName = type.GetImmutableDictionaryConstructingTypeName(); - return underlyingType.Assembly.GetType(constructingTypeName); + return constructingTypeName == null + ? null + : type.Assembly.GetType(constructingTypeName); } public static bool IsNonGenericStackOrQueue(this Type type) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs index 6aa72b315887b..6363e8aa3c666 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/IEnumerableWithAddMethodConverter.cs @@ -15,6 +15,9 @@ internal sealed class IEnumerableWithAddMethodConverter [RequiresUnreferencedCode(JsonSerializer.SerializationUnreferencedCodeMessage)] public IEnumerableWithAddMethodConverter() { } + // Used by source-gen initialization for reflection-free serialization. + public IEnumerableWithAddMethodConverter(bool dummy) { } + protected override void Add(in object? value, ref ReadStack state) { var addMethodDelegate = ((Action?)state.Current.JsonTypeInfo.AddMethodDelegate); @@ -22,8 +25,6 @@ protected override void Add(in object? value, ref ReadStack state) addMethodDelegate((TCollection)state.Current.ReturnValue!, value); } - [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091:UnrecognizedReflectionPattern", - Justification = "The ctor is marked RequiresUnreferencedCode.")] protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { JsonTypeInfo typeInfo = state.Current.JsonTypeInfo; @@ -36,12 +37,7 @@ protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStac state.Current.ReturnValue = constructorDelegate(); - // Initialize add method used to populate the collection. - if (typeInfo.AddMethodDelegate == null) - { - // We verified this exists when we created the converter in the enumerable converter factory. - typeInfo.AddMethodDelegate = options.MemberAccessorStrategy.CreateAddMethodDelegate(); - } + Debug.Assert(typeInfo.AddMethodDelegate != null); } protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, JsonSerializerOptions options, ref WriteStack state) @@ -79,5 +75,15 @@ protected override bool OnWriteResume(Utf8JsonWriter writer, TCollection value, return true; } + + internal override bool RequiresDynamicMemberAccessors => true; + + [UnconditionalSuppressMessage("ReflectionAnalysis", "IL2091:UnrecognizedReflectionPattern", + Justification = "The ctor is marked RequiresUnreferencedCode.")] + internal override void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) + { + Debug.Assert(jsonTypeInfo != null); + jsonTypeInfo.AddMethodDelegate = options.MemberAccessorStrategy.CreateAddMethodDelegate(); + } } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs index 4abff2ad3743a..316a9a35d9b4a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableDictionaryOfTKeyTValueConverter.cs @@ -18,6 +18,9 @@ public ImmutableDictionaryOfTKeyTValueConverter() { } + // Used by source-gen initialization for reflection-free serialization. + public ImmutableDictionaryOfTKeyTValueConverter(bool dummy) { } + protected override void Add(TKey key, in TValue value, JsonSerializerOptions options, ref ReadStack state) { ((Dictionary)state.Current.ReturnValue!)[key] = value; @@ -25,7 +28,7 @@ protected override void Add(TKey key, in TValue value, JsonSerializerOptions opt internal override bool CanHaveIdMetadata => false; - internal override bool IsImmutableCollectionConverter => true; + internal override bool RequiresDynamicMemberAccessors => true; protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs index 37a9dbcc292be..f2f2810e9baf1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Collection/ImmutableEnumerableOfTConverter.cs @@ -17,6 +17,9 @@ public ImmutableEnumerableOfTConverter() { } + // Used by source-gen initialization for reflection-free serialization. + public ImmutableEnumerableOfTConverter(bool dummy) { } + protected override void Add(in TElement value, ref ReadStack state) { ((List)state.Current.ReturnValue!).Add(value); @@ -24,7 +27,7 @@ protected override void Add(in TElement value, ref ReadStack state) internal override bool CanHaveIdMetadata => false; - internal override bool IsImmutableCollectionConverter => true; + internal override bool RequiresDynamicMemberAccessors => true; protected override void CreateCollection(ref Utf8JsonReader reader, ref ReadStack state, JsonSerializerOptions options) { diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs index e62f97cc7bcc9..f5902929b1814 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonConverter.cs @@ -114,7 +114,7 @@ internal bool ShouldFlush(Utf8JsonWriter writer, ref WriteStack state) internal ConstructorInfo? ConstructorInfo { get; set; } - internal virtual bool IsImmutableCollectionConverter { get; } + internal virtual bool RequiresDynamicMemberAccessors { get; } internal virtual void Initialize(JsonSerializerOptions options, JsonTypeInfo? jsonTypeInfo = null) { } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs index 014ea974ed247..1d65fc920f48e 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializer.Read.HandlePropertyName.cs @@ -4,6 +4,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Runtime.CompilerServices; +using System.Text.Json.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerContext.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerContext.cs index a302d92878b9b..e953bdf34daf9 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerContext.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/JsonSerializerContext.cs @@ -51,6 +51,7 @@ internal bool CanUseSerializationLogic Options.IgnoreReadOnlyProperties == _defaultOptions.IgnoreReadOnlyProperties && Options.IncludeFields == _defaultOptions.IncludeFields && Options.PropertyNamingPolicy == _defaultOptions.PropertyNamingPolicy && + Options.DictionaryKeyPolicy == _defaultOptions.DictionaryKeyPolicy && Options.WriteIndented == _defaultOptions.WriteIndented; } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs index 23ebb13a16792..ef2b4d1a31972 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Collections.cs @@ -124,7 +124,7 @@ public static JsonTypeInfo CreateImmutableDictionaryInfo new JsonTypeInfoInternal( options, createObjectFunc, - () => new ImmutableDictionaryOfTKeyTValueConverter(), + () => new ImmutableDictionaryOfTKeyTValueConverter(dummy: false), keyInfo, valueInfo, numberHandling, @@ -133,6 +133,39 @@ public static JsonTypeInfo CreateImmutableDictionaryInfo + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// The generic definition of the key type. + /// The generic definition of the value type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the key type. + /// A instance representing the value type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIDictionaryInfo( + JsonSerializerOptions options, + Func createObjectFunc, + JsonTypeInfo keyInfo, + JsonTypeInfo valueInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IDictionary + where TKey : notnull + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IDictionaryOfTKeyTValueConverter(), + keyInfo, + valueInfo, + numberHandling, + serializeFunc, + typeof(TKey), + typeof(TValue)); + /// /// Creates metadata for types assignable to . /// @@ -153,7 +186,7 @@ public static JsonTypeInfo CreateIReadOnlyDictionaryInfo? serializeFunc) - where TCollection : Dictionary + where TCollection : IReadOnlyDictionary where TKey : notnull => new JsonTypeInfoInternal( options, @@ -191,13 +224,39 @@ public static JsonTypeInfo CreateImmutableEnumerableInfo new JsonTypeInfoInternal( options, createObjectFunc, - () => new ImmutableEnumerableOfTConverter(), + () => new ImmutableEnumerableOfTConverter(dummy: false), elementInfo, numberHandling, serializeFunc, typeof(TElement), createRangeFunc ?? throw new ArgumentNullException(nameof(createRangeFunc))); + /// + /// Creates metadata for types assignable to . + /// + /// The generic definition of the type. + /// + /// A to create an instance of the list when deserializing. + /// A instance representing the element type. + /// The option to apply to number collection elements. + /// An optimized serialization implementation assuming pre-determined defaults. + /// + public static JsonTypeInfo CreateIListInfo( + JsonSerializerOptions options, + Func? createObjectFunc, + JsonTypeInfo objectInfo, + JsonNumberHandling numberHandling, + Action? serializeFunc) + where TCollection : IList + => new JsonTypeInfoInternal( + options, + createObjectFunc, + () => new IListConverter(), + objectInfo, + numberHandling, + serializeFunc, + typeof(object)); + /// /// Creates metadata for types assignable to . /// @@ -209,7 +268,7 @@ public static JsonTypeInfo CreateImmutableEnumerableInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateIListOfTInfo( + public static JsonTypeInfo CreateIListInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -263,7 +322,7 @@ public static JsonTypeInfo CreateISetInfo( /// The option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateICollectionOfTInfo( + public static JsonTypeInfo CreateICollectionInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -290,7 +349,7 @@ public static JsonTypeInfo CreateICollectionOfTInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateStackOfTInfo( + public static JsonTypeInfo CreateStackInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -317,7 +376,7 @@ public static JsonTypeInfo CreateStackOfTInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateQueueOfTInfo( + public static JsonTypeInfo CreateQueueInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -344,7 +403,7 @@ public static JsonTypeInfo CreateQueueOfTInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateConcurrentStackOfTInfo( + public static JsonTypeInfo CreateConcurrentStackInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -371,7 +430,7 @@ public static JsonTypeInfo CreateConcurrentStackOfTInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateConcurrentQueueOfTInfo( + public static JsonTypeInfo CreateConcurrentQueueInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -398,7 +457,7 @@ public static JsonTypeInfo CreateConcurrentQueueOfTInfoThe option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. /// - public static JsonTypeInfo CreateIEnumerableOfTInfo( + public static JsonTypeInfo CreateIEnumerableInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, @@ -420,6 +479,7 @@ public static JsonTypeInfo CreateIEnumerableOfTInfoThe generic definition of the type. /// /// A to create an instance of the list when deserializing. + /// A instance representing instances. /// A instance representing instances. /// The option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. @@ -427,6 +487,7 @@ public static JsonTypeInfo CreateIEnumerableOfTInfo CreateIDictionaryInfo( JsonSerializerOptions options, Func? createObjectFunc, + JsonTypeInfo stringInfo, JsonTypeInfo objectInfo, JsonNumberHandling numberHandling, Action? serializeFunc) @@ -435,11 +496,11 @@ public static JsonTypeInfo CreateIDictionaryInfo( options, createObjectFunc, () => new IDictionaryConverter(), - keyInfo: objectInfo, + keyInfo: stringInfo, valueInfo: objectInfo, numberHandling, serializeFunc, - typeof(object), + typeof(string), typeof(object)); /// @@ -451,22 +512,26 @@ public static JsonTypeInfo CreateIDictionaryInfo( /// A instance representing the element type. /// The option to apply to number collection elements. /// An optimized serialization implementation assuming pre-determined defaults. + /// A method for adding elements to the collection when using the serializer's code-paths. /// public static JsonTypeInfo CreateStackOrQueueInfo( JsonSerializerOptions options, Func? createObjectFunc, JsonTypeInfo elementInfo, JsonNumberHandling numberHandling, - Action? serializeFunc) + Action? serializeFunc, + Action addFunc) where TCollection : IEnumerable => new JsonTypeInfoInternal( options, createObjectFunc, - () => new IEnumerableWithAddMethodConverter(), + () => new IEnumerableWithAddMethodConverter(dummy: false), elementInfo, numberHandling, serializeFunc, - typeof(object)); + typeof(object), + createObjectWithArgs: null, + addFunc: addFunc ?? throw new ArgumentNullException(nameof(addFunc))); /// /// Creates metadata for types assignable to . @@ -488,7 +553,7 @@ public static JsonTypeInfo CreateIEnumerableInfo( => new JsonTypeInfoInternal( options, createObjectFunc, - () => new IEnumerableWithAddMethodConverter(), + () => new IEnumerableConverter(), elementInfo, numberHandling, serializeFunc, diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs index f51bc851a0a53..2a4078f178e3d 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonMetadataServices.Converters.cs @@ -82,7 +82,7 @@ public static partial class JsonMetadataServices /// /// Returns a instance that converts values. /// - internal static JsonConverter JsonElementConverter => s_jsonElementConverter ??= new JsonElementConverter(); + public static JsonConverter JsonElementConverter => s_jsonElementConverter ??= new JsonElementConverter(); private static JsonConverter? s_jsonElementConverter; /// diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs index 7f3057b2c73e1..356a563f049d1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfo.cs @@ -306,9 +306,8 @@ internal JsonTypeInfo(Type type, JsonConverter converter, Type runtimeType, Json ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); - if (converter.IsImmutableCollectionConverter) + if (converter.RequiresDynamicMemberAccessors) { - // Initialize a func to create immutable enumerable instances. converter.Initialize(Options, this); } } @@ -319,9 +318,8 @@ internal JsonTypeInfo(Type type, JsonConverter converter, Type runtimeType, Json ElementType = converter.ElementType; CreateObject = Options.MemberAccessorStrategy.CreateConstructor(runtimeType); - if (converter.IsImmutableCollectionConverter) + if (converter.RequiresDynamicMemberAccessors) { - // Initialize a func to create immutable dictionary instances. converter.Initialize(Options, this); } } diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs index c61a504691b2e..6b59b13b97344 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Metadata/JsonTypeInfoInternalOfT.cs @@ -59,7 +59,8 @@ public JsonTypeInfoInternal( JsonNumberHandling numberHandling, Action? serializeFunc, Type elementType, - object? createObjectWithArgs = null) + object? createObjectWithArgs = null, + object? addFunc = null) : base(typeof(T), options, ConverterStrategy.Enumerable) { JsonConverter converter = new JsonMetadataServicesConverter(converterCreator, ConverterStrategy.Enumerable, keyType: null, elementType); @@ -70,6 +71,7 @@ public JsonTypeInfoInternal( PropertyInfoForTypeInfo = JsonMetadataServices.CreateJsonPropertyInfoForClassInfo(typeof(T), this, converter, options); Serialize = serializeFunc; CreateObjectWithArgs = createObjectWithArgs; + AddMethodDelegate = addFunc; SetCreateObjectFunc(createObjectFunc); } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs index 64b5cd5b9666b..1a90f20a2744c 100644 --- a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.KeyPolicy.cs @@ -47,6 +47,9 @@ public async Task CamelCaseDeserialize() } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Need extension data support.")] +#endif public async Task IgnoreKeyPolicyForExtensionData() { var options = new JsonSerializerOptions @@ -286,6 +289,9 @@ public async Task CamelCaseSerialize_ApplyDictionaryKeyPolicy() } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Need extension data support.")] +#endif public async Task SerializationWithJsonExtensionDataAttribute_IgoneDictionaryKeyPolicy() { var expectedJson = @"{""KeyInt"":1000,""KeyString"":""text"",""KeyBool"":true,""KeyObject"":{},""KeyList"":[],""KeyDictionary"":{}}"; @@ -328,7 +334,7 @@ public async Task CamelCaseSerialize_ForTypedDictionary_ApplyDictionaryKeyPolicy Assert.Equal(JsonCamel, json); } - private class CustomClass + public class CustomClass { public string Name { get; set; } public int Number { get; set; } @@ -361,7 +367,7 @@ public async Task CamelCaseSerialize_ForNestedTypedDictionary_ApplyDictionaryKey Assert.Equal(JsonCamel, json); } - private class TestClassWithDictionary + public class TestClassWithDictionary { public Dictionary Data { get; set; } } @@ -382,6 +388,9 @@ public async Task CamelCaseSerialize_ForClassWithDictionaryProperty_ApplyDiction } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Need KVP support.")] +#endif public async Task CamelCaseSerialize_ForKeyValuePairWithDictionaryValue_ApplyDictionaryKeyPolicy() { const string JsonCamel = @"{""Key"":""KeyPair"",""Value"":{""keyDict"":{""Name"":""text"",""Number"":1000,""isValid"":true,""Values"":[1,2,3]}}}"; diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs index fe04a9b625c5e..738679e1beb63 100644 --- a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Dictionary.cs @@ -28,7 +28,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -40,7 +40,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -52,7 +52,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -64,7 +64,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -76,7 +76,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -88,7 +88,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); } @@ -100,7 +100,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); } @@ -112,7 +112,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json); } @@ -124,7 +124,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); } @@ -136,7 +136,7 @@ public async Task DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } } @@ -155,7 +155,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -167,7 +167,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -179,7 +179,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -191,7 +191,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -206,7 +206,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -222,7 +222,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); } @@ -234,7 +234,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.True(JsonString == json || ReorderedJsonString == json); } @@ -246,7 +246,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -258,7 +258,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -271,7 +271,7 @@ public async Task ImplementsDictionary_DictionaryOfString() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -498,7 +498,7 @@ public async Task ListOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } { @@ -515,7 +515,7 @@ public async Task ListOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } } @@ -539,7 +539,7 @@ public async Task ArrayOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -557,7 +557,7 @@ public async Task ArrayOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } } @@ -581,7 +581,7 @@ public async Task DictionaryOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -599,7 +599,7 @@ public async Task DictionaryOfDictionary() string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } } @@ -633,7 +633,7 @@ public async Task DictionaryOfDictionaryOfDictionary() Assert.Equal(JsonString, json); // Verify that typeof(object) doesn't interfere. - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -666,7 +666,7 @@ public async Task DictionaryOfArrayOfDictionary() Assert.Equal(JsonString, json); // Verify that typeof(object) doesn't interfere. - json = JsonSerializer.Serialize(obj); + json = await JsonSerializerWrapperForString.SerializeWrapper(obj); Assert.Equal(JsonString, json); } @@ -787,6 +787,9 @@ public override void Write(Utf8JsonWriter writer, MyClass value, JsonSerializerO return tests; } +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Too many dynamically generated serializable types to manually add to a serialization context.")] +#endif [Fact] public async Task NestedDictionariesRoundtrip() { @@ -801,6 +804,9 @@ public async Task NestedDictionariesRoundtrip() } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Needs full SimpleTestClass support.")] +#endif public async Task DictionaryOfClasses() { { @@ -843,7 +849,7 @@ public async Task DictionaryOfClasses() } { - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); obj = await JsonSerializerWrapperForString.DeserializeWrapper(json); Assert.Equal(2, obj.Count); @@ -882,7 +888,7 @@ public async Task DictionaryOfClasses() } { - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); @@ -912,7 +918,7 @@ public async Task DictionaryOfClasses() } { - string json = JsonSerializer.Serialize(obj); + string json = await JsonSerializerWrapperForString.SerializeWrapper(obj); obj = await JsonSerializerWrapperForString.DeserializeWrapper>(json); Assert.Equal(2, obj.Count); obj["Key1"].Verify(); @@ -1348,6 +1354,9 @@ public async Task ClassWithPopulatedImmutableDictionary() } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Multi-dim arrays not supported.")] +#endif public async Task DictionaryNotSupported() { string json = @"{""MyDictionary"":{""Key"":""Value""}}"; @@ -1359,6 +1368,9 @@ public async Task DictionaryNotSupported() } [Fact] +#if BUILDING_SOURCE_GENERATOR_TESTS + [ActiveIssue("Multi-dim arrays not supported.")] +#endif public async Task DictionaryNotSupportedButIgnored() { string json = @"{""MyDictionary"":{""Key"":1}}"; @@ -1878,19 +1890,19 @@ public async Task VerifyDictionaryThatHasIncomatibleEnumeratorWithPoco() await Assert.ThrowsAsync(async () => await JsonSerializerWrapperForString.SerializeWrapper(dictionary)); } - private class ClassWithoutParameterlessCtor + public class ClassWithoutParameterlessCtor { public ClassWithoutParameterlessCtor(int num) { } public string Name { get; set; } } - private class ClassWithInternalParameterlessConstructor + public class ClassWithInternalParameterlessConstructor { internal ClassWithInternalParameterlessConstructor() { } public string Name { get; set; } } - private class ClassWithPrivateParameterlessConstructor + public class ClassWithPrivateParameterlessConstructor { private ClassWithPrivateParameterlessConstructor() { } public string Name { get; set; } diff --git a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs index 1d5733dde3a83..9b7900c692f0c 100644 --- a/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs +++ b/src/libraries/System.Text.Json/tests/Common/CollectionTests/CollectionTests.Generic.Read.cs @@ -1239,7 +1239,7 @@ public async Task CollectionWith_BackingField_CanRoundtrip() Assert.Equal(json, serialized); } - private class Client + public class Client { private ICollection _allowedGrantTypes = new HashSetWithBackingCollection(); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs index 77882f662d611..79d4378203b55 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/JsonSerializerContextTests.cs @@ -1,7 +1,9 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Reflection; using System.Text.Json.Serialization; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Text.Json.SourceGeneration.Tests @@ -17,6 +19,46 @@ public static void VariousNestingAndVisibilityLevelsAreSupported() Assert.NotNull(NestedPublicContext.NestedProtectedInternalClass.Default); } + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public static void Converters_AndTypeInfoCreator_NotRooted_WhenMetadataNotPresent() + { + RemoteExecutor.Invoke( + new Action(() => + { + object[] objArr = new object[] { new MyStruct() }; + + // Metadata not generated for MyStruct without JsonSerializableAttribute. + NotSupportedException ex = Assert.Throws( + () => JsonSerializer.Serialize(objArr, MetadataContext.Default.ObjectArray)); + string exAsStr = ex.ToString(); + Assert.Contains(typeof(MyStruct).ToString(), exAsStr); + Assert.Contains("JsonSerializerOptions", exAsStr); + + // This test uses reflection to: + // - Access JsonSerializerOptions.s_defaultSimpleConverters + // - Access JsonSerializerOptions.s_defaultFactoryConverters + // - Access JsonSerializerOptions._typeInfoCreationFunc + // + // If any of them changes, this test will need to be kept in sync. + + // Confirm built-in converters not set. + AssertFieldNull("s_defaultSimpleConverters", optionsInstance: null); + AssertFieldNull("s_defaultFactoryConverters", optionsInstance: null); + + // Confirm type info dynamic creator not set. + AssertFieldNull("_typeInfoCreationFunc", MetadataContext.Default.Options); + + static void AssertFieldNull(string fieldName, JsonSerializerOptions? optionsInstance) + { + BindingFlags bindingFlags = BindingFlags.NonPublic | (optionsInstance == null ? BindingFlags.Static : BindingFlags.Instance); + FieldInfo fieldInfo = typeof(JsonSerializerOptions).GetField(fieldName, bindingFlags); + Assert.NotNull(fieldInfo); + Assert.Null(fieldInfo.GetValue(optionsInstance)); + } + }), + new RemoteInvokeOptions() { ExpectedExitCode = 0 }).Dispose(); + } + [JsonSerializable(typeof(JsonMessage))] internal partial class NestedContext : JsonSerializerContext { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs index 0017021fb4edd..db55741cdca51 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/RealWorldContextTests.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Linq; -using System.Reflection; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; using Xunit; @@ -473,41 +472,6 @@ public class ClassWithEnumAndNullable public DayOfWeek? NullableDay { get; set; } } - [Fact] - public void Converters_AndTypeInfoCreator_NotRooted_WhenMetadataNotPresent() - { - object[] objArr = new object[] { new MyStruct() }; - - // Metadata not generated for MyStruct without JsonSerializableAttribute. - NotSupportedException ex = Assert.Throws( - () => JsonSerializer.Serialize(objArr, DefaultContext.ObjectArray)); - string exAsStr = ex.ToString(); - Assert.Contains(typeof(MyStruct).ToString(), exAsStr); - Assert.Contains("JsonSerializerOptions", exAsStr); - - // This test uses reflection to: - // - Access JsonSerializerOptions.s_defaultSimpleConverters - // - Access JsonSerializerOptions.s_defaultFactoryConverters - // - Access JsonSerializerOptions._typeInfoCreationFunc - // - // If any of them changes, this test will need to be kept in sync. - - // Confirm built-in converters not set. - AssertFieldNull("s_defaultSimpleConverters", optionsInstance: null); - AssertFieldNull("s_defaultFactoryConverters", optionsInstance: null); - - // Confirm type info dynamic creator not set. - AssertFieldNull("_typeInfoCreationFunc", ((JsonSerializerContext)DefaultContext).Options); - - static void AssertFieldNull(string fieldName, JsonSerializerOptions? optionsInstance) - { - BindingFlags bindingFlags = BindingFlags.NonPublic | (optionsInstance == null ? BindingFlags.Static : BindingFlags.Instance); - FieldInfo fieldInfo = typeof(JsonSerializerOptions).GetField(fieldName, bindingFlags); - Assert.NotNull(fieldInfo); - Assert.Null(fieldInfo.GetValue(optionsInstance)); - } - } - private const string ExceptionMessageFromCustomContext = "Exception thrown from custom context."; [Fact] @@ -529,8 +493,6 @@ public void GetTypeInfoCalledDuringPolymorphicSerialization() Assert.Contains(ExceptionMessageFromCustomContext, ex.ToString()); } - internal struct MyStruct { } - internal class CustomContext : JsonSerializerContext { public CustomContext(JsonSerializerOptions options) : base(options, null) { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs index 1a3822f4dfc26..8d581aed66ea4 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/CollectionTests.cs @@ -1,7 +1,12 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Collections; using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Collections.ObjectModel; +using System.Collections.Specialized; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Tests; @@ -10,34 +15,726 @@ namespace System.Text.Json.SourceGeneration.Tests public partial class CollectionTests_Metadata : CollectionTests { public CollectionTests_Metadata() - : this(new JsonSerializerWrapperForString_SourceGen(CollectionTestsContext_Metadata.Default, (options) => new CollectionTestsContext_Metadata(options))) + : this(new StringSerializerWrapper(CollectionTestsContext_Metadata.Default, (options) => new CollectionTestsContext_Metadata(options))) { } - protected CollectionTests_Metadata(Serialization.Tests.JsonSerializerWrapperForString serializerWrapper) - : base(serializerWrapper) + protected CollectionTests_Metadata(JsonSerializerWrapperForString serializerWrapper) + : base(serializerWrapper, new StreamSerializerWrapper()) { } [JsonSourceGenerationOptions(GenerationMode = JsonSourceGenerationMode.Metadata)] [JsonSerializable(typeof(ConcurrentDictionary))] - //[JsonSerializable(typeof())] - //[JsonSerializable(typeof())] - //[JsonSerializable(typeof())] + [JsonSerializable(typeof(ConcurrentQueue))] + [JsonSerializable(typeof(ConcurrentStack))] + [JsonSerializable(typeof(BlockingCollection))] + [JsonSerializable(typeof(ConcurrentBag))] + [JsonSerializable(typeof(GenericConcurrentQueuePrivateConstructor))] + [JsonSerializable(typeof(GenericConcurrentQueueInternalConstructor))] + [JsonSerializable(typeof(GenericConcurrentStackPrivateConstructor))] + [JsonSerializable(typeof(GenericConcurrentStackInternalConstructor))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(SortedDictionary))] + [JsonSerializable(typeof(object))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(ImmutableDictionary))] + [JsonSerializable(typeof(IImmutableDictionary))] + [JsonSerializable(typeof(ImmutableSortedDictionary))] + [JsonSerializable(typeof(Hashtable))] + [JsonSerializable(typeof(SortedList))] + [JsonSerializable(typeof(WrapperForIDictionary))] + [JsonSerializable(typeof(StringToStringDictionaryWrapper))] + [JsonSerializable(typeof(StringToStringSortedDictionaryWrapper))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(GenericIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(StringToStringIImmutableDictionaryWrapper))] + [JsonSerializable(typeof(HashtableWrapper))] + [JsonSerializable(typeof(SortedListWrapper))] + [JsonSerializable(typeof(GenericStructIDictionaryWrapper))] + [JsonSerializable(typeof(GenericStructIDictionaryWrapper?))] + [JsonSerializable(typeof(StructWrapperForIDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(PocoDictionary))] + [JsonSerializable(typeof(IDictionary>))] + [JsonSerializable(typeof(ImmutableDictionary>))] + [JsonSerializable(typeof(IImmutableDictionary>))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(Dictionary[]), TypeInfoPropertyName = "ArrayOfDictionaryStringInt")] + [JsonSerializable(typeof(ImmutableSortedDictionary[]))] + [JsonSerializable(typeof(Dictionary>))] + [JsonSerializable(typeof(ImmutableSortedDictionary>))] + [JsonSerializable(typeof(Dictionary>>))] + [JsonSerializable(typeof(Dictionary[]>))] + [JsonSerializable(typeof(SimpleTestClass))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(PocoDuplicate))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary1))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary2))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary3))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary4))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary5))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary6))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary7))] + [JsonSerializable(typeof(ClassWithIgnoredIDictionary))] + [JsonSerializable(typeof(ClassWithIgnoreAttributeDictionary))] + [JsonSerializable(typeof(ClassWithIgnoredImmutableDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(AllSingleUpperPropertiesParent))] + [JsonSerializable(typeof(ClassWithDictionaryOfString_ChildWithDictionaryOfString))] + [JsonSerializable(typeof(ClassWithDictionaryOfString_ChildWithDictionaryOfString))] + [JsonSerializable(typeof(ClassWithDictionaryAndProperty_DictionaryFirst))] + [JsonSerializable(typeof(ClassWithDictionaryAndProperty_DictionaryLast))] + [JsonSerializable(typeof(SimpleClassWithDictionaries))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringTValue))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringTValue))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringPoco))] + [JsonSerializable(typeof(DictionaryThatHasIncompatibleEnumerator))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(StructWrapperForIDictionary?))] + [JsonSerializable(typeof(ClassWithStructIDictionaryWrapper))] + [JsonSerializable(typeof(Poco))] + [JsonSerializable(typeof(JsonElement))] + [JsonSerializable(typeof(string))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary>))] + [JsonSerializable(typeof(TestClassWithDictionary))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(GenericIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(IDerivedIDictionaryOfTKeyTValue))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List[]), TypeInfoPropertyName = "ArrayOfIntList")] + [JsonSerializable(typeof(StringListWrapper[]))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(StringListWrapper))] + [JsonSerializable(typeof(IEnumerable>))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable[]), TypeInfoPropertyName = "ArrayOfIntIEnumerable")] + [JsonSerializable(typeof(StringIEnumerableWrapper[]))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(StringIEnumerableWrapper))] + [JsonSerializable(typeof(IList>))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList[]), TypeInfoPropertyName = "ArrayOfIntIList")] + [JsonSerializable(typeof(StringIListWrapper[]))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(StringIListWrapper))] + [JsonSerializable(typeof(GenericStructIListWrapper))] + [JsonSerializable(typeof(GenericStructIListWrapper?))] + [JsonSerializable(typeof(GenericStructICollectionWrapper))] + [JsonSerializable(typeof(GenericStructICollectionWrapper?))] + [JsonSerializable(typeof(ICollection>))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(ICollection[]), TypeInfoPropertyName = "ArrayOfIntICollection")] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(IReadOnlyCollection>))] + [JsonSerializable(typeof(GenericIReadOnlyCollectionWrapper>))] + [JsonSerializable(typeof(IReadOnlyCollection))] + [JsonSerializable(typeof(GenericIReadOnlyCollectionWrapper))] + [JsonSerializable(typeof(IReadOnlyCollection[]), TypeInfoPropertyName = "ArrayOfIntIReadOnlyCollection")] + [JsonSerializable(typeof(WrapperForIReadOnlyCollectionOfT[]))] + [JsonSerializable(typeof(IReadOnlyCollection))] + [JsonSerializable(typeof(WrapperForIReadOnlyCollectionOfT))] + [JsonSerializable(typeof(IReadOnlyList>))] + [JsonSerializable(typeof(GenericIReadOnlyListWrapper))] + [JsonSerializable(typeof(IReadOnlyList))] + [JsonSerializable(typeof(GenericIReadOnlyListWrapper))] + [JsonSerializable(typeof(IReadOnlyList[]), TypeInfoPropertyName = "ArrayOfIntIReadOnlyList")] + [JsonSerializable(typeof(StringIReadOnlyListWrapper[]))] + [JsonSerializable(typeof(IReadOnlyList))] + [JsonSerializable(typeof(StringIReadOnlyListWrapper))] + [JsonSerializable(typeof(ISet>))] + [JsonSerializable(typeof(GenericISetWrapper))] + [JsonSerializable(typeof(GenericStructISetWrapper))] + [JsonSerializable(typeof(GenericStructISetWrapper?))] + [JsonSerializable(typeof(ISet>))] + [JsonSerializable(typeof(HashSet>))] + [JsonSerializable(typeof(ISet))] + [JsonSerializable(typeof(ISet[]), TypeInfoPropertyName = "ArrayOfIntISet")] + [JsonSerializable(typeof(ISet))] + [JsonSerializable(typeof(Stack>))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(Stack[]), TypeInfoPropertyName = "ArrayOfIntStack")] + [JsonSerializable(typeof(StringStackWrapper[]))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(StringStackWrapper))] + [JsonSerializable(typeof(Queue>))] + [JsonSerializable(typeof(GenericQueueWrapper))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue[]), TypeInfoPropertyName = "ArrayOfIntQueue")] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(HashSet>))] + [JsonSerializable(typeof(GenericHashSetWrapper))] + [JsonSerializable(typeof(HashSet))] + [JsonSerializable(typeof(HashSet[]), TypeInfoPropertyName = "ArrayOfIntHashSet")] + [JsonSerializable(typeof(HashSet))] + [JsonSerializable(typeof(LinkedList>))] + [JsonSerializable(typeof(GenericLinkedListWrapper))] + [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(LinkedList[]), TypeInfoPropertyName = "ArrayOfIntLinkedList")] + [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(SortedSet[]))] + [JsonSerializable(typeof(StringSortedSetWrapper[]))] + [JsonSerializable(typeof(SortedSet))] + [JsonSerializable(typeof(ClassWithGenericStructIListWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructICollectionWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructIDictionaryWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructISetWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithGenericStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestStructWithNullableGenericStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithGenericCollectionWrappers))] + [JsonSerializable(typeof(string[]))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(MyMyList))] + [JsonSerializable(typeof(MyListString))] + [JsonSerializable(typeof(NetworkWrapper))] + [JsonSerializable(typeof(Client))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(IEnumerable[]))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(IList[]))] + [JsonSerializable(typeof(StructWrapperForIList))] + [JsonSerializable(typeof(StructWrapperForIList?))] + [JsonSerializable(typeof(ClassWithStructIListWrapper))] + [JsonSerializable(typeof(StructWrapperForIDictionary))] + [JsonSerializable(typeof(StructWrapperForIDictionary?))] + [JsonSerializable(typeof(ClassWithStructIDictionaryWrapper))] + [JsonSerializable(typeof(WrapperForIList))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(ICollection[]))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(Stack[]))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue[]))] + [JsonSerializable(typeof(QueueWrapper))] + [JsonSerializable(typeof(ArrayList))] + [JsonSerializable(typeof(ArrayListWrapper))] + [JsonSerializable(typeof(ArrayList[]))] + [JsonSerializable(typeof(SimpleTestClassWithNonGenericCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestStructWithNullableStructCollectionWrappers))] + [JsonSerializable(typeof(Collection))] + [JsonSerializable(typeof(ObservableCollection))] + [JsonSerializable(typeof(SimpleKeyedCollection))] + [JsonSerializable(typeof(ReadOnlyCollection))] + [JsonSerializable(typeof(ReadOnlyObservableCollection))] + [JsonSerializable(typeof(ReadOnlyDictionary))] + [JsonSerializable(typeof(KeyedCollection))] + [JsonSerializable(typeof(BitVector32))] + [JsonSerializable(typeof(HybridDictionary))] + [JsonSerializable(typeof(OrderedDictionary))] + [JsonSerializable(typeof(ListDictionary))] + [JsonSerializable(typeof(StringCollection))] + [JsonSerializable(typeof(StringDictionary))] + [JsonSerializable(typeof(IOrderedDictionary))] + [JsonSerializable(typeof(NameValueCollection))] + [JsonSerializable(typeof(ImmutableArray>))] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(ImmutableArray[]), TypeInfoPropertyName = "ArrayOfImmutableIntArray")] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableArray))] + [JsonSerializable(typeof(IImmutableList>))] + [JsonSerializable(typeof(IImmutableList))] + [JsonSerializable(typeof(IImmutableList[]), TypeInfoPropertyName = "ArrayOfIImmutableIntArrayList")] + [JsonSerializable(typeof(IImmutableList))] + [JsonSerializable(typeof(IImmutableStack>))] + [JsonSerializable(typeof(IImmutableStack))] + [JsonSerializable(typeof(IImmutableStack[]), TypeInfoPropertyName = "ArrayOfIImmutableIntStack")] + [JsonSerializable(typeof(IImmutableStack))] + [JsonSerializable(typeof(IImmutableQueue>))] + [JsonSerializable(typeof(IImmutableQueue))] + [JsonSerializable(typeof(IImmutableQueue[]), TypeInfoPropertyName = "ArrayOfIImmutableIntQueue")] + [JsonSerializable(typeof(IImmutableQueue))] + [JsonSerializable(typeof(IImmutableSet>))] + [JsonSerializable(typeof(IImmutableSet))] + [JsonSerializable(typeof(IImmutableSet[]), TypeInfoPropertyName = "ArrayOfIImmutableIntSet")] + [JsonSerializable(typeof(IImmutableSet))] + [JsonSerializable(typeof(ImmutableHashSet>))] + [JsonSerializable(typeof(ImmutableHashSet))] + [JsonSerializable(typeof(ImmutableHashSet[]), TypeInfoPropertyName = "ArrayOfImmutableIntHashSet")] + [JsonSerializable(typeof(ImmutableHashSet))] + [JsonSerializable(typeof(ImmutableList>))] + [JsonSerializable(typeof(ImmutableList))] + [JsonSerializable(typeof(ImmutableList[]), TypeInfoPropertyName = "ArrayOfImmutableIntList")] + [JsonSerializable(typeof(ImmutableList))] + [JsonSerializable(typeof(ImmutableStack>))] + [JsonSerializable(typeof(ImmutableStack))] + [JsonSerializable(typeof(ImmutableStack[]), TypeInfoPropertyName = "ArrayOfImmutableIntStack")] + [JsonSerializable(typeof(ImmutableStack))] + [JsonSerializable(typeof(ImmutableQueue>))] + [JsonSerializable(typeof(ImmutableQueue))] + [JsonSerializable(typeof(ImmutableQueue[]), TypeInfoPropertyName = "ArrayOfImmutableIntQueue")] + [JsonSerializable(typeof(ImmutableQueue))] + [JsonSerializable(typeof(ImmutableSortedSet[]))] + [JsonSerializable(typeof(ImmutableSortedSet))] + [JsonSerializable(typeof(SimpleTestClassWithIImmutableDictionaryWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableStackWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableQueueWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableSetWrapper))] + [JsonSerializable(typeof(ClassWithPopulatedDictionaryAndNoSetter))] + [JsonSerializable(typeof(StringIImmutableQueueWrapper))] + [JsonSerializable(typeof(StringIImmutableStackWrapper))] + [JsonSerializable(typeof(ClassWithPopulatedDictionaryAndSetter))] + [JsonSerializable(typeof(StringIImmutableListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithObjectImmutableArray))] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(StringIImmutableSetWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(ICollection>))] + [JsonSerializable(typeof(SimpleTestClassWithStringIEnumerableWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringIReadOnlyCollectionWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringIReadOnlyListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(GenericICollectionWrapper>))] + [JsonSerializable(typeof(GenericIEnumerableWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIEnumerableWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericICollectionWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericICollectionWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericIListWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIListWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericISetWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericISetWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericIDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(StringToStringIReadOnlyDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(StringToStringIReadOnlyDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericListWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericListWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericQueueWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericQueueWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericStackWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericStackWrapperInternalConstructor))] + [JsonSerializable(typeof(StringToGenericDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(StringToGenericDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(SimpleTestClassWithNonGenericCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithIEnumerableWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithICollectionWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStackWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithQueueWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(WrapperForIEnumerable))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(DictionaryEntry))] + [JsonSerializable(typeof(Dictionary[]))] + [JsonSerializable(typeof(GenericQueueWrapper))] + [JsonSerializable(typeof(WrapperForIEnumerablePrivateConstructor))] + [JsonSerializable(typeof(WrapperForIEnumerableInternalConstructor))] + [JsonSerializable(typeof(WrapperForICollectionPrivateConstructor))] + [JsonSerializable(typeof(WrapperForICollectionInternalConstructor))] + [JsonSerializable(typeof(WrapperForIListPrivateConstructor))] + [JsonSerializable(typeof(WrapperForIListInternalConstructor))] + [JsonSerializable(typeof(WrapperForIDictionaryPrivateConstructor))] + [JsonSerializable(typeof(WrapperForIDictionaryInternalConstructor))] + [JsonSerializable(typeof(IDerivedICollectionOfT))] + [JsonSerializable(typeof(IDerivedIList))] + [JsonSerializable(typeof(IDerivedISetOfT))] + [JsonSerializable(typeof(ReadOnlyWrapperForIList))] + [JsonSerializable(typeof(ReadOnlyStringIListWrapper))] + [JsonSerializable(typeof(ReadOnlyStringICollectionWrapper))] + [JsonSerializable(typeof(ReadOnlyStringISetWrapper))] + [JsonSerializable(typeof(ReadOnlyWrapperForIDictionary))] + [JsonSerializable(typeof(ReadOnlyStringToStringIDictionaryWrapper))] + [JsonSerializable(typeof(Dictionary[]))] internal sealed partial class CollectionTestsContext_Metadata : JsonSerializerContext { } } - //public partial class CollectionTests_Default : CollectionTests_Metadata - //{ - // public CollectionTests_Default() - // : base(new JsonSerializerWrapperForString_SourceGen(CollectionTestsContext_Default.Default, (options) => new CollectionTestsContext_Default(options))) - // { - // } + public partial class CollectionTests_Default : CollectionTests_Metadata + { + public CollectionTests_Default() + : base(new StringSerializerWrapper(CollectionTestsContext_Default.Default, (options) => new CollectionTestsContext_Default(options))) + { + } - // internal sealed partial class CollectionTestsContext_Default : JsonSerializerContext - // { - // } - //} + [JsonSerializable(typeof(ConcurrentDictionary))] + [JsonSerializable(typeof(ConcurrentQueue))] + [JsonSerializable(typeof(ConcurrentStack))] + [JsonSerializable(typeof(BlockingCollection))] + [JsonSerializable(typeof(ConcurrentBag))] + [JsonSerializable(typeof(GenericConcurrentQueuePrivateConstructor))] + [JsonSerializable(typeof(GenericConcurrentQueueInternalConstructor))] + [JsonSerializable(typeof(GenericConcurrentStackPrivateConstructor))] + [JsonSerializable(typeof(GenericConcurrentStackInternalConstructor))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(SortedDictionary))] + [JsonSerializable(typeof(object))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(ImmutableDictionary))] + [JsonSerializable(typeof(IImmutableDictionary))] + [JsonSerializable(typeof(ImmutableSortedDictionary))] + [JsonSerializable(typeof(Hashtable))] + [JsonSerializable(typeof(SortedList))] + [JsonSerializable(typeof(WrapperForIDictionary))] + [JsonSerializable(typeof(StringToStringDictionaryWrapper))] + [JsonSerializable(typeof(StringToStringSortedDictionaryWrapper))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(GenericIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(StringToStringIImmutableDictionaryWrapper))] + [JsonSerializable(typeof(HashtableWrapper))] + [JsonSerializable(typeof(SortedListWrapper))] + [JsonSerializable(typeof(GenericStructIDictionaryWrapper))] + [JsonSerializable(typeof(GenericStructIDictionaryWrapper?))] + [JsonSerializable(typeof(StructWrapperForIDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(GenericIDictionaryWrapper))] + [JsonSerializable(typeof(PocoDictionary))] + [JsonSerializable(typeof(IDictionary>))] + [JsonSerializable(typeof(ImmutableDictionary>))] + [JsonSerializable(typeof(IImmutableDictionary>))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(Dictionary[]), TypeInfoPropertyName = "ArrayOfDictionaryStringInt")] + [JsonSerializable(typeof(ImmutableSortedDictionary[]))] + [JsonSerializable(typeof(Dictionary>))] + [JsonSerializable(typeof(ImmutableSortedDictionary>))] + [JsonSerializable(typeof(Dictionary>>))] + [JsonSerializable(typeof(Dictionary[]>))] + [JsonSerializable(typeof(SimpleTestClass))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(PocoDuplicate))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary1))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary2))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary3))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary4))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary5))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary6))] + [JsonSerializable(typeof(ClassWithIgnoredDictionary7))] + [JsonSerializable(typeof(ClassWithIgnoredIDictionary))] + [JsonSerializable(typeof(ClassWithIgnoreAttributeDictionary))] + [JsonSerializable(typeof(ClassWithIgnoredImmutableDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(AllSingleUpperPropertiesParent))] + [JsonSerializable(typeof(ClassWithDictionaryOfString_ChildWithDictionaryOfString))] + [JsonSerializable(typeof(ClassWithDictionaryOfString_ChildWithDictionaryOfString))] + [JsonSerializable(typeof(ClassWithDictionaryAndProperty_DictionaryFirst))] + [JsonSerializable(typeof(ClassWithDictionaryAndProperty_DictionaryLast))] + [JsonSerializable(typeof(SimpleClassWithDictionaries))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringTValue))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringTValue))] + [JsonSerializable(typeof(DictionaryThatOnlyImplementsIDictionaryOfStringPoco))] + [JsonSerializable(typeof(DictionaryThatHasIncompatibleEnumerator))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(StructWrapperForIDictionary?))] + [JsonSerializable(typeof(ClassWithStructIDictionaryWrapper))] + [JsonSerializable(typeof(Poco))] + [JsonSerializable(typeof(JsonElement))] + [JsonSerializable(typeof(string))] + [JsonSerializable(typeof(IDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(Dictionary>))] + [JsonSerializable(typeof(TestClassWithDictionary))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(GenericIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(IDerivedIDictionaryOfTKeyTValue))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List>))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(List[]), TypeInfoPropertyName = "ArrayOfIntList")] + [JsonSerializable(typeof(StringListWrapper[]))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(StringListWrapper))] + [JsonSerializable(typeof(IEnumerable>))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable[]), TypeInfoPropertyName = "ArrayOfIntIEnumerable")] + [JsonSerializable(typeof(StringIEnumerableWrapper[]))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(StringIEnumerableWrapper))] + [JsonSerializable(typeof(IList>))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList[]), TypeInfoPropertyName = "ArrayOfIntIList")] + [JsonSerializable(typeof(StringIListWrapper[]))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(StringIListWrapper))] + [JsonSerializable(typeof(GenericStructIListWrapper))] + [JsonSerializable(typeof(GenericStructIListWrapper?))] + [JsonSerializable(typeof(GenericStructICollectionWrapper))] + [JsonSerializable(typeof(GenericStructICollectionWrapper?))] + [JsonSerializable(typeof(ICollection>))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(ICollection[]), TypeInfoPropertyName = "ArrayOfIntICollection")] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(IReadOnlyCollection>))] + [JsonSerializable(typeof(GenericIReadOnlyCollectionWrapper>))] + [JsonSerializable(typeof(IReadOnlyCollection))] + [JsonSerializable(typeof(GenericIReadOnlyCollectionWrapper))] + [JsonSerializable(typeof(IReadOnlyCollection[]), TypeInfoPropertyName = "ArrayOfIntIReadOnlyCollection")] + [JsonSerializable(typeof(WrapperForIReadOnlyCollectionOfT[]))] + [JsonSerializable(typeof(IReadOnlyCollection))] + [JsonSerializable(typeof(WrapperForIReadOnlyCollectionOfT))] + [JsonSerializable(typeof(IReadOnlyList>))] + [JsonSerializable(typeof(GenericIReadOnlyListWrapper))] + [JsonSerializable(typeof(IReadOnlyList))] + [JsonSerializable(typeof(GenericIReadOnlyListWrapper))] + [JsonSerializable(typeof(IReadOnlyList[]), TypeInfoPropertyName = "ArrayOfIntIReadOnlyList")] + [JsonSerializable(typeof(StringIReadOnlyListWrapper[]))] + [JsonSerializable(typeof(IReadOnlyList))] + [JsonSerializable(typeof(StringIReadOnlyListWrapper))] + [JsonSerializable(typeof(ISet>))] + [JsonSerializable(typeof(GenericISetWrapper))] + [JsonSerializable(typeof(GenericStructISetWrapper))] + [JsonSerializable(typeof(GenericStructISetWrapper?))] + [JsonSerializable(typeof(ISet>))] + [JsonSerializable(typeof(HashSet>))] + [JsonSerializable(typeof(ISet))] + [JsonSerializable(typeof(ISet[]), TypeInfoPropertyName = "ArrayOfIntISet")] + [JsonSerializable(typeof(ISet))] + [JsonSerializable(typeof(Stack>))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(Stack[]), TypeInfoPropertyName = "ArrayOfIntStack")] + [JsonSerializable(typeof(StringStackWrapper[]))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(StringStackWrapper))] + [JsonSerializable(typeof(Queue>))] + [JsonSerializable(typeof(GenericQueueWrapper))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue[]), TypeInfoPropertyName = "ArrayOfIntQueue")] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(HashSet>))] + [JsonSerializable(typeof(GenericHashSetWrapper))] + [JsonSerializable(typeof(HashSet))] + [JsonSerializable(typeof(HashSet[]), TypeInfoPropertyName = "ArrayOfIntHashSet")] + [JsonSerializable(typeof(HashSet))] + [JsonSerializable(typeof(LinkedList>))] + [JsonSerializable(typeof(GenericLinkedListWrapper))] + [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(LinkedList[]), TypeInfoPropertyName = "ArrayOfIntLinkedList")] + [JsonSerializable(typeof(LinkedList))] + [JsonSerializable(typeof(SortedSet[]))] + [JsonSerializable(typeof(StringSortedSetWrapper[]))] + [JsonSerializable(typeof(SortedSet))] + [JsonSerializable(typeof(ClassWithGenericStructIListWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructICollectionWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructIDictionaryWrapper))] + [JsonSerializable(typeof(ClassWithGenericStructISetWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithGenericStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestStructWithNullableGenericStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithGenericCollectionWrappers))] + [JsonSerializable(typeof(string[]))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(GenericListWrapper))] + [JsonSerializable(typeof(MyMyList))] + [JsonSerializable(typeof(MyListString))] + [JsonSerializable(typeof(NetworkWrapper))] + [JsonSerializable(typeof(Client))] + [JsonSerializable(typeof(IReadOnlyDictionary))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(GenericIEnumerableWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(IEnumerable[]))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(GenericIListWrapper))] + [JsonSerializable(typeof(IList))] + [JsonSerializable(typeof(IList[]))] + [JsonSerializable(typeof(StructWrapperForIList))] + [JsonSerializable(typeof(StructWrapperForIList?))] + [JsonSerializable(typeof(ClassWithStructIListWrapper))] + [JsonSerializable(typeof(StructWrapperForIDictionary))] + [JsonSerializable(typeof(StructWrapperForIDictionary?))] + [JsonSerializable(typeof(ClassWithStructIDictionaryWrapper))] + [JsonSerializable(typeof(WrapperForIList))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(GenericICollectionWrapper))] + [JsonSerializable(typeof(ICollection))] + [JsonSerializable(typeof(ICollection[]))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(Stack))] + [JsonSerializable(typeof(Stack[]))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue))] + [JsonSerializable(typeof(Queue[]))] + [JsonSerializable(typeof(QueueWrapper))] + [JsonSerializable(typeof(ArrayList))] + [JsonSerializable(typeof(ArrayListWrapper))] + [JsonSerializable(typeof(ArrayList[]))] + [JsonSerializable(typeof(SimpleTestClassWithNonGenericCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithStructCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestStructWithNullableStructCollectionWrappers))] + [JsonSerializable(typeof(Collection))] + [JsonSerializable(typeof(ObservableCollection))] + [JsonSerializable(typeof(SimpleKeyedCollection))] + [JsonSerializable(typeof(ReadOnlyCollection))] + [JsonSerializable(typeof(ReadOnlyObservableCollection))] + [JsonSerializable(typeof(ReadOnlyDictionary))] + [JsonSerializable(typeof(KeyedCollection))] + [JsonSerializable(typeof(BitVector32))] + [JsonSerializable(typeof(HybridDictionary))] + [JsonSerializable(typeof(OrderedDictionary))] + [JsonSerializable(typeof(ListDictionary))] + [JsonSerializable(typeof(StringCollection))] + [JsonSerializable(typeof(StringDictionary))] + [JsonSerializable(typeof(IOrderedDictionary))] + [JsonSerializable(typeof(NameValueCollection))] + [JsonSerializable(typeof(ImmutableArray>))] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(ImmutableArray[]), TypeInfoPropertyName = "ArrayOfImmutableIntArray")] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableArray))] + [JsonSerializable(typeof(IImmutableList>))] + [JsonSerializable(typeof(IImmutableList))] + [JsonSerializable(typeof(IImmutableList[]), TypeInfoPropertyName = "ArrayOfIImmutableIntArrayList")] + [JsonSerializable(typeof(IImmutableList))] + [JsonSerializable(typeof(IImmutableStack>))] + [JsonSerializable(typeof(IImmutableStack))] + [JsonSerializable(typeof(IImmutableStack[]), TypeInfoPropertyName = "ArrayOfIImmutableIntStack")] + [JsonSerializable(typeof(IImmutableStack))] + [JsonSerializable(typeof(IImmutableQueue>))] + [JsonSerializable(typeof(IImmutableQueue))] + [JsonSerializable(typeof(IImmutableQueue[]), TypeInfoPropertyName = "ArrayOfIImmutableIntQueue")] + [JsonSerializable(typeof(IImmutableQueue))] + [JsonSerializable(typeof(IImmutableSet>))] + [JsonSerializable(typeof(IImmutableSet))] + [JsonSerializable(typeof(IImmutableSet[]), TypeInfoPropertyName = "ArrayOfIImmutableIntSet")] + [JsonSerializable(typeof(IImmutableSet))] + [JsonSerializable(typeof(ImmutableHashSet>))] + [JsonSerializable(typeof(ImmutableHashSet))] + [JsonSerializable(typeof(ImmutableHashSet[]), TypeInfoPropertyName = "ArrayOfImmutableIntHashSet")] + [JsonSerializable(typeof(ImmutableHashSet))] + [JsonSerializable(typeof(ImmutableList>))] + [JsonSerializable(typeof(ImmutableList))] + [JsonSerializable(typeof(ImmutableList[]), TypeInfoPropertyName = "ArrayOfImmutableIntList")] + [JsonSerializable(typeof(ImmutableList))] + [JsonSerializable(typeof(ImmutableStack>))] + [JsonSerializable(typeof(ImmutableStack))] + [JsonSerializable(typeof(ImmutableStack[]), TypeInfoPropertyName = "ArrayOfImmutableIntStack")] + [JsonSerializable(typeof(ImmutableStack))] + [JsonSerializable(typeof(ImmutableQueue>))] + [JsonSerializable(typeof(ImmutableQueue))] + [JsonSerializable(typeof(ImmutableQueue[]), TypeInfoPropertyName = "ArrayOfImmutableIntQueue")] + [JsonSerializable(typeof(ImmutableQueue))] + [JsonSerializable(typeof(ImmutableSortedSet[]))] + [JsonSerializable(typeof(ImmutableSortedSet))] + [JsonSerializable(typeof(SimpleTestClassWithIImmutableDictionaryWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableStackWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableQueueWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithImmutableSetWrapper))] + [JsonSerializable(typeof(ClassWithPopulatedDictionaryAndNoSetter))] + [JsonSerializable(typeof(StringIImmutableQueueWrapper))] + [JsonSerializable(typeof(StringIImmutableStackWrapper))] + [JsonSerializable(typeof(ClassWithPopulatedDictionaryAndSetter))] + [JsonSerializable(typeof(StringIImmutableListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithObjectImmutableArray))] + [JsonSerializable(typeof(ImmutableArray))] + [JsonSerializable(typeof(StringIImmutableSetWrapper))] + [JsonSerializable(typeof(IEnumerable))] + [JsonSerializable(typeof(ICollection>))] + [JsonSerializable(typeof(SimpleTestClassWithStringIEnumerableWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringIReadOnlyCollectionWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringIReadOnlyListWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStringToStringIReadOnlyDictionaryWrapper))] + [JsonSerializable(typeof(Dictionary))] + [JsonSerializable(typeof(GenericICollectionWrapper>))] + [JsonSerializable(typeof(GenericIEnumerableWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIEnumerableWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericICollectionWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericICollectionWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericIListWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIListWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericISetWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericISetWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericIDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericIDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(StringToStringIReadOnlyDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(StringToStringIReadOnlyDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericListWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericListWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericQueueWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericQueueWrapperInternalConstructor))] + [JsonSerializable(typeof(GenericStackWrapperPrivateConstructor))] + [JsonSerializable(typeof(GenericStackWrapperInternalConstructor))] + [JsonSerializable(typeof(StringToGenericDictionaryWrapperPrivateConstructor))] + [JsonSerializable(typeof(StringToGenericDictionaryWrapperInternalConstructor))] + [JsonSerializable(typeof(SimpleTestClassWithNonGenericCollectionWrappers))] + [JsonSerializable(typeof(SimpleTestClassWithIEnumerableWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithICollectionWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithStackWrapper))] + [JsonSerializable(typeof(SimpleTestClassWithQueueWrapper))] + [JsonSerializable(typeof(List))] + [JsonSerializable(typeof(WrapperForIEnumerable))] + [JsonSerializable(typeof(GenericStackWrapper))] + [JsonSerializable(typeof(DictionaryEntry))] + [JsonSerializable(typeof(Dictionary[]))] + [JsonSerializable(typeof(GenericQueueWrapper))] + [JsonSerializable(typeof(WrapperForIEnumerablePrivateConstructor))] + [JsonSerializable(typeof(WrapperForIEnumerableInternalConstructor))] + [JsonSerializable(typeof(WrapperForICollectionPrivateConstructor))] + [JsonSerializable(typeof(WrapperForICollectionInternalConstructor))] + [JsonSerializable(typeof(WrapperForIListPrivateConstructor))] + [JsonSerializable(typeof(WrapperForIListInternalConstructor))] + [JsonSerializable(typeof(WrapperForIDictionaryPrivateConstructor))] + [JsonSerializable(typeof(WrapperForIDictionaryInternalConstructor))] + [JsonSerializable(typeof(IDerivedICollectionOfT))] + [JsonSerializable(typeof(IDerivedIList))] + [JsonSerializable(typeof(IDerivedISetOfT))] + [JsonSerializable(typeof(ReadOnlyWrapperForIList))] + [JsonSerializable(typeof(ReadOnlyStringIListWrapper))] + [JsonSerializable(typeof(ReadOnlyStringICollectionWrapper))] + [JsonSerializable(typeof(ReadOnlyStringISetWrapper))] + [JsonSerializable(typeof(ReadOnlyWrapperForIDictionary))] + [JsonSerializable(typeof(ReadOnlyStringToStringIDictionaryWrapper))] + [JsonSerializable(typeof(Dictionary[]))] + internal sealed partial class CollectionTestsContext_Default : JsonSerializerContext + { + } + } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapperForString_SourceGen.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapper.cs similarity index 70% rename from src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapperForString_SourceGen.cs rename to src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapper.cs index dfb968371a224..c119e7fe504cf 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapperForString_SourceGen.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/JsonSerializerWrapper.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.IO; using System.Text.Json.Serialization; using System.Text.Json.Serialization.Metadata; using System.Text.Json.Serialization.Tests; @@ -8,12 +9,12 @@ namespace System.Text.Json.SourceGeneration.Tests { - internal sealed class JsonSerializerWrapperForString_SourceGen : JsonSerializerWrapperForString + internal sealed class StringSerializerWrapper : JsonSerializerWrapperForString { private readonly JsonSerializerContext _defaultContext; private readonly Func _customContextCreator; - public JsonSerializerWrapperForString_SourceGen(JsonSerializerContext defaultContext, Func customContextCreator) + public StringSerializerWrapper(JsonSerializerContext defaultContext, Func customContextCreator) { _defaultContext = defaultContext ?? throw new ArgumentNullException(nameof(defaultContext)); _customContextCreator = customContextCreator ?? throw new ArgumentNullException(nameof(defaultContext)); @@ -37,6 +38,13 @@ private string Serialize(object value, Type type, JsonSerializerOptions options) protected internal override Task SerializeWrapper(T value, JsonSerializerOptions? options = null) { + Type runtimeType = GetRuntimeType(value); + + if (runtimeType != typeof(T)) + { + return SerializeWrapper(value, runtimeType, options); + } + if (options != null) { return Task.FromResult(Serialize(value, options)); @@ -53,6 +61,16 @@ private string Serialize(T value, JsonSerializerOptions options) return JsonSerializer.Serialize(value, typeInfo); } + private static Type GetRuntimeType(in TValue value) + { + if (typeof(TValue) == typeof(object) && value != null) + { + return value.GetType(); + } + + return typeof(TValue); + } + protected internal override Task SerializeWrapper(object value, Type inputType, JsonSerializerContext context) => throw new NotImplementedException(); @@ -99,4 +117,14 @@ protected internal override Task DeserializeWrapper(string json, JsonTypeI protected internal override Task DeserializeWrapper(string json, Type type, JsonSerializerContext context) => throw new NotImplementedException(); } + + internal sealed class StreamSerializerWrapper : JsonSerializerWrapperForStream + { + protected internal override Task DeserializeWrapper(Stream utf8Json, JsonSerializerOptions options = null) => throw new NotImplementedException(); + protected internal override Task DeserializeWrapper(Stream utf8Json, Type returnType, JsonSerializerOptions options = null) => throw new NotImplementedException(); + protected internal override Task DeserializeWrapper(Stream utf8Json, JsonTypeInfo jsonTypeInfo) => throw new NotImplementedException(); + protected internal override Task SerializeWrapper(Stream stream, T value, JsonSerializerOptions options = null) => throw new NotImplementedException(); + protected internal override Task SerializeWrapper(Stream stream, object value, Type inputType, JsonSerializerOptions options = null) => throw new NotImplementedException(); + protected internal override Task SerializeWrapper(Stream stream, T value, JsonTypeInfo jsonTypeInfo) => throw new NotImplementedException(); + } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs index 884108a0f18d5..cc9b3d617107c 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/PropertyVisibilityTests.cs @@ -12,7 +12,7 @@ namespace System.Text.Json.SourceGeneration.Tests public partial class PropertyVisibilityTests_Metadata : PropertyVisibilityTests { public PropertyVisibilityTests_Metadata() - : this(new JsonSerializerWrapperForString_SourceGen(PropertyVisibilityTestsContext_Metadata.Default, (options) => new PropertyVisibilityTestsContext_Metadata(options))) + : this(new StringSerializerWrapper(PropertyVisibilityTestsContext_Metadata.Default, (options) => new PropertyVisibilityTestsContext_Metadata(options))) { } @@ -261,7 +261,7 @@ internal sealed partial class PropertyVisibilityTestsContext_Metadata : JsonSeri public partial class PropertyVisibilityTests_Default : PropertyVisibilityTests_Metadata { public PropertyVisibilityTests_Default() - : base(new JsonSerializerWrapperForString_SourceGen(PropertyVisibilityTestsContext_Default.Default, (options) => new PropertyVisibilityTestsContext_Default(options))) + : base(new StringSerializerWrapper(PropertyVisibilityTestsContext_Default.Default, (options) => new PropertyVisibilityTestsContext_Default(options))) { } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationLogicTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationLogicTests.cs index daa3a4cb71ec9..a086659da5477 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationLogicTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/SerializationLogicTests.cs @@ -52,8 +52,8 @@ public static void SerializationFuncNotInvokedWhenNotSupported(JsonSerializerOpt [Fact] public static void DictionaryFastPathPrimitiveValueSupported() { - Assert.NotNull(DictionaryTypeContext.Default.DictionarySystemStringSystemString.Serialize); - Assert.NotNull(DictionaryTypeContext.Default.DictionarySystemStringSystemTextJsonSourceGenerationTestsJsonMessage.Serialize); + Assert.NotNull(DictionaryTypeContext.Default.DictionaryStringString.Serialize); + Assert.NotNull(DictionaryTypeContext.Default.DictionaryStringJsonMessage.Serialize); Assert.NotNull(DictionaryTypeContext.Default.JsonMessage.Serialize); Assert.Null(DictionaryTypeContext.Default.String.Serialize); Assert.Null(DictionaryTypeContext.Default.Int32.Serialize); diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj index a50b259aacbc9..9b8dc0b1592d7 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/System.Text.Json.SourceGeneration.Tests.csproj @@ -1,7 +1,8 @@ - + $(NetCoreAppCurrent);$(NetFrameworkCurrent) true + true $(NoWarn);SYSLIB0020 @@ -58,7 +59,7 @@ - + diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs index ff110fe377933..50be97c82afc3 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/TestClasses.cs @@ -134,4 +134,6 @@ public class JsonMessage public string Message { get; set; } public int Length => Message?.Length ?? 0; // Read-only property } + + internal struct MyStruct { } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.Collections.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.Collections.cs index 91d8f7a667b18..b5fa2534860bd 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.Collections.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/Stream.Collections.cs @@ -5,7 +5,6 @@ using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.Immutable; -using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; From 01ffde9a7322f3572423cd94dd065e914d89bd38 Mon Sep 17 00:00:00 2001 From: Layomi Akinrinade Date: Wed, 14 Jul 2021 20:31:29 -0700 Subject: [PATCH 3/3] Revert redundant MLC change and address feedback --- .../Reflection/MetadataLoadContextInternal.cs | 28 +++---------------- .../gen/TypeGenerationSpec.cs | 1 + 2 files changed, 5 insertions(+), 24 deletions(-) diff --git a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs index 44107c865011c..1d87aa8d58364 100644 --- a/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs +++ b/src/libraries/System.Text.Json/gen/Reflection/MetadataLoadContextInternal.cs @@ -48,11 +48,7 @@ public MetadataLoadContextInternal(Compilation compilation) string assemblyName = type.Assembly.GetName().Name; IAssemblySymbol assemblySymbol; - if (assemblyName == "System.Private.CoreLib" || - assemblyName == "mscorlib" || - assemblyName == "System.Runtime" || - assemblyName == "System.Private.Uri" || - assemblyName == "System.Collections") + if (assemblyName == "System.Private.CoreLib" || assemblyName == "mscorlib" || assemblyName == "System.Runtime" || assemblyName == "System.Private.Uri") { Type resolvedType = ResolveFromAssembly(type, CoreAssembly.Symbol); if (resolvedType != null) @@ -76,28 +72,12 @@ public MetadataLoadContextInternal(Compilation compilation) assemblyName = typeForwardedFrom.GetConstructorArgument(0); } - Type? candidate; - - if (_assemblies.TryGetValue(new AssemblyName(assemblyName).Name, out assemblySymbol)) - { - candidate = ResolveFromAssembly(type, assemblySymbol); - if (candidate != null) - { - return type; - } - } - - // Last-ditch fallback: check all of the assemblies. - foreach (IAssemblySymbol assembly in _assemblies.Values) + if (!_assemblies.TryGetValue(new AssemblyName(assemblyName).Name, out assemblySymbol)) { - candidate = ResolveFromAssembly(type, assembly); - if (candidate != null) - { - return type; - } + return null; } - throw new NotSupportedException(); + return ResolveFromAssembly(type, assemblySymbol); } private Type? ResolveFromAssembly(Type type, IAssemblySymbol assemblySymbol) diff --git a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs index 0fb7b2e37c059..9241d57c1d593 100644 --- a/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs +++ b/src/libraries/System.Text.Json/gen/TypeGenerationSpec.cs @@ -85,6 +85,7 @@ public string? ImmutableCollectionBuilderName return null; } + Debug.Assert(builderName != null); return $"global::{builderName}.{ReflectionExtensions.CreateRangeMethodName}"; } }