package app.mealsmadeeasy.api.matchers; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import java.util.List; import java.util.Objects; import java.util.function.BiPredicate; import java.util.function.Function; import java.util.function.Predicate; public class ContainsItemsMatcher extends BaseMatcher> { private final List allExpected; private final Predicate isT; private final Function givenToIdFunction; private final Function expectedToIdFunction; private final BiPredicate equalsFunction; public ContainsItemsMatcher( List allExpected, Predicate isT, Function givenToIdFunction, Function expectedToIdFunction, BiPredicate equalsFunction ) { this.allExpected = allExpected; this.isT = isT; this.givenToIdFunction = givenToIdFunction; this.expectedToIdFunction = expectedToIdFunction; this.equalsFunction = equalsFunction; } public ContainsItemsMatcher( List allExpected, Predicate isT, Function givenToIdFunction, Function expectedToIdFunction ) { this(allExpected, isT, givenToIdFunction, expectedToIdFunction, Objects::equals); } @SuppressWarnings("unchecked") @Override public boolean matches(Object o) { if (o instanceof Iterable iterable) { checkExpected: for (final E expected : this.allExpected) { for (final Object item : iterable) { if ( this.isT.test(item) && this.equalsFunction.test( this.givenToIdFunction.apply((T) item), this.expectedToIdFunction.apply(expected) ) ) { continue checkExpected; } } // did not find expected in iterable return false; } // found all expected in iterable return true; } // o is not an iterable return false; } @Override public void describeTo(Description description) { description.appendText("Expected ").appendValue(this.allExpected); } }