package org.hamcrest.object; import org.hamcrest.Description; import org.hamcrest.DiagnosingMatcher; import org.hamcrest.Matcher; import org.hamcrest.TypeSafeDiagnosingMatcher; import org.hamcrest.core.IsEqual; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; import static java.lang.String.format; public class HasEqualValues<T> extends TypeSafeDiagnosingMatcher<T> { private final T expectedObject; private final List<FieldMatcher> fieldMatchers; public HasEqualValues(T expectedObject) { super(expectedObject.getClass()); this.expectedObject = expectedObject; this.fieldMatchers = fieldMatchers(expectedObject); } @Override protected boolean matchesSafely(T item, Description mismatch) { for (FieldMatcher fieldMatcher : fieldMatchers) { if (!fieldMatcher.matches(item, mismatch)) { return false; } } return true; } @Override public void describeTo(Description description) { description.appendText(expectedObject.getClass().getSimpleName()) .appendText(" has values ") .appendList("[", ", ", "]", fieldMatchers); } private static class FieldMatcher extends DiagnosingMatcher<Object> { private final Field field; private final Matcher<Object> matcher; public FieldMatcher(Field field, Object expectedObject) { this.field = field; this.matcher = IsEqual.equalTo(uncheckedGet(field, expectedObject)); } @Override protected boolean matches(Object item, Description mismatch) { final Object actual = uncheckedGet(field, item); if (!matcher.matches(actual)) { mismatch.appendText("'").appendText(field.getName()).appendText("' "); matcher.describeMismatch(actual, mismatch); return false; } return true; } @Override public void describeTo(Description description) { description.appendText(field.getName()) .appendText(": ") .appendDescriptionOf(matcher); } } private static List<FieldMatcher> fieldMatchers(Object expectedObject) { final List<FieldMatcher> result = new ArrayList<>(); for (Field field : expectedObject.getClass().getFields()) { result.add(new FieldMatcher(field, expectedObject)); } return result; } private static Object uncheckedGet(Field field, Object object) { try { return field.get(object); } catch (Exception e) { throw new AssertionError(format("IllegalAccess, reading field '%s' from %s", field.getName(), object)); } } }