| /******************************************************************************* |
| * Copyright (c) 2000, 2017 IBM Corporation and others. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v. 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| *******************************************************************************/ |
| package org.eclipse.dltk.core.tests.model; |
| |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Modifier; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.eclipse.dltk.core.tests.TestSupport; |
| |
| import junit.framework.AssertionFailedError; |
| import junit.framework.Protectable; |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| import junit.framework.TestListener; |
| import junit.framework.TestResult; |
| import junit.framework.TestSuite; |
| |
| /** |
| * A test case class that can be set up (using the setUpSuite() method) and tore |
| * down (using the teardDownSuite() method) once for all test cases of this |
| * class. |
| */ |
| public abstract class SuiteOfTestCases extends TestCase { |
| |
| /* |
| * A test suite that initialize the test case's fields once, then that |
| * copies the values of these fields intto each subsequent test case. |
| */ |
| public static class Suite extends TestSuite { |
| SuiteOfTestCases currentTestCase; |
| |
| /* |
| * Creates a new suite on the given class. This class must be a subclass |
| * of SetupableTestSuite. |
| */ |
| public Suite(Class<? extends SuiteOfTestCases> theClass) { |
| super(theClass); |
| } |
| |
| /** |
| * Creates a new suite on the given class. Only the methods specified in |
| * the second parameter and included in the suite. |
| * |
| * @param theClass |
| * @param methodNames |
| */ |
| public Suite(Class<? extends SuiteOfTestCases> theClass, |
| String... methodNames) { |
| super(theClass.getName()); |
| for (int i = 0; i < methodNames.length; ++i) { |
| final String methodName = methodNames[i]; |
| try { |
| final Method method = theClass.getMethod(methodName, |
| new Class[0]); |
| if (Modifier.isPublic(method.getModifiers()) |
| && !Modifier.isStatic(method.getModifiers())) { |
| addTest(createTest(theClass, methodName)); |
| } else { |
| warning(methodName, "Wrong modifiers"); |
| } |
| } catch (SecurityException e) { |
| warning(methodName, e.toString()); |
| } catch (NoSuchMethodException e) { |
| warning(methodName, e.toString()); |
| } |
| } |
| } |
| |
| private void warning(final String name, final String message) { |
| addTest(new TestCase(name) { |
| @Override |
| protected void runTest() { |
| fail(message); |
| } |
| }); |
| } |
| |
| public Suite(String name) { |
| super(name); |
| } |
| |
| void initialize(SuiteOfTestCases test) { |
| Class<?> currentClass = test.getClass(); |
| while (currentClass != null |
| && !currentClass.equals(SuiteOfTestCases.class)) { |
| Field[] fields = currentClass.getDeclaredFields(); |
| for (int i = 0, length = fields.length; i < length; i++) { |
| Field field = fields[i]; |
| |
| // skip static and final fields |
| int modifiers = field.getModifiers(); |
| if (Modifier.isStatic(modifiers) |
| || Modifier.isFinal(modifiers)) |
| continue; |
| |
| // make the field accessible |
| field.setAccessible(true); |
| |
| try { |
| Object value = field.get(this.currentTestCase); |
| field.set(test, value); |
| } catch (IllegalAccessException e) { |
| } |
| } |
| currentClass = currentClass.getSuperclass(); |
| } |
| } |
| |
| @Override |
| public void run(final TestResult result) { |
| Protectable p = () -> { |
| try { |
| // run suite (first test run will setup the suite) |
| superRun(result); |
| } finally { |
| // tear down the suite |
| if (Suite.this.currentTestCase != null) { |
| // protect against empty test suite |
| Suite.this.currentTestCase.tearDownSuite(); |
| } |
| } |
| }; |
| result.runProtected(this, p); |
| } |
| |
| public void superRun(TestResult result) { |
| super.run(result); |
| } |
| |
| @Override |
| public void runTest(Test test, TestResult result) { |
| if (test instanceof SuiteOfTestCases) { |
| final SuiteOfTestCases current = (SuiteOfTestCases) test; |
| if (this.currentTestCase == null) { |
| // setup suite |
| try { |
| current.setUpSuite(); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| } |
| } else { |
| // copy the values of the previous current test case's |
| // fields into the current one |
| this.initialize(current); |
| } |
| current.parentSuite = this; |
| try { |
| super.runTest(test, result); |
| } finally { |
| current.parentSuite = null; |
| // make current |
| this.currentTestCase = current; |
| } |
| } else { |
| /* |
| * If there was error in TestCase constructor - the test will |
| * not be of the SuiteOfTestCases type |
| */ |
| super.runTest(test, result); |
| } |
| } |
| } |
| |
| Suite parentSuite; |
| private final static Map<String, Suite> initializedSuites = new HashMap<>(); |
| |
| public SuiteOfTestCases(String name) { |
| super(name); |
| } |
| |
| /** |
| * Setup the test suite once before all test cases run. |
| */ |
| public void setUpSuite() throws Exception { |
| } |
| |
| /** |
| * Tear down the test suite once after all test cases have run. |
| */ |
| public void tearDownSuite() throws Exception { |
| } |
| |
| /** |
| * Convenience method for subclasses of {@link SuiteOfTestCases}, identical |
| * to |
| * |
| * <pre> |
| * TestSupport.notYetImplemented(this); |
| * </pre> |
| * |
| * @see TestSupport#notYetImplemented(junit.framework.TestCase) |
| * @return <false> when not itself already in the call stack |
| */ |
| public boolean notYetImplemented() { |
| return TestSupport.notYetImplemented(this); |
| } |
| |
| @Override |
| public void run(TestResult result) { |
| if (TestSupport.ignored(this)) |
| return; |
| if (parentSuite == null) { |
| final String className = getClass().getName(); |
| parentSuite = initializedSuites.get(className); |
| if (parentSuite == null) { |
| parentSuite = new Suite(getClass().getName()); |
| initializedSuites.put(getClass().getName(), parentSuite); |
| System.out.println("setUpSuite() in " + getClass().getName()); |
| // TODO (alex) tearDownSuite() not executed |
| final AtomicBoolean errors = new AtomicBoolean(); |
| final TestListener listener = new TestListener() { |
| @Override |
| public void startTest(Test test) { |
| } |
| |
| @Override |
| public void endTest(Test test) { |
| } |
| |
| @Override |
| public void addFailure(Test test, AssertionFailedError t) { |
| errors.set(true); |
| } |
| |
| @Override |
| public void addError(Test test, Throwable t) { |
| errors.set(true); |
| } |
| }; |
| result.addListener(listener); |
| result.runProtected(this, () -> setUpSuite()); |
| result.removeListener(listener); |
| if (errors.get()) { |
| return; |
| } |
| } else if (parentSuite.currentTestCase != null) { |
| parentSuite.initialize(this); |
| } |
| parentSuite.currentTestCase = this; |
| } |
| super.run(result); |
| } |
| |
| } |