blob: 84b8d3c2910969f04b902343fe0a04190809847e [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 IBM Corporation and others.
* 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
*
*******************************************************************************/
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);
}
}