From bb06c3c700d819a93348a183758f290aa8619ab6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 17:41:47 +0000 Subject: [PATCH 1/8] Initial plan From 228abad20d338adcbb9ef7a25202e0e828a22272 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 18:49:37 +0000 Subject: [PATCH 2/8] Add test for JsonDocumentOptions properties getter Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../JsonDocumentTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs index 73babaa84b4ade..5fb20584b1185e 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs @@ -2269,6 +2269,28 @@ public static void TestDepthInvalid(int depth) }); } + [Fact] + public static void TestJsonDocumentOptionsProperties() + { + var options = new JsonDocumentOptions(); + Assert.True(options.AllowDuplicateProperties); + Assert.False(options.AllowTrailingCommas); + Assert.Equal(JsonCommentHandling.Disallow, options.CommentHandling); + Assert.Equal(0, options.MaxDepth); + + options.AllowDuplicateProperties = false; + Assert.False(options.AllowDuplicateProperties); + + options.AllowTrailingCommas = true; + Assert.True(options.AllowTrailingCommas); + + options.CommentHandling = JsonCommentHandling.Skip; + Assert.Equal(JsonCommentHandling.Skip, options.CommentHandling); + + options.MaxDepth = 128; + Assert.Equal(128, options.MaxDepth); + } + [Theory] [InlineData("{ \"object\": { \"1-1\": null, \"1-2\": \"12\", }, \"array\": [ 4, 8, 1, 9, 2 ] }")] [InlineData("[ 5, 4, 3, 2, 1, ]")] From d8efbbd4c398a890640dd32d39f36df794084db7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 11 Oct 2025 18:54:39 +0000 Subject: [PATCH 3/8] Add additional number comparison tests for edge cases Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System.Text.Json.Tests/Serialization/JsonElementTests.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs index 4064301320eaef..f879c4dddd6a03 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs @@ -95,6 +95,10 @@ public void ReadJsonElementFromStream(int defaultBufferSize) [InlineData("0.000000000000000000000000000000000000000001", "1e-42")] [InlineData("1000000000000000000000000000000000000000000", "1e42")] [InlineData("-1.1e3", "-1100")] + [InlineData("1000", "1e3")] // Trailing zeros in integral part + [InlineData("100", "1e2")] // Trailing zeros in integral part + [InlineData("0.0001", "1e-4")] // Leading zeros in fractional part + [InlineData("0.00100", "0.001")] // Leading and trailing zeros [InlineData("79228162514264337593543950336", "792281625142643375935439503360e-1")] // decimal.MaxValue + 1 [InlineData("79228162514.264337593543950336", "792281625142643375935439503360e-19")] [InlineData("1.75e+300", "1.75E+300")] // Variations in exponent casing From f7eeacc8ba99e26e0325d822ef90626a90291c42 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 16:02:17 +0000 Subject: [PATCH 4/8] Add more comprehensive tests for JsonDocumentOptions and number comparisons Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../JsonDocumentTests.cs | 22 +++++++++++++++++++ .../Serialization/JsonElementTests.cs | 4 ++++ 2 files changed, 26 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs index 5fb20584b1185e..7ab6611f3a511f 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs @@ -2291,6 +2291,28 @@ public static void TestJsonDocumentOptionsProperties() Assert.Equal(128, options.MaxDepth); } + [Fact] + public static void TestJsonDocumentOptionsWithTrailingCommasAndComments() + { + var options = new JsonDocumentOptions + { + AllowTrailingCommas = true, + CommentHandling = JsonCommentHandling.Skip, + MaxDepth = 32 + }; + + string json = @" + { + ""name"": ""test"", // comment + ""values"": [1, 2, 3,], /* trailing comma */ + }"; + + using JsonDocument doc = JsonDocument.Parse(json, options); + Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); + Assert.Equal("test", doc.RootElement.GetProperty("name").GetString()); + Assert.Equal(3, doc.RootElement.GetProperty("values").GetArrayLength()); + } + [Theory] [InlineData("{ \"object\": { \"1-1\": null, \"1-2\": \"12\", }, \"array\": [ 4, 8, 1, 9, 2 ] }")] [InlineData("[ 5, 4, 3, 2, 1, ]")] diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs index f879c4dddd6a03..c864470c120dd6 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs @@ -97,8 +97,12 @@ public void ReadJsonElementFromStream(int defaultBufferSize) [InlineData("-1.1e3", "-1100")] [InlineData("1000", "1e3")] // Trailing zeros in integral part [InlineData("100", "1e2")] // Trailing zeros in integral part + [InlineData("10000", "1e4")] // More trailing zeros in integral part [InlineData("0.0001", "1e-4")] // Leading zeros in fractional part [InlineData("0.00100", "0.001")] // Leading and trailing zeros + [InlineData("0.00000", "0")] // Zero with fractional zeros + [InlineData("0e10", "0e-5")] // Zero with different exponents + [InlineData("5000", "5e3")] // Non-1 with trailing zeros [InlineData("79228162514264337593543950336", "792281625142643375935439503360e-1")] // decimal.MaxValue + 1 [InlineData("79228162514.264337593543950336", "792281625142643375935439503360e-19")] [InlineData("1.75e+300", "1.75E+300")] // Variations in exponent casing From 5516ebf9d08287f8fbeca728af9925bc21655789 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 16:03:40 +0000 Subject: [PATCH 5/8] Add tests for escaped property names with multi-segment buffers Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../JsonDocumentTests.cs | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs index 7ab6611f3a511f..22ff3be40a05ca 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs @@ -2313,6 +2313,34 @@ public static void TestJsonDocumentOptionsWithTrailingCommasAndComments() Assert.Equal(3, doc.RootElement.GetProperty("values").GetArrayLength()); } + [Fact] + public static void TestJsonDocumentWithEscapedPropertyNames() + { + string json = @"{""prop\u0041"":""value1"",""prop\u0042"":""value2"",""prop\u0043"":123}"; + + using JsonDocument doc = JsonDocument.Parse(json); + Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); + Assert.Equal("value1", doc.RootElement.GetProperty("propA").GetString()); + Assert.Equal("value2", doc.RootElement.GetProperty("propB").GetString()); + Assert.Equal(123, doc.RootElement.GetProperty("propC").GetInt32()); + } + + [Fact] + public static void TestJsonDocumentWithMultiSegmentEscapedPropertyNames() + { + string json = @"{""name\u0041"":""test"",""value\u0042"":42,""flag\u0043"":true}"; + byte[] utf8 = Encoding.UTF8.GetBytes(json); + + // Create multi-segment buffer to exercise HasValueSequence path + ReadOnlySequence sequence = JsonTestHelper.GetSequence(utf8, 1); + + using JsonDocument doc = JsonDocument.Parse(sequence); + Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); + Assert.Equal("test", doc.RootElement.GetProperty("nameA").GetString()); + Assert.Equal(42, doc.RootElement.GetProperty("valueB").GetInt32()); + Assert.True(doc.RootElement.GetProperty("flagC").GetBoolean()); + } + [Theory] [InlineData("{ \"object\": { \"1-1\": null, \"1-2\": \"12\", }, \"array\": [ 4, 8, 1, 9, 2 ] }")] [InlineData("[ 5, 4, 3, 2, 1, ]")] From 3880758fc23096ae3f2a5e98aecafbad4c89327e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 17:49:02 +0000 Subject: [PATCH 6/8] Move DeepEquals_TooDeepJsonDocument test to OuterLoop Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System.Text.Json.Tests/Serialization/JsonElementTests.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs index c864470c120dd6..11977499d228c0 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs @@ -242,6 +242,7 @@ public static void DeepEquals_DeepJsonDocument(int depth) Assert.True(JsonElement.DeepEquals(element, element)); } + [OuterLoop] [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported), nameof(PlatformDetection.IsNotMonoInterpreter))] public static async Task DeepEquals_TooDeepJsonDocument_ThrowsInsufficientExecutionStackException() { From 039b3235555edf1e46b84b4be4dbfbd8c7b5b264 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:20:49 +0000 Subject: [PATCH 7/8] Add comprehensive tests for JsonDocumentOptions edge cases Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../JsonDocumentTests.cs | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs index 22ff3be40a05ca..c609568aac2eb3 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs @@ -2341,6 +2341,68 @@ public static void TestJsonDocumentWithMultiSegmentEscapedPropertyNames() Assert.True(doc.RootElement.GetProperty("flagC").GetBoolean()); } + [Fact] + public static void TestAllowDuplicatePropertiesFalseThrowsException() + { + string jsonWithDuplicates = @"{""name"":""first"",""name"":""second""}"; + var options = new JsonDocumentOptions + { + AllowDuplicateProperties = false + }; + + Assert.Throws(() => JsonDocument.Parse(jsonWithDuplicates, options)); + } + + [Fact] + public static void TestAllowDuplicatePropertiesTrueAllowsDuplicates() + { + string jsonWithDuplicates = @"{""name"":""first"",""name"":""second""}"; + var options = new JsonDocumentOptions + { + AllowDuplicateProperties = true + }; + + using JsonDocument doc = JsonDocument.Parse(jsonWithDuplicates, options); + Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); + // The last value wins + Assert.Equal("second", doc.RootElement.GetProperty("name").GetString()); + } + + [Fact] + public static void TestJsonDocumentWithMaxDepth() + { + var options = new JsonDocumentOptions { MaxDepth = 2 }; + + // Should succeed with depth of 2 + string validJson = @"{""level1"":{""level2"":{}}}"; + using JsonDocument doc = JsonDocument.Parse(validJson, options); + Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); + + // Should fail with depth of 3 + string tooDeepJson = @"{""level1"":{""level2"":{""level3"" :{}}}}"; + Assert.Throws(() => JsonDocument.Parse(tooDeepJson, options)); + } + + [Fact] + public static void TestJsonDocumentWithDefaultMaxDepth() + { + var options = new JsonDocumentOptions { MaxDepth = 0 }; // Default is 64 + + // Build a JSON with depth of 65 (should fail with default) + var sb = new System.Text.StringBuilder(); + for (int i = 0; i < 65; i++) + { + sb.Append("{\"a\":"); + } + sb.Append("1"); + for (int i = 0; i < 65; i++) + { + sb.Append("}"); + } + + Assert.Throws(() => JsonDocument.Parse(sb.ToString(), options)); + } + [Theory] [InlineData("{ \"object\": { \"1-1\": null, \"1-2\": \"12\", }, \"array\": [ 4, 8, 1, 9, 2 ] }")] [InlineData("[ 5, 4, 3, 2, 1, ]")] From 4945bc8069f6a906652d2480ad215dc607fbde7b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Oct 2025 18:28:11 +0000 Subject: [PATCH 8/8] Fix MaxDepth tests to use Assert.ThrowsAny for JsonException Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com> --- .../System.Text.Json.Tests/JsonDocumentTests.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs index c609568aac2eb3..b4bce619034479 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonDocumentTests.cs @@ -2371,16 +2371,16 @@ public static void TestAllowDuplicatePropertiesTrueAllowsDuplicates() [Fact] public static void TestJsonDocumentWithMaxDepth() { - var options = new JsonDocumentOptions { MaxDepth = 2 }; + var options = new JsonDocumentOptions { MaxDepth = 3 }; - // Should succeed with depth of 2 + // Should succeed with depth of 3 string validJson = @"{""level1"":{""level2"":{}}}"; using JsonDocument doc = JsonDocument.Parse(validJson, options); Assert.Equal(JsonValueKind.Object, doc.RootElement.ValueKind); - // Should fail with depth of 3 - string tooDeepJson = @"{""level1"":{""level2"":{""level3"" :{}}}}"; - Assert.Throws(() => JsonDocument.Parse(tooDeepJson, options)); + // Should fail with depth of 4 + string tooDeepJson = @"{""level1"":{""level2"":{""level3"":{}}}}"; + Assert.ThrowsAny(() => JsonDocument.Parse(tooDeepJson, options)); } [Fact] @@ -2400,7 +2400,7 @@ public static void TestJsonDocumentWithDefaultMaxDepth() sb.Append("}"); } - Assert.Throws(() => JsonDocument.Parse(sb.ToString(), options)); + Assert.ThrowsAny(() => JsonDocument.Parse(sb.ToString(), options)); } [Theory]