1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import java.lang.invoke.WrongMethodTypeException; 18*795d594fSAndroid Build Coastguard Worker 19*795d594fSAndroid Build Coastguard Worker // Base class for VarHandle unit tests for accessor operations 20*795d594fSAndroid Build Coastguard Worker public abstract class VarHandleUnitTest { 21*795d594fSAndroid Build Coastguard Worker public static VarHandleUnitTestCollector DEFAULT_COLLECTOR = new VarHandleUnitTestCollector(); 22*795d594fSAndroid Build Coastguard Worker 23*795d594fSAndroid Build Coastguard Worker // Error log (lazily initialized on failure). 24*795d594fSAndroid Build Coastguard Worker private StringBuilder lazyErrorLog = null; 25*795d594fSAndroid Build Coastguard Worker 26*795d594fSAndroid Build Coastguard Worker // Tracker of test events (starts, skips, ends) 27*795d594fSAndroid Build Coastguard Worker private final VarHandleUnitTestCollector collector; 28*795d594fSAndroid Build Coastguard Worker VarHandleUnitTest(VarHandleUnitTestCollector collector)29*795d594fSAndroid Build Coastguard Worker public VarHandleUnitTest(VarHandleUnitTestCollector collector) { 30*795d594fSAndroid Build Coastguard Worker this.collector = collector; 31*795d594fSAndroid Build Coastguard Worker } 32*795d594fSAndroid Build Coastguard Worker VarHandleUnitTest()33*795d594fSAndroid Build Coastguard Worker public VarHandleUnitTest() { 34*795d594fSAndroid Build Coastguard Worker this.collector = DEFAULT_COLLECTOR; 35*795d594fSAndroid Build Coastguard Worker } 36*795d594fSAndroid Build Coastguard Worker 37*795d594fSAndroid Build Coastguard Worker // Method that can be overloaded to signify that a test should be 38*795d594fSAndroid Build Coastguard Worker // run or skipped. Returns true if the test should be run and 39*795d594fSAndroid Build Coastguard Worker // false if the test should be skipped. checkGuard()40*795d594fSAndroid Build Coastguard Worker public boolean checkGuard() { 41*795d594fSAndroid Build Coastguard Worker return true; 42*795d594fSAndroid Build Coastguard Worker } 43*795d594fSAndroid Build Coastguard Worker 44*795d594fSAndroid Build Coastguard Worker // Method that implementations should use to perform a specific test. doTest()45*795d594fSAndroid Build Coastguard Worker protected abstract void doTest() throws Exception; 46*795d594fSAndroid Build Coastguard Worker assertTrue(boolean value)47*795d594fSAndroid Build Coastguard Worker public final void assertTrue(boolean value) { 48*795d594fSAndroid Build Coastguard Worker assertEquals(true, value); 49*795d594fSAndroid Build Coastguard Worker } 50*795d594fSAndroid Build Coastguard Worker assertFalse(boolean value)51*795d594fSAndroid Build Coastguard Worker public final void assertFalse(boolean value) { 52*795d594fSAndroid Build Coastguard Worker assertEquals(false, value); 53*795d594fSAndroid Build Coastguard Worker } 54*795d594fSAndroid Build Coastguard Worker assertEquals(boolean expected, boolean actual)55*795d594fSAndroid Build Coastguard Worker public final void assertEquals(boolean expected, boolean actual) { 56*795d594fSAndroid Build Coastguard Worker assertEquals(Boolean.valueOf(expected), Boolean.valueOf(actual)); 57*795d594fSAndroid Build Coastguard Worker } 58*795d594fSAndroid Build Coastguard Worker assertEquals(byte expected, byte actual)59*795d594fSAndroid Build Coastguard Worker public final void assertEquals(byte expected, byte actual) { 60*795d594fSAndroid Build Coastguard Worker assertEquals(Byte.valueOf(expected), Byte.valueOf(actual)); 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker assertEquals(char expected, char actual)63*795d594fSAndroid Build Coastguard Worker public final void assertEquals(char expected, char actual) { 64*795d594fSAndroid Build Coastguard Worker assertEquals(Character.valueOf(expected), Character.valueOf(actual)); 65*795d594fSAndroid Build Coastguard Worker } 66*795d594fSAndroid Build Coastguard Worker assertEquals(short expected, short actual)67*795d594fSAndroid Build Coastguard Worker public final void assertEquals(short expected, short actual) { 68*795d594fSAndroid Build Coastguard Worker assertEquals(Short.valueOf(expected), Short.valueOf(actual)); 69*795d594fSAndroid Build Coastguard Worker } 70*795d594fSAndroid Build Coastguard Worker assertEquals(int expected, int actual)71*795d594fSAndroid Build Coastguard Worker public final void assertEquals(int expected, int actual) { 72*795d594fSAndroid Build Coastguard Worker assertEquals(Integer.valueOf(expected), Integer.valueOf(actual)); 73*795d594fSAndroid Build Coastguard Worker } 74*795d594fSAndroid Build Coastguard Worker assertEquals(long expected, long actual)75*795d594fSAndroid Build Coastguard Worker public final void assertEquals(long expected, long actual) { 76*795d594fSAndroid Build Coastguard Worker assertEquals(Long.valueOf(expected), Long.valueOf(actual)); 77*795d594fSAndroid Build Coastguard Worker } 78*795d594fSAndroid Build Coastguard Worker assertEquals(float expected, float actual)79*795d594fSAndroid Build Coastguard Worker public final void assertEquals(float expected, float actual) { 80*795d594fSAndroid Build Coastguard Worker assertEquals(Float.valueOf(expected), Float.valueOf(actual)); 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker assertEquals(double expected, double actual)83*795d594fSAndroid Build Coastguard Worker public final void assertEquals(double expected, double actual) { 84*795d594fSAndroid Build Coastguard Worker assertEquals(Double.valueOf(expected), Double.valueOf(actual)); 85*795d594fSAndroid Build Coastguard Worker } 86*795d594fSAndroid Build Coastguard Worker assertEquals(Object expected, Object actual)87*795d594fSAndroid Build Coastguard Worker public final void assertEquals(Object expected, Object actual) { 88*795d594fSAndroid Build Coastguard Worker if (expected == null) { 89*795d594fSAndroid Build Coastguard Worker if (actual == null) { 90*795d594fSAndroid Build Coastguard Worker return; 91*795d594fSAndroid Build Coastguard Worker } 92*795d594fSAndroid Build Coastguard Worker } else if (expected.equals(actual)) { 93*795d594fSAndroid Build Coastguard Worker return; 94*795d594fSAndroid Build Coastguard Worker } 95*795d594fSAndroid Build Coastguard Worker failNotEquals("Failed assertion (expected != actual)", expected, actual); 96*795d594fSAndroid Build Coastguard Worker } 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker interface AccessorAccess { apply()99*795d594fSAndroid Build Coastguard Worker void apply() throws Exception; 100*795d594fSAndroid Build Coastguard Worker } 101*795d594fSAndroid Build Coastguard Worker assertThrows(Class expectedException, AccessorAccess access)102*795d594fSAndroid Build Coastguard Worker void assertThrows(Class expectedException, AccessorAccess access) { 103*795d594fSAndroid Build Coastguard Worker try { 104*795d594fSAndroid Build Coastguard Worker access.apply(); 105*795d594fSAndroid Build Coastguard Worker fail("Expected a " + expectedException + ", but not raised"); 106*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 107*795d594fSAndroid Build Coastguard Worker if (!expectedException.isInstance(e)) { 108*795d594fSAndroid Build Coastguard Worker fail("Expected a " + expectedException + ", but got a " + e.getClass(), e); 109*795d594fSAndroid Build Coastguard Worker } 110*795d594fSAndroid Build Coastguard Worker } 111*795d594fSAndroid Build Coastguard Worker } 112*795d594fSAndroid Build Coastguard Worker assertThrowsAIOBE(AccessorAccess access)113*795d594fSAndroid Build Coastguard Worker public final void assertThrowsAIOBE(AccessorAccess access) { 114*795d594fSAndroid Build Coastguard Worker assertThrows(ArrayIndexOutOfBoundsException.class, access); 115*795d594fSAndroid Build Coastguard Worker } 116*795d594fSAndroid Build Coastguard Worker assertThrowsASE(AccessorAccess access)117*795d594fSAndroid Build Coastguard Worker public final void assertThrowsASE(AccessorAccess access) { 118*795d594fSAndroid Build Coastguard Worker assertThrows(ArrayStoreException.class, access); 119*795d594fSAndroid Build Coastguard Worker } 120*795d594fSAndroid Build Coastguard Worker assertThrowsISE(AccessorAccess access)121*795d594fSAndroid Build Coastguard Worker public final void assertThrowsISE(AccessorAccess access) { 122*795d594fSAndroid Build Coastguard Worker assertThrows(IllegalStateException.class, access); 123*795d594fSAndroid Build Coastguard Worker } 124*795d594fSAndroid Build Coastguard Worker assertThrowsIOOBE(AccessorAccess access)125*795d594fSAndroid Build Coastguard Worker public final void assertThrowsIOOBE(AccessorAccess access) { 126*795d594fSAndroid Build Coastguard Worker assertThrows(IndexOutOfBoundsException.class, access); 127*795d594fSAndroid Build Coastguard Worker } 128*795d594fSAndroid Build Coastguard Worker assertThrowsCCE(AccessorAccess access)129*795d594fSAndroid Build Coastguard Worker public final void assertThrowsCCE(AccessorAccess access) { 130*795d594fSAndroid Build Coastguard Worker assertThrows(ClassCastException.class, access); 131*795d594fSAndroid Build Coastguard Worker } 132*795d594fSAndroid Build Coastguard Worker assertThrowsNPE(AccessorAccess access)133*795d594fSAndroid Build Coastguard Worker public final void assertThrowsNPE(AccessorAccess access) { 134*795d594fSAndroid Build Coastguard Worker assertThrows(NullPointerException.class, access); 135*795d594fSAndroid Build Coastguard Worker } 136*795d594fSAndroid Build Coastguard Worker assertThrowsWMTE(AccessorAccess access)137*795d594fSAndroid Build Coastguard Worker public final void assertThrowsWMTE(AccessorAccess access) { 138*795d594fSAndroid Build Coastguard Worker assertThrows(WrongMethodTypeException.class, access); 139*795d594fSAndroid Build Coastguard Worker } 140*795d594fSAndroid Build Coastguard Worker failUnreachable()141*795d594fSAndroid Build Coastguard Worker public final void failUnreachable() { 142*795d594fSAndroid Build Coastguard Worker fail("Unreachable code"); 143*795d594fSAndroid Build Coastguard Worker } 144*795d594fSAndroid Build Coastguard Worker run()145*795d594fSAndroid Build Coastguard Worker public final void run() { 146*795d594fSAndroid Build Coastguard Worker collector.start(getClass().getSimpleName()); 147*795d594fSAndroid Build Coastguard Worker if (!checkGuard()) { 148*795d594fSAndroid Build Coastguard Worker collector.skip(); 149*795d594fSAndroid Build Coastguard Worker return; 150*795d594fSAndroid Build Coastguard Worker } 151*795d594fSAndroid Build Coastguard Worker 152*795d594fSAndroid Build Coastguard Worker try { 153*795d594fSAndroid Build Coastguard Worker doTest(); 154*795d594fSAndroid Build Coastguard Worker } catch (Exception e) { 155*795d594fSAndroid Build Coastguard Worker fail("Unexpected exception", e); 156*795d594fSAndroid Build Coastguard Worker e.printStackTrace(); 157*795d594fSAndroid Build Coastguard Worker } finally { 158*795d594fSAndroid Build Coastguard Worker if (lazyErrorLog == null) { 159*795d594fSAndroid Build Coastguard Worker collector.success(); 160*795d594fSAndroid Build Coastguard Worker } else { 161*795d594fSAndroid Build Coastguard Worker collector.fail(lazyErrorLog.toString()); 162*795d594fSAndroid Build Coastguard Worker } 163*795d594fSAndroid Build Coastguard Worker } 164*795d594fSAndroid Build Coastguard Worker } 165*795d594fSAndroid Build Coastguard Worker failNotEquals(String message, Object expected, Object actual)166*795d594fSAndroid Build Coastguard Worker private void failNotEquals(String message, Object expected, Object actual) { 167*795d594fSAndroid Build Coastguard Worker errorLog() 168*795d594fSAndroid Build Coastguard Worker .append(message) 169*795d594fSAndroid Build Coastguard Worker .append(": ") 170*795d594fSAndroid Build Coastguard Worker .append(expected) 171*795d594fSAndroid Build Coastguard Worker .append(" != ") 172*795d594fSAndroid Build Coastguard Worker .append(actual) 173*795d594fSAndroid Build Coastguard Worker .append(" in ") 174*795d594fSAndroid Build Coastguard Worker .append(getSourceInfo()) 175*795d594fSAndroid Build Coastguard Worker .append('\n'); 176*795d594fSAndroid Build Coastguard Worker } 177*795d594fSAndroid Build Coastguard Worker fail(String message)178*795d594fSAndroid Build Coastguard Worker private void fail(String message) { 179*795d594fSAndroid Build Coastguard Worker errorLog().append(message).append(" in ").append(getSourceInfo()).append('\n'); 180*795d594fSAndroid Build Coastguard Worker } 181*795d594fSAndroid Build Coastguard Worker fail(String message, String detail)182*795d594fSAndroid Build Coastguard Worker private void fail(String message, String detail) { 183*795d594fSAndroid Build Coastguard Worker errorLog() 184*795d594fSAndroid Build Coastguard Worker .append(message) 185*795d594fSAndroid Build Coastguard Worker .append(": ") 186*795d594fSAndroid Build Coastguard Worker .append(detail) 187*795d594fSAndroid Build Coastguard Worker .append(" in ") 188*795d594fSAndroid Build Coastguard Worker .append(getSourceInfo()) 189*795d594fSAndroid Build Coastguard Worker .append('\n'); 190*795d594fSAndroid Build Coastguard Worker } 191*795d594fSAndroid Build Coastguard Worker fail(String message, Exception e)192*795d594fSAndroid Build Coastguard Worker private void fail(String message, Exception e) { 193*795d594fSAndroid Build Coastguard Worker errorLog() 194*795d594fSAndroid Build Coastguard Worker .append(message) 195*795d594fSAndroid Build Coastguard Worker .append(": ") 196*795d594fSAndroid Build Coastguard Worker .append(e.toString()) 197*795d594fSAndroid Build Coastguard Worker .append(" in ") 198*795d594fSAndroid Build Coastguard Worker .append(getSourceInfo(e)) 199*795d594fSAndroid Build Coastguard Worker .append('\n'); 200*795d594fSAndroid Build Coastguard Worker } 201*795d594fSAndroid Build Coastguard Worker getSourceInfo(Exception e)202*795d594fSAndroid Build Coastguard Worker private String getSourceInfo(Exception e) { 203*795d594fSAndroid Build Coastguard Worker // Unit test has thrown an exception. Stack likely looks like 204*795d594fSAndroid Build Coastguard Worker // runtime frames then unit test frames then 205*795d594fSAndroid Build Coastguard Worker // VarHandleUnitFrames. 206*795d594fSAndroid Build Coastguard Worker StackTraceElement[] stackTraceElements = e.getStackTrace(); 207*795d594fSAndroid Build Coastguard Worker int index = 1; 208*795d594fSAndroid Build Coastguard Worker for (int i = 1; i < stackTraceElements.length; ++i) { 209*795d594fSAndroid Build Coastguard Worker if ("VarHandleUnitTest".equals(stackTraceElements[i].getClassName())) { 210*795d594fSAndroid Build Coastguard Worker return stackTraceElements[i - 1].toString(); 211*795d594fSAndroid Build Coastguard Worker } 212*795d594fSAndroid Build Coastguard Worker } 213*795d594fSAndroid Build Coastguard Worker return "Unknown"; 214*795d594fSAndroid Build Coastguard Worker } 215*795d594fSAndroid Build Coastguard Worker getSourceInfo()216*795d594fSAndroid Build Coastguard Worker private String getSourceInfo() { 217*795d594fSAndroid Build Coastguard Worker // Gets source info for a failure such as an assertion. The 218*795d594fSAndroid Build Coastguard Worker // test has called a method on VarHandleUnitTest so the stack 219*795d594fSAndroid Build Coastguard Worker // looks like some frames in VarHandleUnitTest methods and then 220*795d594fSAndroid Build Coastguard Worker // a frame in the test itself. 221*795d594fSAndroid Build Coastguard Worker StackTraceElement[] stackTraceElements = new Exception().getStackTrace(); 222*795d594fSAndroid Build Coastguard Worker for (StackTraceElement stackTraceElement : stackTraceElements) { 223*795d594fSAndroid Build Coastguard Worker if (!"VarHandleUnitTest".equals(stackTraceElement.getClassName())) { 224*795d594fSAndroid Build Coastguard Worker return stackTraceElement.toString(); 225*795d594fSAndroid Build Coastguard Worker } 226*795d594fSAndroid Build Coastguard Worker } 227*795d594fSAndroid Build Coastguard Worker return "Unknown"; 228*795d594fSAndroid Build Coastguard Worker } 229*795d594fSAndroid Build Coastguard Worker errorLog()230*795d594fSAndroid Build Coastguard Worker private StringBuilder errorLog() { 231*795d594fSAndroid Build Coastguard Worker if (lazyErrorLog == null) { 232*795d594fSAndroid Build Coastguard Worker lazyErrorLog = new StringBuilder(); 233*795d594fSAndroid Build Coastguard Worker } 234*795d594fSAndroid Build Coastguard Worker return lazyErrorLog; 235*795d594fSAndroid Build Coastguard Worker } 236*795d594fSAndroid Build Coastguard Worker } 237