1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License"); you
5  * may not use this file except in compliance with the License. You may obtain a
6  * copy of the License at
7  *
8  * http://www.eclipse.org/org/documents/epl-v10.php
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, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  */
16 package com.android.ide.eclipse.tests;
17 
18 import org.eclipse.core.runtime.Plugin;
19 
20 import java.lang.reflect.Modifier;
21 import java.net.URL;
22 import java.util.Enumeration;
23 
24 import junit.framework.TestCase;
25 import junit.framework.TestSuite;
26 
27 /**
28  * Class for collecting all test cases in an eclipse plugin
29  *
30  */
31 public class EclipseTestCollector {
32 
33     /**
34      * Constructor
35      */
EclipseTestCollector()36     public EclipseTestCollector() {
37 
38     }
39 
40     /**
41      * Searches through given plugin, adding all TestCase classes to given suite
42      * @param suite - TestSuite to add to
43      * @param plugin - Plugin to search for tests
44      * @param expectedPackage - expected package for tests. Only test classes
45      *  that start with this package name will be added to suite
46      */
47     @SuppressWarnings({"cast", "unchecked"})
addTestCases(TestSuite suite, Plugin plugin, String expectedPackage)48     public void addTestCases(TestSuite suite, Plugin plugin, String expectedPackage) {
49         if (plugin != null) {
50             Enumeration<?> entries = plugin.getBundle().findEntries("/", "*.class", true);
51 
52             while (entries.hasMoreElements()) {
53                 URL entry = (URL)entries.nextElement();
54                 String filePath = entry.getPath().replace(".class", "");
55                 try {
56                   Class<?> testClass = getClass(filePath, expectedPackage);
57                   if (isTestClass(testClass)) {
58                       // In Eclipse 3.6 RCP Windows-x64, the signature has changed from
59                       //    addTestSuite(Class)
60                       // to:
61                       //    addTestSuite(Class<? extends TestCase>)
62                       // which is enough to create an error. To solve it, we cast into the
63                       // generics expected by the JUnit framework used by 3.6 and suppress the
64                       // warnings generated by the compiler under 3.5
65                       suite.addTestSuite((Class<? extends TestCase>)testClass);
66                   }
67                 }
68                 catch (ClassNotFoundException e) {
69                   // ignore, this is not the class we're looking for
70                   //sLogger.log(Level.INFO, "Could not load class " + filePath);
71               }
72             }
73         }
74     }
75 
76     /**
77      * Returns true if given class should be added to suite
78      */
isTestClass(Class<?> testClass)79     protected boolean isTestClass(Class<?> testClass) {
80         return TestCase.class.isAssignableFrom(testClass) &&
81           Modifier.isPublic(testClass.getModifiers()) &&
82           hasPublicConstructor(testClass);
83     }
84 
85     /**
86      * Returns true if given class has a public constructor
87      */
88     @SuppressWarnings({"unchecked", "cast"})
hasPublicConstructor(Class<?> testClass)89     protected boolean hasPublicConstructor(Class<?> testClass) {
90         try {
91             // In Eclipse 3.6 RCP Windows-x64, the signature has changed from
92             //    getTestConstructor(Class)
93             // to:
94             //    getTestConstructor(Class<? extends TestCase>)
95             // which is enough to create an error. To solve it, we cast into the
96             // generics expected by the JUnit framework used by 3.6 and suppress the
97             // warnings generated by the compiler under 3.5
98             TestSuite.getTestConstructor((Class<? extends TestCase>) testClass);
99         } catch(NoSuchMethodException e) {
100             return false;
101         }
102         return true;
103     }
104 
105     /**
106      * Load the class given by the plugin aka bundle file path
107      * @param filePath - path of class in bundle
108      * @param expectedPackage - expected package of class
109      * @throws ClassNotFoundException
110      */
getClass(String filePath, String expectedPackage)111     protected Class<?> getClass(String filePath, String expectedPackage) throws ClassNotFoundException {
112         String dotPath = filePath.replace('/', '.');
113         // remove the output folders, by finding where package name starts
114         int index = dotPath.indexOf(expectedPackage);
115         if (index == -1) {
116             throw new ClassNotFoundException();
117         }
118         String packagePath = dotPath.substring(index);
119         return Class.forName(packagePath);
120     }
121 }
122