From b3a5e544a01daee84eec897dee1e1485f7f6f2b7 Mon Sep 17 00:00:00 2001 From: Steve Harter Date: Fri, 13 Mar 2020 17:12:09 -0500 Subject: [PATCH] Add polymorphic tests for all root APIs (#33391) --- .../tests/Serialization/PolymorphicTests.cs | 206 +++++++++++++-------- .../tests/Serialization/SerializationWrapper.cs | 116 ++++++++++++ .../tests/System.Text.Json.Tests.csproj | 1 + 3 files changed, 244 insertions(+), 79 deletions(-) create mode 100644 src/libraries/System.Text.Json/tests/Serialization/SerializationWrapper.cs diff --git a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs index 771cabd..c1a352d 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/PolymorphicTests.cs @@ -9,35 +9,67 @@ using Xunit; namespace System.Text.Json.Serialization.Tests { - public static class PolymorphicTests + public class PolymorphicTests_Span : PolymorphicTests { + public PolymorphicTests_Span() : base(SerializationWrapper.SpanSerializer) { } + } + + public class PolymorphicTests_String : PolymorphicTests + { + public PolymorphicTests_String() : base(SerializationWrapper.StringSerializer) { } + } + + public class PolymorphicTests_Stream : PolymorphicTests + { + public PolymorphicTests_Stream() : base(SerializationWrapper.StreamSerializer) { } + } + + public class PolymorphicTests_StreamWithSmallBuffer : PolymorphicTests + { + public PolymorphicTests_StreamWithSmallBuffer() : base(SerializationWrapper.StreamSerializerWithSmallBuffer) { } + } + + public class PolymorphicTests_Writer : PolymorphicTests + { + public PolymorphicTests_Writer() : base(SerializationWrapper.WriterSerializer) { } + } + + public abstract class PolymorphicTests + { + private SerializationWrapper Serializer { get; } + + public PolymorphicTests(SerializationWrapper serializer) + { + Serializer = serializer; + } + [Fact] - public static void PrimitivesAsRootObject() + public void PrimitivesAsRootObject() { - string json = JsonSerializer.Serialize(1); + string json = Serializer.Serialize(1); Assert.Equal("1", json); - json = JsonSerializer.Serialize(1, typeof(object)); + json = Serializer.Serialize(1, typeof(object)); Assert.Equal("1", json); - json = JsonSerializer.Serialize("foo"); + json = Serializer.Serialize("foo"); Assert.Equal(@"""foo""", json); - json = JsonSerializer.Serialize("foo", typeof(object)); + json = Serializer.Serialize("foo", typeof(object)); Assert.Equal(@"""foo""", json); - json = JsonSerializer.Serialize(true); + json = Serializer.Serialize(true); Assert.Equal(@"true", json); - json = JsonSerializer.Serialize(true, typeof(object)); + json = Serializer.Serialize(true, typeof(object)); Assert.Equal(@"true", json); - json = JsonSerializer.Serialize(null); + json = Serializer.Serialize(null); Assert.Equal(@"null", json); - json = JsonSerializer.Serialize((object)null, typeof(object)); + json = Serializer.Serialize((object)null, typeof(object)); Assert.Equal(@"null", json); decimal pi = 3.1415926535897932384626433833m; - json = JsonSerializer.Serialize(pi); + json = Serializer.Serialize(pi); Assert.Equal(@"3.1415926535897932384626433833", json); - json = JsonSerializer.Serialize(pi, typeof(object)); + json = Serializer.Serialize(pi, typeof(object)); Assert.Equal(@"3.1415926535897932384626433833", json); } @@ -71,7 +103,7 @@ namespace System.Text.Json.Serialization.Tests } [Fact] - public static void ArrayAsRootObject() + public void ArrayAsRootObject() { const string ExpectedJson = @"[1,true,{""City"":""MyCity""},null,""foo""]"; const string ReversedExpectedJson = @"[""foo"",null,{""City"":""MyCity""},true,1]"; @@ -82,193 +114,193 @@ namespace System.Text.Json.Serialization.Tests address.Initialize(); var array = new object[] { 1, true, address, null, "foo" }; - string json = JsonSerializer.Serialize(array); + string json = Serializer.Serialize(array); Assert.Equal(ExpectedJson, json); var dictionary = new Dictionary { { "City", "MyCity" } }; var arrayWithDictionary = new object[] { 1, true, dictionary, null, "foo" }; - json = JsonSerializer.Serialize(arrayWithDictionary); + json = Serializer.Serialize(arrayWithDictionary); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(array); + json = Serializer.Serialize(array); Assert.Equal(ExpectedJson, json); List list = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(list); + json = Serializer.Serialize(list); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(list); + json = Serializer.Serialize(list); Assert.Equal(ExpectedJson, json); IEnumerable ienumerable = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(ienumerable); + json = Serializer.Serialize(ienumerable); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(ienumerable); + json = Serializer.Serialize(ienumerable); Assert.Equal(ExpectedJson, json); IList ilist = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(ilist); + json = Serializer.Serialize(ilist); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(ilist); + json = Serializer.Serialize(ilist); Assert.Equal(ExpectedJson, json); ICollection icollection = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(icollection); + json = Serializer.Serialize(icollection); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(icollection); + json = Serializer.Serialize(icollection); Assert.Equal(ExpectedJson, json); IEnumerable genericIEnumerable = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(genericIEnumerable); + json = Serializer.Serialize(genericIEnumerable); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(genericIEnumerable); + json = Serializer.Serialize(genericIEnumerable); Assert.Equal(ExpectedJson, json); IList genericIList = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(genericIList); + json = Serializer.Serialize(genericIList); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(genericIList); + json = Serializer.Serialize(genericIList); Assert.Equal(ExpectedJson, json); ICollection genericICollection = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(genericICollection); + json = Serializer.Serialize(genericICollection); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(genericICollection); + json = Serializer.Serialize(genericICollection); Assert.Equal(ExpectedJson, json); IReadOnlyCollection genericIReadOnlyCollection = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(genericIReadOnlyCollection); + json = Serializer.Serialize(genericIReadOnlyCollection); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(genericIReadOnlyCollection); + json = Serializer.Serialize(genericIReadOnlyCollection); Assert.Equal(ExpectedJson, json); IReadOnlyList genericIReadonlyList = new List { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(genericIReadonlyList); + json = Serializer.Serialize(genericIReadonlyList); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(genericIReadonlyList); + json = Serializer.Serialize(genericIReadonlyList); Assert.Equal(ExpectedJson, json); ISet iset = new HashSet { 1, true, address, null, "foo" }; - json = JsonSerializer.Serialize(iset); + json = Serializer.Serialize(iset); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(iset); + json = Serializer.Serialize(iset); Assert.Equal(ExpectedJson, json); Stack stack = new Stack(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(stack); + json = Serializer.Serialize(stack); Assert.Equal(ReversedExpectedJson, json); - json = JsonSerializer.Serialize(stack); + json = Serializer.Serialize(stack); Assert.Equal(ReversedExpectedJson, json); Queue queue = new Queue(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(queue); + json = Serializer.Serialize(queue); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(queue); + json = Serializer.Serialize(queue); Assert.Equal(ExpectedJson, json); HashSet hashset = new HashSet(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(hashset); + json = Serializer.Serialize(hashset); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(hashset); + json = Serializer.Serialize(hashset); Assert.Equal(ExpectedJson, json); LinkedList linkedlist = new LinkedList(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(linkedlist); + json = Serializer.Serialize(linkedlist); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(linkedlist); + json = Serializer.Serialize(linkedlist); Assert.Equal(ExpectedJson, json); ImmutableArray immutablearray = ImmutableArray.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(immutablearray); + json = Serializer.Serialize(immutablearray); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(immutablearray); + json = Serializer.Serialize(immutablearray); Assert.Equal(ExpectedJson, json); IImmutableList iimmutablelist = ImmutableList.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(iimmutablelist); + json = Serializer.Serialize(iimmutablelist); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(iimmutablelist); + json = Serializer.Serialize(iimmutablelist); Assert.Equal(ExpectedJson, json); IImmutableStack iimmutablestack = ImmutableStack.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(iimmutablestack); + json = Serializer.Serialize(iimmutablestack); Assert.Equal(ReversedExpectedJson, json); - json = JsonSerializer.Serialize(iimmutablestack); + json = Serializer.Serialize(iimmutablestack); Assert.Equal(ReversedExpectedJson, json); IImmutableQueue iimmutablequeue = ImmutableQueue.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(iimmutablequeue); + json = Serializer.Serialize(iimmutablequeue); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(iimmutablequeue); + json = Serializer.Serialize(iimmutablequeue); Assert.Equal(ExpectedJson, json); IImmutableSet iimmutableset = ImmutableHashSet.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(iimmutableset); + json = Serializer.Serialize(iimmutableset); foreach (string obj in expectedObjects) { Assert.Contains(obj, json); } - json = JsonSerializer.Serialize(iimmutableset); + json = Serializer.Serialize(iimmutableset); foreach (string obj in expectedObjects) { Assert.Contains(obj, json); } ImmutableHashSet immutablehashset = ImmutableHashSet.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(immutablehashset); + json = Serializer.Serialize(immutablehashset); foreach (string obj in expectedObjects) { Assert.Contains(obj, json); } - json = JsonSerializer.Serialize(immutablehashset); + json = Serializer.Serialize(immutablehashset); foreach (string obj in expectedObjects) { Assert.Contains(obj, json); } ImmutableList immutablelist = ImmutableList.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(immutablelist); + json = Serializer.Serialize(immutablelist); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(immutablelist); + json = Serializer.Serialize(immutablelist); Assert.Equal(ExpectedJson, json); ImmutableStack immutablestack = ImmutableStack.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(immutablestack); + json = Serializer.Serialize(immutablestack); Assert.Equal(ReversedExpectedJson, json); - json = JsonSerializer.Serialize(immutablestack); + json = Serializer.Serialize(immutablestack); Assert.Equal(ReversedExpectedJson, json); ImmutableQueue immutablequeue = ImmutableQueue.CreateRange(new List { 1, true, address, null, "foo" }); - json = JsonSerializer.Serialize(immutablequeue); + json = Serializer.Serialize(immutablequeue); Assert.Equal(ExpectedJson, json); - json = JsonSerializer.Serialize(immutablequeue); + json = Serializer.Serialize(immutablequeue); Assert.Equal(ExpectedJson, json); } [Fact] - public static void SimpleTestClassAsRootObject() + public void SimpleTestClassAsRootObject() { // Sanity checks on test type. Assert.Equal(typeof(object), typeof(SimpleTestClassWithObject).GetProperty("MyInt16").PropertyType); @@ -279,20 +311,20 @@ namespace System.Text.Json.Serialization.Tests obj.Initialize(); // Verify with actual type. - string json = JsonSerializer.Serialize(obj); + string json = Serializer.Serialize(obj); Assert.Contains(@"""MyInt16"":1", json); Assert.Contains(@"""MyBooleanTrue"":true", json); Assert.Contains(@"""MyInt16Array"":[1]", json); // Verify with object type. - json = JsonSerializer.Serialize(obj); + json = Serializer.Serialize(obj); Assert.Contains(@"""MyInt16"":1", json); Assert.Contains(@"""MyBooleanTrue"":true", json); Assert.Contains(@"""MyInt16Array"":[1]", json); } [Fact] - public static void NestedObjectAsRootObject() + public void NestedObjectAsRootObject() { static void Verify(string json) { @@ -337,43 +369,43 @@ namespace System.Text.Json.Serialization.Tests var obj = new ObjectWithObjectProperties(); - string json = JsonSerializer.Serialize(obj); + string json = Serializer.Serialize(obj); Verify(json); - json = JsonSerializer.Serialize(obj); + json = Serializer.Serialize(obj); Verify(json); } [Fact] - public static void NestedObjectAsRootObjectIgnoreNullable() + public void NestedObjectAsRootObjectIgnoreNullable() { // Ensure that null properties are properly written and support ignore. var obj = new ObjectWithObjectProperties(); obj.NullableInt = null; - string json = JsonSerializer.Serialize(obj); + string json = Serializer.Serialize(obj); Assert.Contains(@"""NullableInt"":null", json); JsonSerializerOptions options = new JsonSerializerOptions(); options.IgnoreNullValues = true; - json = JsonSerializer.Serialize(obj, options); + json = Serializer.Serialize(obj, options); Assert.DoesNotContain(@"""NullableInt"":null", json); } [Fact] - public static void StaticAnalysisBaseline() + public void StaticAnalysisBaseline() { Customer customer = new Customer(); customer.Initialize(); customer.Verify(); - string json = JsonSerializer.Serialize(customer); + string json = Serializer.Serialize(customer); Customer deserializedCustomer = JsonSerializer.Deserialize(json); deserializedCustomer.Verify(); } [Fact] - public static void StaticAnalysis() + public void StaticAnalysis() { Customer customer = new Customer(); customer.Initialize(); @@ -382,7 +414,7 @@ namespace System.Text.Json.Serialization.Tests Person person = customer; // Generic inference used = - string json = JsonSerializer.Serialize(person); + string json = Serializer.Serialize(person); Customer deserializedCustomer = JsonSerializer.Deserialize(json); @@ -393,7 +425,7 @@ namespace System.Text.Json.Serialization.Tests } [Fact] - public static void WriteStringWithRuntimeType() + public void WriteStringWithRuntimeType() { Customer customer = new Customer(); customer.Initialize(); @@ -401,7 +433,7 @@ namespace System.Text.Json.Serialization.Tests Person person = customer; - string json = JsonSerializer.Serialize(person, person.GetType()); + string json = Serializer.Serialize(person, person.GetType()); Customer deserializedCustomer = JsonSerializer.Deserialize(json); @@ -411,7 +443,7 @@ namespace System.Text.Json.Serialization.Tests } [Fact] - public static void StaticAnalysisWithRelationship() + public void StaticAnalysisWithRelationship() { UsaCustomer usaCustomer = new UsaCustomer(); usaCustomer.Initialize(); @@ -423,7 +455,7 @@ namespace System.Text.Json.Serialization.Tests Customer customer = usaCustomer; // Generic inference used = - string json = JsonSerializer.Serialize(customer); + string json = Serializer.Serialize(customer); UsaCustomer deserializedCustomer = JsonSerializer.Deserialize(json); @@ -464,6 +496,22 @@ namespace System.Text.Json.Serialization.Tests Assert.Throws(() => JsonSerializer.Deserialize(@"{"""":{}}")); } + [Fact] + public void AnonymousType() + { + const string Expected = @"{""x"":1,""y"":true}"; + var value = new { x = 1, y = true }; + + // Strongly-typed. + string json = Serializer.Serialize(value); + Assert.Equal(Expected, json); + + // Boxed. + object objValue = value; + json = Serializer.Serialize(objValue); + Assert.Equal(Expected, json); + } + class MyClass { public string Value { get; set; } diff --git a/src/libraries/System.Text.Json/tests/Serialization/SerializationWrapper.cs b/src/libraries/System.Text.Json/tests/Serialization/SerializationWrapper.cs new file mode 100644 index 0000000..628b29e --- /dev/null +++ b/src/libraries/System.Text.Json/tests/Serialization/SerializationWrapper.cs @@ -0,0 +1,116 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.IO; +using System.Threading.Tasks; + +namespace System.Text.Json.Serialization.Tests +{ + /// + /// Base class for wrapping serialization calls which allows tests to run under different configurations. + /// + public abstract class SerializationWrapper + { + private static readonly JsonSerializerOptions _optionsWithSmallBuffer = new JsonSerializerOptions { DefaultBufferSize = 1 }; + + public static SerializationWrapper SpanSerializer => new SpanSerializerWrapper(); + public static SerializationWrapper StringSerializer => new StringSerializerWrapper(); + public static SerializationWrapper StreamSerializer => new StreamSerializerWrapper(); + public static SerializationWrapper StreamSerializerWithSmallBuffer => new StreamSerializerWrapperWithSmallBuffer(); + public static SerializationWrapper WriterSerializer => new WriterSerializerWrapper(); + + protected internal abstract string Serialize(object value, Type inputType, JsonSerializerOptions options = null); + + protected internal abstract string Serialize(T value, JsonSerializerOptions options = null); + + + private class SpanSerializerWrapper : SerializationWrapper + { + protected internal override string Serialize(object value, Type inputType, JsonSerializerOptions options = null) + { + byte[] result = JsonSerializer.SerializeToUtf8Bytes(value, inputType, options); + return Encoding.UTF8.GetString(result); + } + + protected internal override string Serialize(T value, JsonSerializerOptions options = null) + { + byte[] result = JsonSerializer.SerializeToUtf8Bytes(value, options); + return Encoding.UTF8.GetString(result); + } + } + + private class StringSerializerWrapper : SerializationWrapper + { + protected internal override string Serialize(object value, Type inputType, JsonSerializerOptions options = null) + { + return JsonSerializer.Serialize(value, inputType, options); + } + + protected internal override string Serialize(T value, JsonSerializerOptions options = null) + { + return JsonSerializer.Serialize(value, options); + } + } + + private class StreamSerializerWrapper : SerializationWrapper + { + protected internal override string Serialize(object value, Type inputType, JsonSerializerOptions options = null) + { + return Task.Run(async () => + { + using var stream = new MemoryStream(); + await JsonSerializer.SerializeAsync(stream, value, inputType, options); + return Encoding.UTF8.GetString(stream.ToArray()); + }).Result; + } + + protected internal override string Serialize(T value, JsonSerializerOptions options = null) + { + return Task.Run(async () => + { + using var stream = new MemoryStream(); + await JsonSerializer.SerializeAsync(stream, value, options); + return Encoding.UTF8.GetString(stream.ToArray()); + }).Result; + } + } + + private class StreamSerializerWrapperWithSmallBuffer : StreamSerializerWrapper + { + protected internal override string Serialize(object value, Type inputType, JsonSerializerOptions options = null) + { + if (options == null) + { + options = _optionsWithSmallBuffer; + } + + return base.Serialize(value, inputType, options); + } + + protected internal override string Serialize(T value, JsonSerializerOptions options = null) + { + return base.Serialize(value, options); + } + } + + private class WriterSerializerWrapper : SerializationWrapper + { + protected internal override string Serialize(object value, Type inputType, JsonSerializerOptions options = null) + { + using MemoryStream stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream); + JsonSerializer.Serialize(writer, value, inputType, options); + return Encoding.UTF8.GetString(stream.ToArray()); + } + + protected internal override string Serialize(T value, JsonSerializerOptions options = null) + { + using MemoryStream stream = new MemoryStream(); + using var writer = new Utf8JsonWriter(stream); + JsonSerializer.Serialize(writer, value, options); + return Encoding.UTF8.GetString(stream.ToArray()); + } + } + } +} diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj index 555c57d..65d5b69 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj @@ -80,6 +80,7 @@ + -- 2.7.4