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