/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.everrest.core.impl.provider.json;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import static java.util.stream.Collectors.toList;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
public class JsonAssertionHelper {
public void assertThatJsonArrayHasAllItemsFromArray(Object array, JsonValue json) throws Exception {
if (array == null) {
assertTrue(json.isNull());
return;
}
assertTrue(json.isArray());
int length = Array.getLength(array);
assertEquals(length, json.size());
Iterator<JsonValue> jsonIterator = json.getElements();
for (int i = 0; i < length; i++) {
Object value = Array.get(array, i);
JsonValue jsonValue = jsonIterator.next();
if (value == null) {
assertNull(jsonValue);
} else {
assertNotNull(jsonValue);
Class<?> type = value.getClass();
if (isString(type)) {
assertEquals(value, jsonValue.getStringValue());
} else if (type.isEnum()) {
assertEquals(((Enum)value).name(), jsonValue.getStringValue());
} else if (isBoolean(type)) {
assertEquals(value, jsonValue.getBooleanValue());
} else if (isByte(type)) {
assertEquals(value, jsonValue.getByteValue());
} else if (isShort(type)) {
assertEquals(value, jsonValue.getShortValue());
} else if (isInteger(type)) {
assertEquals(value, jsonValue.getIntValue());
} else if (isLong(type)) {
assertEquals(value, jsonValue.getLongValue());
} else if (isFloat(type)) {
assertEquals((Float)value, jsonValue.getFloatValue(), 0.01f);
} else if (isDouble(type)) {
assertEquals((Double)value, jsonValue.getDoubleValue(), 0.01);
} else if (isChar(type)) {
assertEquals(String.valueOf(value), jsonValue.getStringValue());
} else if (type.isArray()) {
assertThatJsonArrayHasAllItemsFromArray((Object[])value, jsonValue);
} else if (isCollection(type)) {
assertThatJsonArrayHasAllItemsFromCollection((Collection<?>)value, jsonValue);
} else if (isMap(type)) {
assertThatJsonHasAllItemsFromMap((Map<String, ?>)value, jsonValue);
} else {
assertThatJsonHasAllFieldsFromObject(value, jsonValue);
}
}
}
}
public void assertThatJsonArrayHasAllItemsFromCollection(Collection<?> collection, JsonValue json) throws Exception {
Object array = collection == null ? null : collection.toArray();
assertThatJsonArrayHasAllItemsFromArray(array, json);
}
public void assertThatJsonHasAllItemsFromMap(Map<String, ?> map, JsonValue json) throws Exception {
if (map == null) {
assertTrue(json.isNull());
return;
}
assertTrue(json.isObject());
for (Map.Entry<String, ?> entry : map.entrySet()) {
Object value = entry.getValue();
String name = entry.getKey();
JsonValue jsonValue = json.getElement(name);
if (value == null) {
assertNull(name, jsonValue);
} else {
assertNotNull(name, jsonValue);
Class<?> type = value.getClass();
if (isString(type)) {
assertEquals(value, jsonValue.getStringValue());
} else if (type.isEnum()) {
assertEquals(((Enum)value).name(), jsonValue.getStringValue());
} else if (isBoolean(type)) {
assertEquals(value, jsonValue.getBooleanValue());
} else if (isByte(type)) {
assertEquals(value, jsonValue.getByteValue());
} else if (isShort(type)) {
assertEquals(value, jsonValue.getShortValue());
} else if (isInteger(type)) {
assertEquals(value, jsonValue.getIntValue());
} else if (isLong(type)) {
assertEquals(value, jsonValue.getLongValue());
} else if (isFloat(type)) {
assertEquals((Float)value, jsonValue.getFloatValue(), 0.01f);
} else if (isDouble(type)) {
assertEquals((Double)value, jsonValue.getDoubleValue(), 0.01);
} else if (isChar(type)) {
assertEquals(String.valueOf(value), jsonValue.getStringValue());
} else if (type.isArray()) {
assertThatJsonArrayHasAllItemsFromArray((Object[])value, jsonValue);
} else if (isCollection(type)) {
assertThatJsonArrayHasAllItemsFromCollection((Collection<?>)value, jsonValue);
} else if (isMap(type)) {
assertThatJsonHasAllItemsFromMap((Map<String, ?>)value, jsonValue);
} else {
assertThatJsonHasAllFieldsFromObject(value, jsonValue);
}
}
}
}
public void assertThatJsonHasAllFieldsFromObject(Object object, JsonValue json) throws Exception {
if (object == null) {
assertTrue(json.isNull());
} else {
assertTrue(object.toString(), json.isObject());
for (Field field : getAllFields(object)) {
field.setAccessible(true);
String fieldName = field.getName();
JsonValue jsonField = json.getElement(fieldName);
assertNotNull(String.format("Expected field %s missed in json", fieldName), jsonField);
Class<?> type = field.getType();
Object value = field.get(object);
if (value == null) {
assertTrue(fieldName, jsonField.isNull());
} else if (isString(type)) {
assertEquals(value, jsonField.getStringValue());
} else if (type.isEnum()) {
assertEquals(((Enum)field.get(object)).name(), jsonField.getStringValue());
} else if (isBoolean(type)) {
assertEquals(value, jsonField.getBooleanValue());
} else if (isByte(type)) {
assertEquals(value, jsonField.getByteValue());
} else if (isShort(type)) {
assertEquals(value, jsonField.getShortValue());
} else if (isInteger(type)) {
assertEquals(value, jsonField.getIntValue());
} else if (isLong(type)) {
assertEquals(value, jsonField.getLongValue());
} else if (isFloat(type)) {
assertEquals((Float)value, jsonField.getFloatValue(), 0.01f);
} else if (isDouble(type)) {
assertEquals((Double)value, jsonField.getDoubleValue(), 0.01);
} else if (isChar(type)) {
assertEquals(String.valueOf(value), jsonField.getStringValue());
} else if (type.isArray()) {
assertThatJsonArrayHasAllItemsFromArray(value, jsonField);
} else if (isCollection(type)) {
assertThatJsonArrayHasAllItemsFromCollection((Collection<?>)value, jsonField);
} else if (isMap(type)) {
assertThatJsonHasAllItemsFromMap((Map<String, ?>)value, jsonField);
} else {
assertThatJsonHasAllFieldsFromObject(value, jsonField);
}
}
}
}
private boolean isBoolean(Class<?> type) {
return type == boolean.class || type == Boolean.class;
}
private boolean isByte(Class<?> type) {
return type == byte.class || type == Byte.class;
}
private boolean isShort(Class<?> type) {
return type == short.class || type == Short.class;
}
private boolean isInteger(Class<?> type) {
return type == int.class || type == Integer.class;
}
private boolean isLong(Class<?> type) {
return type == long.class || type == Long.class;
}
private boolean isFloat(Class<?> type) {
return type == float.class || type == Float.class;
}
private boolean isDouble(Class<?> type) {
return type == double.class || type == Double.class;
}
private boolean isChar(Class<?> type) {
return type == char.class || type == Character.class;
}
private boolean isString(Class<?> type) {
return type == String.class;
}
private boolean isCollection(Class<?> type) {
return Collection.class.isAssignableFrom(type);
}
private boolean isMap(Class<?> type) {
return Map.class.isAssignableFrom(type);
}
private List<Field> getAllFields(Object object) {
List<Field> allFields = new ArrayList<>();
Class<?> aClass = object.getClass();
while (aClass.getSuperclass() != null) {
List<Field> classFields = Arrays.stream(aClass.getDeclaredFields())
.filter((field) -> isNotJsonTransient(field) && isNotGroovyMetaClassField(field))
.collect(toList());
allFields.addAll(classFields);
aClass = aClass.getSuperclass();
}
return allFields;
}
private boolean isNotJsonTransient(Field field) {
return !(Modifier.isTransient(field.getModifiers()) || field.isAnnotationPresent(JsonTransient.class));
}
private boolean isNotGroovyMetaClassField(Field field) {
return !(field.getName().startsWith("$") || field.getName().startsWith("__timeStamp"));
}
}