package com.auth0.json;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeDiagnosingMatcher;
import java.lang.reflect.Array;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class JsonMatcher extends TypeSafeDiagnosingMatcher<String> {
private final String entry;
private final String key;
private final Matcher matcher;
private JsonMatcher(String key, Object value, Matcher valueMatcher) {
this.key = key;
this.matcher = valueMatcher;
if (value != null) {
String stringValue = objectToString(value);
entry = getStringKey(key) + stringValue;
} else {
entry = null;
}
}
@Override
protected boolean matchesSafely(String item, Description mismatchDescription) {
if (item == null) {
mismatchDescription.appendText("JSON was null");
return false;
}
if (matcher != null) {
if (!matcher.matches(item)) {
matcher.describeMismatch(item, mismatchDescription);
return false;
}
if (!item.contains(getStringKey(key))) {
mismatchDescription.appendText("JSON didn't contained the key ").appendValue(key);
return false;
}
}
if (entry != null && !item.contains(entry)) {
mismatchDescription.appendText("JSON was ").appendValue(item);
return false;
}
return true;
}
@Override
public void describeTo(Description description) {
if (matcher == null) {
description.appendText("A JSON with entry ")
.appendValue(entry);
} else {
matcher.describeTo(description);
}
}
public static JsonMatcher hasEntry(String key, Object value) {
return new JsonMatcher(key, value, null);
}
public static JsonMatcher hasEntry(String key, Matcher valueMatcher) {
return new JsonMatcher(key, null, valueMatcher);
}
private String getStringKey(String key) {
return "\"" + key + "\":";
}
private String objectToString(Object value) {
String stringValue;
if (value == null) {
stringValue = "null";
} else if (value instanceof String) {
stringValue = "\"" + value + "\"";
} else if (value instanceof Map) {
stringValue = mapToString((Map<String, Object>) value);
} else if (value instanceof Array) {
stringValue = arrayToString((Object[]) value);
} else if (value instanceof List) {
stringValue = listToString((List<Object>) value);
} else {
stringValue = value.toString();
}
return stringValue;
}
private String arrayToString(Object[] array) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < array.length; i++) {
Object o = array[i];
sb.append(objectToString(o));
if (i + 1 < array.length) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
private String listToString(List<Object> list) {
StringBuilder sb = new StringBuilder();
sb.append("[");
Iterator<Object> it = list.iterator();
while (it.hasNext()) {
Object o = it.next();
sb.append(objectToString(o));
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("]");
return sb.toString();
}
private String mapToString(Map<String, Object> map) {
StringBuilder sb = new StringBuilder();
sb.append("{");
Iterator<Map.Entry<String, Object>> it = map.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, Object> e = it.next();
sb.append("\"" + e.getKey() + "\":" + objectToString(e.getValue()));
if (it.hasNext()) {
sb.append(",");
}
}
sb.append("}");
return sb.toString();
}
}