001// *************************************************************************************************************************** 002// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file * 003// * distributed with this work for additional information regarding copyright ownership. The ASF licenses this file * 004// * to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance * 005// * with the License. You may obtain a copy of the License at * 006// * * 007// * http://www.apache.org/licenses/LICENSE-2.0 * 008// * * 009// * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an * 010// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * 011// * specific language governing permissions and limitations under the License. * 012// *************************************************************************************************************************** 013package org.apache.juneau.assertions; 014 015import java.util.function.*; 016 017import org.apache.juneau.internal.*; 018import org.apache.juneau.json.*; 019import org.apache.juneau.marshall.*; 020import org.apache.juneau.reflect.*; 021import org.apache.juneau.serializer.*; 022 023/** 024 * Used for fluent assertion calls against POJOs. 025 * 026 * @param <R> The return type. 027 */ 028@FluentSetters(returns="FluentObjectAssertion<R>") 029public class FluentObjectAssertion<R> extends FluentAssertion<R> { 030 031 private final Object value; 032 033 private static JsonSerializer JSON = JsonSerializer.create() 034 .ssq() 035 .build(); 036 037 private static JsonSerializer JSON_SORTED = JsonSerializer.create() 038 .ssq() 039 .sortProperties() 040 .sortCollections() 041 .sortMaps() 042 .build(); 043 044 /** 045 * Constructor. 046 * 047 * @param value The object being tested. 048 * @param returns The object to return after the test. 049 */ 050 public FluentObjectAssertion(Object value, R returns) { 051 this(null, value, returns); 052 } 053 054 /** 055 * Constructor. 056 * 057 * @param creator The assertion that created this assertion. 058 * @param value The object being tested. 059 * @param returns The object to return after the test. 060 */ 061 public FluentObjectAssertion(Assertion creator, Object value, R returns) { 062 super(creator, returns); 063 this.value = value; 064 } 065 066 /** 067 * Asserts that the object is an instance of the specified class. 068 * 069 * <h5 class='section'>Example:</h5> 070 * <p class='bcode w800'> 071 * <jc>// Validates that the specified object is an instance of MyBean.</jc> 072 * <jsm>assertObject<jsm>(myPojo).instanceOf(MyBean.<jk>class</jk>); 073 * </p> 074 * 075 * @param parent The value to check against. 076 * @return The response object (for method chaining). 077 * @throws AssertionError If assertion failed. 078 */ 079 public R isType(Class<?> parent) throws AssertionError { 080 exists(); 081 assertNotNull("parent", parent); 082 if (! ClassInfo.of(value).isChildOf(parent)) 083 throw error("Unexpected class.\n\tExpected=[{0}]\n\tActual=[{1}]", className(parent), className(value)); 084 return returns(); 085 } 086 087 /** 088 * Converts this object to text using the specified serializer and returns it as a new assertion. 089 * 090 * <h5 class='section'>Example:</h5> 091 * <p class='bcode w800'> 092 * <jc>// Validates that the specified object is an instance of MyBean.</jc> 093 * <jsm>assertObject<jsm>(myPojo).serialized(XmlSerializer.<jsf>DEFAULT</jsf>).is(<js>"<object><foo>bar</foo><baz>qux</baz></object>"</js>); 094 * </p> 095 * 096 * @param ws The serializer to use to convert the object to text. 097 * @return A new fluent string assertion. 098 */ 099 public FluentStringAssertion<R> serialized(WriterSerializer ws) { 100 try { 101 String s = ws.serialize(this.value); 102 return new FluentStringAssertion<>(this, s, returns()); 103 } catch (SerializeException e) { 104 throw new RuntimeException(e); 105 } 106 } 107 108 /** 109 * Converts this object to a string using {@link Object#toString} and returns it as a new assertion. 110 * 111 * <h5 class='section'>Example:</h5> 112 * <p class='bcode w800'> 113 * <jc>// Validates that the specified object is "foobar" after converting to a string.</jc> 114 * <jsm>assertObject<jsm>(myPojo).string().is(<js>"foobar"</js>); 115 * </p> 116 * 117 * @return A new fluent string assertion. 118 */ 119 public FluentStringAssertion<R> string() { 120 return new FluentStringAssertion<>(this, value == null ? null : value.toString(), returns()); 121 } 122 123 /** 124 * Converts this object to a string using the specified function and returns it as a new assertion. 125 * 126 * <h5 class='section'>Example:</h5> 127 * <p class='bcode w800'> 128 * <jc>// Validates that the specified object is "foobar" after converting to a string.</jc> 129 * <jsm>assertObject<jsm>(myPojo).string(<jv>x</jv>-><jv>x</jv>.toString()).is(<js>"foobar"</js>); 130 * </p> 131 * 132 * @param function The conversion function. 133 * @return A new fluent string assertion. 134 */ 135 public FluentStringAssertion<R> string(Function<Object,String> function) { 136 return new FluentStringAssertion<>(this, function.apply(value), returns()); 137 } 138 139 /** 140 * Converts this object to a string using the specified function and returns it as a new assertion. 141 * 142 * <h5 class='section'>Example:</h5> 143 * <p class='bcode w800'> 144 * <jc>// Validates that the specified object is "foobar" after converting to a string.</jc> 145 * <jsm>assertObject<jsm>(myPojo).string(MyBean.<jk>class</jk>,<jv>x</jv>-><jv>x</jv>.myBeanMethod()).is(<js>"foobar"</js>); 146 * </p> 147 * 148 * @param c The class of the object being converted. 149 * @param function The conversion function. 150 * @param <T> The class of the object being converted. 151 * @return A new fluent string assertion. 152 */ 153 @SuppressWarnings("unchecked") 154 public <T> FluentStringAssertion<R> string(Class<T> c, Function<T,String> function) { 155 return new FluentStringAssertion<>(this, function.apply((T)value), returns()); 156 } 157 158 /** 159 * Converts this object to simplified JSON and returns it as a new assertion. 160 * 161 * <h5 class='section'>Example:</h5> 162 * <p class='bcode w800'> 163 * <jc>// Validates that the specified object is an instance of MyBean.</jc> 164 * <jsm>assertObject<jsm>(myPojo).json().is(<js>"{foo:'bar',baz:'qux'}"</js>); 165 * </p> 166 * 167 * @return A new fluent string assertion. 168 */ 169 public FluentStringAssertion<R> json() { 170 return serialized(JSON); 171 } 172 173 /** 174 * Converts this object to sorted simplified JSON and returns it as a new assertion. 175 * 176 * <h5 class='section'>Example:</h5> 177 * <p class='bcode w800'> 178 * <jc>// Validates that the specified object is an instance of MyBean.</jc> 179 * <jsm>assertObject<jsm>(myPojo).jsonSorted().is(<js>"{baz:'qux',foo:'bar'}"</js>); 180 * </p> 181 * 182 * @return A new fluent string assertion. 183 */ 184 public FluentStringAssertion<R> jsonSorted() { 185 return serialized(JSON_SORTED); 186 } 187 188 /** 189 * Verifies that two objects are equivalent after converting them both to JSON. 190 * 191 * @param o The object to compare against. 192 * @return The response object (for method chaining). 193 * @throws AssertionError If assertion failed. 194 */ 195 public R sameAs(Object o) throws AssertionError { 196 return sameAsSerialized(o, JSON); 197 } 198 199 /** 200 * Verifies that two objects are equivalent after converting them both to sorted JSON. 201 * 202 * <p> 203 * Properties, maps, and collections are all sorted on both objects before comparison. 204 * 205 * @param o The object to compare against. 206 * @return The response object (for method chaining). 207 * @throws AssertionError If assertion failed. 208 */ 209 public R sameAsSorted(Object o) { 210 return sameAsSerialized(o, JSON_SORTED); 211 } 212 213 /** 214 * Asserts that the specified object is the same as this object after converting both to strings using the specified serializer. 215 * 216 * @param o The object to compare against. 217 * @param serializer The serializer to use to serialize this object. 218 * @return The response object (for method chaining). 219 * @throws AssertionError If assertion failed. 220 */ 221 public R sameAsSerialized(Object o, WriterSerializer serializer) { 222 try { 223 String s1 = serializer.serialize(this.value); 224 String s2 = serializer.serialize(o); 225 if (! StringUtils.isEquals(s1, s2)) 226 throw error("Unexpected comparison.\n\tExpected=[{0}]\n\tActual=[{1}]", s2, s1); 227 } catch (SerializeException e) { 228 throw new RuntimeException(e); 229 } 230 return returns(); 231 } 232 233 /** 234 * Asserts that the value equals the specified value. 235 * 236 * @param value The value to check against. 237 * @return The response object (for method chaining). 238 * @throws AssertionError If assertion failed. 239 */ 240 public R isEqual(Object value) throws AssertionError { 241 if (this.value == value) 242 return returns(); 243 exists(); 244 if (! this.value.equals(equivalent(value))) 245 throw error("Unexpected value.\n\tExpected=[{0}]\n\tActual=[{1}]", value, this.value); 246 return returns(); 247 } 248 249 /** 250 * Asserts that the value equals the specified value. 251 * 252 * <p> 253 * Equivalent to {@link #isEqual(Object)}. 254 * 255 * @param value The value to check against. 256 * @return The response object (for method chaining). 257 * @throws AssertionError If assertion failed. 258 */ 259 public R is(Object value) throws AssertionError { 260 return isEqual(equivalent(value)); 261 } 262 263 /** 264 * Asserts that the value equals the specified value. 265 * 266 * @param value The value to check against. 267 * @return The response object (for method chaining). 268 * @throws AssertionError If assertion failed. 269 */ 270 public R doesNotEqual(Object value) throws AssertionError { 271 if (this.value == null && value != null || this.value != null && value == null) 272 return returns(); 273 if (this.value == null || this.value.equals(equivalent(value))) 274 throw error("Unexpected value.\n\tExpected not=[{0}]\n\tActual=[{1}]", value, this.value); 275 return returns(); 276 } 277 278 /** 279 * Asserts that the value passes the specified predicate test. 280 * 281 * @param test The predicate to use to test the value. 282 * @return The response object (for method chaining). 283 * @throws AssertionError If assertion failed. 284 */ 285 public R passes(Predicate<Object> test) throws AssertionError { 286 if (! test.test(value)) 287 throw error("Value did not pass predicate test.\n\tValue=[{0}]", value); 288 return returns(); 289 } 290 291 /** 292 * Asserts that the value passes the specified predicate test. 293 * 294 * @param c The class type of the object being tested. 295 * @param <T> The class type of the object being tested. 296 * @param test The predicate to use to test the value. 297 * @return The response object (for method chaining). 298 * @throws AssertionError If assertion failed. 299 */ 300 @SuppressWarnings("unchecked") 301 public <T> R passes(Class<T> c, Predicate<T> test) throws AssertionError { 302 isType(c); 303 if (! test.test((T)value)) 304 throw error("Value did not pass predicate test.\n\tValue=[{0}]", value); 305 return returns(); 306 } 307 308 /** 309 * Asserts that the object is not null. 310 * 311 * <p> 312 * Equivalent to {@link #isNotNull()}. 313 * 314 * @return The response object (for method chaining). 315 * @throws AssertionError If assertion failed. 316 */ 317 public R exists() throws AssertionError { 318 return isNotNull(); 319 } 320 321 /** 322 * Asserts that the object is null. 323 * 324 * <p> 325 * Equivalent to {@link #isNotNull()}. 326 * 327 * @return The response object (for method chaining). 328 * @throws AssertionError If assertion failed. 329 */ 330 public R doesNotExist() throws AssertionError { 331 return isNull(); 332 } 333 334 /** 335 * Asserts that the object is not null. 336 * 337 * <p> 338 * Equivalent to {@link #isNotNull()}. 339 * 340 * @return The response object (for method chaining). 341 * @throws AssertionError If assertion failed. 342 */ 343 public R isNotNull() throws AssertionError { 344 if (value == null) 345 throw error("Value was null."); 346 return returns(); 347 } 348 349 /** 350 * Asserts that the object i null. 351 * 352 * <p> 353 * Equivalent to {@link #isNotNull()}. 354 * 355 * @return The response object (for method chaining). 356 * @throws AssertionError If assertion failed. 357 */ 358 public R isNull() throws AssertionError { 359 if (value != null) 360 throw error("Value was not null."); 361 return returns(); 362 } 363 364 /** 365 * Asserts that the value equals the specified value. 366 * 367 * <p> 368 * Equivalent to {@link #doesNotEqual(Object)}. 369 * 370 * @param value The value to check against. 371 * @return The response object (for method chaining). 372 * @throws AssertionError If assertion failed. 373 */ 374 public R isNot(Object value) throws AssertionError { 375 return doesNotEqual(equivalent(value)); 376 } 377 378 /** 379 * Asserts that the value is one of the specified values. 380 * 381 * @param values The values to check against. 382 * @return The response object (for method chaining). 383 * @throws AssertionError If assertion failed. 384 */ 385 public R isAny(Object...values) throws AssertionError { 386 exists(); 387 for (Object v : values) 388 if (this.value.equals(equivalent(v))) 389 return returns(); 390 throw error("Expected value not found.\n\tExpected=[{0}]\n\tActual=[{1}]", SimpleJson.DEFAULT.toString(values), value); 391 } 392 393 /** 394 * Asserts that the value is one of the specified values. 395 * 396 * @param values The values to check against. 397 * @return The response object (for method chaining). 398 * @throws AssertionError If assertion failed. 399 */ 400 public R isNotAny(Object...values) throws AssertionError { 401 exists(); 402 for (Object v : values) 403 if (this.value.equals(equivalent(v))) 404 throw error("Unexpected value found.\n\tUnexpected=[{0}]\n\tActual=[{1}]", v, value); 405 return returns(); 406 } 407 408 /** 409 * Subclasses can override this method to provide special conversions on objects being compared. 410 * 411 * @param o The object to cast. 412 * @return The cast object. 413 */ 414 protected Object equivalent(Object o) { 415 return o; 416 } 417 418 // <FluentSetters> 419 420 @Override /* GENERATED - Assertion */ 421 public FluentObjectAssertion<R> msg(String msg, Object...args) { 422 super.msg(msg, args); 423 return this; 424 } 425 426 @Override /* GENERATED - Assertion */ 427 public FluentObjectAssertion<R> stderr() { 428 super.stderr(); 429 return this; 430 } 431 432 @Override /* GENERATED - Assertion */ 433 public FluentObjectAssertion<R> stdout() { 434 super.stdout(); 435 return this; 436 } 437 438 // </FluentSetters> 439}