1/*
2 * Copyright (C) 2008 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.suitebuilder;
18
19import junit.framework.TestCase;
20
21import java.lang.annotation.Annotation;
22import java.lang.reflect.Constructor;
23import java.lang.reflect.InvocationTargetException;
24import java.lang.reflect.Method;
25
26/**
27 * Represents a test to be run. Can be constructed without instantiating the TestCase or even
28 * loading the class.
29 */
30public class TestMethod {
31
32    private final String enclosingClassname;
33    private final String testMethodName;
34    private final Class<? extends TestCase> enclosingClass;
35
36    public TestMethod(Method method, Class<? extends TestCase> enclosingClass) {
37        this(method.getName(), enclosingClass);
38    }
39
40    public TestMethod(String methodName, Class<? extends TestCase> enclosingClass) {
41        this.enclosingClass = enclosingClass;
42        this.enclosingClassname = enclosingClass.getName();
43        this.testMethodName = methodName;
44    }
45
46    public TestMethod(TestCase testCase) {
47        this(testCase.getName(), testCase.getClass());
48    }
49
50    public String getName() {
51        return testMethodName;
52    }
53
54    public String getEnclosingClassname() {
55        return enclosingClassname;
56    }
57
58    public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
59        try {
60            return getEnclosingClass().getMethod(getName()).getAnnotation(annotationClass);
61        } catch (NoSuchMethodException e) {
62            return null;
63        }
64    }
65
66    @SuppressWarnings("unchecked")
67    public Class<? extends TestCase> getEnclosingClass() {
68        return enclosingClass;
69    }
70
71    public TestCase createTest()
72            throws InvocationTargetException, IllegalAccessException, InstantiationException {
73        return instantiateTest(enclosingClass, testMethodName);
74    }
75
76    @SuppressWarnings("unchecked")
77    private TestCase instantiateTest(Class testCaseClass, String testName)
78            throws InvocationTargetException, IllegalAccessException, InstantiationException {
79        Constructor[] constructors = testCaseClass.getConstructors();
80
81        if (constructors.length == 0) {
82            return instantiateTest(testCaseClass.getSuperclass(), testName);
83        } else {
84            for (Constructor constructor : constructors) {
85                Class[] params = constructor.getParameterTypes();
86                if (noargsConstructor(params)) {
87                    TestCase test = ((Constructor<? extends TestCase>) constructor).newInstance();
88                    // JUnit will run just the one test if you call
89                    // {@link TestCase#setName(String)}
90                    test.setName(testName);
91                    return test;
92                } else if (singleStringConstructor(params)) {
93                    return ((Constructor<? extends TestCase>) constructor)
94                            .newInstance(testName);
95                }
96            }
97        }
98        throw new RuntimeException("Unable to locate a constructor for "
99                + testCaseClass.getName());
100    }
101
102    private boolean singleStringConstructor(Class[] params) {
103        return (params.length == 1) && (params[0].equals(String.class));
104    }
105
106    private boolean noargsConstructor(Class[] params) {
107        return params.length == 0;
108    }
109
110    @Override
111    public boolean equals(Object o) {
112        if (this == o) {
113            return true;
114        }
115        if (o == null || getClass() != o.getClass()) {
116            return false;
117        }
118
119        TestMethod that = (TestMethod) o;
120
121        if (enclosingClassname != null
122                ? !enclosingClassname.equals(that.enclosingClassname)
123                : that.enclosingClassname != null) {
124            return false;
125        }
126        if (testMethodName != null
127                ? !testMethodName.equals(that.testMethodName)
128                : that.testMethodName != null) {
129            return false;
130        }
131        return true;
132    }
133
134    @Override
135    public int hashCode() {
136        int result;
137        result = (enclosingClassname != null ? enclosingClassname.hashCode() : 0);
138        result = 31 * result + (testMethodName != null ? testMethodName.hashCode() : 0);
139        return result;
140    }
141
142    @Override
143    public String toString() {
144        return enclosingClassname + "." + testMethodName;
145    }
146}
147