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 static org.apache.juneau.common.internal.ArgUtils.*;
016
017import java.io.*;
018import java.time.*;
019import java.time.temporal.*;
020import java.util.function.*;
021
022import org.apache.juneau.cp.*;
023import org.apache.juneau.internal.*;
024import org.apache.juneau.serializer.*;
025
026/**
027 * Used for fluent assertion calls against {@link ZonedDateTime} objects.
028 *
029 * <h5 class='section'>Example:</h5>
030 * <p class='bjava'>
031 *    <jc>// Validates the response expiration is after the current date.</jc>
032 *    <jv>client</jv>
033 *       .get(<jsf>URL</jsf>)
034 *       .run()
035 *       .getHeader(<js>"Expires"</js>).asDateHeader().assertZonedDateTime().isAfterNow();
036 * </p>
037 *
038 *
039 * <h5 class='section'>Test Methods:</h5>
040 * <p>
041 * <ul class='javatree'>
042 *    <li class='jc'>{@link FluentZonedDateTimeAssertion}
043 *    <ul class='javatreec'>
044 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#is(ZonedDateTime,ChronoUnit) is(ZonedDateTime,ChronoUnit)}
045 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#isAfter(ZonedDateTime) isAfter(ZonedDateTime)}
046 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#isAfterNow() isAfterNow()}
047 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#isBefore(ZonedDateTime) isBefore(ZonedDateTime)}
048 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#isBeforeNow() isBeforeNow()}
049 *       <li class='jm'>{@link FluentZonedDateTimeAssertion#isBetween(ZonedDateTime,ZonedDateTime) isBetween(ZonedDateTime,ZonedDateTime)}
050 *    </ul>
051 *    <li class='jc'>{@link FluentComparableAssertion}
052 *    <ul class='javatreec'>
053 *       <li class='jm'>{@link FluentComparableAssertion#isGt(Comparable) isGt(Comparable)}
054 *       <li class='jm'>{@link FluentComparableAssertion#isGte(Comparable) isGte(Comparable)}
055 *       <li class='jm'>{@link FluentComparableAssertion#isLt(Comparable) isLt(Comparable)}
056 *       <li class='jm'>{@link FluentComparableAssertion#isLte(Comparable) isLte(Comparable)}
057 *       <li class='jm'>{@link FluentComparableAssertion#isBetween(Comparable,Comparable) isBetween(Comparable,Comparable)}
058  *   </ul>
059 *    <li class='jc'>{@link FluentObjectAssertion}
060 *    <ul class='javatreec'>
061 *       <li class='jm'>{@link FluentObjectAssertion#isExists() isExists()}
062 *       <li class='jm'>{@link FluentObjectAssertion#is(Object) is(Object)}
063 *       <li class='jm'>{@link FluentObjectAssertion#is(Predicate) is(Predicate)}
064 *       <li class='jm'>{@link FluentObjectAssertion#isNot(Object) isNot(Object)}
065 *       <li class='jm'>{@link FluentObjectAssertion#isAny(Object...) isAny(Object...)}
066 *       <li class='jm'>{@link FluentObjectAssertion#isNotAny(Object...) isNotAny(Object...)}
067 *       <li class='jm'>{@link FluentObjectAssertion#isNull() isNull()}
068 *       <li class='jm'>{@link FluentObjectAssertion#isNotNull() isNotNull()}
069 *       <li class='jm'>{@link FluentObjectAssertion#isString(String) isString(String)}
070 *       <li class='jm'>{@link FluentObjectAssertion#isJson(String) isJson(String)}
071 *       <li class='jm'>{@link FluentObjectAssertion#isSame(Object) isSame(Object)}
072 *       <li class='jm'>{@link FluentObjectAssertion#isSameJsonAs(Object) isSameJsonAs(Object)}
073 *       <li class='jm'>{@link FluentObjectAssertion#isSameSortedJsonAs(Object) isSameSortedJsonAs(Object)}
074 *       <li class='jm'>{@link FluentObjectAssertion#isSameSerializedAs(Object, WriterSerializer) isSameSerializedAs(Object, WriterSerializer)}
075 *       <li class='jm'>{@link FluentObjectAssertion#isType(Class) isType(Class)}
076 *       <li class='jm'>{@link FluentObjectAssertion#isExactType(Class) isExactType(Class)}
077 *    </ul>
078 * </ul>
079 *
080 * <h5 class='section'>Transform Methods:</h5>
081 * <p>
082 * <ul class='javatree'>
083 *    <li class='jc'>{@link FluentObjectAssertion}
084 *    <ul class='javatreec'>
085 *       <li class='jm'>{@link FluentObjectAssertion#asString() asString()}
086 *       <li class='jm'>{@link FluentObjectAssertion#asString(WriterSerializer) asString(WriterSerializer)}
087 *       <li class='jm'>{@link FluentObjectAssertion#asString(Function) asString(Function)}
088 *       <li class='jm'>{@link FluentObjectAssertion#asJson() asJson()}
089 *       <li class='jm'>{@link FluentObjectAssertion#asJsonSorted() asJsonSorted()}
090 *       <li class='jm'>{@link FluentObjectAssertion#asTransformed(Function) asApplied(Function)}
091 *       <li class='jm'>{@link FluentObjectAssertion#asAny() asAny()}
092 * </ul>
093 * </ul>
094 *
095 * <h5 class='section'>Configuration Methods:</h5>
096 * <p>
097 * <ul class='javatree'>
098 *    <li class='jc'>{@link Assertion}
099 *    <ul class='javatreec'>
100 *       <li class='jm'>{@link Assertion#setMsg(String, Object...) setMsg(String, Object...)}
101 *       <li class='jm'>{@link Assertion#setOut(PrintStream) setOut(PrintStream)}
102 *       <li class='jm'>{@link Assertion#setSilent() setSilent()}
103 *       <li class='jm'>{@link Assertion#setStdOut() setStdOut()}
104 *       <li class='jm'>{@link Assertion#setThrowable(Class) setThrowable(Class)}
105 *    </ul>
106 * </ul>
107 *
108 * <h5 class='section'>See Also:</h5><ul>
109 *    <li class='link'><a class="doclink" href="../../../../index.html#ja.Overview">Overview &gt; juneau-assertions &gt; Overview</a>
110 * </ul>
111 *
112 * @param <R> The return type.
113 */
114@FluentSetters(returns="FluentZonedDateTimeAssertion<R>")
115public class FluentZonedDateTimeAssertion<R> extends FluentComparableAssertion<ZonedDateTime,R> {
116
117   //-----------------------------------------------------------------------------------------------------------------
118   // Static
119   //-----------------------------------------------------------------------------------------------------------------
120
121   private static final Messages MESSAGES = Messages.of(FluentZonedDateTimeAssertion.class, "Messages");
122   private static final String
123      MSG_unexpectedValue = MESSAGES.getString("unexpectedValue"),
124      MSG_valueWasNotAfterExpected = MESSAGES.getString("valueWasNotAfterExpected"),
125      MSG_valueWasNotBeforeExpected = MESSAGES.getString("valueWasNotBeforeExpected");
126
127   //-----------------------------------------------------------------------------------------------------------------
128   // Instance
129   //-----------------------------------------------------------------------------------------------------------------
130
131   /**
132    * Constructor.
133    *
134    * @param value
135    *    The object being tested.
136    *    <br>Can be <jk>null</jk>.
137    * @param returns
138    *    The object to return after a test method is called.
139    *    <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be
140    * used on the same assertion.
141    */
142   public FluentZonedDateTimeAssertion(ZonedDateTime value, R returns) {
143      this(null, value, returns);
144   }
145
146   /**
147    * Chained constructor.
148    *
149    * <p>
150    * Used when transforming one assertion into another so that the assertion config can be used by the new assertion.
151    *
152    * @param creator
153    *    The assertion that created this assertion.
154    *    <br>Should be <jk>null</jk> if this is the top-level assertion.
155    * @param value
156    *    The object being tested.
157    *    <br>Can be <jk>null</jk>.
158    * @param returns
159    *    The object to return after a test method is called.
160    *    <br>If <jk>null</jk>, the test method returns this object allowing multiple test method calls to be
161    * used on the same assertion.
162    */
163   public FluentZonedDateTimeAssertion(Assertion creator, ZonedDateTime value, R returns) {
164      super(creator, value, returns);
165   }
166
167   //-----------------------------------------------------------------------------------------------------------------
168   // Test methods
169   //-----------------------------------------------------------------------------------------------------------------
170
171   /**
172    * Asserts that the value equals the specified value at the specified precision.
173    *
174    * @param value The value to check against.
175    * @param precision The precision (e.g. {@link ChronoUnit#SECONDS}.
176    * @return The fluent return object.
177    * @throws AssertionError If assertion failed.
178    */
179   public R is(ZonedDateTime value, ChronoUnit precision) throws AssertionError {
180      assertArgNotNull("precision", precision);
181      ZonedDateTime v = orElse(null);
182      if (valueIsNull() && value == null)
183         return returns();
184      if (valueIsNotNull() && value != null) {
185         Duration d = Duration.between(value(), value);
186         if (d.compareTo(precision.getDuration()) <= 0)
187            return returns();
188      }
189      throw error(MSG_unexpectedValue, value, v);
190   }
191
192   /**
193    * Asserts that the value is after the specified value.
194    *
195    * @param value The values to check against.
196    * @return The fluent return object.
197    * @throws AssertionError If assertion failed.
198    */
199   public R isAfter(ZonedDateTime value) throws AssertionError {
200      assertArgNotNull("value", value);
201      if (! (value().isAfter(value)))
202         throw error(MSG_valueWasNotAfterExpected, value, value());
203      return returns();
204   }
205
206   /**
207    * Asserts that the value is after the current date.
208    *
209    * @return The fluent return object.
210    * @throws AssertionError If assertion failed.
211    */
212   public R isAfterNow() throws AssertionError {
213      return isAfter(ZonedDateTime.now());
214   }
215
216   /**
217    * Asserts that the value is before the specified value.
218    *
219    * @param value The values to check against.
220    * @return The fluent return object.
221    * @throws AssertionError If assertion failed.
222    */
223   public R isBefore(ZonedDateTime value) throws AssertionError {
224      assertArgNotNull("value", value);
225      if (! (value().isBefore(value)))
226         throw error(MSG_valueWasNotBeforeExpected, value, value());
227      return returns();
228   }
229
230   /**
231    * Asserts that the value is before the current date.
232    *
233    * @return The fluent return object.
234    * @throws AssertionError If assertion failed.
235    */
236   public R isBeforeNow() throws AssertionError {
237      return isBefore(ZonedDateTime.now());
238   }
239
240   /**
241    * Asserts that the value is between (inclusive) the specified upper and lower values.
242    *
243    * @param lower The lower value to check against.
244    * @param upper The upper value to check against.
245    * @return The fluent return object.
246    * @throws AssertionError If assertion failed.
247    */
248   public R isBetween(ZonedDateTime lower, ZonedDateTime upper) throws AssertionError {
249      isExists();
250      assertArgNotNull("lower", lower);
251      assertArgNotNull("upper", upper);
252      isLte(upper);
253      isGte(lower);
254      return returns();
255   }
256
257   //-----------------------------------------------------------------------------------------------------------------
258   // Fluent setters
259   //-----------------------------------------------------------------------------------------------------------------
260
261   // <FluentSetters>
262
263   @Override /* GENERATED - org.apache.juneau.assertions.Assertion */
264   public FluentZonedDateTimeAssertion<R> setMsg(String msg, Object...args) {
265      super.setMsg(msg, args);
266      return this;
267   }
268
269   @Override /* GENERATED - org.apache.juneau.assertions.Assertion */
270   public FluentZonedDateTimeAssertion<R> setOut(PrintStream value) {
271      super.setOut(value);
272      return this;
273   }
274
275   @Override /* GENERATED - org.apache.juneau.assertions.Assertion */
276   public FluentZonedDateTimeAssertion<R> setSilent() {
277      super.setSilent();
278      return this;
279   }
280
281   @Override /* GENERATED - org.apache.juneau.assertions.Assertion */
282   public FluentZonedDateTimeAssertion<R> setStdOut() {
283      super.setStdOut();
284      return this;
285   }
286
287   @Override /* GENERATED - org.apache.juneau.assertions.Assertion */
288   public FluentZonedDateTimeAssertion<R> setThrowable(Class<? extends java.lang.RuntimeException> value) {
289      super.setThrowable(value);
290      return this;
291   }
292
293   // </FluentSetters>
294}