Skip to content

Commit 7561f33

Browse files
committed
Fix bug where actual JSON array doesn't contain JSONObjects with unique keys
1 parent d254e7e commit 7561f33

File tree

2 files changed

+37
-25
lines changed

2 files changed

+37
-25
lines changed

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

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,7 @@ else if (actualCount.get(o) != expectedCount.get(o)) {
181181
}
182182
else if (allJSONObjects(expected)) {
183183
String uniqueKey = findUniqueKey(expected);
184-
if (uniqueKey == null) {
184+
if (uniqueKey == null || !isUsableAsUniqueKey(uniqueKey, actual)) {
185185
// An expensive last resort
186186
recursivelyCompareJSONArray(key, expected, actual, mode, result);
187187
return;
@@ -268,31 +268,37 @@ private static String findUniqueKey(JSONArray expected) throws JSONException {
268268
// Find a unique key for the object (id, name, whatever)
269269
JSONObject o = (JSONObject)expected.get(0); // There's at least one at this point
270270
for(String candidate : getKeys(o)) {
271-
Object candidateValue = o.get(candidate);
272-
if (isSimpleValue(candidateValue)) {
273-
Set<Object> seenValues = new HashSet<Object>();
274-
seenValues.add(candidateValue);
275-
boolean isUsableKey = true;
276-
for(int i = 1 ; i < expected.length() ; ++i) {
277-
JSONObject other = (JSONObject)expected.get(i);
278-
if (!other.has(candidate)) {
279-
isUsableKey = false;
280-
break;
281-
}
282-
Object comparisonValue = other.get(candidate);
283-
if (!isSimpleValue(comparisonValue) || seenValues.contains(comparisonValue)) {
284-
isUsableKey = false;
285-
break;
271+
if (isUsableAsUniqueKey(candidate, expected)) return candidate;
272+
}
273+
// No usable unique key :-(
274+
return null;
275+
}
276+
277+
/**
278+
* {@code candidate} is usable as a unique key if every element in the
279+
* {@code array} is a JSONObject having that key, and no two values are the same.
280+
*/
281+
private static boolean isUsableAsUniqueKey(String candidate, JSONArray array) throws JSONException {
282+
Set<Object> seenValues = new HashSet<Object>();
283+
for (int i = 0 ; i < array.length() ; i++) {
284+
Object item = array.get(i);
285+
if (item instanceof JSONObject) {
286+
JSONObject o = (JSONObject) item;
287+
if (o.has(candidate)) {
288+
Object value = o.get(candidate);
289+
if (isSimpleValue(value) && !seenValues.contains(value)) {
290+
seenValues.add(value);
291+
} else {
292+
return false;
286293
}
287-
seenValues.add(comparisonValue);
288-
}
289-
if (isUsableKey) {
290-
return candidate;
294+
} else {
295+
return false;
291296
}
297+
} else {
298+
return false;
292299
}
293300
}
294-
// No usable unique key :-(
295-
return null;
301+
return true;
296302
}
297303

298304
private static List<Object> jsonArrayToList(JSONArray expected) throws JSONException {

src/test/java/org/skyscreamer/jsonassert/JSONCompareTest.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,15 @@ public void reportsUnmatchesIntegerValueInUnorderedArrayContainingJSONObject() t
6161
}
6262

6363
@Test
64-
@Ignore // currently failing
65-
public void failing() throws JSONException {
66-
compareJSON("[{\"id\": 3}]", "[{}]", NON_EXTENSIBLE);
64+
public void reportsUnmatchedJSONArrayWhereOnlyExpectedContainsJSONObjectWithUniqueKey() throws JSONException {
65+
JSONCompareResult result = compareJSON("[{\"id\": 3}]", "[{}]", LENIENT);
66+
assertThat(result, failsWithMessage(equalTo("Could not find match for element {}")));
67+
}
68+
69+
@Test
70+
public void reportsUnmatchedJSONArrayWhereExpectedContainsJSONObjectWithUniqueKeyButActualContainsElementOfOtherType() throws JSONException {
71+
JSONCompareResult result = compareJSON("[{\"id\": 3}]", "[5]", LENIENT);
72+
assertThat(result, failsWithMessage(equalTo("Could not find match for element 5")));
6773
}
6874

6975
private Matcher<JSONCompareResult> failsWithMessage(final Matcher<String> expectedMessage) {

0 commit comments

Comments
 (0)