Skip to content

Commit f49da4b

Browse files
author
Alberto Colombo
committed
Custom comparator per path
Implement functionality to use custom comparators per specific path elements. Current implementation is quite naive and can only match on simple paths (no wildcards). Updates the Customization class to allow path-matching, and matching of expected and actual values with user-provided EqualityComparator.
1 parent 8f4a25b commit f49da4b

File tree

6 files changed

+125
-6
lines changed

6 files changed

+125
-6
lines changed

src/main/java/org/skyscreamer/jsonassert/Behavior.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,12 @@ public Behavior butExtraFieldsAre(Allowance allowance) {
7777
public Behavior with(Customization customization) {
7878
return Builder.from(this).add(customization).build();
7979
}
80+
81+
public Customization getCustomization(String path) {
82+
for (Customization c : customizations) {
83+
if (c.appliesToPath(path))
84+
return c;
85+
}
86+
return null;
87+
}
8088
}

src/main/java/org/skyscreamer/jsonassert/Customization.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,24 @@
44

55
public final class Customization {
66
private final String path;
7-
private final Matcher<?> matcher;
7+
private final EqualsComparator<Object> comparator;
88

9-
public Customization(String path, Matcher<?> matcher) {
9+
public Customization(String path, EqualsComparator<Object> comparator) {
10+
assert path != null;
11+
assert comparator != null;
1012
this.path = path;
11-
this.matcher = matcher;
13+
this.comparator = comparator;
1214
}
1315

14-
public static Customization customization(String path, Matcher<?> matcher) {
15-
return new Customization(path, matcher);
16+
public static Customization customization(String path, EqualsComparator<Object> comparator) {
17+
return new Customization(path, comparator);
1618
}
19+
20+
public boolean appliesToPath(String path) {
21+
return this.path.equals(path);
22+
}
23+
24+
public boolean matches(Object actual, Object expected) {
25+
return comparator.equal(actual, expected);
26+
}
1727
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package org.skyscreamer.jsonassert;
2+
3+
public interface EqualsComparator<T> {
4+
5+
boolean equal(T o1, T o2);
6+
7+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package org.skyscreamer.jsonassert;
2+
3+
import org.hamcrest.Matcher;
4+
5+
/**
6+
* Delegate equality comparison to an org.hamcrest.Matcher
7+
* @param <T>
8+
*/
9+
public final class HamcrestEqualsComparator<T> implements EqualsComparator<T> {
10+
11+
private final Matcher<?> matcher;
12+
13+
public HamcrestEqualsComparator(Matcher<?> matcher) {
14+
this.matcher = matcher;
15+
}
16+
17+
/**
18+
* The matcher is invoked on the first parameter, ignoring the second
19+
* @param o1
20+
* @param o2 ignored
21+
* @return true if mather matches o1
22+
*/
23+
@Override
24+
public boolean equal(T o1, T o2) {
25+
return matcher.matches(o1);
26+
}
27+
}

src/main/java/org/skyscreamer/jsonassert/JSONCompare.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,12 @@ private static String qualify(String prefix, String key) {
122122

123123
private static void compareValues(String fullKey, Object expectedValue, Object actualValue, Behavior behavior, JSONCompareResult result) throws JSONException
124124
{
125-
if (expectedValue.getClass().isAssignableFrom(actualValue.getClass())) {
125+
Customization customization = behavior.getCustomization(fullKey);
126+
if (customization != null) {
127+
if (!customization.matches(actualValue, expectedValue)) {
128+
result.fail(fullKey, expectedValue, actualValue);
129+
}
130+
} else if (expectedValue.getClass().isAssignableFrom(actualValue.getClass())) {
126131
if (expectedValue instanceof JSONArray) {
127132
compareJSONArray(fullKey , (JSONArray)expectedValue, (JSONArray)actualValue, behavior, result);
128133
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package org.skyscreamer.jsonassert;
2+
3+
import org.hamcrest.BaseMatcher;
4+
import org.hamcrest.Description;
5+
import org.hamcrest.Matcher;
6+
import org.json.JSONException;
7+
import org.junit.Test;
8+
9+
import static org.junit.Assert.assertThat;
10+
import static org.junit.Assert.assertTrue;
11+
import static org.skyscreamer.jsonassert.Behavior.STRICT;
12+
import static org.skyscreamer.jsonassert.Customization.customization;
13+
import static org.skyscreamer.jsonassert.JSONCompare.compareJSON;
14+
15+
public class JSONBehaviourTest {
16+
17+
String actual = "{\"first\":\"actual\", \"second\":1}";
18+
String expected = "{\"first\":\"expected\", \"second\":1}";
19+
20+
String deepActual = "{\n" +
21+
" \"outer\":\n" +
22+
" {\n" +
23+
" \"inner\":\n" +
24+
" {\n" +
25+
" \"value\": \"actual\",\n" +
26+
" \"otherValue\": \"foo\"\n" +
27+
" }\n" +
28+
" }\n" +
29+
"}";
30+
String deepExpected = "{\n" +
31+
" \"outer\":\n" +
32+
" {\n" +
33+
" \"inner\":\n" +
34+
" {\n" +
35+
" \"value\": \"expected\",\n" +
36+
" \"otherValue\": \"foo\"\n" +
37+
" }\n" +
38+
" }\n" +
39+
"}";
40+
41+
EqualsComparator<Object> comparator = new EqualsComparator<Object>() {
42+
@Override
43+
public boolean equal(Object o1, Object o2) {
44+
return o1.toString().equals("actual") && o2.toString().equals("expected");
45+
}
46+
};
47+
48+
@Test
49+
public void whenPathMatchesInCustomizationThenCallCustomMatcher() throws JSONException {
50+
Behavior behavior = STRICT.with(customization("first", comparator));
51+
JSONCompareResult result = compareJSON(expected, actual, behavior);
52+
assertTrue(result.getMessage(), result.passed());
53+
}
54+
55+
@Test
56+
public void whenDeepPathMatchesCallCustomMatcher() throws JSONException {
57+
Behavior behavior = STRICT.with(customization("outer.inner.value", comparator));
58+
JSONCompareResult result = compareJSON(deepExpected, deepActual, behavior);
59+
assertTrue(result.getMessage(), result.passed());
60+
}
61+
62+
}

0 commit comments

Comments
 (0)