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.common.internal.*;
018import org.apache.juneau.cp.*;
019
020/**
021 * Utility class for performing simple validations on objects.
022 *
023 * <p>
024 * Verifications that pass return a null string.  Verifications that don't pass return a string with a useful
025 * error message.
026 *
027 * <h5 class='section'>Example:</h5>
028 * <p class='bjava'>
029 *    <jc>// Validates that our POJO is of type MyBean.</jc>
030 *    String <jv>errorMessage</jv> = <jsm>verify</jsm>(<jv>myPojo</jv>).isType(MyBean.<jk>class</jk>);
031 *    <jk>if</jk> (<jv>errorMessage</jv> != <jk>null</jk>)
032 *       <jk>throw new</jk> RuntimeException(<jv>errorMessage</jv>);
033 * </p>
034 *
035 * <h5 class='section'>See Also:</h5><ul>
036 *    <li class='link'><a class="doclink" href="../../../../index.html#ja.Overview">Overview &gt; juneau-assertions &gt; Overview</a>
037 * </ul>
038 */
039public class Verify {
040
041   //-----------------------------------------------------------------------------------------------------------------
042   // Static
043   //-----------------------------------------------------------------------------------------------------------------
044
045   private static final Messages MESSAGES = Messages.of(Verify.class, "Messages");
046   static final String
047      MSG_unexpectedType = MESSAGES.getString("unexpectedType"),
048      MSG_unexpectedValue = MESSAGES.getString("unexpectedValue");
049
050   /**
051    * Create a new verifier object.
052    *
053    * @param o The object being verified.
054    * @return A new verifier object.
055    */
056   public static Verify verify(Object o) {
057      return new Verify(o);
058   }
059
060   //-----------------------------------------------------------------------------------------------------------------
061   // Instance
062   //-----------------------------------------------------------------------------------------------------------------
063
064   private final Object o;
065   private Supplier<String> msg;
066
067   /**
068    * Create a new verifier object.
069    *
070    * @param o The object being verified.
071    */
072   protected Verify(Object o) {
073      this.o = o;
074   }
075
076   //-----------------------------------------------------------------------------------------------------------------
077   // Config setters
078   //-----------------------------------------------------------------------------------------------------------------
079
080   /**
081    * Overrides the default error message produced by the verification.
082    *
083    * @param msg The error message.
084    * @param args Optional message arguments.
085    * @return This object.
086    */
087   public Verify msg(String msg, Object args) {
088      this.msg = () -> StringUtils.format(msg, args);
089      return this;
090   }
091
092   //-----------------------------------------------------------------------------------------------------------------
093   // Test methods
094   //-----------------------------------------------------------------------------------------------------------------
095
096   /**
097    * Verifies that this object is of the specified type.
098    *
099    * @param type The type to test against.
100    * @return An error message if the object is not of the specified type, otherwise <jk>null</jk>.
101    */
102   public String isType(Class<?> type) {
103      if ((type == null && o == null) || (type != null && type.isInstance(o)))
104         return null;
105      return msg != null ? msg.get() : StringUtils.format(MSG_unexpectedType, type, (o == null ? null : o.getClass()));
106   }
107
108   /**
109    * Verifies that this object is equal to the specified object.
110    *
111    * @param expected The object to test against for equality.
112    * @return An error message if the object is not equal to the specified object, otherwise <jk>null</jk>.
113    */
114   public String is(Object expected) {
115      if (expected == o)
116         return null;
117      if (expected == null || o == null || ! expected.equals(o))
118         return msg != null ? msg.get() : StringUtils.format(MSG_unexpectedValue, expected, o);
119      return null;
120   }
121
122   /**
123    * Verifies that this object is equal to {@link Boolean#TRUE}.
124    *
125    * @return An error message if the object is not true, otherwise <jk>null</jk>.
126    */
127   public String isTrue() {
128      return is(true);
129   }
130
131   /**
132    * Verifies that this object is equal to {@link Boolean#FALSE}.
133    *
134    * @return An error message if the object is not false, otherwise <jk>null</jk>.
135    */
136   public String isFalse() {
137      return is(false);
138   }
139}