From c5afa48e2d8a4ee6474e6d88d1f8fe8baab1f841 Mon Sep 17 00:00:00 2001 From: Etienne Reichenbach Date: Wed, 5 Jun 2019 10:36:01 +0200 Subject: [PATCH] Introduce HasGetterWithValue --- .../hamcrest/beans/HasGetterWithValue.java | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 hamcrest/src/main/java/org/hamcrest/beans/HasGetterWithValue.java diff --git a/hamcrest/src/main/java/org/hamcrest/beans/HasGetterWithValue.java b/hamcrest/src/main/java/org/hamcrest/beans/HasGetterWithValue.java new file mode 100644 index 00000000..637ff68f --- /dev/null +++ b/hamcrest/src/main/java/org/hamcrest/beans/HasGetterWithValue.java @@ -0,0 +1,96 @@ +package org.hamcrest.beans; + +import java.util.function.Function; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.Matchers; +import org.hamcrest.TypeSafeMatcher; + +/** + *

+ * Property matcher like {@link Matchers#hasProperty(String, Matcher)} that instead of using reflection it uses a + * {@link Function}. This is useful when you wish to assert multiple values of the bean within an assertion statement + * (which in some projects is the required number of assertions per test). + *

+ * + *

Example Usage

Consider the situation where we have a class representing a person, with first and last name: + * + *
+ * public class Person {
+ * 	private String firstName;
+ * 	private String lastName;
+ *
+ * 	public Person(String firstName, String lastName) {
+ * 		this.firstName = firstName;
+ * 		this.lastName = lastName;
+ * 	}
+ *
+ * 	public String getFirstName() {
+ * 		return firstName;
+ * 	}
+ *
+ * 	public String getLastName() {
+ * 		return lastName;
+ * 	}
+ * }
+ * 
+ * + * And we would like to test a method that swaps the first name with the last name, then the test would could look like: + * + *
+ * final Person newPerson = swapNames(person);
+ * assertThat(newPerson, both(hasGetterWithValue(Person::getFirstName, is(equalTo(person.getLastName())))).and(hasGetterWithValue(Person::getLastName, is(equalTo(person.getFirstName())))));
+ * 
+ * + * @param + * type of object to match + * @param + * type of the property to match + */ +public class HasGetterWithValue extends TypeSafeMatcher { + + private final Function mapper; + private final Matcher matcher; + + private HasGetterWithValue(final Function mapper, final Matcher matcher) { + this.mapper = mapper; + this.matcher = matcher; + } + + /** {@inheritDoc} */ + @Override + public void describeTo(final Description description) { + description.appendText("hasGetterWithValue(") + .appendDescriptionOf(matcher).appendText(")"); + } + + @Override + public void describeMismatchSafely(final T item, final Description mismatchDescription) { + mismatchDescription.appendText(" was ").appendValue(mapper.apply(item)); + } + + /** {@inheritDoc} */ + @Override + protected boolean matchesSafely(final T item) { + return matcher.matches(mapper.apply(item)); + } + + /** + * Creates a {@link HasGetterWithValue}. + * + * @param + * type of object to match + * @param + * type of the property to match + * @param mapper + * maps form the object to its property + * @param matcher + * matches the property + * @return the matcher created + */ + public static final Matcher hasGetterWithValue(final Function mapper, final Matcher matcher) { + return new HasGetterWithValue<>(mapper, matcher); + } + +} \ No newline at end of file