1 /*
2 * Copyright 2006-2008 The Kuali Foundation
3 *
4 * Licensed under the Educational Community License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/ecl2.php
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package org.kuali.rice.kns.util;
17
18 /**
19 * This class contains utility methods for making assertions in production code (not test code).
20 * Kuali is not using the {@code assert} keyword because those assertions
21 * are not enabled by default. We can use the methods of this class instead, or throw {@link AssertionError} directly. This makes
22 * assertions effective in production and development, and avoids any risk of changes to functionality because any side-effects that
23 * might be involved in the assertion are done consistently. Although {@code AssertionError} can be thrown directly, and sometimes
24 * the compiler requires this, in many cases these method invocations will be easier to read than the extra {@code if} block with
25 * its negated conditional.
26 *
27 * <p/> These assertions are for use in production code. They should not be confused with
28 * {@link junit.framework.Assert}, {@link junit.framework.AssertionFailedError}, nor {@link org.kuali.test.util.KualiTestAssertionUtils},
29 * which are for test code.
30 *
31 * <p/> These methods
32 * should be used such that when they fail and throw {@code AssertionError}, it indicates that there is a bug in our software.
33 * Drawing attention to the bug this way, as soon as it's discovered, reduces the amount of work required to fix it. So, we should
34 * not catch {@code AssertionError} (or {@link Throwable}) and try to handle or work around it; it indicates a need to change some
35 * source code so that the assertion is never false. For more about why, when, and how to use assertions, see <a
36 * href="https://test.kuali.org/confluence/display/KULDEV/Assert+Keyword+And+AssertionError">Kuali's guide to assertions</a> and <a
37 * href="http://java.sun.com/j2se/1.4.2/docs/guide/lang/assert.html">Sun's guide to assertions</a>.
38 *
39 * @see org.kuali.test.util.KualiTestAssertionUtils
40 */
41 public class AssertionUtils {
42
43 /**
44 * Asserts that the {@code isTrue} parameter is true. If this assertion fails, the {@code AssertionError} it throws will have no
45 * detail message, only a stacktrace indicating the source file and line number containing the assertion that failed. <p/> This
46 * method's name is intended to avoid confusion with JUnit asserts (which are for test code, not production code), and its
47 * signature is intended to resemble that of the {@code assert} keyword.
48 *
49 * @param isTrue whether this assertion succeeds. (Boolean objects are auto-unboxed by JDK 1.5.)
50 *
51 * @throws AssertionError if {@code isTrue} is false
52 */
53 public static void assertThat(boolean isTrue) {
54 if (!isTrue) {
55 throw new AssertionError();
56 }
57 }
58
59 /**
60 * Asserts that the {@code isTrue} parameter is true, with a detail message. The purpose of the detail message is to capture and
61 * communicate details about the assertion failure that will help a developer diagnose and fix the bug that led this assertion
62 * to fail. It's meant to be interpreted in the context of a full stack trace and with the source code containing the failed
63 * assertion. It is <em>not</em> a user-level error message. Details like {@code "assertion failed"} are redundant, not
64 * useful. <p/> This method's name is intended to avoid confusion with JUnit asserts (which are for test code, not production
65 * code), and its signature is intended to resemble that of the {@code assert} keyword.
66 *
67 * @param isTrue whether this assertion succeeds. (Boolean objects are auto-unboxed by JDK 1.5.)
68 *
69 * @param detailMessage value to use for the {@code AssertionError}'s detail message. If this is an instance of
70 * {@link Throwable}, then it also becomes the {@code AssertionError}'s cause. (Primitives are auto-boxed by JDK 1.5.)
71 * Objects are converted {@link Object#toString toString}, but only if this assertion fails, so it's better not to
72 * convert this detail in advance. The code will be a little easier to read, and there will be some performance
73 * improvement (altho it may be insignificant). For example, passing just {@code accountingLine} is better than passing
74 * {@code accountingLine.toString()} or {@code "accounting line:"+accountingLine}. Since the assertion has failed, any
75 * inconsistent side-effects from the conversion are not an issue. A {@code null} reference is treated as the String
76 * {@code "null"}.
77 *
78 * @throws AssertionError if {@code isTrue} is false
79 */
80 public static void assertThat(boolean isTrue, Object detailMessage) {
81 if (!isTrue) {
82 throw new AssertionError(detailMessage);
83 }
84 }
85
86 /**
87 * Asserts that the {@code isTrue} parameter is true. This method is convenient for formatting the detail message, and as an
88 * optimization for detail arguments that are expensive to convert to String. For example, suppose {@code foo} and {@code bar}
89 * are two objects with expensive {@link Object#toString} methods. If you use
90 *
91 * <pre>
92 * AssertionUtils.assertThat(foo.equals(bar), "foo: " + foo + " bar: " + bar);
93 * </pre>
94 *
95 * then both object's {@code toString} methods will be invoked every time this assertion is done, even though those details are
96 * not normally needed because this assertion normally succeeds. You can use this method instead to only do those
97 * {@code toString} invocations if this assertion fails:
98 *
99 * <pre>
100 * AssertionUtils.assertThat(foo.equals(bar), "foo: %s bar: %s", foo, bar);
101 * </pre>
102 *
103 * <p/> This method's name is intended to avoid confusion with JUnit asserts (which are for test code, not production code).
104 *
105 * @param isTrue whether this assertion succeeds. (Boolean objects are auto-unboxed by JDK 1.5.)
106 *
107 * @param detailMessageFormat a {@linkplain String#format format string} to be used in constructing the {@code AssertionError}'s
108 * detail message. The purpose of this message is to capture and communicate details about the assertion failure that
109 * will help a developer diagnose and fix the bug that led the assertion to fail. It's meant to be interpreted in the
110 * context of a full stack trace and with the source code containing the failed assertion. It is <em>not</em> a
111 * user-level error message. Details like {@code "assertion failed"} are redundant, not useful. This detail message
112 * cannot be {@code null}.
113 *
114 * @param detailMessageArgs one or more arguments to the format string. Nulls are allowed by some format conversions, such as
115 * {@code "%s"}. (Primitives are auto-boxed by JDK 1.5.) Zero arguments will invoke {@link #assertThat(boolean, Object)}
116 * instead, so the detail message will not be treated as a format string.
117 *
118 * @throws AssertionError if {@code isTrue} is false
119 *
120 * @throws java.util.IllegalFormatException if {@code detailMessageFormat} contains an illegal syntax, a format specifier that
121 * is incompatible with the given arguments, insufficient arguments given the format string, or other illegal
122 * conditions. For specification of all possible formatting errors, see the Details section of
123 * {@link java.util.Formatter}.
124 *
125 * @throws NullPointerException if the {@code detailMessageFormat} is {@code null}
126 *
127 * @see String#format
128 */
129 public static void assertThat(boolean isTrue, String detailMessageFormat, Object... detailMessageArgs) {
130 if (!isTrue) {
131 throw new AssertionError(String.format(detailMessageFormat, detailMessageArgs));
132 }
133 }
134 }