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