001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.assertions;
018
019import java.util.function.*;
020
021import org.apache.juneau.common.utils.*;
022import org.apache.juneau.cp.*;
023
024/**
025 * Utility class for performing simple validations on objects.
026 *
027 * <p>
028 * Verifications that pass return a null string.  Verifications that don't pass return a string with a useful
029 * error message.
030 *
031 * <h5 class='section'>Example:</h5>
032 * <p class='bjava'>
033 *    <jc>// Validates that our POJO is of type MyBean.</jc>
034 *    String <jv>errorMessage</jv> = <jsm>verify</jsm>(<jv>myPojo</jv>).isType(MyBean.<jk>class</jk>);
035 *    <jk>if</jk> (<jv>errorMessage</jv> != <jk>null</jk>)
036 *       <jk>throw new</jk> RuntimeException(<jv>errorMessage</jv>);
037 * </p>
038 *
039 * <h5 class='section'>See Also:</h5><ul>
040 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/JuneauEcosystemOverview">Juneau Ecosystem Overview</a>
041 * </ul>
042 */
043public class Verify {
044
045   //-----------------------------------------------------------------------------------------------------------------
046   // Static
047   //-----------------------------------------------------------------------------------------------------------------
048
049   private static final Messages MESSAGES = Messages.of(Verify.class, "Messages");
050   static final String
051      MSG_unexpectedType = MESSAGES.getString("unexpectedType"),
052      MSG_unexpectedValue = MESSAGES.getString("unexpectedValue");
053
054   /**
055    * Create a new verifier object.
056    *
057    * @param o The object being verified.
058    * @return A new verifier object.
059    */
060   public static Verify verify(Object o) {
061      return new Verify(o);
062   }
063
064   //-----------------------------------------------------------------------------------------------------------------
065   // Instance
066   //-----------------------------------------------------------------------------------------------------------------
067
068   private final Object o;
069   private Supplier<String> msg;
070
071   /**
072    * Create a new verifier object.
073    *
074    * @param o The object being verified.
075    */
076   protected Verify(Object o) {
077      this.o = o;
078   }
079
080   //-----------------------------------------------------------------------------------------------------------------
081   // Config setters
082   //-----------------------------------------------------------------------------------------------------------------
083
084   /**
085    * Overrides the default error message produced by the verification.
086    *
087    * @param msg The error message.
088    * @param args Optional message arguments.
089    * @return This object.
090    */
091   public Verify msg(String msg, Object args) {
092      this.msg = () -> StringUtils.format(msg, args);
093      return this;
094   }
095
096   //-----------------------------------------------------------------------------------------------------------------
097   // Test methods
098   //-----------------------------------------------------------------------------------------------------------------
099
100   /**
101    * Verifies that this object is of the specified type.
102    *
103    * @param type The type to test against.
104    * @return An error message if the object is not of the specified type, otherwise <jk>null</jk>.
105    */
106   public String isType(Class<?> type) {
107      if ((type == null && o == null) || (type != null && type.isInstance(o)))
108         return null;
109      var c = o == null ? null : o.getClass();
110      return msg != null ? msg.get() : StringUtils.format(MSG_unexpectedType, type, c);
111   }
112
113   /**
114    * Verifies that this object is equal to the specified object.
115    *
116    * @param expected The object to test against for equality.
117    * @return An error message if the object is not equal to the specified object, otherwise <jk>null</jk>.
118    */
119   public String is(Object expected) {
120      if (expected == o)
121         return null;
122      if (expected == null || o == null || ! expected.equals(o))
123         return msg != null ? msg.get() : StringUtils.format(MSG_unexpectedValue, expected, o);
124      return null;
125   }
126
127   /**
128    * Verifies that this object is equal to {@link Boolean#TRUE}.
129    *
130    * @return An error message if the object is not true, otherwise <jk>null</jk>.
131    */
132   public String isTrue() {
133      return is(true);
134   }
135
136   /**
137    * Verifies that this object is equal to {@link Boolean#FALSE}.
138    *
139    * @return An error message if the object is not false, otherwise <jk>null</jk>.
140    */
141   public String isFalse() {
142      return is(false);
143   }
144}