/** * Copyright 2010 JBoss Inc * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.drools.eclipse; //Copyright (c) 2006 Alex Blewitt //All rights reserved. This program and the accompanying materials //are made available under the terms of the Eclipse Public License v1.0 //which accompanies this distribution, and is available at //http://www.eclipse.org/legal/epl-v10.html // //Contributors: //Alex Blewitt - Initial API and implementation // import java.lang.reflect.Modifier; import java.net.URL; import java.util.Enumeration; import java.util.Vector; import junit.framework.Test; import junit.framework.TestSuite; import junit.runner.ClassPathTestCollector; import junit.runner.TestCollector; import org.eclipse.core.runtime.Platform; /** * Run all the tests in this project, either computed from the classpath or from * the bundlepath. To use this as-is, drop it into a non-default package that * has the same name as the plugin. For example, if the plugin is called * <code>org.example.foo</code>, this should be placed in a package * <code>org.example.foo</code>, and all tests should live under the * <code>org.example.foo</code> package structure (either directly, or in any * subpackage). By default this will include all non-abstract classes named * <code>XxxTest</code>, excluding <code>XxxPlatformTest</code> if running * outside of the platform. */ public class AllTestsUtil { /** * Detects classes from the bundle PLUGIN_NAME's entries. Uses * <code>bundle.findEntries</code> to obtain a list of classes that live * in the specified PACKAGE_NAME, and adds those to the test path, providing * that they are {@link AllTests#isValidTest(String, boolean) valid}. */ private static class BundleTestDetector implements TestCollector { /* * @see junit.runner.TestCollector#collectTests() */ public Enumeration collectTests() { final Vector tests = new Vector(); try { Enumeration entries = Platform.getBundle(PLUGIN_NAME).findEntries("/", "*" + SUFFIX + ".class", true); while (entries.hasMoreElements()) { URL entry = (URL) entries.nextElement(); // Change the URLs to have Java class names String path = entry.getPath().replace('/', '.'); int start = path.indexOf(PACKAGE_NAME); String name = path.substring(start, path.length() - ".class".length()); if (isValidTest(name, true)) { tests.add(name); } } } catch (Exception e) { // If we get here, the Platform isn't installed and so we fail // quietly. This isn't a problem; we might be outside of the // Platform framework and just running tests locally. It's not // even worth printing anything out to the error log as it would // just confuse people investigating stack traces etc. } return tests.elements(); } } /** * Searches the current classpath for tests, which are those ending with * SUFFIX, excluding those which end in IN_CONTAINER_SUFFIX, providing that * they are {@link AllTests#isValidTest(String, boolean) valid}. */ private static class ClassFileDetector extends ClassPathTestCollector { /* * @see junit.runner.ClassPathTestCollector#isTestClass(java.lang.String) */ protected boolean isTestClass(String classFileName) { return classFileName.endsWith(SUFFIX + ".class") && isValidTest(classNameFromFile(classFileName), false); } } /** * All tests should end in XxxTest */ public static final String SUFFIX = "Test"; /** * All in-container tests should end in XxxPlatformTest */ public static final String IN_CONTAINER_SUFFIX = "Platform" + SUFFIX; /** * The base package name of the tests to run. This defaults to the name of * the package that the AllTests class is in for ease of management but may * be trivially changed if required. Note that at least some identifiable * part must be provided here (so default package names are not allowed) * since the URL that comes up in the bundle entries have a prefix that is * not detectable automatically. Even if this is "org" or "com" that should * be enough. */ public static final String PACKAGE_NAME = AllTests.class.getPackage() .getName(); /** * The name of the plugin to search if the platform is loaded. This defaults * to the name of the package that the AllTests class is in for ease of * management but may be trivially changed if required. */ //PO: this is wrong. we need to use the PLUGIN_ID of the host, not that of the // fragment // public static final String PLUGIN_NAME = AllTests.class.getPackage() // .getName(); public static final String PLUGIN_NAME = "org.drools.eclipse"; /** * Add the tests reported by collector to the list of tests to run * @param collector the test collector to run * @param suite the suite to add the tests to */ private static void addTestsToSuite(TestCollector collector, TestSuite suite) { Enumeration e = collector.collectTests(); while (e.hasMoreElements()) { String name = (String) e.nextElement(); try { suite.addTestSuite(Class.forName(name)); } catch (ClassNotFoundException e1) { System.err.println("Cannot load test: " + e1); } } } /** * Is the test a valid test? * @param name the name of the test * @param inContainer true if we want to include the inContainer tests * @return true if the name is a valid class (can be loaded), that it is not * abstract, and that it ends with SUFFIX, and that either * inContainer tests are to be included or the name does not end * with IN_CONTAINER_SUFFIX */ private static boolean isValidTest(String name, boolean inContainer) { try { return name.endsWith(SUFFIX) && (inContainer || !name.endsWith(IN_CONTAINER_SUFFIX)) && ((Class.forName(name).getModifiers() & Modifier.ABSTRACT) == 0); } catch (ClassNotFoundException e) { System.err.println(e.toString()); return false; } } /** * Return all the tests. If we're in a platform, return everything. If not, * we return those tests that end in SUFFIX but excluding those ending in * IN_CONTAINER_SUFFIX. * @return a suite of tests for JUnit to run * @throws Error if there are no tests to run. */ public static Test suite() { TestSuite suite = new TestSuite(AllTests.class.getName()); addTestsToSuite(new ClassFileDetector(), suite); addTestsToSuite(new BundleTestDetector(), suite); if (suite.countTestCases() == 0) { throw new Error("There are no test cases to run"); } else { return suite; } } }