Skip to content

Commit 4921339

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 1b4cdbb commit 4921339

5 files changed

Lines changed: 142 additions & 0 deletions

File tree

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package org.skyscreamer.jsonassert;
2+
3+
/**
4+
* Associates a custom matcher to a specific jsonpath.
5+
*/
6+
public final class Customization {
7+
private final String path;
8+
private final ValueMatcher<Object> comparator;
9+
10+
public Customization(String path, ValueMatcher<Object> comparator) {
11+
assert path != null;
12+
assert comparator != null;
13+
this.path = path;
14+
this.comparator = comparator;
15+
}
16+
17+
public static Customization customization(String path, ValueMatcher<Object> comparator) {
18+
return new Customization(path, comparator);
19+
}
20+
21+
public boolean appliesToPath(String path) {
22+
return this.path.equals(path);
23+
}
24+
25+
public boolean matches(Object actual, Object expected) {
26+
return comparator.equal(actual, expected);
27+
}
28+
}
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 ValueMatcher<T> {
4+
5+
boolean equal(T o1, T o2);
6+
7+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package org.skyscreamer.jsonassert.comparator;
2+
3+
import org.json.JSONException;
4+
import org.skyscreamer.jsonassert.Customization;
5+
import org.skyscreamer.jsonassert.JSONCompareMode;
6+
import org.skyscreamer.jsonassert.JSONCompareResult;
7+
8+
import java.util.Arrays;
9+
import java.util.Collection;
10+
11+
public class CustomComparator extends DefaultComparator {
12+
13+
private final Collection<Customization> customizations;
14+
15+
public CustomComparator(JSONCompareMode mode, Customization... customizations) {
16+
super(mode);
17+
this.customizations = Arrays.asList(customizations);
18+
}
19+
20+
@Override
21+
public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
22+
Customization customization = getCustomization(prefix);
23+
if (customization != null) {
24+
if (!customization.matches(actualValue, expectedValue)) {
25+
result.fail(prefix, expectedValue, actualValue);
26+
}
27+
} else {
28+
super.compareValues(prefix, expectedValue, actualValue, result);
29+
}
30+
}
31+
32+
private Customization getCustomization(String path) {
33+
for (Customization c : customizations)
34+
if (c.appliesToPath(path))
35+
return c;
36+
return null;
37+
}
38+
}

src/main/java/org/skyscreamer/jsonassert/comparator/DefaultComparator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,15 @@
33
import org.json.JSONArray;
44
import org.json.JSONException;
55
import org.json.JSONObject;
6+
import org.skyscreamer.jsonassert.Customization;
67
import org.skyscreamer.jsonassert.JSONCompareMode;
78
import org.skyscreamer.jsonassert.JSONCompareResult;
89

10+
import java.util.Collection;
11+
import java.util.Collections;
12+
import java.util.HashSet;
13+
import java.util.Set;
14+
915
import static org.skyscreamer.jsonassert.comparator.JSONCompareUtil.allJSONObjects;
1016
import static org.skyscreamer.jsonassert.comparator.JSONCompareUtil.allSimpleValues;
1117

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package org.skyscreamer.jsonassert;
2+
3+
import org.json.JSONException;
4+
import org.junit.Test;
5+
import org.skyscreamer.jsonassert.comparator.CustomComparator;
6+
import org.skyscreamer.jsonassert.comparator.JSONComparator;
7+
8+
import static org.junit.Assert.assertEquals;
9+
import static org.junit.Assert.assertTrue;
10+
import static org.skyscreamer.jsonassert.JSONCompare.compareJSON;
11+
12+
public class JSONCustomComparatorTest {
13+
14+
String actual = "{\"first\":\"actual\", \"second\":1}";
15+
String expected = "{\"first\":\"expected\", \"second\":1}";
16+
17+
String deepActual = "{\n" +
18+
" \"outer\":\n" +
19+
" {\n" +
20+
" \"inner\":\n" +
21+
" {\n" +
22+
" \"value\": \"actual\",\n" +
23+
" \"otherValue\": \"foo\"\n" +
24+
" }\n" +
25+
" }\n" +
26+
"}";
27+
String deepExpected = "{\n" +
28+
" \"outer\":\n" +
29+
" {\n" +
30+
" \"inner\":\n" +
31+
" {\n" +
32+
" \"value\": \"expected\",\n" +
33+
" \"otherValue\": \"foo\"\n" +
34+
" }\n" +
35+
" }\n" +
36+
"}";
37+
38+
int comparatorCallCount = 0;
39+
ValueMatcher<Object> comparator = new ValueMatcher<Object>() {
40+
@Override
41+
public boolean equal(Object o1, Object o2) {
42+
comparatorCallCount++;
43+
return o1.toString().equals("actual") && o2.toString().equals("expected");
44+
}
45+
};
46+
47+
@Test
48+
public void whenPathMatchesInCustomizationThenCallCustomMatcher() throws JSONException {
49+
JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("first", comparator));
50+
JSONCompareResult result = compareJSON(expected, actual, jsonCmp);
51+
assertTrue(result.getMessage(), result.passed());
52+
assertEquals(1, comparatorCallCount);
53+
}
54+
55+
@Test
56+
public void whenDeepPathMatchesCallCustomMatcher() throws JSONException {
57+
JSONComparator jsonCmp = new CustomComparator(JSONCompareMode.STRICT, new Customization("outer.inner.value", comparator));
58+
JSONCompareResult result = compareJSON(deepExpected, deepActual, jsonCmp);
59+
assertTrue(result.getMessage(), result.passed());
60+
assertEquals(1, comparatorCallCount);
61+
}
62+
63+
}

0 commit comments

Comments
 (0)