blob: d69d5f54286ca7f55f0f118f9aec3ab54a55a889 [file] [log] [blame]
/*
* Copyright (c) 2008, 2011-2013 Eike Stepper (Berlin, Germany) 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
*
* Contributors:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.emf.cdo.tests.config.impl;
import org.eclipse.emf.cdo.tests.config.IConstants;
import org.eclipse.emf.cdo.tests.config.IScenario;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Requires;
import org.eclipse.emf.cdo.tests.config.impl.ConfigTest.Skips;
import org.eclipse.net4j.util.om.OMBundle;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import junit.framework.Test;
import junit.framework.TestResult;
import junit.framework.TestSuite;
/**
* @author Eike Stepper
*/
public abstract class ConfigTestSuite implements IConstants
{
public ConfigTestSuite()
{
}
public Test getTestSuite()
{
return getTestSuite(getClass().getName());
}
public Test getTestSuite(String name)
{
TestSuite suite = new MainSuite(name);
initConfigSuites(suite);
return suite;
}
public void addScenario(TestSuite parent, RepositoryConfig repositoryConfig, SessionConfig sessionConfig,
ModelConfig modelConfig)
{
IScenario scenario = new Scenario();
scenario.setRepositoryConfig(repositoryConfig);
scenario.setSessionConfig(sessionConfig);
scenario.setModelConfig(modelConfig);
if (scenario.isValid())
{
TestSuite suite = new TestSuite(scenario.toString());
List<Class<? extends ConfigTest>> testClasses = new ArrayList<Class<? extends ConfigTest>>();
initTestClasses(testClasses, scenario);
for (Class<? extends ConfigTest> testClass : testClasses)
{
try
{
TestWrapper wrapper = new TestWrapper(testClass, scenario, this);
if (wrapper.testCount() != 0)
{
suite.addTest(wrapper);
}
}
catch (ConstraintsViolatedException ex)
{
//$FALL-THROUGH$
}
}
parent.addTest(suite);
}
}
protected List<Class<? extends ConfigTest>> getTestClasses(OMBundle bundle, String packageName)
{
List<Class<? extends ConfigTest>> result = new ArrayList<Class<? extends ConfigTest>>();
for (Iterator<Class<?>> it = bundle.getClasses(); it.hasNext();)
{
Class<?> c = it.next();
if (ConfigTest.class.isAssignableFrom(c) && c.getName().startsWith(packageName))
{
@SuppressWarnings("unchecked")
Class<? extends ConfigTest> configTest = (Class<? extends ConfigTest>)c;
result.add(configTest);
}
}
Collections.sort(result, new Comparator<Class<? extends ConfigTest>>()
{
public int compare(Class<? extends ConfigTest> c1, Class<? extends ConfigTest> c2)
{
return c1.getName().compareTo(c2.getName());
}
});
return result;
}
protected abstract void initConfigSuites(TestSuite parent);
protected abstract void initTestClasses(List<Class<? extends ConfigTest>> testClasses, IScenario scenario);
/**
* Can be overridden by subclasses.
*/
protected void prepareTest(ConfigTest configTest)
{
}
/**
* Can be overridden by subclasses.
*/
protected void mainSuiteFinished()
{
}
/**
* @author Eike Stepper
*/
private final class MainSuite extends TestSuite
{
public MainSuite(String name)
{
super(name);
}
@Override
public void run(TestResult result)
{
super.run(result);
mainSuiteFinished();
}
}
/**
* @author Eike Stepper
*/
private static final class ConstraintsViolatedException extends Exception
{
private static final long serialVersionUID = 1L;
}
/**
* @author Eike Stepper
*/
private static final class TestWrapper extends TestSuite
{
private IScenario scenario;
public TestWrapper(Class<? extends ConfigTest> testClass, IScenario scenario, ConfigTestSuite suite)
throws ConstraintsViolatedException
{
// super(testClass, testClass.getName()); // Important for the UI to set the *qualified* class name!
this.scenario = scenario;
addTestsFromTestCase(testClass, suite);
}
@Override
public void runTest(Test test, TestResult result)
{
if (test instanceof ConfigTest)
{
scenario.save();
ConfigTest configTest = (ConfigTest)test;
configTest.setScenario(scenario);
if (configTest.isValid())
{
super.runTest(configTest, result);
}
}
else
{
super.runTest(test, result);
}
}
private void addTestsFromTestCase(final Class<?> theClass, ConfigTestSuite suite)
throws ConstraintsViolatedException
{
setName(theClass.getName());
try
{
getTestConstructor(theClass); // Avoid generating multiple error messages
}
catch (NoSuchMethodException e)
{
addTest(warning("Class " + theClass.getName()
+ " has no public constructor TestCase(String name) or TestCase()"));
return;
}
if (!Modifier.isPublic(theClass.getModifiers()))
{
addTest(warning("Class " + theClass.getName() + " is not public"));
return;
}
Set<String> capabilities = scenario.getCapabilities();
Class<?> superClass = theClass;
while (Test.class.isAssignableFrom(superClass))
{
if (!validateConstraints(superClass, capabilities))
{
throw new ConstraintsViolatedException();
}
superClass = superClass.getSuperclass();
}
List<String> names = new ArrayList<String>();
superClass = theClass;
while (Test.class.isAssignableFrom(superClass))
{
for (Method method : superClass.getDeclaredMethods())
{
if (validateConstraints(method, capabilities))
{
addTestMethod(method, names, theClass, suite);
}
}
superClass = superClass.getSuperclass();
}
}
private boolean validateConstraints(AnnotatedElement element, Set<String> capabilities)
{
Requires requires = element.getAnnotation(Requires.class);
if (requires != null)
{
for (String require : requires.value())
{
if (!capabilities.contains(require))
{
return false;
}
}
}
Skips skips = element.getAnnotation(Skips.class);
if (skips != null)
{
for (String skip : skips.value())
{
if (capabilities.contains(skip))
{
return false;
}
}
}
return true;
}
private void addTestMethod(Method m, List<String> names, Class<?> theClass, ConfigTestSuite suite)
{
String name = m.getName();
if (names.contains(name))
{
return;
}
if (!isPublicTestMethod(m))
{
if (isTestMethod(m))
{
addTest(warning("Test method isn't public: " + m.getName() + "(" + theClass.getCanonicalName() + ")"));
}
return;
}
names.add(name);
Test test = createTest(theClass, name);
if (test instanceof ConfigTest)
{
ConfigTest configTest = (ConfigTest)test;
suite.prepareTest(configTest);
}
addTest(test);
}
private boolean isPublicTestMethod(Method m)
{
return isTestMethod(m) && Modifier.isPublic(m.getModifiers());
}
private boolean isTestMethod(Method m)
{
return m.getParameterTypes().length == 0 && m.getName().startsWith("test") && m.getReturnType().equals(Void.TYPE);
}
}
}