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}