From 8adb55951154c755a73e913aba9769e168b76b52 Mon Sep 17 00:00:00 2001 From: Jeremy Barton Date: Tue, 16 Jul 2019 09:49:08 -0700 Subject: [PATCH] Add negative tests for ValidateNumber With this change ValidateNumber gets to 100% block coverage. Commit migrated from https://github.com/dotnet/corefx/commit/7fe5f15813aedc2144b348baa2f26e7289618a05 --- .../System/Text/Json/Writer/JsonWriterHelper.cs | 25 ++++----- .../tests/JsonElementWriteTests.cs | 63 ++++++++++++++++++++++ 2 files changed, 76 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs index 7395de8..41f844a 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs @@ -138,10 +138,10 @@ namespace System.Text.Json { // This is a simplified version of the number reader from Utf8JsonReader.TryGetNumber, // because it doesn't need to deal with "NeedsMoreData", or remembering the format. - if (utf8FormattedNumber.IsEmpty) - { - throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); - } + // + // The Debug.Asserts in this method should change to validated ArgumentExceptions if/when + // writing a formatted number becomes public API. + Debug.Assert(!utf8FormattedNumber.IsEmpty); int i = 0; @@ -179,24 +179,25 @@ namespace System.Text.Json { i++; + if (utf8FormattedNumber.Length <= i) + { + throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); + } + while (i < utf8FormattedNumber.Length && JsonHelpers.IsDigit(utf8FormattedNumber[i])) { i++; } - if (utf8FormattedNumber.Length < i) + if (i == utf8FormattedNumber.Length) { - throw new ArgumentException(SR.RequiredDigitNotFoundEndOfData, nameof(utf8FormattedNumber)); + return; } - } - if (i == utf8FormattedNumber.Length) - { - return; + Debug.Assert(i < utf8FormattedNumber.Length); + val = utf8FormattedNumber[i]; } - val = utf8FormattedNumber[i]; - if (val == 'e' || val == 'E') { i++; diff --git a/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs b/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs index ce87015..4533079 100644 --- a/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs +++ b/src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs @@ -4,6 +4,7 @@ using Xunit; using System.Buffers; +using System.IO; namespace System.Text.Json.Tests { @@ -110,6 +111,68 @@ namespace System.Text.Json.Tests } [Theory] + [InlineData("6.022e+23", "6,022e+23")] + [InlineData("6.022e+23", "6.022f+23")] + [InlineData("6.022e+23", "6.022e+ 3")] + [InlineData("6.022e+23", "6e022e+23")] + [InlineData("6.022e+23", "6.022e+f3")] + [InlineData("1", "-")] + [InlineData("12", "+2")] + [InlineData("12", "1e")] + [InlineData("12", "1.")] + [InlineData("12", "02")] + [InlineData("123", "1e+")] + [InlineData("123", "1e-")] + [InlineData("0.12", "0.1e")] + [InlineData("0.123", "0.1e+")] + [InlineData("0.123", "0.1e-")] + [InlineData("10", "+0")] + [InlineData("101", "-01")] + [InlineData("12", "1a")] + [InlineData("10", "00")] + [InlineData("11", "01")] + [InlineData("10.5e-012", "10.5e-0.2")] + [InlineData("10.5e012", "10.5.012")] + [InlineData("0.123", "0.-23")] + [InlineData("12345", "hello")] + public static void WriteCorruptedNumber(string parseJson, string overwriteJson) + { + if (overwriteJson.Length != parseJson.Length) + { + throw new InvalidOperationException("Invalid test, parseJson and overwriteJson must have the same length"); + } + + byte[] utf8Data = Encoding.UTF8.GetBytes(parseJson); + + using (JsonDocument document = JsonDocument.Parse(utf8Data)) + using (MemoryStream stream = new MemoryStream(Array.Empty())) + using (Utf8JsonWriter writer = new Utf8JsonWriter(stream)) + { + // Use fixed and the older version of GetBytes-in-place because of the NetFX build. + unsafe + { + fixed (byte* dataPtr = utf8Data) + fixed (char* inputPtr = overwriteJson) + { + // Overwrite the number in the memory buffer still referenced by the document. + // If it doesn't hit a 100% overlap then we're not testing what we thought we were. + Assert.Equal( + utf8Data.Length, + Encoding.UTF8.GetBytes(inputPtr, overwriteJson.Length, dataPtr, utf8Data.Length)); + } + } + + JsonElement rootElement = document.RootElement; + + Assert.Equal(overwriteJson, rootElement.GetRawText()); + + AssertExtensions.Throws( + "utf8FormattedNumber", + () => rootElement.WriteTo(writer)); + } + } + + [Theory] [InlineData(false)] [InlineData(true)] public static void WriteAsciiString(bool indented) -- 2.7.4