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.rest.client.assertion; 014 015import java.io.*; 016import java.lang.reflect.*; 017import java.util.*; 018import java.util.function.*; 019 020import org.apache.juneau.assertions.*; 021import org.apache.juneau.http.response.*; 022import org.apache.juneau.internal.*; 023import org.apache.juneau.rest.client.*; 024import org.apache.juneau.serializer.*; 025 026/** 027 * Used for fluent assertion calls against {@link ResponseContent} objects. 028 * 029 * <h5 class='topic'>Test Methods</h5> 030 * <p> 031 * <ul class='javatree'> 032 * <li class='jc'>{@link FluentResponseBodyAssertion} 033 * <ul class='javatreec'> 034 * <li class='jm'>{@link FluentResponseBodyAssertion#is(String) is(String)} 035 * <li class='jm'>{@link FluentResponseBodyAssertion#isContains(String...) isContains(String...)} 036 * <li class='jm'>{@link FluentResponseBodyAssertion#isNotContains(String...) isNotContains(String...)} 037 * <li class='jm'>{@link FluentResponseBodyAssertion#isEmpty() isEmpty()} 038 * <li class='jm'>{@link FluentResponseBodyAssertion#isNotEmpty() isNotEmpty()} 039 * </ul> 040 * <li class='jc'>{@link FluentObjectAssertion} 041 * <ul class='javatreec'> 042 * <li class='jm'>{@link FluentObjectAssertion#isExists() isExists()} 043 * <li class='jm'>{@link FluentObjectAssertion#is(Object) is(Object)} 044 * <li class='jm'>{@link FluentObjectAssertion#is(Predicate) is(Predicate)} 045 * <li class='jm'>{@link FluentObjectAssertion#isNot(Object) isNot(Object)} 046 * <li class='jm'>{@link FluentObjectAssertion#isAny(Object...) isAny(Object...)} 047 * <li class='jm'>{@link FluentObjectAssertion#isNotAny(Object...) isNotAny(Object...)} 048 * <li class='jm'>{@link FluentObjectAssertion#isNull() isNull()} 049 * <li class='jm'>{@link FluentObjectAssertion#isNotNull() isNotNull()} 050 * <li class='jm'>{@link FluentObjectAssertion#isString(String) isString(String)} 051 * <li class='jm'>{@link FluentObjectAssertion#isJson(String) isJson(String)} 052 * <li class='jm'>{@link FluentObjectAssertion#isSame(Object) isSame(Object)} 053 * <li class='jm'>{@link FluentObjectAssertion#isSameJsonAs(Object) isSameJsonAs(Object)} 054 * <li class='jm'>{@link FluentObjectAssertion#isSameSortedJsonAs(Object) isSameSortedJsonAs(Object)} 055 * <li class='jm'>{@link FluentObjectAssertion#isSameSerializedAs(Object, WriterSerializer) isSameSerializedAs(Object, WriterSerializer)} 056 * <li class='jm'>{@link FluentObjectAssertion#isType(Class) isType(Class)} 057 * <li class='jm'>{@link FluentObjectAssertion#isExactType(Class) isExactType(Class)} 058 * </ul> 059 * </ul> 060 * 061 * <h5 class='topic'>Transform Methods</h5> 062 * <p> 063 * <ul class='javatree'> 064 * <li class='jc'>{@link FluentResponseBodyAssertion} 065 * <ul class='javatreec'> 066 * <li class='jm'>{@link FluentResponseBodyAssertion#asBytes() asBytes()} 067 * <li class='jm'>{@link FluentResponseBodyAssertion#as(Class) as(Class)} 068 * <li class='jm'>{@link FluentResponseBodyAssertion#as(Type,Type...) as(Type,Type...)} 069 * </ul> 070 * <li class='jc'>{@link FluentObjectAssertion} 071 * <ul class='javatreec'> 072 * <li class='jm'>{@link FluentObjectAssertion#asString() asString()} 073 * <li class='jm'>{@link FluentObjectAssertion#asString(WriterSerializer) asString(WriterSerializer)} 074 * <li class='jm'>{@link FluentObjectAssertion#asString(Function) asString(Function)} 075 * <li class='jm'>{@link FluentObjectAssertion#asJson() asJson()} 076 * <li class='jm'>{@link FluentObjectAssertion#asJsonSorted() asJsonSorted()} 077 * <li class='jm'>{@link FluentObjectAssertion#asTransformed(Function) asApplied(Function)} 078 * <li class='jm'>{@link FluentObjectAssertion#asAny() asAny()} 079 * </ul> 080 * </ul> 081 * 082 * <h5 class='topic'>Configuration Methods</h5> 083 * <p> 084 * <ul class='javatree'> 085 * <li class='jc'>{@link Assertion} 086 * <ul class='javatreec'> 087 * <li class='jm'>{@link Assertion#setMsg(String, Object...) setMsg(String, Object...)} 088 * <li class='jm'>{@link Assertion#setOut(PrintStream) setOut(PrintStream)} 089 * <li class='jm'>{@link Assertion#setSilent() setSilent()} 090 * <li class='jm'>{@link Assertion#setStdOut() setStdOut()} 091 * <li class='jm'>{@link Assertion#setThrowable(Class) setThrowable(Class)} 092 * </ul> 093 * </ul> 094 * 095 * <h5 class='section'>See Also:</h5><ul> 096 * <li class='link'><a class="doclink" href="../../../../../../index.html#ja.Overview">juneau-assertions</a> 097 * <li class='link'><a class="doclink" href="../../../../../../index.html#juneau-rest-client">juneau-rest-client</a> 098 * </ul> 099 * 100 * @param <R> The return type. 101 */ 102@FluentSetters(returns="FluentResponseBodyAssertion<R>") 103public class FluentResponseBodyAssertion<R> extends FluentObjectAssertion<ResponseContent,R> { 104 105 //----------------------------------------------------------------------------------------------------------------- 106 // Constructors 107 //----------------------------------------------------------------------------------------------------------------- 108 109 /** 110 * Constructor. 111 * 112 * @param value 113 * The object being tested. 114 * <br>Can be <jk>null</jk>. 115 * @param returns 116 * The object to return after a test method is called. 117 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 118 * used on the same assertion. 119 */ 120 public FluentResponseBodyAssertion(ResponseContent value, R returns) { 121 this(null, value, returns); 122 } 123 124 /** 125 * Chained constructor. 126 * 127 * <p> 128 * Used when transforming one assertion into another so that the assertion config can be used by the new assertion. 129 * 130 * @param creator 131 * The assertion that created this assertion. 132 * <br>Should be <jk>null</jk> if this is the top-level assertion. 133 * @param value 134 * The object being tested. 135 * <br>Can be <jk>null</jk>. 136 * @param returns 137 * The object to return after a test method is called. 138 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 139 * used on the same assertion. 140 */ 141 public FluentResponseBodyAssertion(Assertion creator, ResponseContent value, R returns) { 142 super(creator, value, returns); 143 setThrowable(BadRequest.class); 144 } 145 146 //----------------------------------------------------------------------------------------------------------------- 147 // Transform methods 148 //----------------------------------------------------------------------------------------------------------------- 149 150 /** 151 * Provides the ability to perform fluent-style assertions on this response body. 152 * 153 * <h5 class='section'>Examples:</h5> 154 * <p class='bjava'> 155 * <jc>// Validates the response body equals the text "OK".</jc> 156 * <jv>client</jv> 157 * .get(<jsf>URI</jsf>) 158 * .run() 159 * .assertContent().is(<js>"OK"</js>); 160 * 161 * <jc>// Validates the response body contains the text "OK".</jc> 162 * <jv>client</jv> 163 * .get(<jsf>URI</jsf>) 164 * .run() 165 * .assertContent().isContains(<js>"OK"</js>); 166 * 167 * <jc>// Validates the response body passes a predicate test.</jc> 168 * <jv>client</jv> 169 * .get(<jsf>URI</jsf>) 170 * .run() 171 * .assertContent().is(<jv>x</jv> -> <jv>x</jv>.contains(<js>"OK"</js>)); 172 * 173 * <jc>// Validates the response body matches a regular expression.</jc> 174 * <jv>client</jv> 175 * .get(<jsf>URI</jsf>) 176 * .run() 177 * .assertContent().isPattern(<js>".*OK.*"</js>); 178 * 179 * <jc>// Validates the response body matches a regular expression using regex flags.</jc> 180 * <jv>client</jv> 181 * .get(<jsf>URI</jsf>) 182 * .run() 183 * .assertContent().isPattern(<js>".*OK.*"</js>, <jsf>MULTILINE</jsf> & <jsf>CASE_INSENSITIVE</jsf>); 184 * 185 * <jc>// Validates the response body matches a regular expression in the form of an existing Pattern.</jc> 186 * Pattern <jv>pattern</jv> = Pattern.<jsm>compile</jsm>(<js>".*OK.*"</js>); 187 * <jv>client</jv> 188 * .get(<jsf>URI</jsf>) 189 * .run() 190 * .assertContent().isPattern(<jv>pattern</jv>); 191 * </p> 192 * 193 * <p> 194 * The assertion test returns the original response object allowing you to chain multiple requests like so: 195 * <p class='bjava'> 196 * <jc>// Validates the response body matches a regular expression.</jc> 197 * MyBean <jv>bean</jv> = <jv>client</jv> 198 * .get(<jsf>URI</jsf>) 199 * .run() 200 * .assertContent().isPattern(<js>".*OK.*"</js>); 201 * .assertContent().isNotPattern(<js>".*ERROR.*"</js>) 202 * .getContent().as(MyBean.<jk>class</jk>); 203 * </p> 204 * 205 * <h5 class='section'>Notes:</h5><ul> 206 * <li class='note'> 207 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 208 * <li class='note'> 209 * When using this method, the body is automatically cached by calling the {@link ResponseContent#cache()}. 210 * <li class='note'> 211 * The input stream is automatically closed after this call. 212 * </ul> 213 * 214 * @return A new fluent assertion object. 215 */ 216 @Override 217 public FluentStringAssertion<R> asString() { 218 return new FluentStringAssertion<>(valueAsString(), returns()); 219 } 220 221 /** 222 * Provides the ability to perform fluent-style assertions on the bytes of the response body. 223 * 224 * <h5 class='section'>Examples:</h5> 225 * <p class='bjava'> 226 * <jc>// Validates the response body equals the text "foo".</jc> 227 * <jv>client</jv> 228 * .get(<jsf>URI</jsf>) 229 * .run() 230 * .assertContent().asBytes().asHex().is(<js>"666F6F"</js>); 231 * </p> 232 * 233 * <h5 class='section'>Notes:</h5><ul> 234 * <li class='note'> 235 * If no charset was found on the <code>Content-Type</code> response header, <js>"UTF-8"</js> is assumed. 236 * <li class='note'> 237 * When using this method, the body is automatically cached by calling the {@link ResponseContent#cache()}. 238 * <li class='note'> 239 * The input stream is automatically closed after this call. 240 * </ul> 241 * 242 * @return A new fluent assertion object. 243 */ 244 public FluentByteArrayAssertion<R> asBytes() { 245 return new FluentByteArrayAssertion<>(valueAsBytes(), returns()); 246 } 247 248 /** 249 * Converts the body to a type using {@link ResponseContent#as(Class)} and then returns the value as an object assertion. 250 * 251 * <h5 class='section'>Examples:</h5> 252 * <p class='bjava'> 253 * <jc>// Validates the response body as a list of strings and validates the length.</jc> 254 * <jv>client</jv> 255 * .get(<js>"/myBean"</js>) 256 * .run() 257 * .assertContent().as(List.<jk>class</jk>, String.<jk>class</jk>).is(<jv>x</jv> -> <jv>x</jv>.size() > 0); 258 * </p> 259 * 260 * @param <T> The object type to create. 261 * @param type The object type to create. 262 * @return A new fluent assertion object. 263 */ 264 public <T> FluentAnyAssertion<T,R> as(Class<T> type) { 265 return new FluentAnyAssertion<>(valueAsType(type), returns()); 266 } 267 268 /** 269 * Converts the body to a type using {@link ResponseContent#as(Type,Type...)} and then returns the value as an object assertion. 270 * 271 * <h5 class='section'>Examples:</h5> 272 * <p class='bjava'> 273 * <jc>// Validates the response body as a list of strings and validates the length.</jc> 274 * <jv>client</jv> 275 * .get(<js>"/myBean"</js>) 276 * .run() 277 * .assertContent().as(List.<jk>class</jk>, String.<jk>class</jk>).is(<jv>x</jv> -> <jv>x</jv>.size() > 0); 278 * </p> 279 * 280 * <p> 281 * See <a class="doclink" href="../../../../../../index.html#jm.ComplexDataTypes">Complex Data Types</a> for information on defining complex generic types of {@link Map Maps} and {@link Collection Collections}. 282 * 283 * @param type The object type to create. 284 * @param args Optional type arguments. 285 * @return A new fluent assertion object. 286 */ 287 public FluentAnyAssertion<Object,R> as(Type type, Type...args) { 288 return new FluentAnyAssertion<>(valueAsType(type, args), returns()); 289 } 290 291 //----------------------------------------------------------------------------------------------------------------- 292 // Test methods 293 //----------------------------------------------------------------------------------------------------------------- 294 295 /** 296 * Asserts that the body contains the specified value. 297 * 298 * @param value The value to check against. 299 * @return This object. 300 * @throws AssertionError If assertion failed. 301 */ 302 public R is(String value) throws AssertionError { 303 return asString().is(value); 304 } 305 306 /** 307 * Asserts that the text contains all of the specified substrings. 308 * 309 * @param values The values to check against. 310 * @return This object. 311 * @throws AssertionError If assertion failed. 312 */ 313 public R isContains(String...values) throws AssertionError { 314 return asString().isContains(values); 315 } 316 317 /** 318 * Asserts that the body doesn't contain any of the specified substrings. 319 * 320 * @param values The values to check against. 321 * @return This object. 322 * @throws AssertionError If assertion failed. 323 */ 324 public R isNotContains(String...values) throws AssertionError { 325 return asString().isNotContains(values); 326 } 327 328 /** 329 * Asserts that the body is empty. 330 * 331 * @return This object. 332 * @throws AssertionError If assertion failed. 333 */ 334 public R isEmpty() { 335 return asString().isEmpty(); 336 } 337 338 /** 339 * Asserts that the body is not empty. 340 * 341 * @return This object. 342 * @throws AssertionError If assertion failed. 343 */ 344 public R isNotEmpty() { 345 return asString().isNotEmpty(); 346 } 347 348 //----------------------------------------------------------------------------------------------------------------- 349 // Helper methods. 350 //----------------------------------------------------------------------------------------------------------------- 351 352 @Override 353 protected String valueAsString() throws AssertionError { 354 try { 355 return value().cache().asString(); 356 } catch (RestCallException e) { 357 throw error(e, "Exception occurred during call."); 358 } 359 } 360 361 private byte[] valueAsBytes() throws AssertionError { 362 try { 363 return value().cache().asBytes(); 364 } catch (RestCallException e) { 365 throw error(e, "Exception occurred during call."); 366 } 367 } 368 369 private <T> T valueAsType(Type type, Type...args) throws AssertionError { 370 try { 371 return value().cache().as(type, args); 372 } catch (RestCallException e) { 373 throw error(e, "Exception occurred during call."); 374 } 375 } 376 377 //----------------------------------------------------------------------------------------------------------------- 378 // Fluent setters 379 //----------------------------------------------------------------------------------------------------------------- 380 381 // <FluentSetters> 382 383 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 384 public FluentResponseBodyAssertion<R> setMsg(String msg, Object...args) { 385 super.setMsg(msg, args); 386 return this; 387 } 388 389 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 390 public FluentResponseBodyAssertion<R> setOut(PrintStream value) { 391 super.setOut(value); 392 return this; 393 } 394 395 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 396 public FluentResponseBodyAssertion<R> setSilent() { 397 super.setSilent(); 398 return this; 399 } 400 401 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 402 public FluentResponseBodyAssertion<R> setStdOut() { 403 super.setStdOut(); 404 return this; 405 } 406 407 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 408 public FluentResponseBodyAssertion<R> setThrowable(Class<? extends java.lang.RuntimeException> value) { 409 super.setThrowable(value); 410 return this; 411 } 412 413 // </FluentSetters> 414}