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