private static void AssertJsonEqual(JsonElement expected, JsonElement actual) { JsonValueKind valueKind = expected.ValueKind; Assert.Equal(valueKind, actual.ValueKind); switch (valueKind) { case JsonValueKind.Object: var propertyNames = new HashSet <string>(); foreach (JsonProperty property in expected.EnumerateObject()) { propertyNames.Add(property.Name); } foreach (JsonProperty property in actual.EnumerateObject()) { propertyNames.Add(property.Name); } foreach (string name in propertyNames) { AssertJsonEqual(expected.GetProperty(name), actual.GetProperty(name)); } break; case JsonValueKind.Array: JsonElement.ArrayEnumerator expectedEnumerator = actual.EnumerateArray(); JsonElement.ArrayEnumerator actualEnumerator = expected.EnumerateArray(); while (expectedEnumerator.MoveNext()) { Assert.True(actualEnumerator.MoveNext()); AssertJsonEqual(expectedEnumerator.Current, actualEnumerator.Current); } Assert.False(actualEnumerator.MoveNext()); break; case JsonValueKind.String: Assert.Equal(expected.GetString(), actual.GetString()); break; case JsonValueKind.Number: case JsonValueKind.True: case JsonValueKind.False: case JsonValueKind.Null: Assert.Equal(expected.GetRawText(), actual.GetRawText()); break; default: Debug.Fail($"Unexpected JsonValueKind: JsonValueKind.{valueKind}."); break; } }
private static void AssertJsonEqualCore(JsonElement expected, JsonElement actual, Stack <object> path) { JsonValueKind valueKind = expected.ValueKind; AssertTrue(passCondition: valueKind == actual.ValueKind); switch (valueKind) { case JsonValueKind.Object: var expectedProperties = new List <string>(); foreach (JsonProperty property in expected.EnumerateObject()) { expectedProperties.Add(property.Name); } var actualProperties = new List <string>(); foreach (JsonProperty property in actual.EnumerateObject()) { actualProperties.Add(property.Name); } foreach (var property in expectedProperties.Except(actualProperties)) { AssertTrue(passCondition: false, $"Property \"{property}\" missing from actual object."); } foreach (var property in actualProperties.Except(expectedProperties)) { AssertTrue(passCondition: false, $"Actual object defines additional property \"{property}\"."); } foreach (string name in expectedProperties) { path.Push(name); AssertJsonEqualCore(expected.GetProperty(name), actual.GetProperty(name), path); path.Pop(); } break; case JsonValueKind.Array: JsonElement.ArrayEnumerator expectedEnumerator = expected.EnumerateArray(); JsonElement.ArrayEnumerator actualEnumerator = actual.EnumerateArray(); int i = 0; while (expectedEnumerator.MoveNext()) { AssertTrue(passCondition: actualEnumerator.MoveNext(), "Actual array contains fewer elements."); path.Push(i++); AssertJsonEqualCore(expectedEnumerator.Current, actualEnumerator.Current, path); path.Pop(); } AssertTrue(passCondition: !actualEnumerator.MoveNext(), "Actual array contains additional elements."); break; case JsonValueKind.String: AssertTrue(passCondition: expected.GetString() == actual.GetString()); break; case JsonValueKind.Number: case JsonValueKind.True: case JsonValueKind.False: case JsonValueKind.Null: AssertTrue(passCondition: expected.GetRawText() == actual.GetRawText()); break; default: Debug.Fail($"Unexpected JsonValueKind: JsonValueKind.{valueKind}."); break; } void AssertTrue(bool passCondition, string?message = null) { if (!passCondition) { message ??= "Expected JSON does not match actual value"; Assert.Fail($"{message}\nExpected JSON: {expected}\n Actual JSON: {actual}\n in JsonPath: {BuildJsonPath(path)}"); }