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.assertions; 018 019import static org.apache.juneau.assertions.AssertionPredicate.*; 020import java.text.*; 021import java.util.*; 022import java.util.function.*; 023import java.util.regex.*; 024 025import org.apache.juneau.common.utils.*; 026import org.apache.juneau.cp.*; 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 Overview</a> 051 * </ul> 052 */ 053public class AssertionPredicates { 054 055 /** 056 * Constructor. 057 */ 058 protected AssertionPredicates() {} 059 060 private static final Function<Object,String> TYPENAME = x -> x == null ? null : x.getClass().getName(); 061 062 private static final Messages MESSAGES = Messages.of(AssertionPredicates.class, "Messages"); 063 private static final String 064 MSG_valueWasNull = MESSAGES.getString("valueWasNull"), 065 MSG_valueWasNotNull = MESSAGES.getString("valueWasNotNull"), 066 MSG_valueDidNotMatchExpected = MESSAGES.getString("valueDidNotMatchExpected"), 067 MSG_valueDidNotContainExpected = MESSAGES.getString("valueDidNotContainExpected"), 068 MSG_valueUnexpectedlyMatched = MESSAGES.getString("valueUnexpectedlyMatched"), 069 MSG_valueWasNotExpectedType = MESSAGES.getString("valueWasNotExpectedType"), 070 MSG_valueDidNotMatchPattern = MESSAGES.getString("valueDidNotMatchPattern"); 071 072 /** 073 * Predicate that always returns <jk>true</jk>. 074 * 075 * <p> 076 * Note that this typically has the same affect as a <jk>null</jk> predicate. 077 * 078 * @param <T> The object type being tested. 079 * @return A new predicate. 080 */ 081 public static final <T> AssertionPredicate<T> any() { 082 return test(x -> true, null); 083 } 084 085 /** 086 * Predicate that returns <jk>true</jk> if the tested value is not null. 087 * 088 * <p> 089 * Assertion error message is <js>"Value was null."</js>. 090 * 091 * @param <T> The object type being tested. 092 * @return A new predicate. 093 */ 094 public static final <T> AssertionPredicate<T> notNull() { 095 return test(x -> x != null, MSG_valueWasNull); 096 } 097 098 /** 099 * Predicate that returns <jk>true</jk> if the tested value is null. 100 * 101 * <p> 102 * Assertion error message is <js>"Value was not null."</js>. 103 * 104 * @param <T> The object type being tested. 105 * @return A new predicate. 106 */ 107 public static final <T> AssertionPredicate<T> isNull() { 108 return test(x -> x == null, MSG_valueWasNotNull); 109 } 110 111 /** 112 * Predicate that returns <jk>true</jk> if the tested value equals the specified value. 113 * 114 * <p> 115 * Uses standard Java equality for testing. 116 * 117 * <p> 118 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 119 * 120 * @param <T> The object type being tested. 121 * @param value The specified value. 122 * @return A new predicate. 123 */ 124 public static final <T> AssertionPredicate<T> eq(Object value) { 125 return test(x -> Objects.equals(x, value), MSG_valueDidNotMatchExpected, value, VALUE); 126 } 127 128 /** 129 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified value. 130 * 131 * <p> 132 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 133 * 134 * @param <T> The object type being tested. 135 * @param value The specified value. 136 * @return A new predicate. 137 */ 138 public static final <T> AssertionPredicate<T> eq(String value) { 139 return test(x -> Objects.equals(Utils.s(x), value), MSG_valueDidNotMatchExpected, value, VALUE); 140 } 141 142 /** 143 * Predicate that returns <jk>true</jk> if the tested value does not match the specified value. 144 * 145 * <p> 146 * Assertion error message is <js>"Value unexpectedly matched. Value='{0}'."</js>. 147 * 148 * @param <T> The object type being tested. 149 * @param value The specified value. 150 * @return A new predicate. 151 */ 152 public static final <T> AssertionPredicate<T> ne(Object value) { 153 return test(x -> ! Objects.equals(x, value), MSG_valueUnexpectedlyMatched, VALUE); 154 } 155 156 /** 157 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value. 158 * 159 * <p> 160 * Assertion error message is <js>"Value unexpectedly matched. Value='{0}'."</js>. 161 * 162 * @param <T> The object type being tested. 163 * @param value The specified value. 164 * @return A new predicate. 165 */ 166 public static final <T> AssertionPredicate<T> ne(String value) { 167 return test(x -> ! Objects.equals(Utils.s(x), value), MSG_valueUnexpectedlyMatched, VALUE); 168 } 169 170 /** 171 * Predicate that returns <jk>true</jk> if the tested value converted to a string does not match the specified value ignoring case. 172 * 173 * <p> 174 * Assertion error message is <js>"Value did not match expected. Expected='{0}', Actual='{1}'."</js>. 175 * 176 * @param <T> The object type being tested. 177 * @param value The specified value. 178 * @return A new predicate. 179 */ 180 public static final <T> AssertionPredicate<T> eqic(String value) { 181 return test(x -> Utils.eqic(Utils.s(x), value), MSG_valueDidNotMatchExpected, value, VALUE); 182 } 183 184 /** 185 * Predicate that returns <jk>true</jk> if the tested value converted to a string contains the specified substring. 186 * 187 * <p> 188 * Assertion error message is <js>"Value did not contain expected. Expected='{0}', Actual='{1}'."</js>. 189 * 190 * @param <T> The object type being tested. 191 * @param value The specified value. 192 * @return A new predicate. 193 */ 194 public static final <T> AssertionPredicate<T> contains(String value) { 195 return test(x -> StringUtils.contains(Utils.s(x), value), MSG_valueDidNotContainExpected, value, VALUE); 196 } 197 198 /** 199 * Predicate that returns <jk>true</jk> if the tested value is the specified or child type. 200 * 201 * <p> 202 * Assertion error message is <js>"Value was not expected type. Expected='{0}', Actual='{1}'."</js>. 203 * 204 * @param <T> The object type being tested. 205 * @param type The specified type. 206 * @return A new predicate. 207 */ 208 public static final <T> AssertionPredicate<T> type(Class<?> type) { 209 Utils.assertArgNotNull("type", type); 210 return test(x -> x != null && type.isAssignableFrom(x.getClass()), MSG_valueWasNotExpectedType, type, TYPENAME); 211 } 212 213 /** 214 * Predicate that returns <jk>true</jk> if the tested value is exactly specified type. 215 * 216 * <p> 217 * Assertion error message is <js>"Value was not expected type. Expected='{0}', Actual='{1}'."</js>. 218 * 219 * @param <T> The object type being tested. 220 * @param type The specified type. 221 * @return A new predicate. 222 */ 223 public static final <T> AssertionPredicate<T> exactType(Class<?> type) { 224 Utils.assertArgNotNull("type", type); 225 return test(x -> x != null && x.getClass().equals(type), MSG_valueWasNotExpectedType, type, TYPENAME); 226 } 227 228 /** 229 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified match pattern. 230 * 231 * <p> 232 * Match pattern can contain the <js>"*"</js> meta-character. 233 * 234 * <p> 235 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 236 * 237 * @param <T> The object type being tested. 238 * @param value The specified value. 239 * @return A new predicate. 240 */ 241 public static final <T> AssertionPredicate<T> match(String value) { 242 Utils.assertArgNotNull("value", value); 243 var p = Utils.getMatchPattern3(value); 244 return test(x -> x != null && p.matcher(Utils.s(x)).matches(), MSG_valueDidNotMatchPattern, value, VALUE); 245 } 246 247 /** 248 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 249 * 250 * <p> 251 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 252 * 253 * @param <T> The object type being tested. 254 * @param expression The regular expression to match. 255 * @return A new predicate. 256 */ 257 public static final <T> AssertionPredicate<T> regex(String expression) { 258 Utils.assertArgNotNull("expression", expression); 259 var p = Pattern.compile(expression); 260 return test(x -> x != null && p.matcher(Utils.s(x)).matches(), MSG_valueDidNotMatchPattern, expression, VALUE); 261 } 262 263 /** 264 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 265 * 266 * <p> 267 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 268 * 269 * @param <T> The object type being tested. 270 * @param expression The regular expression to match. 271 * @param flags Match flags, a bit mask that may include: 272 * <ul> 273 * <li>{@link Pattern#CASE_INSENSITIVE CASE_INSENSITIVE} 274 * <li>{@link Pattern#MULTILINE MULTILINE} 275 * <li>{@link Pattern#DOTALL DOTALL} 276 * <li>{@link Pattern#UNICODE_CASE UNICODE_CASE} 277 * <li>{@link Pattern#CANON_EQ CANON_EQ} 278 * <li>{@link Pattern#UNIX_LINES UNIX_LINES} 279 * <li>{@link Pattern#LITERAL LITERAL} 280 * <li>{@link Pattern#UNICODE_CHARACTER_CLASS UNICODE_CHARACTER_CLASS} 281 * <li>{@link Pattern#COMMENTS COMMENTS} 282 * @return A new predicate. 283 */ 284 public static final <T> AssertionPredicate<T> regex(String expression, int flags) { 285 Utils.assertArgNotNull("expression", expression); 286 var p = Pattern.compile(expression, flags); 287 return test(x -> x != null && p.matcher(Utils.s(x)).matches(), MSG_valueDidNotMatchPattern, expression, VALUE); 288 } 289 290 /** 291 * Predicate that returns <jk>true</jk> if the tested value converted to a string matches the specified regular expression. 292 * 293 * <p> 294 * Assertion error message is <js>"Value did not match pattern. Pattern='{0}', Actual='{1}'."</js>. 295 * 296 * @param <T> The object type being tested. 297 * @param value The regular expression to match. 298 * @return A new predicate. 299 */ 300 public static final <T> AssertionPredicate<T> regex(Pattern value) { 301 Utils.assertArgNotNull("value", value); 302 return test(x -> x != null && value.matcher(Utils.s(x)).matches(), MSG_valueDidNotMatchPattern, value.pattern(), VALUE); 303 } 304 305 /** 306 * Predicate that wraps another predicate. 307 * 308 * <p> 309 * If the predicate extends from {@link AssertionPredicate}, the assertion error 310 * message is <js>"Value did not pass test."</js> followed by the inner assertion error. 311 * Otherwise the message is <js>"Value did not pass test. Value='{0}'."</js> 312 * 313 * @param <T> The object type being tested. 314 * @param predicate The predicate to run. 315 * @return A new predicate. 316 */ 317 public static final <T> AssertionPredicate<T> test(Predicate<T> predicate) { 318 return new AssertionPredicate<>(predicate, null); 319 } 320 321 /** 322 * Predicate that wraps another predicate. 323 * 324 * <p> 325 * If the message specified is <jk>null</jk> and the predicate extends from {@link AssertionPredicate}, the assertion error 326 * message is <js>"Value did not pass test."</js> followed by the inner assertion error. 327 * Otherwise the message is <js>"Value did not pass test. Value='{0}'."</js> 328 * 329 * @param <T> The object type being tested. 330 * @param predicate The predicate to run. 331 * @param msg 332 * The error message if predicate fails. 333 * <br>Supports {@link MessageFormat}-style arguments. 334 * @param args 335 * Optional message arguments. 336 * <br>Can contain {@code #VALUE} to specify the value itself as an argument. 337 * <br>Can contain {@link Function functions} to apply to the tested value. 338 * @return A new predicate. 339 */ 340 public static final <T> AssertionPredicate<T> test(Predicate<T> predicate, String msg, Object...args) { 341 return new AssertionPredicate<>(predicate, msg, args); 342 } 343 344 /** 345 * Combines the specified predicates into a singled AND'ed predicate. 346 * 347 * <p> 348 * Assertion error message is <js>"Predicate test #x failed."</js> followed by 349 * the inner failed message if the failed predicate extends from {@link AssertionPredicate}. 350 * 351 * @param <T> The predicate type. 352 * @param predicates The predicates to combine. 353 * @return The combined predicates. 354 */ 355 @SafeVarargs 356 public static final <T> AssertionPredicate<T> and(Predicate<T>...predicates) { 357 return new AssertionPredicate.And<>(predicates); 358 } 359 360 /** 361 * Combines the specified predicates into a singled OR'ed predicate. 362 * 363 * <p> 364 * Assertion error message is <js>"No predicate tests passed."</js>. 365 * 366 * @param <T> The predicate type. 367 * @param predicates The predicates to combine. 368 * @return The combined predicates. 369 */ 370 @SafeVarargs 371 public static final <T> AssertionPredicate<T> or(Predicate<T>...predicates) { 372 return new AssertionPredicate.Or<>(predicates); 373 } 374 375 /** 376 * Negates the specified predicate. 377 * 378 * <p> 379 * Assertion error message is <js>"Predicate test unexpectedly passed."</js>. 380 * 381 * @param <T> The predicate type. 382 * @param predicate The predicate to negate. 383 * @return The combined predicates. 384 */ 385 public static final <T> AssertionPredicate<T> not(Predicate<T> predicate) { 386 return new AssertionPredicate.Not<>(predicate); 387 } 388}