1 /*
2  * Copyright (C) 2020 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 
17 package android.location.cts.common;
18 
19 import android.util.Log;
20 
21 import junit.framework.Assert;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 /**
27  * Custom Assertion class. This is useful for doing multiple validations together
28  * without failing the test. Tests don’t stop running even if an assertion condition fails,
29  * but the test itself is marked as a failed test to indicate the right result
30  * at the end of the test.
31  */
32 public class SoftAssert {
33 
34     List<String> mErrorList;
35     private String mTag;
36 
SoftAssert(String source)37     public SoftAssert(String source) {
38         mErrorList = new ArrayList<>();
39         mTag = source;
40     }
41 
42     /**
43      * Check if condition is true
44      *
45      * @param message        test message
46      * @param eventTimeInNs  the time at which the condition occurred
47      * @param expectedResult expected value
48      * @param actualResult   actual value
49      * @param condition      condition for test
50      */
assertTrue(String message, Long eventTimeInNs, String expectedResult, String actualResult, boolean condition)51     public void assertTrue(String message, Long eventTimeInNs, String expectedResult,
52                            String actualResult, boolean condition) {
53         if (condition) {
54             Log.i(mTag, message + ", (Test: PASS, actual : " +
55                     actualResult + ", expected: " + expectedResult + ")");
56         } else {
57             String errorMessage = "";
58             if (eventTimeInNs != null) {
59                 errorMessage = "At time = " + eventTimeInNs + " ns, ";
60             }
61             errorMessage += message +
62                     " (Test: FAIL, actual :" + actualResult + ", " +
63                     "expected: " + expectedResult + ")";
64             Log.e(mTag, errorMessage);
65             mErrorList.add(errorMessage);
66         }
67     }
68 
69     /**
70      * assertTrue without eventTime
71      *
72      * @param message        test message
73      * @param expectedResult expected value
74      * @param actualResult   actual value
75      * @param condition      condition for test
76      */
assertTrue(String message, String expectedResult, String actualResult, boolean condition)77     public void assertTrue(String message, String expectedResult,
78         String actualResult, boolean condition) {
79         assertTrue(message, null, expectedResult, actualResult, condition);
80     }
81 
82     /**
83      * Check if a condition is true.
84      * NOTE: A failure is downgraded to a warning.
85      *
86      * @param message        the message associated with the condition
87      * @param eventTimeInNs  the time at which the condition occurred
88      * @param expectedResult the expected result of the condition
89      * @param actualResult   the actual result of the condition
90      * @param condition      the condition status
91      */
assertTrueAsWarning( String message, long eventTimeInNs, String expectedResult, String actualResult, boolean condition)92     public void assertTrueAsWarning(
93             String message,
94             long eventTimeInNs,
95             String expectedResult,
96             String actualResult,
97             boolean condition) {
98         if (condition) {
99             String formattedMessage = String.format(
100                     "%s, (Test: PASS, actual : %s, expected : %s)",
101                     message,
102                     actualResult,
103                     expectedResult);
104             Log.i(mTag, formattedMessage);
105         } else {
106             String formattedMessage = String.format(
107                     "At time = %d ns, %s (Test: WARNING, actual : %s, expected : %s).",
108                     eventTimeInNs,
109                     message,
110                     actualResult,
111                     expectedResult);
112             failAsWarning(mTag, formattedMessage);
113         }
114     }
115 
116     /**
117      * Check if condition is true
118      *
119      * @param message   test message
120      * @param condition condition for test
121      */
assertTrue(String message, boolean condition)122     public void assertTrue(String message, boolean condition) {
123         assertOrWarnTrue(true, message, condition);
124     }
125 
126     /**
127      * Check if condition is true
128      *
129      * @param strict      if true, add this to the failure list, else, log a warning message
130      * @param message     message to describe the test - output on pass or fail
131      * @param condition   condition for test
132      */
assertOrWarnTrue(boolean strict, String message, boolean condition)133     public void assertOrWarnTrue(boolean strict, String message, boolean condition) {
134         if (condition) {
135             Log.i(mTag, "(Test: PASS) " + message);
136         } else {
137             String errorMessage = "(Test: FAIL) " + message;
138             Log.i(mTag, errorMessage);
139             if (strict) {
140                 mErrorList.add(errorMessage);
141             } else {
142                 failAsWarning(mTag, errorMessage);
143             }
144         }
145     }
146 
147     /**
148      * Assert all conditions together. This method collates all the failures and decides
149      * whether to fail the test or not at the end. This must be called at the end of the test.
150      */
assertAll()151     public void assertAll() {
152         if (mErrorList.isEmpty()) {
153             Log.i(mTag, "All test pass.");
154             // Test pass if there are no error message in errorMessageSet
155             Assert.assertTrue(true);
156         } else {
157             StringBuilder message = new StringBuilder();
158             for (String msg : mErrorList) {
159                 message.append(msg + "\n");
160             }
161             Log.e(mTag, "Failing tests are: \n" + message);
162             Assert.fail("Failing tests are: \n" + message);
163         }
164     }
165 
166     /**
167      * A hard or soft failure, depending on the setting.
168      * TODO - make this cleaner - e.g. refactor this out completely: get rid of static methods,
169      * and make a class (say TestVerification) the only entry point for verifications,
170      * so strict vs not can be abstracted away test implementations.
171      */
failOrWarning(boolean testIsStrict, String message, boolean condition)172     public static void failOrWarning(boolean testIsStrict, String message, boolean condition) {
173         if (testIsStrict) {
174             Assert.assertTrue(message, condition);
175         } else {
176             if (!condition) {
177                 failAsWarning("", message);
178             }
179         }
180     }
181 
182     /**
183      * A soft failure. In the current state of the tests, it will only log a warning and let the
184      * test be reported as 'pass'.
185      */
failAsWarning(String tag, String message)186     public static void failAsWarning(String tag, String message) {
187         Log.w(tag, message + " [NOTE: in a future release this feature might become mandatory, and"
188                 + " this warning will fail the test].");
189     }
190 }
191