1/*
2 * Copyright (C) 2007 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
17package android.test;
18
19import android.app.Instrumentation;
20import android.content.Context;
21import android.os.PerformanceCollector.PerformanceResultsWriter;
22
23import com.google.android.collect.Lists;
24
25import junit.framework.Test;
26import junit.framework.TestCase;
27import junit.framework.TestListener;
28import junit.framework.TestResult;
29import junit.framework.TestSuite;
30import junit.runner.BaseTestRunner;
31
32import java.lang.reflect.Constructor;
33import java.lang.reflect.InvocationTargetException;
34import java.util.List;
35
36/**
37 * @deprecated Use
38 * <a href="{@docRoot}reference/android/support/test/runner/AndroidJUnitRunner.html">
39 * AndroidJUnitRunner</a> instead. New tests should be written using the
40 * <a href="{@docRoot}tools/testing-support-library/index.html">Android Testing Support Library</a>.
41 */
42@Deprecated
43public class AndroidTestRunner extends BaseTestRunner {
44
45    private TestResult mTestResult;
46    private String mTestClassName;
47    private List<TestCase> mTestCases;
48    private Context mContext;
49    private boolean mSkipExecution = false;
50
51    private List<TestListener> mTestListeners = Lists.newArrayList();
52    private Instrumentation mInstrumentation;
53    private PerformanceResultsWriter mPerfWriter;
54
55    @SuppressWarnings("unchecked")
56    public void setTestClassName(String testClassName, String testMethodName) {
57        Class testClass = loadTestClass(testClassName);
58
59        if (shouldRunSingleTestMethod(testMethodName, testClass)) {
60            TestCase testCase = buildSingleTestMethod(testClass, testMethodName);
61            mTestCases = Lists.newArrayList(testCase);
62            mTestClassName = testClass.getSimpleName();
63        } else {
64            setTest(getTest(testClass), testClass);
65        }
66    }
67
68    public void setTest(Test test) {
69        setTest(test, test.getClass());
70    }
71
72    private void setTest(Test test, Class<? extends Test> testClass) {
73        mTestCases = (List<TestCase>) TestCaseUtil.getTests(test, true);
74        if (TestSuite.class.isAssignableFrom(testClass)) {
75            mTestClassName = TestCaseUtil.getTestName(test);
76        } else {
77            mTestClassName = testClass.getSimpleName();
78        }
79    }
80
81    public void clearTestListeners() {
82        mTestListeners.clear();
83    }
84
85    public void addTestListener(TestListener testListener) {
86        if (testListener != null) {
87            mTestListeners.add(testListener);
88        }
89    }
90
91    @SuppressWarnings("unchecked")
92    private Class<? extends Test> loadTestClass(String testClassName) {
93        try {
94            return (Class<? extends Test>) mContext.getClassLoader().loadClass(testClassName);
95        } catch (ClassNotFoundException e) {
96            runFailed("Could not find test class. Class: " + testClassName);
97        }
98        return null;
99    }
100
101    private TestCase buildSingleTestMethod(Class testClass, String testMethodName) {
102        try {
103            Constructor c = testClass.getConstructor();
104            return newSingleTestMethod(testClass, testMethodName, c);
105        } catch (NoSuchMethodException e) {
106        }
107
108        try {
109            Constructor c = testClass.getConstructor(String.class);
110            return newSingleTestMethod(testClass, testMethodName, c, testMethodName);
111        } catch (NoSuchMethodException e) {
112        }
113
114        return null;
115    }
116
117    private TestCase newSingleTestMethod(Class testClass, String testMethodName,
118            Constructor constructor, Object... args) {
119        try {
120            TestCase testCase = (TestCase) constructor.newInstance(args);
121            testCase.setName(testMethodName);
122            return testCase;
123        } catch (IllegalAccessException e) {
124            runFailed("Could not access test class. Class: " + testClass.getName());
125        } catch (InstantiationException e) {
126            runFailed("Could not instantiate test class. Class: " + testClass.getName());
127        } catch (IllegalArgumentException e) {
128            runFailed("Illegal argument passed to constructor. Class: " + testClass.getName());
129        } catch (InvocationTargetException e) {
130            runFailed("Constructor thew an exception. Class: " + testClass.getName());
131        }
132        return null;
133    }
134
135    private boolean shouldRunSingleTestMethod(String testMethodName,
136            Class<? extends Test> testClass) {
137        return testMethodName != null && TestCase.class.isAssignableFrom(testClass);
138    }
139
140    private Test getTest(Class clazz) {
141        if (TestSuiteProvider.class.isAssignableFrom(clazz)) {
142            try {
143                TestSuiteProvider testSuiteProvider =
144                        (TestSuiteProvider) clazz.getConstructor().newInstance();
145                return testSuiteProvider.getTestSuite();
146            } catch (InstantiationException e) {
147                runFailed("Could not instantiate test suite provider. Class: " + clazz.getName());
148            } catch (IllegalAccessException e) {
149                runFailed("Illegal access of test suite provider. Class: " + clazz.getName());
150            } catch (InvocationTargetException e) {
151                runFailed("Invocation exception test suite provider. Class: " + clazz.getName());
152            } catch (NoSuchMethodException e) {
153                runFailed("No such method on test suite provider. Class: " + clazz.getName());
154            }
155        }
156        return getTest(clazz.getName());
157    }
158
159    protected TestResult createTestResult() {
160        if (mSkipExecution) {
161            return new NoExecTestResult();
162        }
163        return new TestResult();
164    }
165
166    void setSkipExecution(boolean skip) {
167        mSkipExecution = skip;
168    }
169
170    public List<TestCase> getTestCases() {
171        return mTestCases;
172    }
173
174    public String getTestClassName() {
175        return mTestClassName;
176    }
177
178    public TestResult getTestResult() {
179        return mTestResult;
180    }
181
182    public void runTest() {
183        runTest(createTestResult());
184    }
185
186    public void runTest(TestResult testResult) {
187        mTestResult = testResult;
188
189        for (TestListener testListener : mTestListeners) {
190            mTestResult.addListener(testListener);
191        }
192
193        Context testContext = mInstrumentation == null ? mContext : mInstrumentation.getContext();
194        for (TestCase testCase : mTestCases) {
195            setContextIfAndroidTestCase(testCase, mContext, testContext);
196            setInstrumentationIfInstrumentationTestCase(testCase, mInstrumentation);
197            setPerformanceWriterIfPerformanceCollectorTestCase(testCase, mPerfWriter);
198            testCase.run(mTestResult);
199        }
200    }
201
202    private void setContextIfAndroidTestCase(Test test, Context context, Context testContext) {
203        if (AndroidTestCase.class.isAssignableFrom(test.getClass())) {
204            ((AndroidTestCase) test).setContext(context);
205            ((AndroidTestCase) test).setTestContext(testContext);
206        }
207    }
208
209    public void setContext(Context context) {
210        mContext = context;
211    }
212
213    private void setInstrumentationIfInstrumentationTestCase(
214            Test test, Instrumentation instrumentation) {
215        if (InstrumentationTestCase.class.isAssignableFrom(test.getClass())) {
216            ((InstrumentationTestCase) test).injectInstrumentation(instrumentation);
217        }
218    }
219
220    private void setPerformanceWriterIfPerformanceCollectorTestCase(
221            Test test, PerformanceResultsWriter writer) {
222        if (PerformanceCollectorTestCase.class.isAssignableFrom(test.getClass())) {
223            ((PerformanceCollectorTestCase) test).setPerformanceResultsWriter(writer);
224        }
225    }
226
227    public void setInstrumentation(Instrumentation instrumentation) {
228        mInstrumentation = instrumentation;
229    }
230
231    /**
232     * @deprecated Incorrect spelling,
233     * use {@link #setInstrumentation(android.app.Instrumentation)} instead.
234     */
235    @Deprecated
236    public void setInstrumentaiton(Instrumentation instrumentation) {
237        setInstrumentation(instrumentation);
238    }
239
240    /**
241     * {@hide} Pending approval for public API.
242     */
243    public void setPerformanceResultsWriter(PerformanceResultsWriter writer) {
244        mPerfWriter = writer;
245    }
246
247    @Override
248    protected Class loadSuiteClass(String suiteClassName) throws ClassNotFoundException {
249        return mContext.getClassLoader().loadClass(suiteClassName);
250    }
251
252    public void testStarted(String testName) {
253    }
254
255    public void testEnded(String testName) {
256    }
257
258    public void testFailed(int status, Test test, Throwable t) {
259    }
260
261    protected void runFailed(String message) {
262        throw new RuntimeException(message);
263    }
264}
265