Update float converter and related tests (dotnet/corefx#37894)
authorSteve Harter <steveharter@users.noreply.github.com>
Thu, 30 May 2019 14:35:25 +0000 (07:35 -0700)
committerGitHub <noreply@github.com>
Thu, 30 May 2019 14:35:25 +0000 (07:35 -0700)
Commit migrated from https://github.com/dotnet/corefx/commit/adc16f3d53b18467d5ed92fd1b988b0c21901ab9

src/libraries/System.Text.Json/src/System/Text/Json/JsonHelpers.cs
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/JsonValueConverterSingle.cs
src/libraries/System.Text.Json/tests/Serialization/Value.ReadTests.cs
src/libraries/System.Text.Json/tests/System.Text.Json.Tests.csproj

index 4485067..a96e32c 100644 (file)
@@ -60,15 +60,6 @@ namespace System.Text.Json
         /// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive.
         /// </summary>
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
-        public static bool IsInRangeInclusive(double value, double lowerBound, double upperBound)
-            // For floating-point, do a direct comparison as it is more accurate than subtracting.
-            => (value >= lowerBound) && (value <= upperBound);
-
-        /// <summary>
-        /// Returns <see langword="true"/> if <paramref name="value"/> is between
-        /// <paramref name="lowerBound"/> and <paramref name="upperBound"/>, inclusive.
-        /// </summary>
-        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         public static bool IsInRangeInclusive(JsonTokenType value, JsonTokenType lowerBound, JsonTokenType upperBound)
             => (value - lowerBound) <= (upperBound - lowerBound);
 
index a2fefee..967fe18 100644 (file)
@@ -10,16 +10,13 @@ namespace System.Text.Json.Serialization.Converters
     {
         public override bool TryRead(Type valueType, ref Utf8JsonReader reader, out float value)
         {
-            if (reader.TokenType != JsonTokenType.Number ||
-                !reader.TryGetDouble(out double rawValue) ||
-                !JsonHelpers.IsInRangeInclusive(rawValue, float.MinValue, float.MaxValue))
+            if (reader.TokenType != JsonTokenType.Number)
             {
                 value = default;
                 return false;
             }
 
-            value = (float)rawValue;
-            return true;
+            return reader.TryGetSingle(out value);
         }
 
         public override void Write(float value, Utf8JsonWriter writer)
index 5adca84..e27e6a1 100644 (file)
@@ -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.Globalization;
 using Xunit;
 
 namespace System.Text.Json.Serialization.Tests
@@ -139,12 +140,6 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<ushort?>((ushort.MinValue - 1).ToString()));
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<ushort?>((ushort.MaxValue + 1).ToString()));
 
-            // To ensure range failure, just use double's MinValue and MaxValue (instead of float.MinValue\MaxValue +-1)
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<float>(double.MinValue.ToString()));
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<float>(double.MaxValue.ToString()));
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<float?>(double.MinValue.ToString()));
-            Assert.Throws<JsonException>(() => JsonSerializer.Parse<float?>(double.MaxValue.ToString()));
-
             // These are natively supported by the reader:
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<int>(((long)int.MinValue - 1).ToString()));
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<int>(((long)int.MaxValue + 1).ToString()));
@@ -170,12 +165,6 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<decimal>(decimal.MaxValue.ToString() + "0"));
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<decimal?>(decimal.MinValue.ToString() + "0"));
             Assert.Throws<JsonException>(() => JsonSerializer.Parse<decimal?>(decimal.MaxValue.ToString() + "0"));
-
-            // todo: determine why these don't throw (issue with reader?)
-            //Assert.Throws<JsonException>(() => JsonSerializer.Parse<double>(double.MinValue.ToString() + "0"));
-            //Assert.Throws<JsonException>(() => JsonSerializer.Parse<double>(double.MaxValue.ToString() + "0"));
-            //Assert.Throws<JsonException>(() => JsonSerializer.Parse<double?>(double.MinValue.ToString() + "0"));
-            //Assert.Throws<JsonException>(() => JsonSerializer.Parse<double?>(double.MaxValue.ToString() + "0"));
         }
 
         [Fact]
@@ -193,10 +182,6 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(ushort.MaxValue, JsonSerializer.Parse<ushort>(ushort.MaxValue.ToString()));
             Assert.Equal(ushort.MaxValue, JsonSerializer.Parse<ushort?>(ushort.MaxValue.ToString()));
 
-            // todo: these fail due to double->float conversion
-            //Assert.Equal(float.MaxValue, JsonSerializer.Parse<float>(float.MaxValue.ToString()));
-            //Assert.Equal(float.MaxValue, JsonSerializer.Parse<float?>(float.MaxValue.ToString()));
-
             Assert.Equal(int.MaxValue, JsonSerializer.Parse<int>(int.MaxValue.ToString()));
             Assert.Equal(int.MaxValue, JsonSerializer.Parse<int?>(int.MaxValue.ToString()));
 
@@ -209,12 +194,46 @@ namespace System.Text.Json.Serialization.Tests
             Assert.Equal(ulong.MaxValue, JsonSerializer.Parse<ulong>(ulong.MaxValue.ToString()));
             Assert.Equal(ulong.MaxValue, JsonSerializer.Parse<ulong?>(ulong.MaxValue.ToString()));
 
