118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/*
218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Copyright (C) 2012 The Android Open Source Project
318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Licensed under the Apache License, Version 2.0 (the "License");
518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * you may not use this file except in compliance with the License.
618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * You may obtain a copy of the License at
718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *      http://www.apache.org/licenses/LICENSE-2.0
918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
1018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * Unless required by applicable law or agreed to in writing, software
1118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * distributed under the License is distributed on an "AS IS" BASIS,
1218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * See the License for the specific language governing permissions and
1418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * limitations under the License.
1518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */
1618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
1718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupackage com.android.uiautomator.testrunner;
1818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
1918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport junit.framework.TestCase;
2018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
2118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.lang.reflect.Method;
2218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.ArrayList;
2318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.Collections;
2418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhuimport java.util.List;
2518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
2618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu/**
2718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * A convenient class that encapsulates functions for adding test classes
2818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu *
2918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu * @hide
3018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu */
3118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhupublic class TestCaseCollector {
3218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
3318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private ClassLoader mClassLoader;
3418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private List<TestCase> mTestCases;
3518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private TestCaseFilter mFilter;
3618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
3718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public TestCaseCollector(ClassLoader classLoader, TestCaseFilter filter) {
3818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mClassLoader = classLoader;
3918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mTestCases = new ArrayList<TestCase>();
4018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        mFilter = filter;
4118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
4218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
4318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
4418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Adds classes to test by providing a list of class names in string
4518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
4618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * The class name may be in "<class name>#<method name>" format
4718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
4818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @param classNames class must be subclass of {@link UiAutomatorTestCase}
4918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @throws ClassNotFoundException
5018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
5118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public void addTestClasses(List<String> classNames) throws ClassNotFoundException {
5218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        for (String className : classNames) {
5318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            addTestClass(className);
5418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
5518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
5618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
5718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
5818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Adds class to test by providing class name in string.
5918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
6018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * The class name may be in "<class name>#<method name>" format
6118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
6218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @param className classes must be subclass of {@link UiAutomatorTestCase}
6318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @throws ClassNotFoundException
6418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
6518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public void addTestClass(String className) throws ClassNotFoundException {
6618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        int hashPos = className.indexOf('#');
6718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        String methodName = null;
6818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if (hashPos != -1) {
6918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            methodName = className.substring(hashPos + 1);
7018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            className = className.substring(0, hashPos);
7118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
7218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        addTestClass(className, methodName);
7318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
7418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
7518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
7618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Adds class to test by providing class name and method name in separate strings
7718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
7818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @param className class must be subclass of {@link UiAutomatorTestCase}
7918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @param methodName may be null, in which case all "public void testNNN(void)" functions
8018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *                   will be added
8118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @throws ClassNotFoundException
8218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
8318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public void addTestClass(String className, String methodName) throws ClassNotFoundException {
8418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        Class<?> clazz = mClassLoader.loadClass(className);
8518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if (methodName != null) {
8618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            addSingleTestMethod(clazz, methodName);
8718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } else {
8818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            Method[] methods = clazz.getMethods();
8918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            for (Method method : methods) {
9018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                if (mFilter.accept(method)) {
9118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    addSingleTestMethod(clazz, method.getName());
9218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                }
9318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
9418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
9518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
9618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
9718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
9818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Gets the list of added test cases so far
9918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * @return a list of {@link TestCase}
10018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
10118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public List<TestCase> getTestCases() {
10218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        return Collections.unmodifiableList(mTestCases);
10318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
10418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
10518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    protected void addSingleTestMethod(Class<?> clazz, String method) {
10618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        if (!(mFilter.accept(clazz))) {
10718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            throw new RuntimeException("Test class must be derived from UiAutomatorTestCase");
10818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
10918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        try {
11018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            TestCase testCase = (TestCase) clazz.newInstance();
11118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            testCase.setName(method);
11218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestCases.add(testCase);
11318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } catch (InstantiationException e) {
11418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestCases.add(error(clazz, "InstantiationException: could not instantiate " +
11518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    "test class. Class: " + clazz.getName()));
11618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        } catch (IllegalAccessException e) {
11718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            mTestCases.add(error(clazz, "IllegalAccessException: could not instantiate " +
11818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                    "test class. Class: " + clazz.getName()));
11918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        }
12018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
12118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
12218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    private UiAutomatorTestCase error(Class<?> clazz, final String message) {
12318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        UiAutomatorTestCase warning = new UiAutomatorTestCase() {
12418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            protected void runTest() {
12518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu                fail(message);
12618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu            }
12718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        };
12818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
12918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        warning.setName(clazz.getName());
13018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        return warning;
13118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
13218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
13318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    /**
13418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     * Determine if a class and its method should be accepted into test suite
13518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     *
13618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu     */
13718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    public interface TestCaseFilter {
13818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
13918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        /**
14018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * Determine that based on the method signature, if it can be accepted
14118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * @param method
14218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         */
14318b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public boolean accept(Method method);
14418b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu
14518b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        /**
14618b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * Determine that based on the class type, if it can be accepted
14718b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * @param clazz
14818b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         * @return
14918b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu         */
15018b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu        public boolean accept(Class<?> clazz);
15118b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu    }
15218b892c723e812a7e111f102d2b0c0782b116bb6Guang Zhu}
153