From: Marco Rossignoli Date: Thu, 13 Jun 2019 17:10:01 +0000 (+0200) Subject: [3.0 Bug fix]JsonSerializer.Parse throws for UInt64 backed enum with value -1 (dotnet... X-Git-Tag: submit/tizen/20210909.063632~11031^2~1304 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=646ad5efff47282c4104fd5a21e10693a75fac42;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [3.0 Bug fix]JsonSerializer.Parse throws for UInt64 backed enum with value -1 (dotnet/corefx#38373) * fix ulong enum converter * save work * address PR feedback * add more tests * remove -1 = Max support for unsigned * address PR fedback * update tests * address PR feedback * address PR feedback * address PR feedback Commit migrated from https://github.com/dotnet/corefx/commit/42e11c64d878d5875dbc6f5d228cb034ee4b2e59 --- diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterEnum.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterEnum.cs index 653ff7b..455209f 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterEnum.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterEnum.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Runtime.CompilerServices; using System.Text.Json.Serialization.Policies; namespace System.Text.Json.Serialization.Converters @@ -9,7 +10,7 @@ namespace System.Text.Json.Serialization.Converters internal sealed class JsonValueConverterEnum : JsonValueConverter where TValue : struct, Enum { - private static readonly bool s_isUint64 = Enum.GetUnderlyingType(typeof(TValue)) == typeof(ulong); + private static readonly TypeCode s_enumTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(typeof(TValue))); public bool TreatAsString { get; private set; } @@ -39,18 +40,87 @@ namespace System.Text.Json.Serialization.Converters return false; } - if (s_isUint64) - { - if (reader.TryGetUInt64(out ulong ulongValue)) - { - value = (TValue)Enum.ToObject(valueType, ulongValue); - return true; - } - } - else if (reader.TryGetInt64(out long longValue)) + // When utf8reader/writer will support all primitive types we should remove custom bound checks + // https://github.com/dotnet/corefx/issues/36125 + + switch (s_enumTypeCode) { - value = (TValue)Enum.ToObject(valueType, longValue); - return true; + case TypeCode.SByte: + { + if (reader.TryGetInt32(out int byte8) && JsonHelpers.IsInRangeInclusive(byte8, sbyte.MinValue, sbyte.MaxValue)) + { + sbyte byte8Value = (sbyte)byte8; + value = Unsafe.As(ref byte8Value); + return true; + } + break; + } + case TypeCode.Byte: + { + if (reader.TryGetUInt32(out uint ubyte8) && JsonHelpers.IsInRangeInclusive(ubyte8, byte.MinValue, byte.MaxValue)) + { + byte ubyte8Value = (byte)ubyte8; + value = Unsafe.As(ref ubyte8Value); + return true; + } + break; + } + case TypeCode.Int16: + { + if (reader.TryGetInt32(out int int16) && JsonHelpers.IsInRangeInclusive(int16, short.MinValue, short.MaxValue)) + { + short shortValue = (short)int16; + value = Unsafe.As(ref shortValue); + return true; + } + break; + } + case TypeCode.UInt16: + { + if (reader.TryGetUInt32(out uint uint16) && JsonHelpers.IsInRangeInclusive(uint16, ushort.MinValue, ushort.MaxValue)) + { + ushort ushortValue = (ushort)uint16; + value = Unsafe.As(ref ushortValue); + return true; + } + break; + } + case TypeCode.Int32: + { + if (reader.TryGetInt32(out int int32)) + { + value = Unsafe.As(ref int32); + return true; + } + break; + } + case TypeCode.UInt32: + { + if (reader.TryGetUInt32(out uint uint32)) + { + value = Unsafe.As(ref uint32); + return true; + } + break; + } + case TypeCode.Int64: + { + if (reader.TryGetInt64(out long int64)) + { + value = Unsafe.As(ref int64); + return true; + } + break; + } + case TypeCode.UInt64: + { + if (reader.TryGetUInt64(out ulong uint64)) + { + value = Unsafe.As(ref uint64); + return true; + } + break; + } } value = default; @@ -63,7 +133,7 @@ namespace System.Text.Json.Serialization.Converters { writer.WriteStringValue(value.ToString()); } - else if (s_isUint64) + else if (s_enumTypeCode == TypeCode.UInt64) { // Use the ulong converter to prevent conversion into a signed\long value. ulong ulongValue = Convert.ToUInt64(value); @@ -83,7 +153,7 @@ namespace System.Text.Json.Serialization.Converters { writer.WriteString(propertyName, value.ToString()); } - else if (s_isUint64) + else if (s_enumTypeCode == TypeCode.UInt64) { // Use the ulong converter to prevent conversion into a signed\long value. ulong ulongValue = Convert.ToUInt64(value); diff --git a/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs b/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs index 70e6a1a..2df4405 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/EnumTests.cs @@ -18,6 +18,11 @@ namespace System.Text.Json.Serialization.Tests @"""MyEnum"" : 2" + @"}"; + private static readonly string s_jsonInt16Enum = + @"{" + + @"""MyInt16Enum"" : 2" + + @"}"; + private static readonly string s_jsonInt64EnumMin = @"{" + @"""MyInt64Enum"" : " + long.MinValue + @@ -33,25 +38,236 @@ namespace System.Text.Json.Serialization.Tests @"""MyUInt64Enum"" : " + ulong.MaxValue + @"}"; + private static readonly string s_jsonUInt16EnumMax = + @"{" + + @"""MyUInt16Enum"" : " + ushort.MaxValue + + @"}"; + private static readonly string s_jsonByteEnum = @"{" + @"""MyByteEnum"" : " + byte.MaxValue + @"}"; - private const string UlongMaxPlus1 = "18446744073709551616"; // ulong.MaxValue + 1; + private static readonly string s_jsonSByteEnum = + @"{" + + @"""MySByteEnum"" : " + sbyte.MaxValue + + @"}"; + + private const string UInt64MaxPlus1 = "18446744073709551616"; // ulong.MaxValue + 1; + private const string MinusUInt64MaxMinus1 = "-18446744073709551616"; // -ulong.MaxValue - 1 + + private const string Int64MaxPlus1 = "9223372036854775808"; // long.MaxValue + 1; + private const string Int64MinMinus1 = "-9223372036854775809"; // long.MinValue - 1 + + private const string UInt32MaxPlus1 = "4294967296"; // uint.MaxValue + 1; + private const string MinusUInt32MaxMinus1 = "-4294967296"; // -uint.MaxValue - 1 + + private const string Int32MaxPlus1 = "2147483648"; // int.MaxValue + 1; + private const string Int32MinMinus1 = "-2147483649"; // int.MinValue - 1 + + private const string UInt16MaxPlus1 = "65536"; // ushort.MaxValue + 1; + private const string MinusUInt16MaxMinus1 = "-65536"; // -ushort.MaxValue - 1 + + private const string Int16MaxPlus1 = "32768"; // int.MaxValue + 1; + private const string Int16MinMinus1 = "-32769"; // int.MinValue - 1 + + private const string ByteMaxPlus1 = "256"; // byte.MaxValue + 1; + private const string MinusByteMaxMinus1 = "-257"; // -byte.MaxValue - 1 + + [Fact] + public static void Parse_MinusByteMaxMinus1_Throws() + { + Assert.Equal(int.Parse(MinusByteMaxMinus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {MinusByteMaxMinus1} }}").MyEnum); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {MinusByteMaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {MinusByteMaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {MinusByteMaxMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{MinusByteMaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{MinusByteMaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{MinusByteMaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{MinusByteMaxMinus1}\" }}")); + } + + [Fact] + public static void Parse_ByteMaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {ByteMaxPlus1} }}")); + Assert.Equal(int.Parse(ByteMaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {ByteMaxPlus1} }}").MyEnum); + Assert.Equal(int.Parse(ByteMaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {ByteMaxPlus1} }}").MyUInt32Enum); + Assert.Equal(int.Parse(ByteMaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {ByteMaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{ByteMaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{ByteMaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{ByteMaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{ByteMaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_Int16MinMinus1_Throws() + { + Assert.Equal(int.Parse(Int16MinMinus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {Int16MinMinus1} }}").MyEnum); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int16MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int16MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int16MinMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int16MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int16MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int16MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int16MinMinus1}\" }}")); + } + + [Fact] + public static void Parse_Int16MaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int16MaxPlus1} }}")); + Assert.Equal(int.Parse(Int16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {Int16MaxPlus1} }}").MyEnum); + Assert.Equal(int.Parse(Int16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int16MaxPlus1} }}").MyUInt32Enum); + Assert.Equal(int.Parse(Int16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int16MaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int16MaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_MinusUInt16MaxMinus1_Throws() + { + Assert.Equal(int.Parse(MinusUInt16MaxMinus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {MinusUInt16MaxMinus1} }}").MyEnum); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {MinusUInt16MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {MinusUInt16MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {MinusUInt16MaxMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{MinusUInt16MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{MinusUInt16MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{MinusUInt16MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{MinusUInt16MaxMinus1}\" }}")); + } + + [Fact] + public static void Parse_UInt16MaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {UInt16MaxPlus1} }}")); + Assert.Equal(int.Parse(UInt16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyEnum\" : {UInt16MaxPlus1} }}").MyEnum); + Assert.Equal(int.Parse(UInt16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {UInt16MaxPlus1} }}").MyUInt32Enum); + Assert.Equal(int.Parse(UInt16MaxPlus1), (int)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {UInt16MaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{UInt16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{UInt16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{UInt16MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{UInt16MaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_Int32MinMinus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {Int32MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int32MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int32MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int32MinMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int32MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int32MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int32MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int32MinMinus1}\" }}")); + } + + [Fact] + public static void Parse_Int32MaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {Int32MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int32MaxPlus1} }}")); + Assert.Equal(ulong.Parse(Int32MaxPlus1), (ulong)JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int32MaxPlus1} }}").MyUInt32Enum); + Assert.Equal(ulong.Parse(Int32MaxPlus1), (ulong)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int32MaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int32MaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_MinusUInt32MaxMinus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {MinusUInt32MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {MinusUInt32MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {MinusUInt32MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {MinusUInt32MaxMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int64MinMinus1}\" }}")); + } + + [Fact] + public static void Parse_UInt32MaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {UInt32MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {UInt32MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {UInt32MaxPlus1} }}")); + Assert.Equal(ulong.Parse(UInt32MaxPlus1), (ulong)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {UInt32MaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{UInt32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{UInt32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{UInt32MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{UInt32MaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_Int64MinMinus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {Int64MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int64MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int64MinMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int64MinMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int64MinMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int64MinMinus1}\" }}")); + } + + [Fact] + public static void Parse_Int64MaxPlus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {Int64MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {Int64MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {Int64MaxPlus1} }}")); + Assert.Equal(ulong.Parse(Int64MaxPlus1), (ulong)JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {Int64MaxPlus1} }}").MyUInt64Enum); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{Int64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{Int64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{Int64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{Int64MaxPlus1}\" }}")); + } + + [Fact] + public static void Parse_MinusUInt64MaxMinus1_Throws() + { + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {MinusUInt64MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {MinusUInt64MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {MinusUInt64MaxMinus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {MinusUInt64MaxMinus1} }}")); + + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{MinusUInt64MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{MinusUInt64MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{MinusUInt64MaxMinus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{MinusUInt64MaxMinus1}\" }}")); + } [Fact] - public static void Parse_UlongMaxPlus1_Throws() + public static void Parse_UInt64MaxPlus1_Throws() { - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {UlongMaxPlus1} }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {UlongMaxPlus1} }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {UlongMaxPlus1} }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {UlongMaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : {UInt64MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {UInt64MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : {UInt64MaxPlus1} }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : {UInt64MaxPlus1} }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{UlongMaxPlus1}\" }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{UlongMaxPlus1}\" }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{UlongMaxPlus1}\" }}")); - Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{UlongMaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{UInt64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{UInt64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt32Enum\" : \"{UInt64MaxPlus1}\" }}")); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyUInt64Enum\" : \"{UInt64MaxPlus1}\" }}")); } [Fact] @@ -73,12 +289,9 @@ namespace System.Text.Json.Serialization.Tests } [Fact] - public static void Parse_MaxValuePlus1_QuotedVsNotQuoted_QuotedThrows() + public static void Parse_MaxValuePlus1_QuotedVsNotQuoted_Throws() { - SimpleTestClass result = JsonSerializer.Parse( - $"{{ \"MyByteEnum\" : {(ulong)byte.MaxValue + 1}, \"MyUInt32Enum\" : {(ulong)UInt32.MaxValue + 1} }}"); - Assert.Equal((SampleByteEnum)0, result.MyByteEnum); - Assert.Equal((SampleUInt32Enum)0, result.MyUInt32Enum); + Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : {(ulong)byte.MaxValue + 1}, \"MyUInt32Enum\" : {(ulong)UInt32.MaxValue + 1} }}")); // Quoted throws Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{(ulong)byte.MaxValue + 1}\" }}")); @@ -89,10 +302,9 @@ namespace System.Text.Json.Serialization.Tests public static void Parse_Negative1_QuotedVsUnquoted_QuotedThrows() { string json = "{ \"MyByteEnum\" : -1, \"MyUInt32Enum\" : -1 }"; - SimpleTestClass result = JsonSerializer.Parse(json); - Assert.Equal((SampleByteEnum)byte.MaxValue, result.MyByteEnum); - Assert.Equal((SampleUInt32Enum)UInt32.MaxValue, result.MyUInt32Enum); + Assert.Throws(() => JsonSerializer.Parse(json)); + // Quoted throws Assert.Throws(() => JsonSerializer.Parse("{ \"MyByteEnum\" : \"-1\" }")); Assert.Throws(() => JsonSerializer.Parse("{ \"MyUInt32Enum\" : \"-1\" }")); @@ -103,11 +315,9 @@ namespace System.Text.Json.Serialization.Tests [InlineData("{ \"MyUInt64Enum\" : -1 }")] [InlineData("{ \"MyUInt64Enum\" : -1, \"MyUInt32Enum\" : -1 }")] [InlineData("{ \"MyUInt64Enum\" : -1, \"MyUInt32Enum\" : -1, \"MyByteEnum\" : -1 }")] - [ActiveIssue(38363)] - public static void Parse_Negative1ForUInt64Enum_ShouldNotThrow(string json) + public static void Parse_Negative1ForUInt64Enum_Throw(string json) { - SimpleTestClass result = JsonSerializer.Parse(json); - Assert.Equal((SampleUInt64Enum)UInt64.MaxValue, result.MyUInt64Enum); + Assert.Throws(() => JsonSerializer.Parse(json)); } [Theory] @@ -115,13 +325,10 @@ namespace System.Text.Json.Serialization.Tests [InlineData((ulong)byte.MaxValue + 2, (ulong)UInt32.MaxValue + 2, (SampleByteEnum)1, (SampleUInt32Enum)1)] [InlineData((ulong)byte.MaxValue + 13, (ulong)UInt32.MaxValue + 13, (SampleByteEnum)12, (SampleUInt32Enum)12)] [InlineData((ulong)byte.MaxValue * 2, (ulong)UInt32.MaxValue * 2, (SampleByteEnum)byte.MaxValue - 1, (SampleUInt32Enum)UInt32.MaxValue - 1)] - public static void Parse_Ulong_JsonWithAcceptableInvalidNumber_Success(ulong i, ulong j, SampleByteEnum e1, SampleUInt32Enum e2) + public static void Parse_Ulong_InvalidNumber_Throw(ulong i, ulong j, SampleByteEnum e1, SampleUInt32Enum e2) { string json = $"{{ \"MyByteEnum\" : {i}, \"MyUInt32Enum\" : {j} }}"; - SimpleTestClass result = JsonSerializer.Parse(json); - Assert.Equal(e1, result.MyByteEnum); - Assert.Equal(e2, result.MyUInt32Enum); - + Assert.Throws(() => JsonSerializer.Parse(json)); Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyEnum\" : \"{i}\" }}")); Assert.Throws(() => JsonSerializer.Parse($"{{ \"MyByteEnum\" : \"{j}\" }}")); } @@ -140,6 +347,13 @@ namespace System.Text.Json.Serialization.Tests } [Fact] + public static void EnumAsInt16() + { + SimpleTestClass obj = JsonSerializer.Parse(s_jsonInt16Enum); + Assert.Equal(SampleEnumInt16.Two, obj.MyInt16Enum); + } + + [Fact] public static void EnumAsInt64Min() { SimpleTestClass obj = JsonSerializer.Parse(s_jsonInt64EnumMin); @@ -161,10 +375,24 @@ namespace System.Text.Json.Serialization.Tests } [Fact] + public static void EnumAsUInt16Max() + { + SimpleTestClass obj = JsonSerializer.Parse(s_jsonUInt16EnumMax); + Assert.Equal(SampleEnumUInt16.Max, obj.MyUInt16Enum); + } + + [Fact] public static void EnumAsByteMax() { SimpleTestClass obj = JsonSerializer.Parse(s_jsonByteEnum); Assert.Equal(SampleByteEnum.Max, obj.MyByteEnum); } + + [Fact] + public static void EnumAsSByteMax() + { + SimpleTestClass obj = JsonSerializer.Parse(s_jsonSByteEnum); + Assert.Equal(SampleSByteEnum.Max, obj.MySByteEnum); + } } } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs index c788fd2..8049d12 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.SimpleTestClass.cs @@ -28,10 +28,13 @@ namespace System.Text.Json.Serialization.Tests public double MyDouble { get; set; } public DateTime MyDateTime { get; set; } public DateTimeOffset MyDateTimeOffset { get; set; } + public SampleSByteEnum MySByteEnum { get; set; } public SampleByteEnum MyByteEnum { get; set; } public SampleEnum MyEnum { get; set; } + public SampleEnumInt16 MyInt16Enum { get; set; } public SampleInt64Enum MyInt64Enum { get; set; } public SampleUInt32Enum MyUInt32Enum { get; set; } + public SampleEnumUInt16 MyUInt16Enum { get; set; } public SampleUInt64Enum MyUInt64Enum { get; set; } public short[] MyInt16Array { get; set; } public int[] MyInt32Array { get; set; } diff --git a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs index ef9dcc8..db237f8 100644 --- a/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs +++ b/src/libraries/System.Text.Json/tests/Serialization/TestClasses.cs @@ -22,12 +22,33 @@ namespace System.Text.Json.Serialization.Tests Max = byte.MaxValue } + public enum SampleSByteEnum : sbyte + { + One = 0, + Two = 1, + Max = sbyte.MaxValue + } + public enum SampleEnum { One = 1, Two = 2 } + public enum SampleEnumInt16 : short + { + One = 1, + Two = 2, + Max = short.MaxValue + } + + public enum SampleEnumUInt16 : ushort + { + One = 1, + Two = 2, + Max = ushort.MaxValue + } + public enum SampleInt64Enum : long { Min = long.MinValue,