001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.assertions; 014 015import static org.apache.juneau.assertions.AssertionPredicate.*; 016import static org.apache.juneau.common.internal.ArgUtils.*; 017import static org.apache.juneau.common.internal.StringUtils.*; 018 019import java.text.*; 020import java.util.*; 021import java.util.function.*; 022import java.util.regex.*; 023 024import org.apache.juneau.common.internal.*; 025import org.apache.juneau.cp.*; 026 027/** 028 * Predefined {@link AssertionPredicate} objects. 029 * 030 * <p> 031 * Typically used wherever predicates are allowed for testing of {@link Assertion} objects such as... 032 * <ul> 033 * <li>{@link FluentObjectAssertion#is(Predicate)} 034 * <li>{@link FluentArrayAssertion#is(Predicate...)} 035 * <li>{@link FluentPrimitiveArrayAssertion#is(Predicate...)} 036 * <li>{@link FluentListAssertion#isEach(Predicate...)} 037 * </ul> 038 * 039 * <h5 class='section'>Example:</h5> 040 * <p class='bjava'> 041 * <jc>// Asserts that a list contains te specified values.</jc> 042 * List<Object> <jv>myList</jv> = AList.<jsm>of</jsm>(...); 043 * <jsm>assertList</jsm>(<jv>myList</jv>) 044 * .is(<jsm>eq</jsm>(<js>"foo"</js>), <jsm>any</jsm>(), <jsm>match</jsm>(<js>"bar*"</js>)); 045 * </p> 046 * 047 * <h5 class='section'>See Also:</h5> 048 * <ul> 049 * <li class='link'><a class="doclink" href="../../../../index.html#ja.Overview">Overview > juneau-assertions > Overview</a> 050 * </ul> 051 */ 052public class AssertionPredicates { 053 054 private static Function<Object,String> TYPENAME = x -> x == null ? null : x.getClass().getName(); 055 056 private static final Messages MESSAGES = Messages.of(AssertionPredicates.class, "Messages"); 057 private static final String 058 MSG_valueWasNull = MESSAGES.getString("valueWasNull"), 059 MSG_valueWasNotNull = MESSAGES.getString("valueWasNotNull"), 060 MSG_valueDidNotMatchExpected = MESSAGES.getString("valueDidNotMatchExpected"), 061 MSG_valueDidNotContainExpected = MESSAGES.getString("valueDidNotContainExpected"), 062 MSG_valueUnexpectedlyMatched = MESSAGES.getString("valueUnexpectedlyMatched"), 063 MSG_valueWasNotExpectedType = MESSAGES.getString("valueWasNotExpectedType"), 064 MSG_valueDidNotMatchPattern = MESSAGES.getString("valueDidNotMatchPattern"); 065 066 /** 067 * Predicate that always returns <jk>true</jk>. 068 * 069 * <p> 070 * Note that this typically has the same affect as a <jk>null</jk> predicate. 071 * 072 * @param <T> The object type being tested. 073 * @return A new predicate. 074 */ 075 public static final <T> AssertionPredicate<T> any() { 076 return test(x -> true, null); 077 } 078 079 /** 080 * Predicate that returns <jk>true</jk> if the tested value is not null. 081 * 082 * <p> 083 * Assertion error message is <js>"Value was null."</js>. 084 * 085 * @param <T> The object type being tested. 086 * @return A new predicate. 087 */ 088 public static final <T> AssertionPredicate<T> notNull() { 089 return test(x -> x != null, MSG_valueWasNull); 090 } 091 092 /** 093 * Predicate that returns <jk>true</jk> if the tested value is null. 094 * 095 * <p> 096 * Assertion error message is <js>"Value was not null."</js>. 097 * 098 * @param <T> The object type being tested. 099 * @return A new predicate. 100 */ 101 public static final <T> AssertionPredicate<T> isNull() { 102 return test(x -> x == null, MSG_valueWasNotNull); 103 } 104 105 /** 106 * Predicate that returns <jk>true</jk> if the tested value equals the specified value. 107 * 108 * <p> 109 * Uses standard Java equality for testing. 110 * 111 * <p> 112 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 113 * 114 * @param <T> The object type being tested. 115 * @param value The specified value. 116 * @return A new predicate. 117 */ 118 public static final <T> AssertionPredicate<T> eq(Object value) { 119 return test(x -> Objects.equals(x, value), MSG_valueDidNotMatchExpected, value, VALUE); 120 } 121 122 /** 123 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified value. 124 * 125 * <p> 126 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 127 * 128 * @param <T> The object type being tested. 129 * @param value The specified value. 130 * @return A new predicate. 131 */ 132 public static final <T> AssertionPredicate<T> eq(String value) { 133 return test(x -> Objects.equals(stringify(x), value), MSG_valueDidNotMatchExpected, value, VALUE); 134 } 135 136 /** 137 * Predicate that returns <jk>true</jk> if the tested value does not match the specified value. 138 * 139 * <p> 140 * Assertion error message is <js>"Value unexpectedly matched. Value='{0}'."</js>. 141 * 142 * @param <T> The object type being tested. 143 * @param value The specified value. 144 * @return A new predicate. 145 */ 146 public static final <T> AssertionPredicate<T> ne(Object value) { 147 return test(x -> ! Objects.equals(x, value), MSG_valueUnexpectedlyMatched, VALUE); 148 } 149 150 /** 151 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value. 152 * 153 * <p> 154 * Assertion error message is <js>"Value unexpectedly matched. Value='{0}'."</js>. 155 * 156 * @param <T> The object type being tested. 157 * @param value The specified value. 158 * @return A new predicate. 159 */ 160 public static final <T> AssertionPredicate<T> ne(String value) { 161 return test(x -> ! Objects.equals(stringify(x), value), MSG_valueUnexpectedlyMatched, VALUE); 162 } 163 164 /** 165 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value ignoring case. 166 * 167 * <p> 168 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 169 * 170 * @param <T> The object type being tested. 171 * @param value The specified value. 172 * @return A new predicate. 173 */ 174 public static final <T> AssertionPredicate<T> eqic(String value) { 175 return test(x -> StringUtils.eqic(stringify(x), value), MSG_valueDidNotMatchExpected, value, VALUE); 176 } 177 178 /** 179 * Predicate that returns <jk>true</jk> if the tested value converted to a string contains the specified substring. 180 * 181 * <p> 182 * Assertion error message is <js>"Value did not contain expected. Expected='{0}', Actual='{1}'."</js>. 183 * 184 * @param <T> The object type being tested. 185 * @param value The specified value. 186 * @return A new predicate. 187 */ 188 public static final <T> AssertionPredicate<T> contains(String value) { 189 return test(x -> StringUtils.contains(stringify(x), value), MSG_valueDidNotContainExpected, value, VALUE); 190 } 191 192 /** 193 * Predicate that returns <jk>true</jk> if the tested value is the specified or child type. 194 * 195 * <p> 196 * Assertion error message is <js>"Value was not expected type. Expected='{0}', Actual='{1}'."</js>. 197 * 198 * @param <T> The object type being tested. 199 * @param type The specified type. 200 * @return A new predicate. 201 */ 202 public static final <T> AssertionPredicate<T> type(Class<?> type) { 203 assertArgNotNull("type", type); 204 return test(x -> x != null && type.isAssignableFrom(x.getClass()), MSG_valueWasNotExpectedType, type, TYPENAME); 205 } 206 207 /** 208 * Predicate that returns <jk>true</jk> if the tested value is exactly specified type. 209 * 210 * <p> 211 * Assertion error message is <js>"Value was not expected type. Expected='{0}', Actual='{1}'."</js>. 212 * 213 * @param <T> The object type being tested. 214 * @param type The specified type. 215 * @return A new predicate. 216 */ 217 public static final <T> AssertionPredicate<T> exactType(Class<?> type) { 218 assertArgNotNull("type", type); 219 return test(x -> x != null && x.getClass().equals(type), MSG_valueWasNotExpectedType, type, TYPENAME); 220 } 221 222 /** 223 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified match pattern. 224 * 225 * <p> 226 * Match pattern can contain the <js>"*"</js> meta-character. 227 * 228 * <p> 229 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 230 * 231 * @param <T> The object type being tested. 232 * @param value The specified value. 233 * @return A new predicate. 234 */ 235 public static final <T> AssertionPredicate<T> match(String value) { 236 assertArgNotNull("value", value); 237 Pattern p = StringUtils.getMatchPattern(value); 238 return test(x -> x != null && p.matcher(stringify(x)).matches(), MSG_valueDidNotMatchPattern, value, VALUE); 239 } 240 241 /** 242 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 243 * 244 * <p> 245 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 246 * 247 * @param <T> The object type being tested. 248 * @param expression The regular expression to match. 249 * @return A new predicate. 250 */ 251 public static final <T> AssertionPredicate<T> regex(String expression) { 252 assertArgNotNull("expression", expression); 253 Pattern p = Pattern.compile(expression); 254 return test(x -> x != null && p.matcher(stringify(x)).matches(), MSG_valueDidNotMatchPattern, expression, VALUE); 255 } 256 257 /** 258 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 259 * 260 * <p> 261 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 262 * 263 * @param <T> The object type being tested. 264 * @param expression The regular expression to match. 265 * @param flags Match flags, a bit mask that may include: 266 * <ul> 267 * <li>{@link Pattern#CASE_INSENSITIVE CASE_INSENSITIVE} 268 * <li>{@link Pattern#MULTILINE MULTILINE} 269 * <li>{@link Pattern#DOTALL DOTALL} 270 * <li>{@link Pattern#UNICODE_CASE UNICODE_CASE} 271 * <li>{@link Pattern#CANON_EQ CANON_EQ} 272 * <li>{@link Pattern#UNIX_LINES UNIX_LINES} 273 * <li>{@link Pattern#LITERAL LITERAL} 274 * <li>{@link Pattern#UNICODE_CHARACTER_CLASS UNICODE_CHARACTER_CLASS} 275 * <li>{@link Pattern#COMMENTS COMMENTS} 276 * @return A new predicate. 277 */ 278 public static final <T> AssertionPredicate<T> regex(String expression, int flags) { 279 assertArgNotNull("expression", expression); 280 Pattern p = Pattern.compile(expression, flags); 281 return test(x -> x != null && p.matcher(stringify(x)).matches(), MSG_valueDidNotMatchPattern, expression, VALUE); 282 } 283 284 /** 285 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 286 * 287 * <p> 288 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 289 * 290 * @param <T> The object type being tested. 291 * @param value The regular expression to match. 292 * @return A new predicate. 293 */ 294 public static final <T> AssertionPredicate<T> regex(Pattern value) { 295 assertArgNotNull("value", value); 296 return test(x -> x != null && value.matcher(stringify(x)).matches(), MSG_valueDidNotMatchPattern, value.pattern(), VALUE); 297 } 298 299 /** 300 * Predicate that wraps another predicate. 301 * 302 * <p> 303 * If the predicate extends from {@link AssertionPredicate}, the assertion error 304 * message is <js>"Value did not pass test."</js> followed by the inner assertion error. 305 * Otherwise the message is <js>"Value did not pass test. Value='{0}'."</js> 306 * 307 * @param <T> The object type being tested. 308 * @param predicate The predicate to run. 309 * @return A new predicate. 310 */ 311 public static final <T> AssertionPredicate<T> test(Predicate<T> predicate) { 312 return new AssertionPredicate<>(predicate, null); 313 } 314 315 /** 316 * Predicate that wraps another predicate. 317 * 318 * <p> 319 * If the message specified is <jk>null</jk> and the predicate extends from {@link AssertionPredicate}, the assertion error 320 * message is <js>"Value did not pass test."</js> followed by the inner assertion error. 321 * Otherwise the message is <js>"Value did not pass test. Value='{0}'."</js> 322 * 323 * @param <T> The object type being tested. 324 * @param predicate The predicate to run. 325 * @param msg 326 * The error message if predicate fails. 327 * <br>Supports {@link MessageFormat}-style arguments. 328 * @param args 329 * Optional message arguments. 330 * <br>Can contain {@code #VALUE} to specify the value itself as an argument. 331 * <br>Can contain {@link Function functions} to apply to the tested value. 332 * @return A new predicate. 333 */ 334 public static final <T> AssertionPredicate<T> test(Predicate<T> predicate, String msg, Object...args) { 335 return new AssertionPredicate<>(predicate, msg, args); 336 } 337 338 /** 339 * Combines the specified predicates into a singled AND'ed predicate. 340 * 341 * <p> 342 * Assertion error message is <js>"Predicate test #x failed."</js> followed by 343 * the inner failed message if the failed predicate extends from {@link AssertionPredicate}. 344 * 345 * @param <T> The predicate type. 346 * @param predicates The predicates to combine. 347 * @return The combined predicates. 348 */ 349 @SafeVarargs 350 public static final <T> AssertionPredicate<T> and(Predicate<T>...predicates) { 351 return new AssertionPredicate.And<>(predicates); 352 } 353 354 /** 355 * Combines the specified predicates into a singled OR'ed predicate. 356 * 357 * <p> 358 * Assertion error message is <js>"No predicate tests passed."</js>. 359 * 360 * @param <T> The predicate type. 361 * @param predicates The predicates to combine. 362 * @return The combined predicates. 363 */ 364 @SafeVarargs 365 public static final <T> AssertionPredicate<T> or(Predicate<T>...predicates) { 366 return new AssertionPredicate.Or<>(predicates); 367 } 368 369 /** 370 * Negates the specified predicate. 371 * 372 * <p> 373 * Assertion error message is <js>"Predicate test unexpectedly passed."</js>. 374 * 375 * @param <T> The predicate type. 376 * @param predicate The predicate to negate. 377 * @return The combined predicates. 378 */ 379 public static final <T> AssertionPredicate<T> not(Predicate<T> predicate) { 380 return new AssertionPredicate.Not<>(predicate); 381 } 382}