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.reflect.ReflectionUtils.*; 020import static org.apache.juneau.commons.utils.Shorts.*; 021 022import java.io.*; 023import java.time.*; 024import java.util.*; 025import java.util.function.*; 026 027import org.apache.juneau.commons.function.*; 028 029 030/** 031 * Used for assertion calls against generic POJOs. 032 * 033 * <p> 034 * Extends from {@link FluentObjectAssertion} allowing you to perform basic assertions, but adds several transform 035 * methods to convert to more-specific assertion types. 036 * 037 * <h5 class='section'>Example:</h5> 038 * <p class='bjava'> 039 * <jk>import static</jk> org.apache.juneau.bct.assertions.Assertions.*; 040 * 041 * List<MyBean> <jv>listOfBeans</jv> = ...; 042 * <jsm>assertList</jsm>(<jv>listOfBeans</jv>) 043 * .asItem(1) <jc>// Returns an AnyAssertion.</jc> 044 * .asBean() <jc>// Transforms to BeanAssertion.</jc> 045 * .asProperty(<js>"foo"</js>) <jc>// Returns an AnyAssertion.</jc> 046 * .asString() <jc>// Transforms to StringAssertion.</jc> 047 * .is(<js>"bar"</js>); <jc>// Performs test.</jc> 048 * </p> 049 * 050 * <h5 class='section'>Test Methods:</h5> 051 * <p> 052 * <ul class='javatree'> 053 * <li class='jc'>{@link FluentObjectAssertion} 054 * <ul class='javatreec'> 055 * <li class='jm'>{@link FluentObjectAssertion#isExists() isExists()} 056 * <li class='jm'>{@link FluentObjectAssertion#is(Object) is(Object)} 057 * <li class='jm'>{@link FluentObjectAssertion#is(Predicate) is(Predicate)} 058 * <li class='jm'>{@link FluentObjectAssertion#isNot(Object) isNot(Object)} 059 * <li class='jm'>{@link FluentObjectAssertion#isAny(Object...) isAny(Object...)} 060 * <li class='jm'>{@link FluentObjectAssertion#isNotAny(Object...) isNotAny(Object...)} 061 * <li class='jm'>{@link FluentObjectAssertion#isNull() isNull()} 062 * <li class='jm'>{@link FluentObjectAssertion#isNotNull() isNotNull()} 063 * <li class='jm'>{@link FluentObjectAssertion#isString(String) isString(String)} 064 * <li class='jm'>{@link FluentObjectAssertion#isSame(Object) isSame(Object)} 065 * <li class='jm'>{@link FluentObjectAssertion#isType(Class) isType(Class)} 066 * <li class='jm'>{@link FluentObjectAssertion#isExactType(Class) isExactType(Class)} 067 * </ul> 068 * </ul> 069 * 070 * <h5 class='section'>Transform Methods:</h5> 071 * <p> 072 * <ul class='javatree'> 073 * <li class='jc'>{@link FluentAnyAssertion} 074 * <ul class='javatreec'> 075 * <li class='jm'>{@link FluentAnyAssertion#asArray(Class) asArray(Class)} 076 * <li class='jm'>{@link FluentAnyAssertion#asIntArray() asIntArray()} 077 * <li class='jm'>{@link FluentAnyAssertion#asLongArray() asLongArray()} 078 * <li class='jm'>{@link FluentAnyAssertion#asShortArray() asShortArray()} 079 * <li class='jm'>{@link FluentAnyAssertion#asFloatArray() asFloatArray()} 080 * <li class='jm'>{@link FluentAnyAssertion#asDoubleArray() asDoubleArray()} 081 * <li class='jm'>{@link FluentAnyAssertion#asCharArray() asCharArray()} 082 * <li class='jm'>{@link FluentAnyAssertion#asByteArray() asByteArray()} 083 * <li class='jm'>{@link FluentAnyAssertion#asBooleanArray() asBooleanArray()} 084 * <li class='jm'>{@link FluentAnyAssertion#asBoolean() asBoolean()} 085 * <li class='jm'>{@link FluentAnyAssertion#asBytes() asBytes()} 086 * <li class='jm'>{@link FluentAnyAssertion#asCollection() asCollection()} 087 * <li class='jm'>{@link FluentAnyAssertion#asCollection(Class) asCollection(Class)} 088 * <li class='jm'>{@link FluentAnyAssertion#asStringList() asStringList()} 089 * <li class='jm'>{@link FluentAnyAssertion#asComparable() asComparable()} 090 * <li class='jm'>{@link FluentAnyAssertion#asDate() asDate()} 091 * <li class='jm'>{@link FluentAnyAssertion#asInteger() asInteger()} 092 * <li class='jm'>{@link FluentAnyAssertion#asLong() asLong()} 093 * <li class='jm'>{@link FluentAnyAssertion#asList() asList()} 094 * <li class='jm'>{@link FluentAnyAssertion#asList(Class) asList(Class)} 095 * <li class='jm'>{@link FluentAnyAssertion#asMap() asMap()} 096 * <li class='jm'>{@link FluentAnyAssertion#asMap(Class,Class) asMap(Class,Class)} 097 * <li class='jm'>{@link FluentAnyAssertion#asBean() asBean()} 098 * <li class='jm'>{@link FluentAnyAssertion#asBean(Class) asBean(Class)} 099 * <li class='jm'>{@link FluentAnyAssertion#asBeanList(Class) asBeanList(Class)} 100 * <li class='jm'>{@link FluentAnyAssertion#asZonedDateTime() asZonedDateTime()} 101 * </ul> 102 * <li class='jc'>{@link FluentObjectAssertion} 103 * <ul class='javatreec'> 104 * <li class='jm'>{@link FluentObjectAssertion#asString() asString()} 105 * <li class='jm'>{@link FluentObjectAssertion#asString(ThrowingFunction) asString(ThrowingFunction)} 106 * <li class='jm'>{@link FluentObjectAssertion#asTransformed(UnaryOperator) asTransformed(UnaryOperator)} 107 * <li class='jm'>{@link FluentObjectAssertion#asAny() asAny()} 108 * </ul> 109 * </ul> 110 * 111 * <h5 class='section'>Configuration Methods:</h5> 112 * <p> 113 * <ul class='javatree'> 114 * <li class='jc'>{@link Assertion} 115 * <ul class='javatreec'> 116 * <li class='jm'>{@link Assertion#setMsg(String, Object...) setMsg(String, Object...)} 117 * <li class='jm'>{@link Assertion#setOut(PrintStream) setOut(PrintStream)} 118 * <li class='jm'>{@link Assertion#setSilent() setSilent()} 119 * <li class='jm'>{@link Assertion#setStdOut() setStdOut()} 120 * <li class='jm'>{@link Assertion#setThrowable(Class) setThrowable(Class)} 121 * </ul> 122 * </ul> 123 * 124 * <h5 class='section'>See Also:</h5><ul> 125 * <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauEcosystemOverview">Juneau Ecosystem</a> 126 * </ul> 127 * 128 * @param <T> The object type. 129 * @param <R> The return type. 130 */ 131@SuppressWarnings({ 132 "java:S115", // Constants use UPPER_snakeCase convention 133 "java:S1192", // Duplicated literals (argument/property names) read more clearly inline than as constants 134 "unchecked" // The as*() narrowing methods re-type this assertion's value via cast(), which cannot be verified at compile time 135}) 136public class FluentAnyAssertion<T,R> extends FluentObjectAssertion<T,R> { 137 138 // @formatter:off 139 private static final Messages MESSAGES = Messages.of(FluentAnyAssertion.class, "Messages"); 140 private static final String 141 MSG_objectWasNotType = MESSAGES.getString("objectWasNotType"); 142 // @formatter:on 143 144 /** 145 * Chained constructor. 146 * 147 * <p> 148 * Used when transforming one assertion into another so that the assertion config can be used by the new assertion. 149 * 150 * @param creator 151 * The assertion that created this assertion. 152 * <br>Should be <jk>null</jk> if this is the top-level assertion. 153 * @param value 154 * The object being tested. 155 * <br>Can be <jk>null</jk> (assertions such as {@code isNull()} then operate on the absence of a value). 156 * @param returns 157 * The object to return after a test method is called. 158 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 159 * used on the same assertion. 160 */ 161 public FluentAnyAssertion(Assertion creator, T value, R returns) { 162 super(creator, value, returns); 163 } 164 165 /** 166 * Constructor. 167 * 168 * @param value 169 * The object being tested. 170 * <br>Can be <jk>null</jk> (assertions such as {@code isNull()} then operate on the absence of a value). 171 * @param returns 172 * The object to return after a test method is called. 173 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 174 * used on the same assertion. 175 */ 176 public FluentAnyAssertion(T value, R returns) { 177 this(null, value, returns); 178 } 179 180 /** 181 * Converts this object assertion into an array assertion. 182 * 183 * @param <E> The element type of the array. 184 * @param elementType The element type of the array. 185 * @return A new assertion. 186 * @throws AssertionError If object is not an array. 187 */ 188 public <E> FluentArrayAssertion<E,R> asArray(Class<E> elementType) throws AssertionError { 189 reqnn("elementType", elementType); 190 return new FluentArrayAssertion<>(this, cast(arrayClass(elementType)), returns()); 191 } 192 193 /** 194 * Converts this object assertion into a bean assertion. 195 * 196 * @return A new assertion. 197 * @throws AssertionError If object is not a bean. 198 */ 199 public FluentBeanAssertion<T,R> asBean() { 200 return new FluentBeanAssertion<>(this, orElse(null), returns()); 201 } 202 203 /** 204 * Converts this object assertion into a bean assertion. 205 * 206 * @param <T2> The bean type. 207 * @param beanType The bean type. 208 * @return A new assertion. 209 * @throws AssertionError If object is not a bean. 210 */ 211 public <T2> FluentBeanAssertion<T2,R> asBean(Class<T2> beanType) { 212 reqnn("beanType", beanType); 213 return new FluentBeanAssertion<>(this, cast(beanType), returns()); 214 } 215 216 /** 217 * Converts this object assertion into a list-of-beans assertion. 218 * 219 * @param <T2> The bean type. 220 * @param beanType The bean type. 221 * @return A new assertion. 222 * @throws AssertionError If object is not a bean. 223 */ 224 public <T2> FluentBeanListAssertion<T2,R> asBeanList(Class<T2> beanType) { 225 reqnn("beanType", beanType); 226 return new FluentBeanListAssertion<>(this, cast(List.class), returns()); 227 } 228 229 /** 230 * Converts this object assertion into a boolean assertion. 231 * 232 * @return A new assertion. 233 * @throws AssertionError If object is not a boolean. 234 */ 235 public FluentBooleanAssertion<R> asBoolean() { 236 return new FluentBooleanAssertion<>(this, cast(Boolean.class), returns()); 237 } 238 239 /** 240 * Converts this object assertion into a primitive boolean array assertion. 241 * 242 * @return A new assertion. 243 * @throws AssertionError If object is not an boolean array. 244 */ 245 public FluentPrimitiveArrayAssertion<Boolean,boolean[],R> asBooleanArray() throws AssertionError { 246 return new FluentPrimitiveArrayAssertion<>(this, cast(boolean[].class), returns()); 247 } 248 249 /** 250 * Converts this object assertion into a primitive byte array assertion. 251 * 252 * @return A new assertion. 253 * @throws AssertionError If object is not an byte array. 254 */ 255 public FluentPrimitiveArrayAssertion<Byte,byte[],R> asByteArray() throws AssertionError { 256 return new FluentPrimitiveArrayAssertion<>(this, cast(byte[].class), returns()); 257 } 258 259 /** 260 * Converts this object assertion into a byte array assertion. 261 * 262 * @return A new assertion. 263 * @throws AssertionError If object is not a byte array. 264 */ 265 public FluentByteArrayAssertion<R> asBytes() { 266 return new FluentByteArrayAssertion<>(this, cast(byte[].class), returns()); 267 } 268 269 /** 270 * Converts this object assertion into a primitive char array assertion. 271 * 272 * @return A new assertion. 273 * @throws AssertionError If object is not an char array. 274 */ 275 public FluentPrimitiveArrayAssertion<Character,char[],R> asCharArray() throws AssertionError { 276 return new FluentPrimitiveArrayAssertion<>(this, cast(char[].class), returns()); 277 } 278 279 /** 280 * Converts this object assertion into a collection assertion. 281 * 282 * @return A new assertion. 283 * @throws AssertionError If object is not a collection. 284 */ 285 public FluentCollectionAssertion<Object,R> asCollection() { 286 return asCollection(Object.class); 287 } 288 289 /** 290 * Converts this object assertion into a collection assertion. 291 * 292 * @param <E> The element type of the collection. 293 * @param elementType The element type of the collection. 294 * @return A new assertion. 295 * @throws AssertionError If object is not a collection. 296 */ 297 public <E> FluentCollectionAssertion<E,R> asCollection(Class<E> elementType) { 298 reqnn("elementType", elementType); 299 return new FluentCollectionAssertion<>(this, cast(Collection.class), returns()); 300 } 301 302 /** 303 * Converts this object assertion into a comparable object assertion. 304 * 305 * @param <T2> The comparable type. 306 * @return A new assertion. 307 * @throws AssertionError If object is not an instance of {@link Comparable}. 308 */ 309 public <T2 extends Comparable<T2>> FluentComparableAssertion<T2,R> asComparable() { 310 return new FluentComparableAssertion<>(this, (T2)cast(Comparable.class), returns()); 311 } 312 313 /** 314 * Converts this object assertion into a date assertion. 315 * 316 * @return A new assertion. 317 * @throws AssertionError If object is not a date. 318 */ 319 public FluentDateAssertion<R> asDate() { 320 return new FluentDateAssertion<>(this, cast(Date.class), returns()); 321 } 322 323 /** 324 * Converts this object assertion into a primitive double array assertion. 325 * 326 * @return A new assertion. 327 * @throws AssertionError If object is not an double array. 328 */ 329 public FluentPrimitiveArrayAssertion<Double,double[],R> asDoubleArray() throws AssertionError { 330 return new FluentPrimitiveArrayAssertion<>(this, cast(double[].class), returns()); 331 } 332 333 /** 334 * Converts this object assertion into a primitive float array assertion. 335 * 336 * @return A new assertion. 337 * @throws AssertionError If object is not an float array. 338 */ 339 public FluentPrimitiveArrayAssertion<Float,float[],R> asFloatArray() throws AssertionError { 340 return new FluentPrimitiveArrayAssertion<>(this, cast(float[].class), returns()); 341 } 342 343 /** 344 * Converts this object assertion into a primitive int array assertion. 345 * 346 * @return A new assertion. 347 * @throws AssertionError If object is not an int array. 348 */ 349 public FluentPrimitiveArrayAssertion<Integer,int[],R> asIntArray() throws AssertionError { 350 return new FluentPrimitiveArrayAssertion<>(this, cast(int[].class), returns()); 351 } 352 353 /** 354 * Converts this object assertion into an integer assertion. 355 * 356 * @return A new assertion. 357 * @throws AssertionError If object is not an integer. 358 */ 359 public FluentIntegerAssertion<R> asInteger() { 360 return new FluentIntegerAssertion<>(this, cast(Integer.class), returns()); 361 } 362 363 /** 364 * Converts this object assertion into a list assertion. 365 * 366 * @return A new assertion. 367 * @throws AssertionError If object is not a list. 368 */ 369 public FluentListAssertion<Object,R> asList() { 370 return asList(Object.class); 371 } 372 373 /** 374 * Converts this object assertion into a list assertion. 375 * 376 * @param <E> The element type. 377 * @param elementType The element type. 378 * @return A new assertion. 379 * @throws AssertionError If object is not a list. 380 */ 381 public <E> FluentListAssertion<E,R> asList(Class<E> elementType) { 382 reqnn("elementType", elementType); 383 return new FluentListAssertion<>(this, cast(List.class), returns()); 384 } 385 386 /** 387 * Converts this object assertion into a long assertion. 388 * 389 * @return A new assertion. 390 * @throws AssertionError If object is not a long. 391 */ 392 public FluentLongAssertion<R> asLong() { 393 return new FluentLongAssertion<>(this, cast(Long.class), returns()); 394 } 395 396 /** 397 * Converts this object assertion into a primitive long array assertion. 398 * 399 * @return A new assertion. 400 * @throws AssertionError If object is not an long array. 401 */ 402 public FluentPrimitiveArrayAssertion<Long,long[],R> asLongArray() throws AssertionError { 403 return new FluentPrimitiveArrayAssertion<>(this, cast(long[].class), returns()); 404 } 405 406 /** 407 * Converts this object assertion into a map assertion. 408 * 409 * @return A new assertion. 410 * @throws AssertionError If object is not a map. 411 */ 412 public FluentMapAssertion<String,Object,R> asMap() { 413 return asMap(String.class, Object.class); 414 } 415 416 /** 417 * Converts this object assertion into a map assertion with the specified key and value types. 418 * 419 * @param <K> The key type. 420 * @param <V> The value type. 421 * @param keyType The key type. 422 * @param valueType The value type. 423 * @return A new assertion. 424 * @throws AssertionError If object is not a map. 425 */ 426 public <K,V> FluentMapAssertion<K,V,R> asMap(Class<K> keyType, Class<V> valueType) { 427 reqnn("keyType", keyType); 428 reqnn("valueType", valueType); 429 return new FluentMapAssertion<>(this, cast(Map.class), returns()); 430 } 431 432 /** 433 * Converts this object assertion into a primitive short array assertion. 434 * 435 * @return A new assertion. 436 * @throws AssertionError If object is not an short array. 437 */ 438 public FluentPrimitiveArrayAssertion<Short,short[],R> asShortArray() throws AssertionError { 439 return new FluentPrimitiveArrayAssertion<>(this, cast(short[].class), returns()); 440 } 441 442 /** 443 * Converts this object assertion into a collection assertion. 444 * 445 * @return A new assertion. 446 * @throws AssertionError If object is not a collection. 447 */ 448 public FluentStringListAssertion<R> asStringList() { 449 return new FluentStringListAssertion<>(this, cast(List.class), returns()); 450 } 451 452 /** 453 * Converts this object assertion into a zoned-datetime assertion. 454 * 455 * @return A new assertion. 456 * @throws AssertionError If object is not a zoned-datetime. 457 */ 458 public FluentZonedDateTimeAssertion<R> asZonedDateTime() { 459 return new FluentZonedDateTimeAssertion<>(this, cast(ZonedDateTime.class), returns()); 460 } 461 462 @Override /* Overridden from Assertion */ 463 public FluentAnyAssertion<T,R> setMsg(String msg, Object...args) { 464 super.setMsg(msg, args); 465 return this; 466 } 467 468 @Override /* Overridden from Assertion */ 469 public FluentAnyAssertion<T,R> setOut(PrintStream value) { 470 super.setOut(value); 471 return this; 472 } 473 474 @Override /* Overridden from Assertion */ 475 public FluentAnyAssertion<T,R> setSilent() { 476 super.setSilent(); 477 return this; 478 } 479 480 @Override /* Overridden from Assertion */ 481 public FluentAnyAssertion<T,R> setStdOut() { 482 super.setStdOut(); 483 return this; 484 } 485 486 @Override /* Overridden from Assertion */ 487 public FluentAnyAssertion<T,R> setThrowable(Class<? extends RuntimeException> value) { 488 super.setThrowable(value); 489 return this; 490 } 491 492 private <T2> T2 cast(Class<T2> c) throws AssertionError { 493 Object o = orElse(null); 494 if (o == null || c.isInstance(o)) 495 return c.cast(o); 496 throw new BasicAssertionError(MSG_objectWasNotType, info(c).getNameFull(), cn(o.getClass())); 497 } 498}