Skip to content

Commit 6dcd8d1

Browse files
Fix JsonNode.DeepEquals (#112800)
1 parent 57ed254 commit 6dcd8d1

File tree

3 files changed

+139
-3
lines changed

3 files changed

+139
-3
lines changed

src/libraries/System.Text.Json/src/System/Text/Json/Nodes/JsonObject.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,9 +187,7 @@ internal override bool DeepEqualsCore(JsonNode node)
187187

188188
foreach (KeyValuePair<string, JsonNode?> item in currentDict)
189189
{
190-
otherDict.TryGetValue(item.Key, out JsonNode? jsonNode);
191-
192-
if (!DeepEquals(item.Value, jsonNode))
190+
if (!otherDict.TryGetValue(item.Key, out JsonNode? jsonNode) || !DeepEquals(item.Value, jsonNode))
193191
{
194192
return false;
195193
}

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/JsonNode/JsonNodeTests.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,139 @@ public static void ReplaceWith()
169169
jsonNode["a"].ReplaceWith("c");
170170
Assert.Equal("{\"a\":\"c\"}", jsonNode.ToJsonString());
171171
}
172+
173+
[Theory]
174+
[InlineData("null", " null ")]
175+
[InlineData("false", " false ")]
176+
[InlineData("true", " true ")]
177+
[InlineData("-0.0", "0")]
178+
[InlineData("0", "0.0000e4")]
179+
[InlineData("0", "0.0000e-4")]
180+
[InlineData("1", "1.0")]
181+
[InlineData("1", "1e0")]
182+
[InlineData("1", "1.0000")]
183+
[InlineData("1", "1.0000e0")]
184+
[InlineData("1", "0.10000e1")]
185+
[InlineData("1", "10.0000e-1")]
186+
[InlineData("10001", "1.0001e4")]
187+
[InlineData("10001e-3", "1.0001e1")]
188+
[InlineData("1", "0.1e1")]
189+
[InlineData("0.1", "1e-1")]
190+
[InlineData("0.001", "1e-3")]
191+
[InlineData("1e9", "1000000000")]
192+
[InlineData("11", "1.100000000e1")]
193+
[InlineData("3.141592653589793", "3141592653589793E-15")]
194+
[InlineData("0.000000000000000000000000000000000000000001", "1e-42")]
195+
[InlineData("1000000000000000000000000000000000000000000", "1e42")]
196+
[InlineData("-1.1e3", "-1100")]
197+
[InlineData("79228162514264337593543950336", "792281625142643375935439503360e-1")] // decimal.MaxValue + 1
198+
[InlineData("79228162514.264337593543950336", "792281625142643375935439503360e-19")]
199+
[InlineData("1.75e+300", "1.75E+300")] // Variations in exponent casing
200+
[InlineData( // > 256 digits
201+
"1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
202+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
203+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
204+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
205+
206+
"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
207+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
208+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
209+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001" + "E-512")]
210+
[InlineData("\"\"", " \"\"")]
211+
[InlineData("\"ABC\"", "\"\\u0041\\u0042\\u0043\"")]
212+
[InlineData("{ }", " { }")]
213+
[InlineData("""{ "x" : 1, "y" : 2 }""", """{ "x" : 1, "y" : 2 }""")]
214+
[InlineData("""{ "x" : 1, "y" : 2 }""", """{ "y" : 2, "x" : 1 }""")]
215+
[InlineData("""[]""", """ [ ]""")]
216+
[InlineData("""[1, 2, 3]""", """ [1, 2, 3 ]""")]
217+
[InlineData("""[null, false, 3.14, "ABC", { "x" : 1, "y" : 2 }, []]""",
218+
"""[null, false, 314e-2, "\u0041\u0042\u0043", { "y" : 2, "x" : 1 }, [ ] ]""")]
219+
public static void DeepEquals_EqualValuesReturnTrue(string value1, string value2)
220+
{
221+
JsonNode node1 = JsonNode.Parse(value1);
222+
JsonNode node2 = JsonNode.Parse(value2);
223+
224+
AssertDeepEqual(node1, node2);
225+
}
226+
227+
[Theory]
228+
// Kind mismatch
229+
[InlineData("null", "false")]
230+
[InlineData("null", "42")]
231+
[InlineData("null", "\"str\"")]
232+
[InlineData("null", "{}")]
233+
[InlineData("null", "[]")]
234+
[InlineData("false", "42")]
235+
[InlineData("false", "\"str\"")]
236+
[InlineData("false", "{}")]
237+
[InlineData("false", "[]")]
238+
[InlineData("42", "\"str\"")]
239+
[InlineData("42", "{}")]
240+
[InlineData("42", "[]")]
241+
[InlineData("\"str\"", "{}")]
242+
[InlineData("\"str\"", "[]")]
243+
[InlineData("{}", "[]")]
244+
// Value mismatch
245+
[InlineData("false", "true")]
246+
[InlineData("0", "1")]
247+
[InlineData("1", "-1")]
248+
[InlineData("1.1", "-1.1")]
249+
[InlineData("1.1e5", "-1.1e5")]
250+
[InlineData("0", "1e-1024")]
251+
[InlineData("1", "0.1")]
252+
[InlineData("1", "1.1")]
253+
[InlineData("1", "1e1")]
254+
[InlineData("1", "1.00001")]
255+
[InlineData("1", "1.0000e1")]
256+
[InlineData("1", "0.1000e-1")]
257+
[InlineData("1", "10.0000e-2")]
258+
[InlineData("10001", "1.0001e3")]
259+
[InlineData("10001e-3", "1.0001e2")]
260+
[InlineData("1", "0.1e2")]
261+
[InlineData("0.1", "1e-2")]
262+
[InlineData("0.001", "1e-4")]
263+
[InlineData("1e9", "1000000001")]
264+
[InlineData("11", "1.100000001e1")]
265+
[InlineData("0.000000000000000000000000000000000000000001", "1e-43")]
266+
[InlineData("1000000000000000000000000000000000000000000", "1e43")]
267+
[InlineData("-1.1e3", "-1100.1")]
268+
[InlineData("79228162514264337593543950336", "7922816251426433759354395033600e-1")] // decimal.MaxValue + 1
269+
[InlineData("79228162514.264337593543950336", "7922816251426433759354395033601e-19")]
270+
[InlineData("1.75e+300", "1.75E+301")] // Variations in exponent casing
271+
[InlineData("1e2147483647", "1e-2147483648")] // int.MaxValue, int.MinValue exponents
272+
[InlineData( // > 256 digits
273+
"1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
274+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
275+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
276+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001",
277+
278+
"100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
279+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
280+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" +
281+
"00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003" + "E-512")]
282+
[InlineData("\"\"", " \" \"")]
283+
[InlineData("\"ABC\"", " \"ABc\"")]
284+
[InlineData("[1]", "[]")]
285+
[InlineData("[1]", "[2]")]
286+
[InlineData("[1,2,3]", "[1,2,3,4]")]
287+
[InlineData("[1,2,3]", "[1,3,2]")]
288+
[InlineData("{}", """{ "Prop" : null }""")]
289+
[InlineData("""{ "Prop" : 1 }""", """{ "Prop" : null }""")]
290+
[InlineData("""{ "Prop1" : 1 }""", """{ "Prop1" : 1, "Prop2" : 2 }""")]
291+
[InlineData("""{ "Prop1" : 1, "Prop2": {} }""", """{ "Prop1" : 1, "Prop2" : 2 }""")]
292+
[InlineData("""{ "Prop1" : 1, "Prop2": {}, "Prop3": false }""", """{ "Prop1" : 1, "Prop2" : { "c" : null }, "Prop3" : false }""")]
293+
[InlineData("""{ "Prop1" : 1, "Prop2": {}, "Prop3": false }""", """{ "Prop1" : 1, "Prop3" : true, "Prop2" : {} }""")]
294+
// Regression tests for https://github.com/dotnet/runtime/issues/112769
295+
[InlineData("""{"test1":null}""", """{"test2":null}""")]
296+
[InlineData("""{"test1":null, "test2":null}""", """{"test3":null, "test4":null}""")]
297+
[InlineData("""{"test1":null, "test2":null}""", """{"test3":null}""")]
298+
[InlineData("""{"test1":null}""", """{"test2":[null]}""")]
299+
public static void DeepEquals_NotEqualValuesReturnFalse(string value1, string value2)
300+
{
301+
JsonNode obj1 = JsonNode.Parse(value1);
302+
JsonNode obj2 = JsonNode.Parse(value2);
303+
304+
AssertNotDeepEqual(obj1, obj2);
305+
}
172306
}
173307
}

src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/JsonElementTests.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,10 @@ public static void DeepEquals_EqualValuesReturnTrue(string value1, string value2
203203
[InlineData("""{ "Prop1" : 1, "Prop2": {}, "Prop3": false }""", """{ "Prop1" : 1, "Prop2" : { "c" : null }, "Prop3" : false }""")]
204204
[InlineData("""{ "Prop1" : 1, "Prop2": {}, "Prop3": false }""", """{ "Prop1" : 1, "Prop3" : true, "Prop2" : {} }""")]
205205
[InlineData("""{ "Prop3" : null, "Prop1" : 1, "Prop1" : 2 }""", """{ "Prop1" : 2, "Prop1" : 1, "Prop3" : null }""")]
206+
[InlineData("""{"test1":null}""", """{"test2":null}""")]
207+
[InlineData("""{"test1":null, "test2":null}""", """{"test3":null, "test4":null}""")]
208+
[InlineData("""{"test1":null, "test2":null}""", """{"test3":null}""")]
209+
[InlineData("""{"test1":null}""", """{"test2":[null]}""")]
206210
public static void DeepEquals_NotEqualValuesReturnFalse(string value1, string value2)
207211
{
208212
JsonElement element1 = JsonDocument.Parse(value1).RootElement;

0 commit comments

Comments
 (0)