Skip to content

Commit 7928d10

Browse files
Duncan MackinderDuncan Mackinder
authored andcommitted
Improve JavaDoc and unit test coverage
Standardise some failure messages, add unit tests for additional cases and to verify failure descriptions are correct, improve unit test coverage, add JavaDoc
1 parent 3bb2d5c commit 7928d10

File tree

8 files changed

+377
-59
lines changed

8 files changed

+377
-59
lines changed

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

Lines changed: 79 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,85 @@
77
import org.skyscreamer.jsonassert.comparator.JSONComparator;
88

99
/**
10-
* A value matcher for arrays. This operates like STRICT_ORDER array match,
10+
* <p>A value matcher for arrays. This operates like STRICT_ORDER array match,
1111
* however if expected array has less elements than actual array the matching
1212
* process loops through the expected array to get expected elements for the
1313
* additional actual elements. In general the expected array will contain a
1414
* single element which is matched against each actual array element in turn.
1515
* This allows simple verification of constant array element components and
1616
* coupled with RegularExpressionValueMatcher can be used to match specific
17-
* array element components against a regular expression pattern. If the
17+
* array element components against a regular expression pattern. As a convenience to reduce syntactic complexity of expected string, if the
1818
* expected object is not an array, a one element expected array is created
19-
* containing whatever is provided as the expected value.
19+
* containing whatever is provided as the expected value.</p>
20+
*
21+
* <p>Some examples of typical usage idioms listed below.</p>
22+
*
23+
* <p>Assuming JSON to be verified is held in String variable ARRAY_OF_JSONOBJECTS and contains:</p>
24+
*
25+
* <code>{a:[{background:white,id:1,type:row}, {background:grey,id:2,type:row}, {background:white,id:3,type:row}, {background:grey,id:4,type:row}]}</code>
26+
*
27+
* <p>then:</p>
28+
*
29+
* <p>To verify that the 'id' attribute of first element of array 'a' is '1':</p>
30+
*
31+
* <code>
32+
* JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT);<br/>
33+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator, 0));<br/>
34+
* JSONAssert.assertEquals("{a:[{id:1}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization));
35+
* </code>
36+
*
37+
* <p>To simplify complexity of expected JSON string, the value <code>"a:[{id:1}]}"</code> may be replaced by <code>"a:{id:1}}"</code></p>
38+
*
39+
* <p>To verify that the 'type' attribute of second and third elements of array 'a' is 'row':</p>
40+
*
41+
* <code>
42+
* JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT);<br/>
43+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator, 1, 2));<br/>
44+
* JSONAssert.assertEquals("{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization));
45+
* </code>
46+
*
47+
* <p>To verify that the 'type' attribute of every element of array 'a' is 'row':</p>
48+
*
49+
* <code>
50+
* JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT);<br/>
51+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator));<br/>
52+
* JSONAssert.assertEquals("{a:[{type:row}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization));
53+
* </code>
54+
*
55+
* <p>To verify that the 'background' attribute of every element of array 'a' alternates between 'white' and 'grey' starting with first element 'background' being 'white':</p>
56+
*
57+
* <code>
58+
* JSONComparator comparator = new DefaultComparator(JSONCompareMode.LENIENT);<br/>
59+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator));<br/>
60+
* JSONAssert.assertEquals("{a:[{background:white},{background:grey}]}", ARRAY_OF_JSONOBJECTS, new CustomComparator(JSONCompareMode.LENIENT, customization));
61+
* </code>
62+
*
63+
* <p>Assuming JSON to be verified is held in String variable ARRAY_OF_JSONARRAYS and contains:</p>
64+
*
65+
* <code>{a:[[6,7,8], [9,10,11], [12,13,14], [19,20,21,22]]}</code>
66+
*
67+
* <p>then:</p>
68+
*
69+
* <p>To verify that the first three elements of JSON array 'a' are JSON arrays of length 3:</p>
70+
*
71+
* <code>
72+
* JSONComparator comparator = new ArraySizeComparator(JSONCompareMode.STRICT_ORDER);<br/>
73+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator, 0, 2));<br/>
74+
* JSONAssert.assertEquals("{a:[[3]]}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization));
75+
* </code>
76+
*
77+
* <p>NOTE: simplified expected JSON strings are not possible in this case as ArraySizeComparator does not support them.</p>
78+
*
79+
* <p>To verify that the second elements of JSON array 'a' is a JSON array whose first element has the value 9:</p>
80+
*
81+
* <code>
82+
* Customization innerCustomization = new Customization("a[1]", new ArrayValueMatcher&lt;Object&gt;(comparator, 0));<br/>
83+
* JSONComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, innerCustomization);<br/>
84+
* Customization customization = new Customization("a", new ArrayValueMatcher&lt;Object&gt;(comparator, 1));<br/>
85+
* JSONAssert.assertEquals("{a:[[9]]}", ARRAY_OF_JSONARRAYS, new CustomComparator(JSONCompareMode.LENIENT, customization));
86+
* </code>
87+
*
88+
* <p>To simplify complexity of expected JSON string, the value <code>"{a:[[9]]}"</code> may be replaced by <code>"{a:[9]}"</code> or <code>"{a:9}"</code></p>
2089
*
2190
* @author Duncan Mackinder
2291
*
@@ -44,9 +113,11 @@ public ArrayValueMatcher(JSONComparator comparator) {
44113
*
45114
* @param comparator
46115
* comparator to use to compare elements
116+
* @param index
117+
* index of the array element to be compared
47118
*/
48-
public ArrayValueMatcher(JSONComparator comparator, int i) {
49-
this(comparator, i, i);
119+
public ArrayValueMatcher(JSONComparator comparator, int index) {
120+
this(comparator, index, index);
50121
}
51122

52123
/**
@@ -56,8 +127,8 @@ public ArrayValueMatcher(JSONComparator comparator, int i) {
56127
*
57128
* @param comparator
58129
* comparator to use to compare elements
59-
* @from first element in actual array to compare
60-
* @to last element in actual array to compare
130+
* @from first element in actual array to compared
131+
* @to last element in actual array to compared
61132
*/
62133
public ArrayValueMatcher(JSONComparator comparator, int from, int to) {
63134
assert comparator != null : "comparator null";
@@ -95,7 +166,7 @@ public boolean equal(String prefix, T actual, T expected, JSONCompareResult resu
95166
Object expectedElement = expectedArray.get((i - first) % expectedLen);
96167
comparator.compareValues(elementPrefix, expectedElement, actualElement, result);
97168
}
98-
// values must match since no exceptions thrown
169+
// any failures have already been passed to result, so return true
99170
return true;
100171
}
101172
catch (JSONException e) {

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

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,30 @@
1111
*/
1212
public interface LocationAwareValueMatcher<T> extends ValueMatcher<T> {
1313

14-
boolean equal(String prefix, T actual, T expected, JSONCompareResult result);
14+
/**
15+
* Match actual value with expected value. If match fails any of the
16+
* following may occur, return false, pass failure details to specified
17+
* JSONCompareResult and return true, or throw ValueMatcherException
18+
* containing failure details. Passing failure details to JSONCompareResult
19+
* or returning via ValueMatcherException enables more useful failure
20+
* description for cases where expected value depends entirely or in part on
21+
* configuration of the ValueMatcher and therefore expected value passed to
22+
* this method will not give a useful indication of expected value.
23+
*
24+
* @param prefix
25+
* JSON path of the JSON item being tested
26+
* @param actual
27+
* JSON value being tested
28+
* @param expected
29+
* expected JSON value
30+
* @param result
31+
* JSONCompareResult to which match failure may be passed
32+
* @return true if expected and actual equal or any difference has already
33+
* been passed to specified result instance, false otherwise.
34+
* @throws ValueMatcherException
35+
* if expected and actual values not equal and ValueMatcher
36+
* needs to override default comparison failure message that
37+
* would be generated if this method returned false.
38+
*/
39+
boolean equal(String prefix, T actual, T expected, JSONCompareResult result) throws ValueMatcherException;
1540
}

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

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,34 @@ public class ValueMatcherException extends RuntimeException {
1313

1414
private final String actual;
1515

16+
/**
17+
* Create new ValueMatcherException
18+
*
19+
* @param message
20+
* description of exception
21+
* @param expected
22+
* value expected by ValueMatcher
23+
* @param actual
24+
* value being tested by ValueMatcher
25+
*/
1626
public ValueMatcherException(String message, String expected, String actual) {
1727
super(message);
1828
this.expected = expected;
1929
this.actual = actual;
2030
}
21-
22-
public ValueMatcherException(Throwable cause, String expected, String actual) {
23-
super(cause);
24-
this.expected = expected;
25-
this.actual = actual;
26-
}
2731

32+
/**
33+
* Create new ValueMatcherException
34+
*
35+
* @param message
36+
* description of exception
37+
* @param cause
38+
* cause of ValueMatcherException
39+
* @param expected
40+
* value expected by ValueMatcher
41+
* @param actual
42+
* value being tested by ValueMatcher
43+
*/
2844
public ValueMatcherException(String message, Throwable cause, String expected, String actual) {
2945
super(message, cause);
3046
this.expected = expected;

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

Lines changed: 66 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,106 @@
11
package org.skyscreamer.jsonassert.comparator;
22

3+
import java.text.MessageFormat;
4+
35
import org.json.JSONArray;
46
import org.json.JSONException;
57
import org.skyscreamer.jsonassert.JSONCompareMode;
68
import org.skyscreamer.jsonassert.JSONCompareResult;
79

810
/**
9-
* A JSONAssert array size comparator. Expected array should consist of either 1
10-
* or 2 integer values that define maximum and minimum size of that the actual
11-
* array is expected to be. If expected array contains a single integer value
12-
* then the actual array must contain exactly that number of elements.
11+
* A JSONAssert array size comparator.
12+
*
13+
* <p>Some typical usage idioms are listed below.</p>
14+
*
15+
* <p>Assuming JSON to be verified is held in String variable ARRAY_OF_JSONOBJECTS and contains:</p>
16+
*
17+
* <code>{a:[7, 8, 9]}</code>
18+
*
19+
* <p>then:</p>
20+
*
21+
* <p>To verify that array 'a' contains 3 elements:</p>
22+
*
23+
* <code>
24+
* JSONAssert.assertEquals("{a:[3]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(JSONCompareMode.LENIENT));
25+
* </code>
26+
*
27+
* <p>To verify that array 'a' contains between 2 and 6 elements:</p>
28+
*
29+
* <code>
30+
* JSONAssert.assertEquals("{a:[2,6]}", ARRAY_OF_JSONOBJECTS, new ArraySizeComparator(JSONCompareMode.LENIENT));
31+
* </code>
1332
*
1433
* @author Duncan Mackinder
1534
*
1635
*/
1736
public class ArraySizeComparator extends DefaultComparator {
1837

38+
/**
39+
* Create new ArraySizeComparator.
40+
*
41+
* @param mode
42+
* comparison mode, has no impact on ArraySizeComparator but is
43+
* used by instance of superclass DefaultComparator to control
44+
* comparison of JSON items other than arrays.
45+
*/
1946
public ArraySizeComparator(JSONCompareMode mode) {
2047
super(mode);
2148
}
2249

50+
/**
51+
* Expected array should consist of either 1 or 2 integer values that define
52+
* maximum and minimum valid lengths of the actual array. If expected array
53+
* contains a single integer value, then the actual array must contain
54+
* exactly that number of elements.
55+
*/
2356
@Override
2457
public void compareJSONArray(String prefix, JSONArray expected,
2558
JSONArray actual, JSONCompareResult result) throws JSONException {
59+
String arrayPrefix = prefix + "[]";
2660
if (expected.length() < 1 || expected.length() > 2) {
27-
result.fail(prefix + ": invalid expectation, length=" + expected.length());
61+
result.fail(MessageFormat
62+
.format("{0}: invalid expectation: expected array should contain either 1 or 2 elements but contains {1} elements",
63+
arrayPrefix, expected.length()));
2864
return;
2965
}
3066
if (!(expected.get(0) instanceof Number)) {
31-
result.fail(prefix + ": min expected length not a number: " + expected.get(0));
67+
result.fail(MessageFormat
68+
.format("{0}: invalid expectation: {1}expected array size ''{2}'' not a number",
69+
arrayPrefix, (expected.length() == 1? "": "minimum "), expected.get(0)));
3270
return;
3371
}
3472
if ((expected.length() == 2 && !(expected.get(1) instanceof Number))) {
35-
result.fail(prefix + ": max expected length not a number: " + expected.get(1));
73+
result.fail(MessageFormat
74+
.format("{0}: invalid expectation: maximum expected array size ''{1}'' not a number",
75+
arrayPrefix, expected.get(1)));
3676
return;
3777
}
3878
int minExpectedLength = expected.getInt(0);
3979
if (minExpectedLength < 0) {
40-
result.fail(prefix + ": invalid expectation, invalid min expected length: " + minExpectedLength);
80+
result.fail(MessageFormat
81+
.format("{0}: invalid expectation: minimum expected array size ''{1}'' negative",
82+
arrayPrefix, minExpectedLength));
4183
return;
4284
}
43-
int maxExpectedLength = expected.length() == 2? expected.getInt(1): minExpectedLength;
85+
int maxExpectedLength = expected.length() == 2 ? expected.getInt(1)
86+
: minExpectedLength;
4487
if (maxExpectedLength < minExpectedLength) {
45-
result.fail(prefix + ": invalid expectation, invalid expected length range: "+ minExpectedLength+" to " + maxExpectedLength);
88+
result.fail(MessageFormat
89+
.format("{0}: invalid expectation: maximum expected array size ''{1}'' less than minimum expected array size ''{2}''",
90+
arrayPrefix, maxExpectedLength, minExpectedLength));
4691
return;
4792
}
48-
if (actual.length() < minExpectedLength || actual.length() > maxExpectedLength) {
49-
result.fail(prefix + "[]: Expected " + minExpectedLength + (expected.length() == 2? (" to "+maxExpectedLength): "")
50-
+ " values but got " + actual.length());
93+
if (actual.length() < minExpectedLength
94+
|| actual.length() > maxExpectedLength) {
95+
result.fail(
96+
arrayPrefix,
97+
MessageFormat.format(
98+
"array size of {0}{1} elements",
99+
minExpectedLength,
100+
(expected.length() == 2 ? (" to " + maxExpectedLength)
101+
: "")),
102+
MessageFormat.format("{0} elements",
103+
actual.length()));
51104
}
52105
}
53106

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

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ public CustomComparator(JSONCompareMode mode, Customization... customizations)
2222
public void compareValues(String prefix, Object expectedValue, Object actualValue, JSONCompareResult result) throws JSONException {
2323
Customization customization = getCustomization(prefix);
2424
if (customization != null) {
25-
try {
26-
if (!customization.matches(prefix, actualValue, expectedValue, result)) {
27-
result.fail(prefix, expectedValue, actualValue);
28-
}
29-
}
30-
catch (ValueMatcherException e) {
31-
result.fail(prefix, e);
32-
}
25+
try {
26+
if (!customization.matches(prefix, actualValue, expectedValue, result)) {
27+
result.fail(prefix, expectedValue, actualValue);
28+
}
29+
}
30+
catch (ValueMatcherException e) {
31+
result.fail(prefix, e);
32+
}
3333
} else {
3434
super.compareValues(prefix, expectedValue, actualValue, result);
3535
}

0 commit comments

Comments
 (0)