From 589cd355197bb1ea8edfc12ac0d10a3a97642a38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Reyes=20Rodr=C3=ADguez?= Date: Wed, 3 Jul 2019 20:49:54 +0200 Subject: [PATCH 1/4] Add support to scientific notation numbers with decimal separators --- .../src/System/Text/Json/Writer/JsonWriterHelper.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index b9e64ca855d1..f9603d7d506b 100644 --- a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -172,13 +172,22 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) return; } + //The non digit character inside the number byte val = utf8FormattedNumber[i]; if (val == '.') { i++; + + while (i < utf8FormattedNumber.Length && JsonHelpers.IsDigit(utf8FormattedNumber[i])) + { + i++; + } } - else if (val == 'e' || val == 'E') + + val = utf8FormattedNumber[i]; + + if (val == 'e' || val == 'E') { i++; From 6fb92be8e712a804cf24ff49e1884f16900b7042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Reyes=20Rodr=C3=ADguez?= Date: Thu, 11 Jul 2019 21:37:52 +0200 Subject: [PATCH 2/4] Add support to scientific notation numbers with decimal separators - Included character validations and added some new number to tests --- .../Text/Json/Writer/JsonWriterHelper.cs | 22 ++++++++++++------- .../tests/Utf8JsonWriterTests.cs | 7 ++++++ 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index f9603d7d506b..4d067cba9424 100644 --- a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -185,17 +185,25 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) } } + if (utf8FormattedNumber.Length <= i) + { + throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); + } + + if (i == utf8FormattedNumber.Length) + { + return; + } + val = utf8FormattedNumber[i]; if (val == 'e' || val == 'E') { i++; - if (i >= utf8FormattedNumber.Length) + if (utf8FormattedNumber.Length <= i) { - throw new ArgumentException( - SR.RequiredDigitNotFoundEndOfData, - nameof(utf8FormattedNumber)); + throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); } val = utf8FormattedNumber[i]; @@ -212,11 +220,9 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) nameof(utf8FormattedNumber)); } - if (i >= utf8FormattedNumber.Length) + if (utf8FormattedNumber.Length <= i) { - throw new ArgumentException( - SR.RequiredDigitNotFoundEndOfData, - nameof(utf8FormattedNumber)); + throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); } while (i < utf8FormattedNumber.Length && JsonHelpers.IsDigit(utf8FormattedNumber[i])) diff --git a/src/System.Text.Json/tests/Utf8JsonWriterTests.cs b/src/System.Text.Json/tests/Utf8JsonWriterTests.cs index 8b8500894ecd..64cf08b6217c 100644 --- a/src/System.Text.Json/tests/Utf8JsonWriterTests.cs +++ b/src/System.Text.Json/tests/Utf8JsonWriterTests.cs @@ -3747,6 +3747,13 @@ public void WriteNumbers(bool formatted, bool skipValidation, string keyString) doubles[2] = double.MinValue; doubles[3] = 12.345e1; doubles[4] = -123.45e1; + doubles[5] = 6.022e-23; + doubles[6] = -6.022e-23; + doubles[7] = 1e200; + doubles[8] = -1e200; + doubles[9] = 1e-200; + doubles[10] = -1e-200; + for (int i = 5; i < numberOfItems; i++) { var value = random.NextDouble(); From 25c8455725ad61fdcab52b6ed4471f99d352605f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Reyes=20Rodr=C3=ADguez?= Date: Sat, 13 Jul 2019 14:51:44 +0200 Subject: [PATCH 3/4] Some fixes and more tests cases added --- .../Text/Json/Writer/JsonWriterHelper.cs | 10 ++-- .../tests/JsonElementWriteTests.cs | 47 +++++++++++++++---- 2 files changed, 44 insertions(+), 13 deletions(-) diff --git a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 4d067cba9424..a6430394097b 100644 --- a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -140,6 +140,7 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) // because it doesn't need to deal with "NeedsMoreData", or remembering the format. if (utf8FormattedNumber.IsEmpty) { + //ThrowHelper.ThrowArgumentException(nameof(utf8FormattedNumber), utf8FormattedNumber); throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); } @@ -183,13 +184,14 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) { i++; } - } - if (utf8FormattedNumber.Length <= i) - { - throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); + if (utf8FormattedNumber.Length < i) + { + throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); + } } + if (i == utf8FormattedNumber.Length) { return; diff --git a/src/System.Text.Json/tests/JsonElementWriteTests.cs b/src/System.Text.Json/tests/JsonElementWriteTests.cs index 7866ef6cf17a..a26c056aca84 100644 --- a/src/System.Text.Json/tests/JsonElementWriteTests.cs +++ b/src/System.Text.Json/tests/JsonElementWriteTests.cs @@ -30,11 +30,39 @@ public static void WriteNumber(bool indented) } [Theory] - [InlineData(false)] - [InlineData(true)] - public static void WriteNumberScientific(bool indented) + [InlineData("1e6", false)] + [InlineData("1e6", true)] + [InlineData("1e+6", false)] + [InlineData("1e+6", true)] + [InlineData("1e-6", false)] + [InlineData("1e-6", true)] + [InlineData("-1e6", false)] + [InlineData("-1e6", true)] + [InlineData("-1e+6", true)] + [InlineData("-1e+6", true)] + [InlineData("-1e-6", false)] + [InlineData("-1e-6", true)] + public static void WriteNumberScientific(string value, bool indented) + { + WriteSimpleValue(indented, value); + } + + [Theory] + [InlineData("5.012e-20", false)] + [InlineData("5.012e-20", true)] + [InlineData("5.012e20", false)] + [InlineData("5.012e20", true)] + [InlineData("5.012e+20", false)] + [InlineData("5.012e+20", true)] + [InlineData("-5.012e-20", false)] + [InlineData("-5.012e-20", true)] + [InlineData("-5.012e20", false)] + [InlineData("-5.012e20", true)] + [InlineData("-5.012e+20", false)] + [InlineData("-5.012e+20", true)] + public static void WriteNumberDecimalScientific(string value, bool indented) { - WriteSimpleValue(indented, "1e6"); + WriteSimpleValue(indented, value); } [Theory] @@ -56,19 +84,20 @@ public static void WriteNumberOverprecise(bool indented) } [Theory] - [InlineData(false)] - [InlineData(true)] - public static void WriteNumberTooLargeScientific(bool indented) + [InlineData("1e400", false)] + [InlineData("1e400", true)] + [InlineData("-1e400", false)] + [InlineData("-1e400", true)] + public static void WriteNumberTooLargeScientific(string value, bool indented) { // This value is a reference "potential interoperability problem" from // https://tools.ietf.org/html/rfc7159#section-6 - const string OneQuarticGoogol = "1e400"; // This just validates we write the literal number 1e400 even though it is too // large to be represented by System.Double and would be converted to // PositiveInfinity instead (or throw if using double.Parse on frameworks // older than .NET Core 3.0). - WriteSimpleValue(indented, OneQuarticGoogol); + WriteSimpleValue(indented, value); } [Theory] From e1991a4f9c5cff43908a03d2c787e8246cfa5583 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Reyes=20Rodr=C3=ADguez?= Date: Mon, 15 Jul 2019 18:05:49 +0200 Subject: [PATCH 4/4] Fixed the requested issues and changes --- .../src/System/Text/Json/Writer/JsonWriterHelper.cs | 4 +--- src/System.Text.Json/tests/JsonElementWriteTests.cs | 11 +++++------ src/System.Text.Json/tests/Utf8JsonWriterTests.cs | 6 ------ 3 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index a6430394097b..7395de80b056 100644 --- a/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -140,7 +140,6 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) // because it doesn't need to deal with "NeedsMoreData", or remembering the format. if (utf8FormattedNumber.IsEmpty) { - //ThrowHelper.ThrowArgumentException(nameof(utf8FormattedNumber), utf8FormattedNumber); throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); } @@ -173,7 +172,7 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) return; } - //The non digit character inside the number + // The non digit character inside the number byte val = utf8FormattedNumber[i]; if (val == '.') @@ -191,7 +190,6 @@ internal static void ValidateNumber(ReadOnlySpan utf8FormattedNumber) } } - if (i == utf8FormattedNumber.Length) { return; diff --git a/src/System.Text.Json/tests/JsonElementWriteTests.cs b/src/System.Text.Json/tests/JsonElementWriteTests.cs index a26c056aca84..25830ea6274d 100644 --- a/src/System.Text.Json/tests/JsonElementWriteTests.cs +++ b/src/System.Text.Json/tests/JsonElementWriteTests.cs @@ -84,20 +84,19 @@ public static void WriteNumberOverprecise(bool indented) } [Theory] - [InlineData("1e400", false)] - [InlineData("1e400", true)] - [InlineData("-1e400", false)] - [InlineData("-1e400", true)] - public static void WriteNumberTooLargeScientific(string value, bool indented) + [InlineData(false)] + [InlineData(true)] + public static void WriteNumberTooLargeScientific(bool indented) { // This value is a reference "potential interoperability problem" from // https://tools.ietf.org/html/rfc7159#section-6 + const string OneQuarticGoogol = "1e400"; // This just validates we write the literal number 1e400 even though it is too // large to be represented by System.Double and would be converted to // PositiveInfinity instead (or throw if using double.Parse on frameworks // older than .NET Core 3.0). - WriteSimpleValue(indented, value); + WriteSimpleValue(indented, OneQuarticGoogol); } [Theory] diff --git a/src/System.Text.Json/tests/Utf8JsonWriterTests.cs b/src/System.Text.Json/tests/Utf8JsonWriterTests.cs index 64cf08b6217c..1cc9e0e12bbb 100644 --- a/src/System.Text.Json/tests/Utf8JsonWriterTests.cs +++ b/src/System.Text.Json/tests/Utf8JsonWriterTests.cs @@ -3747,12 +3747,6 @@ public void WriteNumbers(bool formatted, bool skipValidation, string keyString) doubles[2] = double.MinValue; doubles[3] = 12.345e1; doubles[4] = -123.45e1; - doubles[5] = 6.022e-23; - doubles[6] = -6.022e-23; - doubles[7] = 1e200; - doubles[8] = -1e200; - doubles[9] = 1e-200; - doubles[10] = -1e-200; for (int i = 5; i < numberOfItems; i++) {