All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.juneau.assertions.AssertionPredicate Maven / Gradle / Ivy

The newest version!
// ***************************************************************************************************************************
// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance            *
// * with the License.  You may obtain a copy of the License at                                                              *
// *                                                                                                                         *
// *  http://www.apache.org/licenses/LICENSE-2.0                                                                             *
// *                                                                                                                         *
// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an  *
// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the License for the        *
// * specific language governing permissions and limitations under the License.                                              *
// ***************************************************************************************************************************
package org.apache.juneau.assertions;

import static org.apache.juneau.common.internal.StringUtils.*;

import java.text.*;
import java.util.function.*;

import org.apache.juneau.common.internal.StringUtils;
import org.apache.juneau.cp.*;

/**
 * Wrapper around a {@link Predicate} that allows for an error message for when the predicate fails.
 *
 * 

* Typically used wherever predicates are allowed for testing of {@link Assertion} objects such as... *

    *
  • {@link FluentObjectAssertion#is(Predicate)} *
  • {@link FluentArrayAssertion#is(Predicate...)} *
  • {@link FluentPrimitiveArrayAssertion#is(Predicate...)} *
  • {@link FluentListAssertion#isEach(Predicate...)} *
* *

* See {@link AssertionPredicates} for a set of predefined predicates for common use cases. * *

Example:
*

* // Asserts that a bean passes a custom test. * // AssertionError with specified message is thrown otherwise. * Predicate<MyBean> predicate = new AssertionPredicate<MyBean>( * x -> x.getFoo().equals("bar"), * "Foo did not equal bar. Bean was=''{0}''", * VALUE * ); * assertObject(myBean).is(predicate); *

* *
See Also:
* * * @param the type of input being tested. */ public class AssertionPredicate implements Predicate { //----------------------------------------------------------------------------------------------------------------- // Static //----------------------------------------------------------------------------------------------------------------- /** * Argument placeholder for tested value. */ public static final Function VALUE = StringUtils::stringifyDeep; private static final Messages MESSAGES = Messages.of(AssertionPredicate.class, "Messages"); private static final String MSG_valueDidNotPassTest = MESSAGES.getString("valueDidNotPassTest"), MSG_valueDidNotPassTestWithValue = MESSAGES.getString("valueDidNotPassTestWithValue"); //----------------------------------------------------------------------------------------------------------------- // Instance //----------------------------------------------------------------------------------------------------------------- private final Predicate inner; private final String message; private final Object[] args; final ThreadLocal failedMessage = new ThreadLocal<>(); /** * Constructor. * * @param inner The predicate test. * @param message * The error message if predicate fails. *
Supports {@link MessageFormat}-style arguments. * @param args * Optional message arguments. *
Can contain {@link #VALUE} to specify the value itself as an argument. *
Can contain {@link Function functions} to apply to the tested value. */ public AssertionPredicate(Predicate inner, String message, Object...args) { this.inner = inner; if (message != null) { this.message = message; this.args = args; } else if (inner instanceof AssertionPredicate) { this.message = MSG_valueDidNotPassTest; this.args = new Object[]{}; } else { this.message = MSG_valueDidNotPassTestWithValue; this.args = new Object[]{VALUE}; } } AssertionPredicate() { this.inner = null; this.message = null; this.args = null; } //----------------------------------------------------------------------------------------------------------------- // Test methods //----------------------------------------------------------------------------------------------------------------- @Override /* Predicate */ @SuppressWarnings({"unchecked","rawtypes"}) public boolean test(T t) { failedMessage.remove(); boolean b = inner.test(t); if (! b) { String m = message; Object[] args = new Object[this.args.length]; for (int i = 0; i < args.length; i++) { Object a = this.args[i]; if (a instanceof Function) args[i] = ((Function)a).apply(t); else args[i] = a; } m = format(m, args); if (inner instanceof AssertionPredicate) m += "\n\t" + ((AssertionPredicate)inner).getFailureMessage(); failedMessage.set(m); } return inner.test(t); } //----------------------------------------------------------------------------------------------------------------- // Utility methods //----------------------------------------------------------------------------------------------------------------- /** * Returns the error message from the last call to this assertion. * * @return The error message, or null if there was no failure. */ protected String getFailureMessage() { return failedMessage.get(); } //----------------------------------------------------------------------------------------------------------------- // Subclasses //----------------------------------------------------------------------------------------------------------------- /** * Encapsulates multiple predicates into a single AND operation. * *

* Similar to stream(predicates).reduce(x->true, Predicate::and) but * provides for {@link #getFailureMessage()} to return a useful message. * * @param the type of input being tested. */ public static class And extends AssertionPredicate { private final Predicate[] inner; private static final Messages MESSAGES = Messages.of(AssertionPredicate.class, "Messages"); private static final String MSG_predicateTestFailed = MESSAGES.getString("predicateTestFailed"); /** * Constructor. * * @param inner The inner predicates to run. */ @SafeVarargs public And(Predicate...inner) { this.inner = inner; } @Override /* Predicate */ public boolean test(T t) { failedMessage.remove(); for (int i = 0; i < inner.length; i++) { Predicate p = inner[i]; if (p != null) { boolean b = p.test(t); if (! b) { String m = format(MSG_predicateTestFailed, i+1); if (p instanceof AssertionPredicate) m += "\n\t" + ((AssertionPredicate)p).getFailureMessage(); failedMessage.set(m); return false; } } } return true; } } /** * Encapsulates multiple predicates into a single OR operation. * *

* Similar to stream(predicates).reduce(x->true, Predicate::or) but * provides for {@link #getFailureMessage()} to return a useful message. * * @param the type of input being tested. */ public static class Or extends AssertionPredicate { private static final Messages MESSAGES = Messages.of(AssertionPredicate.class, "Messages"); private static final String MSG_noPredicateTestsPassed = MESSAGES.getString("noPredicateTestsPassed"); private final Predicate[] inner; /** * Constructor. * * @param inner The inner predicates to run. */ @SafeVarargs public Or(Predicate...inner) { this.inner = inner; } @Override /* Predicate */ public boolean test(T t) { failedMessage.remove(); for (Predicate p : inner) if (p != null) if (p.test(t)) return true; String m = format(MSG_noPredicateTestsPassed); failedMessage.set(m); return false; } } /** * Negates an assertion. * *

* Similar to predicate.negate() but provides for {@link #getFailureMessage()} to return a useful message. * * @param the type of input being tested. */ public static class Not extends AssertionPredicate { private static final Messages MESSAGES = Messages.of(AssertionPredicate.class, "Messages"); private static final String MSG_predicateTestsUnexpectedlyPassed = MESSAGES.getString("predicateTestsUnexpectedlyPassed"); private final Predicate inner; /** * Constructor. * * @param inner The inner predicates to run. */ public Not(Predicate inner) { this.inner = inner; } @Override /* Predicate */ public boolean test(T t) { failedMessage.remove(); Predicate p = inner; if (p != null) { boolean b = p.test(t); if (b) { failedMessage.set(format(MSG_predicateTestsUnexpectedlyPassed)); return false; } } return true; } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy