From bb9212b4c79d2732ab5a1291a4bcc261f78ffa06 Mon Sep 17 00:00:00 2001 From: florin Date: Sun, 2 Oct 2022 17:08:20 +0300 Subject: [PATCH 1/6] in progress --- .../java/io/json/compare/JSONCompare.java | 18 +-- .../compare/matcher/AbstractJsonMatcher.java | 7 +- .../compare/matcher/JsonArrayMatcher.java | 152 +++++++++--------- .../io/json/compare/matcher/JsonMatcher.java | 20 ++- .../compare/matcher/JsonObjectMatcher.java | 63 ++++---- .../json/compare/matcher/JsonPathMatcher.java | 18 +-- .../compare/matcher/JsonValueMatcher.java | 58 +++---- 7 files changed, 167 insertions(+), 169 deletions(-) diff --git a/src/main/java/io/json/compare/JSONCompare.java b/src/main/java/io/json/compare/JSONCompare.java index c27e784..9ff2243 100644 --- a/src/main/java/io/json/compare/JSONCompare.java +++ b/src/main/java/io/json/compare/JSONCompare.java @@ -2,11 +2,11 @@ import com.fasterxml.jackson.databind.JsonNode; import io.json.compare.matcher.JsonMatcher; -import io.json.compare.matcher.MatcherException; import io.json.compare.util.JsonUtils; import org.junit.jupiter.api.AssertionFailureBuilder; import java.io.IOException; +import java.util.List; import java.util.Set; @@ -62,11 +62,10 @@ public static void assertNotMatches(Object expected, Object actual, Set compareModes, String message) { JsonNode expectedJson = toJson(expected); JsonNode actualJson = toJson(actual); - try { - new JsonMatcher(expectedJson, actualJson, - comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); - } catch (MatcherException e) { - String defaultMessage = String.format("%s\n", e.getMessage()); + List diffs = new JsonMatcher(expectedJson, actualJson, + comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); + if (!diffs.isEmpty()) { + String defaultMessage = String.format("%s\n", String.join("\n", diffs)); if (comparator == null || comparator.getClass().equals(DefaultJsonComparator.class)) { defaultMessage += "\n\n" + ASSERTION_ERROR_HINT_MESSAGE + "\n"; } @@ -78,10 +77,9 @@ public static void assertMatches(Object expected, Object actual, JsonComparator public static void assertNotMatches(Object expected, Object actual, JsonComparator comparator, Set compareModes, String message) { JsonNode expectedJson = toJson(expected); JsonNode actualJson = toJson(actual); - try { - new JsonMatcher(expectedJson, actualJson, - comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); - } catch (MatcherException e) { + List diffs = new JsonMatcher(expectedJson, actualJson, + comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); + if (!diffs.isEmpty()) { return; } String defaultMessage = "JSONs are equal"; diff --git a/src/main/java/io/json/compare/matcher/AbstractJsonMatcher.java b/src/main/java/io/json/compare/matcher/AbstractJsonMatcher.java index d4c2b7b..31ca2b8 100644 --- a/src/main/java/io/json/compare/matcher/AbstractJsonMatcher.java +++ b/src/main/java/io/json/compare/matcher/AbstractJsonMatcher.java @@ -5,10 +5,7 @@ import io.json.compare.DefaultJsonComparator; import io.json.compare.JsonComparator; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Optional; -import java.util.Set; +import java.util.*; abstract class AbstractJsonMatcher { @@ -27,7 +24,7 @@ abstract class AbstractJsonMatcher { this.compareModes = compareModes == null ? new HashSet<>() : compareModes; } - protected abstract void match() throws MatcherException; + protected abstract List match(); protected static UseCase getUseCase(JsonNode node) { if (node.isValueNode()) { diff --git a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java index 0b0c49f..e81d48a 100644 --- a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java @@ -2,11 +2,11 @@ import com.fasterxml.jackson.databind.JsonNode; import io.json.compare.CompareMode; -import io.json.compare.JSONCompare; import io.json.compare.JsonComparator; -import io.json.compare.util.MessageUtil; +import java.util.Collections; import java.util.HashSet; +import java.util.List; import java.util.Set; class JsonArrayMatcher extends AbstractJsonMatcher { @@ -18,79 +18,81 @@ class JsonArrayMatcher extends AbstractJsonMatcher { } @Override - public void match() throws MatcherException { - for (int i = 0; i < expected.size(); i++) { - JsonNode expElement = expected.get(i); - if (isJsonPathNode(expElement)) { - new JsonMatcher(expElement, actual, comparator, compareModes).match(); - } else { - matchWithActualJsonArray(i, expElement, actual); - } - } - if (compareModes.contains(CompareMode.JSON_ARRAY_NON_EXTENSIBLE) && expected.size() < actual.size()) { - throw new MatcherException("Actual JSON ARRAY has extra elements"); - } + public List match() { + return Collections.emptyList(); +// List diffs = new ArrayList<>(); +// for (int i = 0; i < expected.size(); i++) { +// JsonNode expElement = expected.get(i); +// if (isJsonPathNode(expElement)) { +// diffs.addAll(new JsonMatcher(expElement, actual, comparator, compareModes).match()); +// } else { +// matchWithActualJsonArray(i, expElement, actual); +// } +// } +// if (compareModes.contains(CompareMode.JSON_ARRAY_NON_EXTENSIBLE) && expected.size() < actual.size()) { +// throw new MatcherException("Actual JSON ARRAY has extra elements"); +// } } - private void matchWithActualJsonArray(int expPosition, JsonNode expElement, JsonNode actual) throws MatcherException { - UseCase useCase = getUseCase(expElement); - boolean found = false; - actualElementsLoop: - for (int j = 0; j < actual.size(); j++) { - if (matchedPositions.contains(j)) { - continue; - } - if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER) && j != expPosition) { - continue; - } - switch (useCase) { - case MATCH: - JsonNode actElement = actual.get(j); - try { - new JsonMatcher(expElement, actElement, comparator, compareModes).match(); - } catch (MatcherException e) { - if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER)) { - throw new MatcherException(String - .format("JSON ARRAY elements differ at position %s:\n%s", expPosition + 1, - MessageUtil.cropL(JSONCompare.prettyPrint(expElement)))); - } - continue actualElementsLoop; - } - found = true; - matchedPositions.add(j); - break actualElementsLoop; - case MATCH_ANY: - matchedPositions.add(j); - return; - case DO_NOT_MATCH: - actElement = actual.get(j); - if (!areOfSameType(expElement, actElement)) { - continue actualElementsLoop; - } - try { - new JsonMatcher(expElement, actElement, comparator, compareModes).match(); - } catch (MatcherException e) { - found = true; - break actualElementsLoop; - } - break; - case DO_NOT_MATCH_ANY: - throw new MatcherException("Expected element from position " + (expPosition + 1) - + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); - } - } - if (!found && useCase == UseCase.MATCH) { - throw new MatcherException("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" - + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); - } - if (found && useCase == UseCase.DO_NOT_MATCH) { - throw new MatcherException("Expected element from position " + (expPosition + 1) - + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); - } - if (useCase == UseCase.MATCH_ANY) { - throw new MatcherException("Expected condition of type MATCH_ANY from position " + (expPosition + 1) - + " was NOT MET. Actual Json Array has no extra elements:\n" - + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); - } - } +// private void matchWithActualJsonArray(int expPosition, JsonNode expElement, JsonNode actual) { +// UseCase useCase = getUseCase(expElement); +// boolean found = false; +// actualElementsLoop: +// for (int j = 0; j < actual.size(); j++) { +// if (matchedPositions.contains(j)) { +// continue; +// } +// if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER) && j != expPosition) { +// continue; +// } +// switch (useCase) { +// case MATCH: +// JsonNode actElement = actual.get(j); +// try { +// new JsonMatcher(expElement, actElement, comparator, compareModes).match(); +// } catch (MatcherException e) { +// if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER)) { +// throw new MatcherException(String +// .format("JSON ARRAY elements differ at position %s:\n%s", expPosition + 1, +// MessageUtil.cropL(JSONCompare.prettyPrint(expElement)))); +// } +// continue actualElementsLoop; +// } +// found = true; +// matchedPositions.add(j); +// break actualElementsLoop; +// case MATCH_ANY: +// matchedPositions.add(j); +// return; +// case DO_NOT_MATCH: +// actElement = actual.get(j); +// if (!areOfSameType(expElement, actElement)) { +// continue actualElementsLoop; +// } +// try { +// new JsonMatcher(expElement, actElement, comparator, compareModes).match(); +// } catch (MatcherException e) { +// found = true; +// break actualElementsLoop; +// } +// break; +// case DO_NOT_MATCH_ANY: +// throw new MatcherException("Expected element from position " + (expPosition + 1) +// + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); +// } +// } +// if (!found && useCase == UseCase.MATCH) { +// throw new MatcherException("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" +// + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); +// } +// if (found && useCase == UseCase.DO_NOT_MATCH) { +// throw new MatcherException("Expected element from position " + (expPosition + 1) +// + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); +// } +// if (useCase == UseCase.MATCH_ANY) { +// throw new MatcherException("Expected condition of type MATCH_ANY from position " + (expPosition + 1) +// + " was NOT MET. Actual Json Array has no extra elements:\n" +// + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); +// } +// } } diff --git a/src/main/java/io/json/compare/matcher/JsonMatcher.java b/src/main/java/io/json/compare/matcher/JsonMatcher.java index 1b9639c..0b62eba 100644 --- a/src/main/java/io/json/compare/matcher/JsonMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonMatcher.java @@ -4,6 +4,9 @@ import io.json.compare.CompareMode; import io.json.compare.JsonComparator; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Set; public class JsonMatcher extends AbstractJsonMatcher { @@ -13,20 +16,21 @@ public JsonMatcher(JsonNode expected, JsonNode actual, JsonComparator comparator } @Override - public void match() throws MatcherException { + public List match() { if (isJsonObject(expected) && isJsonObject(actual)) { - new JsonObjectMatcher(expected, actual, comparator, compareModes).match(); + return new JsonObjectMatcher(expected, actual, comparator, compareModes).match(); } else if (isJsonArray(expected) && isJsonArray(actual)) { - new JsonArrayMatcher(expected, actual, comparator, compareModes).match(); + return new JsonArrayMatcher(expected, actual, comparator, compareModes).match(); } else if (isValueNode(expected) && isValueNode(actual)) { - new JsonValueMatcher(expected, actual, comparator, compareModes).match(); + return new JsonValueMatcher(expected, actual, comparator, compareModes).match(); } else if (isJsonPathNode(expected)) { - new JsonObjectMatcher(expected, actual, comparator, compareModes).match(); + return new JsonObjectMatcher(expected, actual, comparator, compareModes).match(); } else if (isMissingNode(expected) && isMissingNode(actual)) { - //do nothing + return Collections.emptyList(); } else { - throw new MatcherException("Different JSON types: " - + expected.getClass().getSimpleName() + " vs " + actual.getClass().getSimpleName()); + List diffs = new ArrayList<>(); + diffs.add("Different JSON types: expected" + expected.getClass().getSimpleName() + " but got " + actual.getClass().getSimpleName()); + return diffs; } } } diff --git a/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java b/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java index b1cee9a..0ac83ed 100644 --- a/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java @@ -16,7 +16,9 @@ class JsonObjectMatcher extends AbstractJsonMatcher { } @Override - public void match() throws MatcherException { + public List match() { + List diffs = new ArrayList<>(); + Iterator> it = expected.fields(); while (it.hasNext()) { Map.Entry entry = it.next(); @@ -27,21 +29,22 @@ public void match() throws MatcherException { Optional jsonPathExpression = extractJsonPathExp(expectedSanitizedField); List> candidateEntries = null; if (!jsonPathExpression.isPresent()) { - candidateEntries = searchCandidateEntriesByField(expectedSanitizedField, actual); + candidateEntries = searchCandidatesByField(expectedSanitizedField, actual); } switch (useCase) { case MATCH_ANY: case MATCH: if (!jsonPathExpression.isPresent()) { if (candidateEntries.isEmpty()) { - throw new MatcherException(String.format("Field '%s' was not found or cannot be matched", expectedField)); + diffs.add(String.format("Field '%s' was not found", expectedField)); + } else { + diffs.addAll(matchWithCandidates(expectedSanitizedField, expectedValue, candidateEntries)); } - matchWithCandidateEntries(expectedSanitizedField, expectedValue, candidateEntries); } else { try { - new JsonPathMatcher(jsonPathExpression.get(), expectedValue, actual, comparator, compareModes).match(); + diffs.addAll(new JsonPathMatcher(jsonPathExpression.get(), expectedValue, actual, comparator, compareModes).match()); } catch (PathNotFoundException e) { - throw new MatcherException(String.format("%s <- json path ('%s')", e.getMessage(), jsonPathExpression.get())); + diffs.add(String.format("json path ('%s') -> %s", jsonPathExpression.get(), e.getMessage())); } } break; @@ -49,7 +52,7 @@ public void match() throws MatcherException { case DO_NOT_MATCH: if (!jsonPathExpression.isPresent()) { if (!candidateEntries.isEmpty()) { - throw new MatcherException(String.format("Field '%s' was found", expectedField)); + diffs.add(String.format("Field '%s' was found", expectedField)); } } else { try { @@ -57,42 +60,44 @@ public void match() throws MatcherException { } catch (PathNotFoundException e) { break; } - throw new MatcherException(String.format("Json path '%s' was found", expectedField)); + diffs.add(String.format("Json path '%s' was found", expectedField)); } break; } } if (compareModes.contains(CompareMode.JSON_OBJECT_NON_EXTENSIBLE) && expected.size() < actual.size()) { - throw new MatcherException("Actual JSON OBJECT has extra fields"); + diffs.add("Actual JSON OBJECT has extra fields"); } + return diffs; } - private void matchWithCandidateEntries(String expectedKey, JsonNode expectedValue, List> candidates) throws MatcherException { + private List matchWithCandidates(String expectedKey, JsonNode expectedValue, List> candidates) { + List diffs = new ArrayList<>(); + UseCase expectedValueUseCase = getUseCase(expectedValue); - for (ListIterator> it = candidates.listIterator(); it.hasNext(); ) { - Map.Entry candidateEntry = it.next(); - String candidateField = candidateEntry.getKey(); + + for (Map.Entry candidateEntry : candidates) { + String candidateKey = candidateEntry.getKey(); + if (expectedValueUseCase == UseCase.MATCH_ANY) { - matchedFieldNames.add(candidateField); - break; + matchedFieldNames.add(candidateKey); + return Collections.emptyList(); } + JsonNode candidateValue = candidateEntry.getValue(); - try { - new JsonMatcher(expectedValue, candidateValue, comparator, compareModes).match(); - } catch (MatcherException e) { - if (it.hasNext()) { - continue; - } else { - throw new MatcherException(String.format("%s <- %s", e.getMessage(), expectedKey)); - } + List candidateDiffs = new JsonMatcher(expectedValue, candidateValue, comparator, compareModes).match(); + if (candidateDiffs.isEmpty()) { + matchedFieldNames.add(candidateKey); + return Collections.emptyList(); + } else { + candidateDiffs.forEach(diff -> diffs.add(String.format("%s -> %s", expectedKey, diff))); } - matchedFieldNames.add(candidateField); - break; } + return diffs; } - private List> searchCandidateEntriesByField(String fieldName, JsonNode target) { - List> candidatesList = new ArrayList<>(); + private List> searchCandidatesByField(String fieldName, JsonNode target) { + List> candidates = new ArrayList<>(); Iterator> it = target.fields(); while (it.hasNext()) { Map.Entry entry = it.next(); @@ -101,9 +106,9 @@ private List> searchCandidateEntriesByField(String f continue; } if (comparator.compareFields(fieldName, key)) { - candidatesList.add(entry); + candidates.add(entry); } } - return candidatesList; + return candidates; } } \ No newline at end of file diff --git a/src/main/java/io/json/compare/matcher/JsonPathMatcher.java b/src/main/java/io/json/compare/matcher/JsonPathMatcher.java index 506c3c1..b0a9a91 100644 --- a/src/main/java/io/json/compare/matcher/JsonPathMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonPathMatcher.java @@ -10,6 +10,8 @@ import io.json.compare.CompareMode; import io.json.compare.JsonComparator; +import java.util.ArrayList; +import java.util.List; import java.util.Set; class JsonPathMatcher extends AbstractJsonMatcher { @@ -26,14 +28,12 @@ class JsonPathMatcher extends AbstractJsonMatcher { } @Override - public void match() throws MatcherException { - JsonNode result = null; - try { - result = MAPPER.convertValue(PARSE_CONTEXT.parse(actual).read(jsonPath), JsonNode.class); - new JsonMatcher(expected, result, comparator, compareModes).match(); - } catch (MatcherException e) { - throw new MatcherException(String.format("Expected json path result:\n%s\nBut got:\n%s\n\n%s <- json path ('%s')", - expected, result, e.getMessage(), jsonPath)); - } + public List match() { + List diffs = new ArrayList<>(); + JsonNode result = MAPPER.convertValue(PARSE_CONTEXT.parse(actual).read(jsonPath), JsonNode.class); + List jsonPathDiffs = new JsonMatcher(expected, result, comparator, compareModes).match(); + jsonPathDiffs.forEach(diff -> diffs.add(String.format("Json path ('%s') -> Expected json path result:\n%s\nBut got:\n%s\n\n%s", + jsonPath, expected, result, diff))); + return diffs; } } \ No newline at end of file diff --git a/src/main/java/io/json/compare/matcher/JsonValueMatcher.java b/src/main/java/io/json/compare/matcher/JsonValueMatcher.java index 8ac6e5f..93d7545 100644 --- a/src/main/java/io/json/compare/matcher/JsonValueMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonValueMatcher.java @@ -4,6 +4,8 @@ import io.json.compare.CompareMode; import io.json.compare.JsonComparator; +import java.util.ArrayList; +import java.util.List; import java.util.Set; class JsonValueMatcher extends AbstractJsonMatcher { @@ -13,41 +15,31 @@ class JsonValueMatcher extends AbstractJsonMatcher { } @Override - public void match() throws MatcherException { - UseCase useCase = getUseCase(expected.asText()); - matchTextTypes(); - matchNumberTypes(); - matchBooleanTypes(); - matchNullTypes(); - String expectedText = sanitize(expected.asText()); - String actualText = actual.asText(); + public List match() { + List diffs = new ArrayList<>(); + String diff = "Expected %s: %s But got: %s"; - if (!useCase.equals(UseCase.MATCH_ANY) && comparator.compareValues(expectedText, actualText) != useCase.equals(UseCase.MATCH)) { - throw new MatcherException(String.format("Expected value: %s But found: %s ", expected, actual)); - } - } - - private void matchNullTypes() throws MatcherException { if (expected.isNull() && !actual.isNull()) { - throw new MatcherException(String.format("Expected value: %s But found: %s ", expected, actual)); - } - } - - private void matchNumberTypes() throws MatcherException { - if (expected.isNumber() && !actual.isNumber()) { - throw new MatcherException(String.format("Expected value: %s But found: %s ", expected, actual)); - } - } - - private void matchBooleanTypes() throws MatcherException { - if (expected.isBoolean() && !actual.isBoolean()) { - throw new MatcherException(String.format("Expected value: %s But found: %s ", expected, actual)); - } - } - - private void matchTextTypes() throws MatcherException { - if (actual.isTextual() && !expected.isTextual()) { - throw new MatcherException(String.format("Expected value: %s But found: %s ", expected, actual)); + diffs.add(String.format(diff, "null", expected, actual)); + return diffs; + } else if (expected.isNumber() && !actual.isNumber()) { + diffs.add(String.format(diff, "number", expected, actual)); + return diffs; + } else if (expected.isBoolean() && !actual.isBoolean()) { + diffs.add(String.format(diff, "boolean", expected, actual)); + return diffs; + } else if (actual.isTextual() && !expected.isTextual()) { + diffs.add(String.format(diff, "text", expected, actual)); + return diffs; + } else { + UseCase useCase = getUseCase(expected.asText()); + String expectedText = sanitize(expected.asText()); + String actualText = actual.asText(); + + if (!useCase.equals(UseCase.MATCH_ANY) && comparator.compareValues(expectedText, actualText) != useCase.equals(UseCase.MATCH)) { + diffs.add(String.format(diff, "value", expected, actual)); + } + return diffs; } } } \ No newline at end of file From 2399edce245f607cbde5ec26aa50ae8767cf427c Mon Sep 17 00:00:00 2001 From: florin Date: Sun, 2 Oct 2022 19:37:33 +0300 Subject: [PATCH 2/6] refactor with diffs --- .../java/io/json/compare/JSONCompare.java | 5 +- .../compare/matcher/JsonArrayMatcher.java | 157 +++++++++--------- .../compare/matcher/JsonObjectMatcher.java | 10 +- .../compare/matcher/JsonValueMatcher.java | 4 +- .../compare/matcher/MatcherException.java | 8 - .../compare/matcher/JSONPathCompareTests.java | 9 +- .../matcher/diffs/JsonObjectDiffTests.java | 14 ++ .../matcher/diffs/JsonValueDiffTests.java | 49 ++++++ .../compare/matcher/issues/Issue11Test.java | 2 +- 9 files changed, 160 insertions(+), 98 deletions(-) delete mode 100644 src/main/java/io/json/compare/matcher/MatcherException.java create mode 100644 src/test/java/io/json/compare/matcher/diffs/JsonObjectDiffTests.java create mode 100644 src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java diff --git a/src/main/java/io/json/compare/JSONCompare.java b/src/main/java/io/json/compare/JSONCompare.java index 9ff2243..6e75ed2 100644 --- a/src/main/java/io/json/compare/JSONCompare.java +++ b/src/main/java/io/json/compare/JSONCompare.java @@ -65,7 +65,8 @@ public static void assertMatches(Object expected, Object actual, JsonComparator List diffs = new JsonMatcher(expectedJson, actualJson, comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); if (!diffs.isEmpty()) { - String defaultMessage = String.format("%s\n", String.join("\n", diffs)); + String defaultMessage = String.format("FOUND %s DIFFERENCE(S):\n\n%s\n", + diffs.size(), String.join("\n_____________________________________\n", diffs)); if (comparator == null || comparator.getClass().equals(DefaultJsonComparator.class)) { defaultMessage += "\n\n" + ASSERTION_ERROR_HINT_MESSAGE + "\n"; } @@ -82,7 +83,7 @@ public static void assertNotMatches(Object expected, Object actual, JsonComparat if (!diffs.isEmpty()) { return; } - String defaultMessage = "JSONs are equal"; + String defaultMessage = "\nJSONs are equal"; AssertionFailureBuilder.assertionFailure().message(message == null ? defaultMessage : defaultMessage + "\n" + message) .expected(prettyPrint(expectedJson)).actual(prettyPrint(actualJson)) .includeValuesInMessage(false).buildAndThrow(); diff --git a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java index e81d48a..641be5d 100644 --- a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java @@ -2,12 +2,11 @@ import com.fasterxml.jackson.databind.JsonNode; import io.json.compare.CompareMode; +import io.json.compare.JSONCompare; import io.json.compare.JsonComparator; +import io.json.compare.util.MessageUtil; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Set; +import java.util.*; class JsonArrayMatcher extends AbstractJsonMatcher { @@ -19,80 +18,82 @@ class JsonArrayMatcher extends AbstractJsonMatcher { @Override public List match() { - return Collections.emptyList(); -// List diffs = new ArrayList<>(); -// for (int i = 0; i < expected.size(); i++) { -// JsonNode expElement = expected.get(i); -// if (isJsonPathNode(expElement)) { -// diffs.addAll(new JsonMatcher(expElement, actual, comparator, compareModes).match()); -// } else { -// matchWithActualJsonArray(i, expElement, actual); -// } -// } -// if (compareModes.contains(CompareMode.JSON_ARRAY_NON_EXTENSIBLE) && expected.size() < actual.size()) { -// throw new MatcherException("Actual JSON ARRAY has extra elements"); -// } + List diffs = new ArrayList<>(); + + for (int i = 0; i < expected.size(); i++) { + JsonNode expElement = expected.get(i); + if (isJsonPathNode(expElement)) { + diffs.addAll(new JsonMatcher(expElement, actual, comparator, compareModes).match()); + } else { + diffs.addAll(matchWithJsonArray(i, expElement, actual)); + } + } + if (compareModes.contains(CompareMode.JSON_ARRAY_NON_EXTENSIBLE) && expected.size() < actual.size()) { + diffs.add("Actual JSON ARRAY has extra elements"); + } + return diffs; } -// private void matchWithActualJsonArray(int expPosition, JsonNode expElement, JsonNode actual) { -// UseCase useCase = getUseCase(expElement); -// boolean found = false; -// actualElementsLoop: -// for (int j = 0; j < actual.size(); j++) { -// if (matchedPositions.contains(j)) { -// continue; -// } -// if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER) && j != expPosition) { -// continue; -// } -// switch (useCase) { -// case MATCH: -// JsonNode actElement = actual.get(j); -// try { -// new JsonMatcher(expElement, actElement, comparator, compareModes).match(); -// } catch (MatcherException e) { -// if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER)) { -// throw new MatcherException(String -// .format("JSON ARRAY elements differ at position %s:\n%s", expPosition + 1, -// MessageUtil.cropL(JSONCompare.prettyPrint(expElement)))); -// } -// continue actualElementsLoop; -// } -// found = true; -// matchedPositions.add(j); -// break actualElementsLoop; -// case MATCH_ANY: -// matchedPositions.add(j); -// return; -// case DO_NOT_MATCH: -// actElement = actual.get(j); -// if (!areOfSameType(expElement, actElement)) { -// continue actualElementsLoop; -// } -// try { -// new JsonMatcher(expElement, actElement, comparator, compareModes).match(); -// } catch (MatcherException e) { -// found = true; -// break actualElementsLoop; -// } -// break; -// case DO_NOT_MATCH_ANY: -// throw new MatcherException("Expected element from position " + (expPosition + 1) -// + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); -// } -// } -// if (!found && useCase == UseCase.MATCH) { -// throw new MatcherException("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" -// + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); -// } -// if (found && useCase == UseCase.DO_NOT_MATCH) { -// throw new MatcherException("Expected element from position " + (expPosition + 1) -// + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); -// } -// if (useCase == UseCase.MATCH_ANY) { -// throw new MatcherException("Expected condition of type MATCH_ANY from position " + (expPosition + 1) -// + " was NOT MET. Actual Json Array has no extra elements:\n" -// + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); -// } -// } + private List matchWithJsonArray(int expPosition, JsonNode expElement, JsonNode actualArray) { + List diffs = new ArrayList<>(); + UseCase useCase = getUseCase(expElement); + boolean found = false; + + for (int j = 0; j < actualArray.size(); j++) { + if (matchedPositions.contains(j)) { + continue; + } + if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER) && j != expPosition) { + continue; + } + List elementDiffs; + switch (useCase) { + case MATCH: + JsonNode actElement = actualArray.get(j); + elementDiffs = new JsonMatcher(expElement, actElement, comparator, compareModes).match(); + if (elementDiffs.isEmpty()) { + matchedPositions.add(j); + return Collections.emptyList(); + } else { + if (compareModes.contains(CompareMode.JSON_ARRAY_STRICT_ORDER)) { + diffs.add(String.format("JSON ARRAY elements differ at position %s:\n%s\nDifferences:\n%s", expPosition + 1, + MessageUtil.cropL(JSONCompare.prettyPrint(expElement)), String.join("\n", elementDiffs))); + return diffs; + } + } + break; + case MATCH_ANY: + matchedPositions.add(j); + return Collections.emptyList(); + case DO_NOT_MATCH: + actElement = actualArray.get(j); + if (areOfSameType(expElement, actElement)) { + elementDiffs = new JsonMatcher(expElement, actElement, comparator, compareModes).match(); + if (!elementDiffs.isEmpty()) { + found = true; + } + } + break; + case DO_NOT_MATCH_ANY: + diffs.add(String.format("Actual JSON array has extra elements.\nCondition %s from position %s means there" + + " should be no more actual elements to match", + expElement, expPosition + 1)); + return diffs; + } + if (found) { + break; + } + } + if (!found && useCase == UseCase.MATCH) { + diffs.add("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" + + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); + } else if (found) { + diffs.add("Expected element from position " + (expPosition + 1) + + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); + } else if (useCase == UseCase.MATCH_ANY) { + diffs.add(String.format("Actual Json Array has no extra elements. Condition %s from position %s means there" + + " should be more actual elements", expElement, expPosition + 1)); + } + return diffs; + } } diff --git a/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java b/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java index 0ac83ed..58174c3 100644 --- a/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonObjectMatcher.java @@ -71,26 +71,26 @@ public List match() { return diffs; } - private List matchWithCandidates(String expectedKey, JsonNode expectedValue, List> candidates) { + private List matchWithCandidates(String expectedField, JsonNode expectedValue, List> candidates) { List diffs = new ArrayList<>(); UseCase expectedValueUseCase = getUseCase(expectedValue); for (Map.Entry candidateEntry : candidates) { - String candidateKey = candidateEntry.getKey(); + String candidateField = candidateEntry.getKey(); if (expectedValueUseCase == UseCase.MATCH_ANY) { - matchedFieldNames.add(candidateKey); + matchedFieldNames.add(candidateField); return Collections.emptyList(); } JsonNode candidateValue = candidateEntry.getValue(); List candidateDiffs = new JsonMatcher(expectedValue, candidateValue, comparator, compareModes).match(); if (candidateDiffs.isEmpty()) { - matchedFieldNames.add(candidateKey); + matchedFieldNames.add(candidateField); return Collections.emptyList(); } else { - candidateDiffs.forEach(diff -> diffs.add(String.format("%s -> %s", expectedKey, diff))); + candidateDiffs.forEach(diff -> diffs.add(String.format("%s -> %s", expectedField, diff))); } } return diffs; diff --git a/src/main/java/io/json/compare/matcher/JsonValueMatcher.java b/src/main/java/io/json/compare/matcher/JsonValueMatcher.java index 93d7545..f0c37cd 100644 --- a/src/main/java/io/json/compare/matcher/JsonValueMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonValueMatcher.java @@ -17,10 +17,10 @@ class JsonValueMatcher extends AbstractJsonMatcher { @Override public List match() { List diffs = new ArrayList<>(); - String diff = "Expected %s: %s But got: %s"; + String diff = "\nExpected %s: %s But got: %s"; if (expected.isNull() && !actual.isNull()) { - diffs.add(String.format(diff, "null", expected, actual)); + diffs.add(String.format(diff, "null", "", actual)); return diffs; } else if (expected.isNumber() && !actual.isNumber()) { diffs.add(String.format(diff, "number", expected, actual)); diff --git a/src/main/java/io/json/compare/matcher/MatcherException.java b/src/main/java/io/json/compare/matcher/MatcherException.java deleted file mode 100644 index e96074c..0000000 --- a/src/main/java/io/json/compare/matcher/MatcherException.java +++ /dev/null @@ -1,8 +0,0 @@ -package io.json.compare.matcher; - -public class MatcherException extends Exception { - - public MatcherException(String msg) { - super(msg); - } -} diff --git a/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java b/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java index 6250ddc..506f7c8 100644 --- a/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java +++ b/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java @@ -196,7 +196,9 @@ public void checkInvalidOrNotFoundJsonPathErrorMessage() { try { JSONCompare.assertMatches(expected, actual); } catch (AssertionError e) { - assertTrue(e.getMessage().contains("No results for path: $['idontexist'] <- json path ('$.idontexist') <- a11 <- a1 <- a")); + assertTrue(e.getMessage().contains("FOUND 1 DIFFERENCE(S):\n" + + "\n" + + "a -> a1 -> a11 -> json path ('$.idontexist') -> No results for path: $['idontexist']")); return; } fail("No error thrown"); @@ -216,7 +218,10 @@ public void checkJsonPathAssertionErrorMessage() { try { JSONCompare.assertMatches(expected, actual); } catch (AssertionError e) { - assertTrue(e.getMessage().contains("But found: \"lorem\" <- json path ('$.a') <- a11 <- a1 <- a")); + assertTrue(e.getMessage().contains("a -> a1 -> a11 -> Json path ('$.a') -> Expected json path result:\n" + + "\"lorem1\"\n" + + "But got:\n" + + "\"lorem\"")); return; } fail("No error thrown"); diff --git a/src/test/java/io/json/compare/matcher/diffs/JsonObjectDiffTests.java b/src/test/java/io/json/compare/matcher/diffs/JsonObjectDiffTests.java new file mode 100644 index 0000000..1f52498 --- /dev/null +++ b/src/test/java/io/json/compare/matcher/diffs/JsonObjectDiffTests.java @@ -0,0 +1,14 @@ +package io.json.compare.matcher.diffs; + +import io.json.compare.JSONCompare; +import org.junit.jupiter.api.Test; + +public class JsonObjectDiffTests { + + @Test + public void compareWithNumbers() { + String expected = "{\"b\":1,\"a\":2}"; + String actual = "{\"a\":2,\"b\":1}"; + JSONCompare.assertMatches(expected, actual); + } +} diff --git a/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java b/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java new file mode 100644 index 0000000..16104c3 --- /dev/null +++ b/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java @@ -0,0 +1,49 @@ +package io.json.compare.matcher.diffs; + +import io.json.compare.JSONCompare; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +public class JsonValueDiffTests { + + @Test + public void compareNulls() { + String expected = "{\"a\":null}"; + String actual = "{\"a\":\"null\"}"; + AssertionError error = assertThrows(AssertionError.class, () -> JSONCompare.assertMatches(expected, actual)); + assertTrue(error.getMessage().matches("(?s).*FOUND 1 DIFFERENCE.*a ->.*Expected null: But got: \"null\".*")); + JSONCompare.assertNotMatches(expected, actual); + } + + @Test + public void compareBooleans() { + String expected = "{\"a\":false}"; + String actual = "{\"a\":\"false\"}"; + AssertionError error = assertThrows(AssertionError.class, () -> JSONCompare.assertMatches(expected, actual)); + assertTrue(error.getMessage().matches("(?s).*FOUND 1 DIFFERENCE.*a ->.*Expected boolean: false But got: \"false\".*")); + JSONCompare.assertNotMatches(expected, actual); + } + + @Test + public void compareNumbers() { + String expected = "{\"a\":2}"; + String actual = "{\"a\":\"2\"}"; + AssertionError error = assertThrows(AssertionError.class, () -> JSONCompare.assertMatches(expected, actual)); + assertTrue(error.getMessage().matches("(?s).*FOUND 1 DIFFERENCE.*a ->.*Expected number: 2 But got: \"2\".*")); + JSONCompare.assertNotMatches(expected, actual); + } + + @Test + public void compareAll() { + String expected = "{\"a\":null,\"b\":1,\"c\":false,\"d\":\"false\"}"; + String actual = "{\"a\":\"null\",\"b\":\"1\",\"c\":\"false\",\"d\":false}"; + AssertionError error = assertThrows(AssertionError.class, () -> JSONCompare.assertMatches(expected, actual)); + assertTrue(error.getMessage().matches("(?s).*FOUND 3 DIFFERENCE.*" + + "a ->.*Expected null: But got: \"null\".*" + + "b ->.*Expected number: 1 But got: \"1\".*" + + "c ->.*Expected boolean: false But got: \"false\".*")); + JSONCompare.assertNotMatches(expected, actual); + } +} diff --git a/src/test/java/io/json/compare/matcher/issues/Issue11Test.java b/src/test/java/io/json/compare/matcher/issues/Issue11Test.java index 6a3201c..7af9907 100644 --- a/src/test/java/io/json/compare/matcher/issues/Issue11Test.java +++ b/src/test/java/io/json/compare/matcher/issues/Issue11Test.java @@ -232,7 +232,7 @@ public void testJsonArrayStrictOrderWithRegexFieldsThrowsCorrectMessage() { try { JSONCompare.assertMatches(expected, actual, new HashSet<>(Arrays.asList(CompareMode.JSON_ARRAY_STRICT_ORDER))); } catch (AssertionError e) { - assertTrue(e.getMessage().contains("was not found or cannot be matched")); + assertTrue(e.getMessage().contains("was not found")); } } From e7071d06d1511402d005675d710646b68f89cf55 Mon Sep 17 00:00:00 2001 From: florin Date: Sun, 2 Oct 2022 19:54:25 +0300 Subject: [PATCH 3/6] refactor --- src/main/java/io/json/compare/JSONCompare.java | 5 +++-- .../java/io/json/compare/matcher/JSONPathCompareTests.java | 1 + 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/json/compare/JSONCompare.java b/src/main/java/io/json/compare/JSONCompare.java index 6e75ed2..af6b7b9 100644 --- a/src/main/java/io/json/compare/JSONCompare.java +++ b/src/main/java/io/json/compare/JSONCompare.java @@ -65,8 +65,9 @@ public static void assertMatches(Object expected, Object actual, JsonComparator List diffs = new JsonMatcher(expectedJson, actualJson, comparator == null ? new DefaultJsonComparator() : comparator, compareModes).match(); if (!diffs.isEmpty()) { - String defaultMessage = String.format("FOUND %s DIFFERENCE(S):\n\n%s\n", - diffs.size(), String.join("\n_____________________________________\n", diffs)); + String defaultMessage = String.format("FOUND %s DIFFERENCE(S):\n%s\n", + diffs.size(), diffs.stream().map(diff -> + "\n_________________________DIFF__________________________\n" + diff).reduce(String::concat).get()); if (comparator == null || comparator.getClass().equals(DefaultJsonComparator.class)) { defaultMessage += "\n\n" + ASSERTION_ERROR_HINT_MESSAGE + "\n"; } diff --git a/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java b/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java index 506f7c8..390504a 100644 --- a/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java +++ b/src/test/java/io/json/compare/matcher/JSONPathCompareTests.java @@ -198,6 +198,7 @@ public void checkInvalidOrNotFoundJsonPathErrorMessage() { } catch (AssertionError e) { assertTrue(e.getMessage().contains("FOUND 1 DIFFERENCE(S):\n" + "\n" + + "_________________________DIFF__________________________\n" + "a -> a1 -> a11 -> json path ('$.idontexist') -> No results for path: $['idontexist']")); return; } From 0816ea1b3cf48eaf586c0bcba3564fba5851dcfd Mon Sep 17 00:00:00 2001 From: florin Date: Mon, 3 Oct 2022 08:52:22 +0300 Subject: [PATCH 4/6] refactor --- .../io/json/compare/matcher/JsonArrayMatcher.java | 13 ++++--------- .../compare/matcher/diffs/JsonValueDiffTests.java | 9 +++++---- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java index 641be5d..1e70313 100644 --- a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java @@ -37,7 +37,6 @@ public List match() { private List matchWithJsonArray(int expPosition, JsonNode expElement, JsonNode actualArray) { List diffs = new ArrayList<>(); UseCase useCase = getUseCase(expElement); - boolean found = false; for (int j = 0; j < actualArray.size(); j++) { if (matchedPositions.contains(j)) { @@ -70,7 +69,9 @@ private List matchWithJsonArray(int expPosition, JsonNode expElement, Js if (areOfSameType(expElement, actElement)) { elementDiffs = new JsonMatcher(expElement, actElement, comparator, compareModes).match(); if (!elementDiffs.isEmpty()) { - found = true; + diffs.add("Expected element from position " + (expPosition + 1) + + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); + return diffs; } } break; @@ -80,16 +81,10 @@ private List matchWithJsonArray(int expPosition, JsonNode expElement, Js expElement, expPosition + 1)); return diffs; } - if (found) { - break; - } } - if (!found && useCase == UseCase.MATCH) { + if (useCase == UseCase.MATCH) { diffs.add("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); - } else if (found) { - diffs.add("Expected element from position " + (expPosition + 1) - + " was FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); } else if (useCase == UseCase.MATCH_ANY) { diffs.add(String.format("Actual Json Array has no extra elements. Condition %s from position %s means there" + " should be more actual elements", expElement, expPosition + 1)); diff --git a/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java b/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java index 16104c3..c358ee5 100644 --- a/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java +++ b/src/test/java/io/json/compare/matcher/diffs/JsonValueDiffTests.java @@ -37,13 +37,14 @@ public void compareNumbers() { @Test public void compareAll() { - String expected = "{\"a\":null,\"b\":1,\"c\":false,\"d\":\"false\"}"; - String actual = "{\"a\":\"null\",\"b\":\"1\",\"c\":\"false\",\"d\":false}"; + String expected = "{\"a\":null,\"b\":1,\"c\":false,\"d\":\"false\",\"e\":\"text\"}"; + String actual = "{\"a\":\"null\",\"b\":\"1\",\"c\":\"false\",\"d\":false,\"e\":false}"; AssertionError error = assertThrows(AssertionError.class, () -> JSONCompare.assertMatches(expected, actual)); - assertTrue(error.getMessage().matches("(?s).*FOUND 3 DIFFERENCE.*" + + assertTrue(error.getMessage().matches("(?s).*FOUND 4 DIFFERENCE.*" + "a ->.*Expected null: But got: \"null\".*" + "b ->.*Expected number: 1 But got: \"1\".*" + - "c ->.*Expected boolean: false But got: \"false\".*")); + "c ->.*Expected boolean: false But got: \"false\".*" + + "e ->.*Expected value: \"text\" But got: false.*")); JSONCompare.assertNotMatches(expected, actual); } } From 848c47927f2456d527ebc072c49d33b09501eeae Mon Sep 17 00:00:00 2001 From: florin Date: Mon, 3 Oct 2022 09:00:52 +0300 Subject: [PATCH 5/6] refactor --- src/main/java/io/json/compare/matcher/JsonArrayMatcher.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java index 1e70313..6e3a6ef 100644 --- a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java @@ -76,8 +76,8 @@ private List matchWithJsonArray(int expPosition, JsonNode expElement, Js } break; case DO_NOT_MATCH_ANY: - diffs.add(String.format("Actual JSON array has extra elements.\nCondition %s from position %s means there" + - " should be no more actual elements to match", + diffs.add(String.format("Actual JSON array has extra elements.\nExpected condition %s from position %s means there" + + " should be no more actual elements other than the ones expected", expElement, expPosition + 1)); return diffs; } @@ -86,7 +86,7 @@ private List matchWithJsonArray(int expPosition, JsonNode expElement, Js diffs.add("Expected element from position " + (expPosition + 1) + " was NOT FOUND:\n" + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); } else if (useCase == UseCase.MATCH_ANY) { - diffs.add(String.format("Actual Json Array has no extra elements. Condition %s from position %s means there" + + diffs.add(String.format("Actual Json Array has no extra elements. Expected condition %s from position %s means there" + " should be more actual elements", expElement, expPosition + 1)); } return diffs; From cc7a2b33262528b0091cc2ac75b1a0c5bea6b24e Mon Sep 17 00:00:00 2001 From: florin Date: Mon, 3 Oct 2022 11:29:26 +0300 Subject: [PATCH 6/6] refactor --- src/main/java/io/json/compare/matcher/JsonArrayMatcher.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java index 6e3a6ef..e8c7544 100644 --- a/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java +++ b/src/main/java/io/json/compare/matcher/JsonArrayMatcher.java @@ -87,7 +87,7 @@ private List matchWithJsonArray(int expPosition, JsonNode expElement, Js + MessageUtil.cropL(JSONCompare.prettyPrint(expElement))); } else if (useCase == UseCase.MATCH_ANY) { diffs.add(String.format("Actual Json Array has no extra elements. Expected condition %s from position %s means there" + - " should be more actual elements", expElement, expPosition + 1)); + " should be more actual elements to match", expElement, expPosition + 1)); } return diffs; }