-            Assert.Equal(decimal.MaxValue, JsonSerializer.Parse<decimal>(decimal.MaxValue.ToString()));
-            Assert.Equal(decimal.MaxValue, JsonSerializer.Parse<decimal?>(decimal.MaxValue.ToString()));
+            Assert.Equal(decimal.MaxValue, JsonSerializer.Parse<decimal>(decimal.MaxValue.ToString(CultureInfo.InvariantCulture)));
+            Assert.Equal(decimal.MaxValue, JsonSerializer.Parse<decimal?>(decimal.MaxValue.ToString(CultureInfo.InvariantCulture)));
+        }
 
-            // todo: these are failing; do we need round-trip format "R"?
-            //Assert.Equal(double.MaxValue, JsonSerializer.Parse<double>(double.MaxValue.ToString()));
-            //Assert.Equal(double.MaxValue, JsonSerializer.Parse<double?>(double.MaxValue.ToString()));
+        [Fact]
+        [SkipOnTargetFramework(TargetFrameworkMonikers.NetFramework, "Skipped since NETFX has different semantics and bugs with floating point.")]
+        public static void RangePassFloatingPoint()
+        {
+            // Verify overflow\underflow.
+            // On NETFX these throw.
+            Assert.True(float.IsNegativeInfinity(JsonSerializer.Parse<float>(double.MinValue.ToString(CultureInfo.InvariantCulture))));
+            Assert.True(float.IsPositiveInfinity(JsonSerializer.Parse<float>(double.MaxValue.ToString(CultureInfo.InvariantCulture))));
+            Assert.True(float.IsNegativeInfinity(JsonSerializer.Parse<float?>(double.MinValue.ToString(CultureInfo.InvariantCulture)).Value));
+            Assert.True(float.IsPositiveInfinity(JsonSerializer.Parse<float?>(double.MaxValue.ToString(CultureInfo.InvariantCulture)).Value));
+
+            Assert.True(double.IsNegativeInfinity(JsonSerializer.Parse<double>(double.MinValue.ToString(CultureInfo.InvariantCulture) + "0")));
+            Assert.True(double.IsPositiveInfinity(JsonSerializer.Parse<double>(double.MaxValue.ToString(CultureInfo.InvariantCulture) + "0")));
+            Assert.True(double.IsNegativeInfinity(JsonSerializer.Parse<double?>(double.MinValue.ToString(CultureInfo.InvariantCulture) + "0").Value));
+            Assert.True(double.IsPositiveInfinity(JsonSerializer.Parse<double?>(double.MaxValue.ToString(CultureInfo.InvariantCulture) + "0").Value));
+
+            // Verify sign is correct.
+            // On NETFX a value of -0 does not keep the sign.
+            Assert.Equal(0x0000000000000000ul, (ulong)BitConverter.DoubleToInt64Bits(JsonSerializer.Parse<double>("0")));
+            Assert.Equal(0x8000000000000000ul, (ulong)BitConverter.DoubleToInt64Bits(JsonSerializer.Parse<double>("-0")));
+            Assert.Equal(0x8000000000000000ul, (ulong)BitConverter.DoubleToInt64Bits(JsonSerializer.Parse<double>("-0.0")));
+
+#if BUILDING_INBOX_LIBRARY
+            // Verify sign is correct; SingleToInt32Bits not available on netfx.
+            Assert.Equal(0x00000000u, (uint)BitConverter.SingleToInt32Bits(JsonSerializer.Parse<float>("0")));
+            Assert.Equal(0x80000000u, (uint)BitConverter.SingleToInt32Bits(JsonSerializer.Parse<float>("-0")));
+            Assert.Equal(0x80000000u, (uint)BitConverter.SingleToInt32Bits(JsonSerializer.Parse<float>("-0.0")));
+#endif
+
+            // Verify Round-tripping.
+            // On NETFX round tripping is not supported.
+            Assert.Equal(float.MaxValue, JsonSerializer.Parse<float>(float.MaxValue.ToString(CultureInfo.InvariantCulture)));
+            Assert.Equal(float.MaxValue, JsonSerializer.Parse<float?>(float.MaxValue.ToString(CultureInfo.InvariantCulture)));
+
+            Assert.Equal(double.MaxValue, JsonSerializer.Parse<double>(double.MaxValue.ToString(CultureInfo.InvariantCulture)));
+            Assert.Equal(double.MaxValue, JsonSerializer.Parse<double?>(double.MaxValue.ToString(CultureInfo.InvariantCulture)));
         }
 
         [Fact]
index f9490f3..12e65fd 100644 (file)
@@ -2,6 +2,7 @@
   <PropertyGroup>
     <ProjectGuid>{5F553243-042C-45C0-8E49-C739131E11C3}</ProjectGuid>
     <Configurations>netcoreapp-Debug;netcoreapp-Release;netstandard-Debug;netstandard-Release;uap-Windows_NT-Debug;uap-Windows_NT-Release</Configurations>
+    <DefineConstants Condition="'$(TargetsNETStandard)' != 'true'">$(DefineConstants);BUILDING_INBOX_LIBRARY</DefineConstants>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="$(CommonTestPath)\System\IO\WrappedMemoryStream.cs">