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..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 @@ -2269,6 +2269,140 @@ 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); + } + + [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()); + } + + [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()); + } + + [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 = 3 }; + + // 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 4 + string tooDeepJson = @"{""level1"":{""level2"":{""level3"":{}}}}"; + Assert.ThrowsAny(() => 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.ThrowsAny(() => 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, ]")] 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..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 @@ -95,6 +95,14 @@ 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("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 @@ -234,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() {