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