1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache 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.apache.org/licenses/LICENSE-2.0
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 com.android.messaging.util;
17 
18 import android.os.Looper;
19 
20 import java.util.Arrays;
21 
22 public final class Assert {
23     public static @interface RunsOnMainThread {}
24     public static @interface DoesNotRunOnMainThread {}
25     public static @interface RunsOnAnyThread {}
26 
27     private static final String TEST_THREAD_SUBSTRING = "test";
28 
29     private static boolean sIsEngBuild;
30     private static boolean sShouldCrash;
31 
32     // Private constructor so no one creates this class.
Assert()33     private Assert() {
34     }
35 
36     // The proguard rules will strip this method out on user/userdebug builds.
37     // If you change the method signature you MUST edit proguard-release.flags.
setIfEngBuild()38     private static void setIfEngBuild() {
39         sShouldCrash = sIsEngBuild = true;
40     }
41 
refreshGservices(final BugleGservices gservices)42     private static void refreshGservices(final BugleGservices gservices) {
43         sShouldCrash = sIsEngBuild;
44         if (!sShouldCrash) {
45             sShouldCrash = gservices.getBoolean(
46                     BugleGservicesKeys.ASSERTS_FATAL,
47                     BugleGservicesKeys.ASSERTS_FATAL_DEFAULT);
48         }
49     }
50 
51     // Static initializer block to find out if we're running an eng or
52     // release build.
53     static {
setIfEngBuild()54         setIfEngBuild();
55     }
56 
57     // This is called from FactoryImpl once the Gservices class is initialized.
initializeGservices(final BugleGservices gservices)58     public static void initializeGservices (final BugleGservices gservices) {
59         gservices.registerForChanges(new Runnable() {
60             @Override
61             public void run() {
62                 refreshGservices(gservices);
63             }
64         });
65         refreshGservices(gservices);
66     }
67 
68     /**
69      * Halt execution if this is not an eng build.
70      * <p>Intended for use in code paths that should be run only for tests and never on
71      * a real build.
72      * <p>Note that this will crash on a user build even though asserts don't normally
73      * crash on a user build.
74      */
isEngBuild()75     public static void isEngBuild() {
76         isTrueReleaseCheck(sIsEngBuild);
77     }
78 
79     /**
80      * Halt execution if this isn't the case.
81      */
isTrue(final boolean condition)82     public static void isTrue(final boolean condition) {
83         if (!condition) {
84             fail("Expected condition to be true", false);
85         }
86     }
87 
88     /**
89      * Halt execution if this isn't the case.
90      */
isFalse(final boolean condition)91     public static void isFalse(final boolean condition) {
92         if (condition) {
93             fail("Expected condition to be false", false);
94         }
95     }
96 
97     /**
98      * Halt execution even in release builds if this isn't the case.
99      */
isTrueReleaseCheck(final boolean condition)100     public static void isTrueReleaseCheck(final boolean condition) {
101         if (!condition) {
102             fail("Expected condition to be true", true);
103         }
104     }
105 
equals(final int expected, final int actual)106     public static void equals(final int expected, final int actual) {
107         if (expected != actual) {
108             fail("Expected " + expected + " but got " + actual, false);
109         }
110     }
111 
equals(final long expected, final long actual)112     public static void equals(final long expected, final long actual) {
113         if (expected != actual) {
114             fail("Expected " + expected + " but got " + actual, false);
115         }
116     }
117 
equals(final Object expected, final Object actual)118     public static void equals(final Object expected, final Object actual) {
119         if (expected != actual
120                 && (expected == null || actual == null || !expected.equals(actual))) {
121             fail("Expected " + expected + " but got " + actual, false);
122         }
123     }
124 
oneOf(final int actual, final int ...expected)125     public static void oneOf(final int actual, final int ...expected) {
126         for (int value : expected) {
127             if (actual == value) {
128                 return;
129             }
130         }
131         fail("Expected value to be one of " + Arrays.toString(expected) + " but was " + actual);
132     }
133 
inRange( final int val, final int rangeMinInclusive, final int rangeMaxInclusive)134     public static void inRange(
135             final int val, final int rangeMinInclusive, final int rangeMaxInclusive) {
136         if (val < rangeMinInclusive || val > rangeMaxInclusive) {
137             fail("Expected value in range [" + rangeMinInclusive + ", " +
138                     rangeMaxInclusive + "], but was " + val, false);
139         }
140     }
141 
inRange( final long val, final long rangeMinInclusive, final long rangeMaxInclusive)142     public static void inRange(
143             final long val, final long rangeMinInclusive, final long rangeMaxInclusive) {
144         if (val < rangeMinInclusive || val > rangeMaxInclusive) {
145             fail("Expected value in range [" + rangeMinInclusive + ", " +
146                     rangeMaxInclusive + "], but was " + val, false);
147         }
148     }
149 
isMainThread()150     public static void isMainThread() {
151         if (Looper.myLooper() != Looper.getMainLooper()
152                 && !Thread.currentThread().getName().contains(TEST_THREAD_SUBSTRING)) {
153             fail("Expected to run on main thread", false);
154         }
155     }
156 
isNotMainThread()157     public static void isNotMainThread() {
158         if (Looper.myLooper() == Looper.getMainLooper()
159                 && !Thread.currentThread().getName().contains(TEST_THREAD_SUBSTRING)) {
160             fail("Not expected to run on main thread", false);
161         }
162     }
163 
164     /**
165      * Halt execution if the value passed in is not null
166      * @param obj The object to check
167      */
isNull(final Object obj)168     public static void isNull(final Object obj) {
169         if (obj != null) {
170             fail("Expected object to be null", false);
171         }
172     }
173 
174     /**
175      * Halt execution if the value passed in is not null
176      * @param obj The object to check
177      * @param failureMessage message to print when halting execution
178      */
isNull(final Object obj, final String failureMessage)179     public static void isNull(final Object obj, final String failureMessage) {
180         if (obj != null) {
181             fail(failureMessage, false);
182         }
183     }
184 
185     /**
186      * Halt execution if the value passed in is null
187      * @param obj The object to check
188      */
notNull(final Object obj)189     public static void notNull(final Object obj) {
190         if (obj == null) {
191             fail("Expected value to be non-null", false);
192         }
193     }
194 
fail(final String message)195     public static void fail(final String message) {
196         fail("Assert.fail() called: " + message, false);
197     }
198 
fail(final String message, final boolean crashRelease)199     private static void fail(final String message, final boolean crashRelease) {
200         LogUtil.e(LogUtil.BUGLE_TAG, message);
201         if (crashRelease || sShouldCrash) {
202             throw new AssertionError(message);
203         } else {
204             // Find the method whose assertion failed. We're using a depth of 2, because all public
205             // Assert methods delegate to this one (see javadoc on getCaller() for details).
206             StackTraceElement caller = DebugUtils.getCaller(2);
207             if (caller != null) {
208                 // This log message can be de-obfuscated by the Proguard retrace tool, just like a
209                 // full stack trace from a crash.
210                 LogUtil.e(LogUtil.BUGLE_TAG, "\tat " + caller.toString());
211             }
212         }
213     }
214 }
215