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