Add negative tests for ValidateNumber
authorJeremy Barton <jbarton@microsoft.com>
Tue, 16 Jul 2019 16:49:08 +0000 (09:49 -0700)
committerGitHub <noreply@github.com>
Tue, 16 Jul 2019 16:49:08 +0000 (09:49 -0700)
With this change ValidateNumber gets to 100% block coverage.

Commit migrated from https://github.com/dotnet/corefx/commit/7fe5f15813aedc2144b348baa2f26e7289618a05

src/libraries/System.Text.Json/src/System/Text/Json/Writer/JsonWriterHelper.cs
src/libraries/System.Text.Json/tests/JsonElementWriteTests.cs

index 7395de8..41f844a 100644 (file)
@@ -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++;
index ce87015..4533079 100644 (file)
@@ -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<byte>()))
+            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<ArgumentException>(
+                    "utf8FormattedNumber",
+                    () => rootElement.WriteTo(writer));
+            }
+        }
+
+        [Theory]
         [InlineData(false)]
         [InlineData(true)]
         public static void WriteAsciiString(bool indented)