package org.test4j.hamcrest.matcher.property;
import static org.test4j.hamcrest.matcher.property.reflection.ReflectionComparatorFactory.createRefectionComparator;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.test4j.hamcrest.matcher.property.difference.Difference;
import org.test4j.hamcrest.matcher.property.reflection.EqMode;
import org.test4j.hamcrest.matcher.property.reflection.ReflectionComparator;
import org.test4j.hamcrest.matcher.property.report.DefaultDifferenceReport;
import org.test4j.hamcrest.matcher.property.report.DifferenceReport;
import org.test4j.module.ICore.DataMap;
import org.test4j.tools.commons.ArrayHelper;
import org.test4j.tools.commons.ListHelper;
import org.test4j.tools.exception.NoSuchFieldRuntimeException;
import org.test4j.tools.reflector.PropertyAccessor;
import ext.test4j.hamcrest.BaseMatcher;
import ext.test4j.hamcrest.Description;
import ext.test4j.hamcrest.StringDescription;
/**
* 把实际对象按照Map中的key值取出来,进行反射比较
*
* @author darui.wudr
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class MapListPropertyEqaulMatcher extends BaseMatcher {
private final List<DataMap> expected;
private EqMode[] modes;
public MapListPropertyEqaulMatcher(List<DataMap> expected, EqMode[] modes) {
this.expected = expected;
this.modes = modes;
if (expected == null) {
throw new AssertionError("MapPropertyEqaulMatcher, the expected map can't be null.");
}
}
public boolean matches(Object actual) {
if (actual == null) {
this.self.appendText("MapPropertyEqaulMatcher, the actual object can't be null or list/array.");
return false;
}
if (ArrayHelper.isCollOrArray(actual) == false) {
this.self.appendText("MapPropertyEqaulMatcher, the actual object must be an array or a list.");
return false;
}
List list = ListHelper.toList(actual);
if (this.expected.size() != list.size()) {
this.self.appendText("MapPropertyEqaulMatcher, the size ofexpeced object is " + this.expected.size()
+ ", but the size of actual list is " + list.size() + ".");
return false;
}
Set<String> keys = this.getAllKeys();
List<Map<String, ?>> actuals = getObjectArrayFromList(list, keys, false);
List<Map<String, ?>> expecteds = getObjectArrayFromList(this.expected, keys, true);
ReflectionComparator reflectionComparator = createRefectionComparator(modes);
this.difference = reflectionComparator.getDifference(expecteds, actuals);
return difference == null;
}
private List<Map<String, ?>> getObjectArrayFromList(List list, Set<String> keys, boolean isExpected) {
List<Map<String, ?>> result = new ArrayList<Map<String, ?>>();
for (Object o : list) {
Map<String, Object> map = new HashMap<String, Object>();
for (String key : keys) {
try {
Object value = PropertyAccessor.getPropertyByOgnl(o, key, true);
map.put(key, value);
} catch (NoSuchFieldRuntimeException e) {
if (isExpected) {
map.put(key, null);
} else {
throw e;
}
}
}
result.add(map);
}
return result;
}
private Set<String> getAllKeys() {
Set<String> keys = new HashSet<String>();
for (Map map : this.expected) {
Set set = map.keySet();
keys.addAll(set);
}
return keys;
}
private StringDescription self = new StringDescription();
private Difference difference;
public void describeTo(Description description) {
description.appendText(self.toString());
if (difference != null) {
DifferenceReport differenceReport = new DefaultDifferenceReport();
description.appendText(differenceReport.createReport(difference));
}
}
}