From 18838a368f25a59f913ca023d5beeb8fc4d26b6e Mon Sep 17 00:00:00 2001 From: Lukas Krecan Date: Thu, 4 Jul 2024 17:21:32 +0200 Subject: [PATCH] #44 Normalizer attempt --- .../net/javacrumbs/jsonunit/core/Option.java | 1 + .../jsonunit/core/internal/Diff.java | 9 +++- .../jsonunit/core/internal/Normalizer.java | 49 +++++++++++++++++++ .../test/base/AbstractAssertJTest.java | 11 +++++ 4 files changed, 69 insertions(+), 1 deletion(-) create mode 100644 json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Normalizer.java diff --git a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/Option.java b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/Option.java index 003bae96..be264431 100644 --- a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/Option.java +++ b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/Option.java @@ -50,6 +50,7 @@ public enum Option { */ IGNORING_VALUES, + REPORTING_DIFFERENCE_AS_STRING, /** * Stops comparison at the first difference. Can bring performance boots to use-cases that do not need the full list of all differences. */ diff --git a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Diff.java b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Diff.java index 1e6da2d7..5326b150 100644 --- a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Diff.java +++ b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Diff.java @@ -21,6 +21,7 @@ import static net.javacrumbs.jsonunit.core.Option.IGNORING_EXTRA_ARRAY_ITEMS; import static net.javacrumbs.jsonunit.core.Option.IGNORING_EXTRA_FIELDS; import static net.javacrumbs.jsonunit.core.Option.IGNORING_VALUES; +import static net.javacrumbs.jsonunit.core.Option.REPORTING_DIFFERENCE_AS_STRING; import static net.javacrumbs.jsonunit.core.Option.TREATING_NULL_AS_ABSENT; import static net.javacrumbs.jsonunit.core.internal.ClassUtils.isClassPresent; import static net.javacrumbs.jsonunit.core.internal.DifferenceContextImpl.differenceContext; @@ -34,6 +35,7 @@ import static net.javacrumbs.jsonunit.core.internal.JsonUtils.quoteIfNeeded; import static net.javacrumbs.jsonunit.core.internal.Node.KeyValue; import static net.javacrumbs.jsonunit.core.internal.Node.NodeType; +import static net.javacrumbs.jsonunit.core.internal.Normalizer.toNormalizedString; import java.math.BigDecimal; import java.util.ArrayList; @@ -55,6 +57,7 @@ import net.javacrumbs.jsonunit.core.internal.ArrayComparison.ComparisonResult; import net.javacrumbs.jsonunit.core.internal.ArrayComparison.NodeWithIndex; import net.javacrumbs.jsonunit.core.listener.Difference; +import org.opentest4j.AssertionFailedError; /** * Compares JSON structures. Mainly for internal use, the API might be more volatile than the rest. @@ -720,7 +723,11 @@ public void failIfDifferent() { public void failIfDifferent(String message) { if (!similar()) { - throw createException(message, differences); + if (!configuration.getOptions().contains(REPORTING_DIFFERENCE_AS_STRING)) { + throw createException(message, differences); + } else { + throw new AssertionFailedError("JSONs are different", toNormalizedString(expectedRoot), toNormalizedString(actualRoot)); //FIXME: paths + } } } diff --git a/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Normalizer.java b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Normalizer.java new file mode 100644 index 00000000..2d9cd5d5 --- /dev/null +++ b/json-unit-core/src/main/java/net/javacrumbs/jsonunit/core/internal/Normalizer.java @@ -0,0 +1,49 @@ +package net.javacrumbs.jsonunit.core.internal; + +import static java.util.Comparator.comparing; + +import java.util.Iterator; +import java.util.Spliterators; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; +import net.javacrumbs.jsonunit.core.internal.Node.KeyValue; + +class Normalizer { + + private static int depth = 2; + + static String toNormalizedString(Node node) { + StringBuilder sb = new StringBuilder(); + normalize(node, sb, 0); + return sb.toString(); + } + + private static void normalize(Node node, StringBuilder sb, int indent) { + switch (node.getNodeType()) { + case OBJECT -> { + addIndent(sb, indent); + sb.append("{\n"); + stream(node.fields()).sorted(comparing(KeyValue::getKey)).forEach(keyValue -> { + addIndent(sb, indent + depth); + sb.append('"').append(keyValue.getKey()).append("\": "); + normalize(keyValue.getValue(), sb, indent + depth); + sb.append(",\n"); + }); + addIndent(sb, indent); + sb.append("}"); + } + case STRING -> sb.append('\"').append(node).append('"'); + default -> sb.append(node); + } + } + + private static void addIndent(StringBuilder sb, int indent) { + for (int i = 0; i < indent; i++) { + sb.append(' '); + } + } + + private static Stream stream(Iterator iterator) { + return StreamSupport.stream(Spliterators.spliteratorUnknownSize(iterator, 0), false); + } +} diff --git a/tests/test-base/src/main/java/net/javacrumbs/jsonunit/test/base/AbstractAssertJTest.java b/tests/test-base/src/main/java/net/javacrumbs/jsonunit/test/base/AbstractAssertJTest.java index 7dae6de0..f805fac4 100644 --- a/tests/test-base/src/main/java/net/javacrumbs/jsonunit/test/base/AbstractAssertJTest.java +++ b/tests/test-base/src/main/java/net/javacrumbs/jsonunit/test/base/AbstractAssertJTest.java @@ -54,6 +54,7 @@ import net.javacrumbs.jsonunit.test.base.AbstractJsonAssertTest.DivisionMatcher; import org.hamcrest.Matcher; import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.opentest4j.AssertionFailedError; import org.opentest4j.MultipleFailuresError; @@ -2303,6 +2304,16 @@ void shouldFailFast() { """); } + @Nested + class ReportAsString { + @Test + void shouldSortMapKeys() { + assertThatJson("{\"a\": {\"c\": 1}, \"b\": 3}") + .when(Option.REPORTING_DIFFERENCE_AS_STRING) + .isEqualTo("{\"b\": 1, \"a\": {\"c\": 2}}"); + } + } + private static final String json = """ {