1 /*
2  * Copyright (C) 2018 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 // Base class for VarHandle unit tests for accessor operations
18 public abstract class VarHandleUnitTest {
19     public static VarHandleUnitTestCollector DEFAULT_COLLECTOR = new VarHandleUnitTestCollector();
20 
21     // Error log (lazily initialized on failure).
22     private StringBuilder lazyErrorLog = null;
23 
24     // Tracker of test events (starts, skips, ends)
25     private final VarHandleUnitTestCollector collector;
26 
VarHandleUnitTest(VarHandleUnitTestCollector collector)27     public VarHandleUnitTest(VarHandleUnitTestCollector collector) {
28         this.collector = collector;
29     }
30 
VarHandleUnitTest()31     public VarHandleUnitTest() {
32         this.collector = DEFAULT_COLLECTOR;
33     }
34 
35     // Method that can be overloaded to signify that a test should be
36     // run or skipped. Returns true if the test should be run and
37     // false if the test should be skipped.
checkGuard()38     public boolean checkGuard() {
39         return true;
40     }
41 
42     // Method that implementations should use to perform a specific test.
doTest()43     protected abstract void doTest() throws Exception;
44 
assertTrue(boolean value)45     public final void assertTrue(boolean value) {
46         assertEquals(true, value);
47     }
48 
assertFalse(boolean value)49     public final void assertFalse(boolean value) {
50         assertEquals(false, value);
51     }
52 
assertEquals(boolean expected, boolean actual)53     public final void assertEquals(boolean expected, boolean actual) {
54         assertEquals(Boolean.valueOf(expected), Boolean.valueOf(actual));
55     }
56 
assertEquals(byte expected, byte actual)57     public final void assertEquals(byte expected, byte actual) {
58         assertEquals(Byte.valueOf(expected), Byte.valueOf(actual));
59     }
60 
assertEquals(char expected, char actual)61     public final void assertEquals(char expected, char actual) {
62         assertEquals(Character.valueOf(expected), Character.valueOf(actual));
63     }
64 
assertEquals(short expected, short actual)65     public final void assertEquals(short expected, short actual) {
66         assertEquals(Short.valueOf(expected), Short.valueOf(actual));
67     }
68 
assertEquals(int expected, int actual)69     public final void assertEquals(int expected, int actual) {
70         assertEquals(Integer.valueOf(expected), Integer.valueOf(actual));
71     }
72 
assertEquals(long expected, long actual)73     public final void assertEquals(long expected, long actual) {
74         assertEquals(Long.valueOf(expected), Long.valueOf(actual));
75     }
76 
assertEquals(float expected, float actual)77     public final void assertEquals(float expected, float actual) {
78         assertEquals(Float.valueOf(expected), Float.valueOf(actual));
79     }
80 
assertEquals(double expected, double actual)81     public final void assertEquals(double expected, double actual) {
82         assertEquals(Double.valueOf(expected), Double.valueOf(actual));
83     }
84 
assertEquals(Object expected, Object actual)85     public final void assertEquals(Object expected, Object actual) {
86         if (expected == null) {
87             if (actual == null) {
88                 return;
89             }
90         } else if (expected.equals(actual)) {
91             return;
92         }
93         failNotEquals("Failed assertion (expected != actual)", expected, actual);
94     }
95 
failUnreachable()96     public final void failUnreachable() {
97         fail("Unreachable code");
98     }
99 
run()100     public final void run() {
101         collector.start(getClass().getSimpleName());
102         if (!checkGuard()) {
103             collector.skip();
104             return;
105         }
106 
107         try {
108             doTest();
109         } catch (Exception e) {
110             fail("Unexpected exception", e);
111         } finally {
112             if (lazyErrorLog == null) {
113                 collector.success();
114             } else {
115                 collector.fail(lazyErrorLog.toString());
116             }
117         }
118     }
119 
failNotEquals(String message, Object expected, Object actual)120     private void failNotEquals(String message, Object expected, Object actual) {
121         errorLog()
122                 .append(message)
123                 .append(": ")
124                 .append(expected)
125                 .append(" != ")
126                 .append(actual)
127                 .append(" in ")
128                 .append(getSourceInfo())
129                 .append('\n');
130     }
131 
fail(String message)132     private void fail(String message) {
133         errorLog().append(message).append(" in ").append(getSourceInfo()).append('\n');
134     }
135 
fail(String message, String detail)136     private void fail(String message, String detail) {
137         errorLog()
138                 .append(message)
139                 .append(": ")
140                 .append(detail)
141                 .append(" in ")
142                 .append(getSourceInfo())
143                 .append('\n');
144     }
145 
fail(String message, Exception e)146     private void fail(String message, Exception e) {
147         errorLog()
148                 .append(message)
149                 .append(": ")
150                 .append(e.toString())
151                 .append(" in ")
152                 .append(getSourceInfo(e))
153                 .append('\n');
154     }
155 
getSourceInfo(Exception e)156     private String getSourceInfo(Exception e) {
157         // Unit test has thrown an exception. Stack likely looks like
158         // runtime frames then unit test frames then
159         // VarHandleUnitFrames.
160         StackTraceElement[] stackTraceElements = e.getStackTrace();
161         int index = 1;
162         for (int i = 1; i < stackTraceElements.length; ++i) {
163             if ("VarHandleUnitTest".equals(stackTraceElements[i].getClassName())) {
164                 return stackTraceElements[i - 1].toString();
165             }
166         }
167         return "Unknown";
168     }
169 
getSourceInfo()170     private String getSourceInfo() {
171         // Gets source info for a failure such as an assertion. The
172         // test has called a method on VarHandleUnitTest so the stack
173         // looks like some frames in VarHandleUnitTest methods and then
174         // a frame in the test itself.
175         StackTraceElement[] stackTraceElements = new Exception().getStackTrace();
176         for (StackTraceElement stackTraceElement : stackTraceElements) {
177             if (!"VarHandleUnitTest".equals(stackTraceElement.getClassName())) {
178                 return stackTraceElement.toString();
179             }
180         }
181         return "Unknown";
182     }
183 
errorLog()184     private StringBuilder errorLog() {
185         if (lazyErrorLog == null) {
186             lazyErrorLog = new StringBuilder();
187         }
188         return lazyErrorLog;
189     }
190 }
191