From f00eda3890b785440cd4eaeaaf9df6f7acb36767 Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Fri, 19 Aug 2022 17:37:38 +0200 Subject: [PATCH 1/2] Add functional custom JsonConverter tests for Int128/UInt128/Half --- ...rtersForUnsupportedTypesFunctionalTests.cs | 100 ++++++++++++++++++ .../System.Text.Json.Tests.csproj | 3 + 2 files changed, 103 insertions(+) create mode 100644 src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs new file mode 100644 index 00000000000000..ecd2b49eb640d0 --- /dev/null +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs @@ -0,0 +1,100 @@ +// 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 Xunit; + +namespace System.Text.Json.Serialization.Tests +{ + public static class ConvertersForUnsupportedTypesFunctionalTests + { + [Theory] + [MemberData(nameof(GetTestData))] + public static void RoundtripValues(string expectedValueAsString, T value) + { + JsonSerializerOptions options = new() + { + Converters = { new Int128Converter(), new UInt128Converter(), new HalfConverter() } + }; + + ClassWithProperty wrappedValue = new() + { + Property = value + }; + + string json = JsonSerializer.Serialize(value, options); + Assert.Equal(expectedValueAsString, json); + + T deserializedValue = JsonSerializer.Deserialize(json, options); + Assert.Equal(value, deserializedValue); + + json = JsonSerializer.Serialize(wrappedValue, options); + Assert.Equal($"{{\"Property\":{expectedValueAsString}}}", json); + ClassWithProperty deserializedWrappedValue = JsonSerializer.Deserialize>(json, options); + Assert.Equal(wrappedValue.Property, deserializedWrappedValue.Property); + } + + public static IEnumerable GetTestData() + { + yield return GetTestCase("0", Int128.Zero); + yield return GetTestCase("-1", new Int128(ulong.MaxValue, ulong.MaxValue)); + yield return GetTestCase(Int128.MaxValue.ToString(), Int128.MaxValue); + yield return GetTestCase(ulong.MaxValue.ToString(), new Int128(0UL, ulong.MaxValue)); + yield return GetTestCase(ulong.MaxValue.ToString() + "173", new Int128(0UL, ulong.MaxValue) * 1000 + 173); + + yield return GetTestCase("0", UInt128.Zero); + yield return GetTestCase(UInt128.MaxValue.ToString(), UInt128.MaxValue); + yield return GetTestCase(ulong.MaxValue.ToString(), new UInt128(0UL, ulong.MaxValue)); + yield return GetTestCase(ulong.MaxValue.ToString() + "173", new UInt128(0UL, ulong.MaxValue) * 1000 + 173); + + yield return GetTestCase("0", Half.Zero); + yield return GetTestCase(Half.MaxValue.ToString(), Half.MaxValue); + yield return GetTestCase(Half.MinValue.ToString(), Half.MinValue); + yield return GetTestCase(((Half)1.45f).ToString(), (Half)1.45f); + + static object[] GetTestCase(string expectedValue, object value) => new object[] { expectedValue, value }; + } + + internal class ClassWithProperty + { + public T Property { get; set; } + } + + internal class HalfConverter : SimpleConverter + { + public override Half Parse(string value) => Half.Parse(value); + } + + internal class UInt128Converter : SimpleConverter + { + public override UInt128 Parse(string value) => UInt128.Parse(value); + } + + internal class Int128Converter : SimpleConverter + { + public override Int128 Parse(string value) => Int128.Parse(value); + } + + internal abstract class SimpleConverter : JsonConverter + { + public abstract T Parse(string value); + + public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.HasValueSequence) + { + return Parse(Encoding.UTF8.GetString(reader.ValueSequence)); + } + else + { + return Parse(Encoding.UTF8.GetString(reader.ValueSpan)); + } + } + + public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) + { + writer.WriteRawValue(value.ToString()); + } + } + } +} 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 4efc9ade0fd0e4..749f6364889bac 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 @@ -226,6 +226,9 @@ + + + From 814f8814c108ee7895653e67193ed96d0c5d623c Mon Sep 17 00:00:00 2001 From: Krzysztof Wicher Date: Fri, 19 Aug 2022 21:38:07 +0200 Subject: [PATCH 2/2] use invariant culture --- ...rtersForUnsupportedTypesFunctionalTests.cs | 47 +++++++++++++------ 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs index ecd2b49eb640d0..847a5cf8f50e86 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/ConvertersForUnsupportedTypesFunctionalTests.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; +using System.Globalization; +using System.Numerics; using Xunit; namespace System.Text.Json.Serialization.Tests @@ -14,7 +16,7 @@ public static void RoundtripValues(string expectedValueAsString, T value) { JsonSerializerOptions options = new() { - Converters = { new Int128Converter(), new UInt128Converter(), new HalfConverter() } + Converters = { new Int128Converter(), new UInt128Converter(), new HalfConverter(), new BigIntegerConverter() } }; ClassWithProperty wrappedValue = new() @@ -36,21 +38,28 @@ public static void RoundtripValues(string expectedValueAsString, T value) public static IEnumerable GetTestData() { + NumberFormatInfo nfi = CultureInfo.InvariantCulture.NumberFormat; + yield return GetTestCase("0", Int128.Zero); yield return GetTestCase("-1", new Int128(ulong.MaxValue, ulong.MaxValue)); - yield return GetTestCase(Int128.MaxValue.ToString(), Int128.MaxValue); - yield return GetTestCase(ulong.MaxValue.ToString(), new Int128(0UL, ulong.MaxValue)); - yield return GetTestCase(ulong.MaxValue.ToString() + "173", new Int128(0UL, ulong.MaxValue) * 1000 + 173); + yield return GetTestCase(Int128.MaxValue.ToString(nfi), Int128.MaxValue); + yield return GetTestCase(ulong.MaxValue.ToString(nfi), new Int128(0UL, ulong.MaxValue)); + yield return GetTestCase(ulong.MaxValue.ToString(nfi) + "173", new Int128(0UL, ulong.MaxValue) * 1000 + 173); yield return GetTestCase("0", UInt128.Zero); - yield return GetTestCase(UInt128.MaxValue.ToString(), UInt128.MaxValue); - yield return GetTestCase(ulong.MaxValue.ToString(), new UInt128(0UL, ulong.MaxValue)); - yield return GetTestCase(ulong.MaxValue.ToString() + "173", new UInt128(0UL, ulong.MaxValue) * 1000 + 173); + yield return GetTestCase(UInt128.MaxValue.ToString(nfi), UInt128.MaxValue); + yield return GetTestCase(ulong.MaxValue.ToString(nfi), new UInt128(0UL, ulong.MaxValue)); + yield return GetTestCase(ulong.MaxValue.ToString(nfi) + "173", new UInt128(0UL, ulong.MaxValue) * 1000 + 173); yield return GetTestCase("0", Half.Zero); - yield return GetTestCase(Half.MaxValue.ToString(), Half.MaxValue); - yield return GetTestCase(Half.MinValue.ToString(), Half.MinValue); - yield return GetTestCase(((Half)1.45f).ToString(), (Half)1.45f); + yield return GetTestCase(Half.MaxValue.ToString(nfi), Half.MaxValue); + yield return GetTestCase(Half.MinValue.ToString(nfi), Half.MinValue); + yield return GetTestCase(((Half)1.45f).ToString(nfi), (Half)1.45f); + + yield return GetTestCase("0", BigInteger.Zero); + yield return GetTestCase("1", BigInteger.One); + yield return GetTestCase(ulong.MaxValue.ToString(nfi), (BigInteger)ulong.MaxValue); + yield return GetTestCase("-123", (BigInteger)(-123)); static object[] GetTestCase(string expectedValue, object value) => new object[] { expectedValue, value }; } @@ -62,22 +71,32 @@ internal class ClassWithProperty internal class HalfConverter : SimpleConverter { - public override Half Parse(string value) => Half.Parse(value); + public override Half Parse(string value) => Half.Parse(value, CultureInfo.InvariantCulture.NumberFormat); + public override string ToString(Half value) => value.ToString(CultureInfo.InvariantCulture.NumberFormat); } internal class UInt128Converter : SimpleConverter { - public override UInt128 Parse(string value) => UInt128.Parse(value); + public override UInt128 Parse(string value) => UInt128.Parse(value, CultureInfo.InvariantCulture.NumberFormat); + public override string ToString(UInt128 value) => value.ToString(CultureInfo.InvariantCulture.NumberFormat); } internal class Int128Converter : SimpleConverter { - public override Int128 Parse(string value) => Int128.Parse(value); + public override Int128 Parse(string value) => Int128.Parse(value, CultureInfo.InvariantCulture.NumberFormat); + public override string ToString(Int128 value) => value.ToString(CultureInfo.InvariantCulture.NumberFormat); + } + + internal class BigIntegerConverter : SimpleConverter + { + public override BigInteger Parse(string value) => BigInteger.Parse(value, CultureInfo.InvariantCulture.NumberFormat); + public override string ToString(BigInteger value) => value.ToString(CultureInfo.InvariantCulture.NumberFormat); } internal abstract class SimpleConverter : JsonConverter { public abstract T Parse(string value); + public abstract string ToString(T value); public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { @@ -93,7 +112,7 @@ public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerial public override void Write(Utf8JsonWriter writer, T value, JsonSerializerOptions options) { - writer.WriteRawValue(value.ToString()); + writer.WriteRawValue(ToString(value)); } } }