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