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.assertions; 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.httppart.*; 024import org.apache.juneau.serializer.*; 025 026/** 027 * Used for fluent assertion calls against {@link RequestContent} objects. 028 * 029 * <h5 class='topic'>Test Methods</h5> 030 * <p> 031 * <ul class='javatree'> 032 * <li class='jc'>{@link FluentRequestContentAssertion} 033 * <ul class='javatreec'> 034 * <li class='jm'>{@link FluentRequestContentAssertion#is(String) is(String)} 035 * <li class='jm'>{@link FluentRequestContentAssertion#isContains(String...) isContains(String...)} 036 * <li class='jm'>{@link FluentRequestContentAssertion#isNotContains(String...) isNotContains(String...)} 037 * <li class='jm'>{@link FluentRequestContentAssertion#isEmpty() isEmpty()} 038 * <li class='jm'>{@link FluentRequestContentAssertion#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 FluentRequestContentAssertion} 065 * <ul class='javatreec'> 066 * <li class='jm'>{@link FluentRequestContentAssertion#asBytes() asBytes()} 067 * <li class='jm'>{@link FluentRequestContentAssertion#as(Class) as(Class)} 068 * <li class='jm'>{@link FluentRequestContentAssertion#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 * </ul> 098 * 099 * @param <R> The return type. 100 */ 101@FluentSetters(returns="FluentRequestContentAssertion<R>") 102public class FluentRequestContentAssertion<R> extends FluentObjectAssertion<RequestContent,R> { 103 104 //----------------------------------------------------------------------------------------------------------------- 105 // Constructors 106 //----------------------------------------------------------------------------------------------------------------- 107 108 /** 109 * Constructor. 110 * 111 * @param value 112 * The object being tested. 113 * <br>Can be <jk>null</jk>. 114 * @param returns 115 * The object to return after a test method is called. 116 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 117 * used on the same assertion. 118 */ 119 public FluentRequestContentAssertion(RequestContent value, R returns) { 120 this(null, value, returns); 121 } 122 123 /** 124 * Chained constructor. 125 * 126 * <p> 127 * Used when transforming one assertion into another so that the assertion config can be used by the new assertion. 128 * 129 * @param creator 130 * The assertion that created this assertion. 131 * <br>Should be <jk>null</jk> if this is the top-level assertion. 132 * @param value 133 * The object being tested. 134 * <br>Can be <jk>null</jk>. 135 * @param returns 136 * The object to return after a test method is called. 137 * <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be 138 * used on the same assertion. 139 */ 140 public FluentRequestContentAssertion(Assertion creator, RequestContent value, R returns) { 141 super(creator, value, returns); 142 setThrowable(BadRequest.class); 143 } 144 145 //----------------------------------------------------------------------------------------------------------------- 146 // Transform methods 147 //----------------------------------------------------------------------------------------------------------------- 148 149 /** 150 * Provides the ability to perform fluent-style assertions on the bytes of the request content. 151 * 152 * <h5 class='section'>Examples:</h5> 153 * <p class='bjava'> 154 * <jc>// Validates the request content equals the text "foo".</jc> 155 * <jv>request</jv> 156 * .assertContent().asBytes().asHex().is(<js>"666F6F"</js>); 157 * </p> 158 * 159 * <h5 class='section'>Notes:</h5><ul> 160 * <li class='note'> 161 * If no charset was found on the <code>Content-Type</code> request header, <js>"UTF-8"</js> is assumed. 162 * <li class='note'> 163 * When using this method, the content is automatically cached by calling the {@link RequestContent#cache()}. 164 * <li class='note'> 165 * The input stream is automatically closed after this call. 166 * </ul> 167 * 168 * @return A new fluent assertion object. 169 */ 170 public FluentByteArrayAssertion<R> asBytes() { 171 return new FluentByteArrayAssertion<>(valueAsBytes(), returns()); 172 } 173 174 /** 175 * Converts the content to a type using {@link RequestContent#as(Class)} and then returns the value as an object assertion. 176 * 177 * <h5 class='section'>Examples:</h5> 178 * <p class='bjava'> 179 * <jc>// Validates the request content bean is the expected value.</jc> 180 * <jv>request</jv> 181 * .assertContent() 182 * .as(MyBean.<jk>class</jk>) 183 * .asJson().is(<js>"{foo:'bar'}"</js>); 184 * </p> 185 * 186 * <h5 class='section'>Notes:</h5><ul> 187 * <li class='note'> 188 * If no charset was found on the <code>Content-Type</code> request header, <js>"UTF-8"</js> is assumed. 189 * <li class='note'> 190 * When using this method, the content is automatically cached by calling the {@link RequestContent#cache()}. 191 * <li class='note'> 192 * The input stream is automatically closed after this call. 193 * </ul> 194 * 195 * <p> 196 * 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}. 197 * 198 * @param <T> The object type to create. 199 * @param type The object type to create. 200 * @return A new fluent assertion object. 201 */ 202 public <T> FluentObjectAssertion<T,R> as(Class<T> type) { 203 return new FluentObjectAssertion<>(valueAsType(type), returns()); 204 } 205 206 /** 207 * Converts the content to a type using {@link RequestContent#as(Type,Type...)} and then returns the value as an object assertion. 208 * 209 * <h5 class='section'>Examples:</h5> 210 * <p class='bjava'> 211 * <jc>// Validates the request content bean is the expected value.</jc> 212 * <jv>request</jv> 213 * .assertContent() 214 * .as(Map.<jk>class</jk>,String.<jk>class</jk>,Integer.<jk>class</jk>) 215 * .asJson().is(<js>"{foo:123}"</js>); 216 * </p> 217 * 218 * <h5 class='section'>Notes:</h5><ul> 219 * <li class='note'> 220 * If no charset was found on the <code>Content-Type</code> request header, <js>"UTF-8"</js> is assumed. 221 * <li class='note'> 222 * When using this method, the content is automatically cached by calling the {@link RequestContent#cache()}. 223 * <li class='note'> 224 * The input stream is automatically closed after this call. 225 * </ul> 226 * 227 * <p> 228 * 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}. 229 * 230 * @param <T> The type to create. 231 * @param type The object type to create. 232 * @param args Optional type arguments. 233 * @return A new fluent assertion object. 234 */ 235 public <T> FluentObjectAssertion<T,R> as(Type type, Type...args) { 236 return new FluentObjectAssertion<>(valueAsType(type, args), returns()); 237 } 238 239 //----------------------------------------------------------------------------------------------------------------- 240 // Test methods 241 //----------------------------------------------------------------------------------------------------------------- 242 243 /** 244 * Asserts that the content contains the specified value. 245 * 246 * @param values The value to check against. 247 * @return This object. 248 * @throws AssertionError If assertion failed. 249 */ 250 public R is(String values) throws AssertionError { 251 return asString().is(values); 252 } 253 254 /** 255 * Asserts that the text contains all of the specified substrings. 256 * 257 * @param values The values to check against. 258 * @return This object. 259 * @throws AssertionError If assertion failed. 260 */ 261 public R isContains(String...values) throws AssertionError { 262 return asString().isContains(values); 263 } 264 265 /** 266 * Asserts that the content doesn't contain any of the specified substrings. 267 * 268 * @param values The values to check against. 269 * @return This object. 270 * @throws AssertionError If assertion failed. 271 */ 272 public R isNotContains(String...values) throws AssertionError { 273 return asString().isNotContains(values); 274 } 275 276 /** 277 * Asserts that the content is empty. 278 * 279 * @return This object. 280 * @throws AssertionError If assertion failed. 281 */ 282 public R isEmpty() { 283 return asString().isEmpty(); 284 } 285 286 /** 287 * Asserts that the content is not empty. 288 * 289 * @return This object. 290 * @throws AssertionError If assertion failed. 291 */ 292 public R isNotEmpty() { 293 return asString().isNotEmpty(); 294 } 295 296 //----------------------------------------------------------------------------------------------------------------- 297 // Helper methods. 298 //----------------------------------------------------------------------------------------------------------------- 299 300 @Override 301 protected String valueAsString() throws AssertionError { 302 try { 303 return value().cache().asString(); 304 } catch (IOException e) { 305 throw error(e, "Exception occurred during call."); 306 } 307 } 308 309 private byte[] valueAsBytes() throws AssertionError { 310 try { 311 return value().cache().asBytes(); 312 } catch (IOException e) { 313 throw error(e, "Exception occurred during call."); 314 } 315 } 316 317 private <T> T valueAsType(Class<T> c) throws AssertionError { 318 try { 319 return value().cache().as(c); 320 } catch (IOException e) { 321 throw error(e, "Exception occurred during call."); 322 } 323 } 324 325 private <T> T valueAsType(Type c, Type...args) throws AssertionError { 326 try { 327 return value().cache().as(c, args); 328 } catch (IOException e) { 329 throw error(e, "Exception occurred during call."); 330 } 331 } 332 333 //----------------------------------------------------------------------------------------------------------------- 334 // Fluent setters 335 //----------------------------------------------------------------------------------------------------------------- 336 337 // <FluentSetters> 338 339 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 340 public FluentRequestContentAssertion<R> setMsg(String msg, Object...args) { 341 super.setMsg(msg, args); 342 return this; 343 } 344 345 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 346 public FluentRequestContentAssertion<R> setOut(PrintStream value) { 347 super.setOut(value); 348 return this; 349 } 350 351 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 352 public FluentRequestContentAssertion<R> setSilent() { 353 super.setSilent(); 354 return this; 355 } 356 357 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 358 public FluentRequestContentAssertion<R> setStdOut() { 359 super.setStdOut(); 360 return this; 361 } 362 363 @Override /* GENERATED - org.apache.juneau.assertions.Assertion */ 364 public FluentRequestContentAssertion<R> setThrowable(Class<? extends java.lang.RuntimeException> value) { 365 super.setThrowable(value); 366 return this; 367 } 368 369 // </FluentSetters> 370}