package net.sf.cotta.test;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
abstract public class TestCase extends junit.framework.TestCase {
private List<Closeable> resourcesToClose;
public TestCase() {
loadFixtures();
}
public TestCase(String name) {
super(name);
loadFixtures();
}
private void loadFixtures() {
FixtureRepository.instance().register(this);
}
public void runBare() throws Throwable {
runBare(FixtureRepository.instance());
}
void runBare(FixtureRepository repository) throws Throwable {
repository.fixtureSetUp(this);
try {
reallyRunBare(repository);
} finally {
closeResources();
repository.fixtureTearDown(this);
resetsFieldsToSaveMemoryForLargeTestSuite();
}
}
private void closeResources() {
if (resourcesToClose == null) {
return;
}
for (Closeable aResourcesToClose : resourcesToClose) {
try {
(aResourcesToClose).close();
} catch (Exception e) {
// ignore exception
}
}
}
private void resetsFieldsToSaveMemoryForLargeTestSuite() {
Class<?> aClass = getClass();
for (Class<?> testClass = aClass; !testClass.equals(TestCase.class); testClass = testClass.getSuperclass()) {
reset(testClass);
}
}
private void reset(Class<?> aClass) {
for (Field field : aClass.getDeclaredFields()) {
reset(field);
}
}
private void reset(Field field) {
if (Modifier.isPublic(field.getModifiers())
&& !Modifier.isStatic(field.getModifiers())) {
try {
field.set(this, null);
} catch (IllegalAccessException e) {
throw new IllegalStateException("couldn't reset field " + field.getName(), e);
}
}
}
private void reallyRunBare(FixtureRepository repository) throws Throwable {
Throwable exception = null;
repository.beforeMethod(this);
beforeMethod();
try {
runTest();
} catch (Throwable running) {
exception = running;
}
finally {
try {
afterMethod();
} catch (Throwable tearingDown) {
if (exception == null) {
exception = tearingDown;
}
}
repository.afterMethod(this);
}
if (exception != null) {
throw exception;
}
}
/**
* Register resources to be closed when test is finished, all exceptions will be ignored
* @param resource resource to close
*/
protected void registerResource(Closeable resource) {
if (resourcesToClose == null) {
resourcesToClose = new ArrayList<Closeable>(3);
}
resourcesToClose.add(resource);
}
/**
* @throws Exception
* @deprecated call beforeMethod instead
*/
@Deprecated
final protected void setUp() throws Exception {
throw new UnsupportedOperationException("you should call super.beforeMethod() instead. Otherwise super.beforeMethod() might be skipped");
}
/**
* @throws Exception
* @deprecated call afterMethod instead
*/
@Deprecated
final protected void tearDown() throws Exception {
throw new UnsupportedOperationException("you should call super.afterMethod() instead. Otherwise super.afterMethod() might be skipped");
}
/**
* Method to be called before the test method. You don't need to call this empty implementation
* @throws Exception exception
*/
public void beforeMethod() throws Exception {
}
/**
* Method to be called after the test method. You don't need to call this empty implemenation from subclass
* @throws Exception exception
*/
public void afterMethod() throws Exception {
}
public static AssertionFactory ensure = new AssertionFactory();
public void inject(Object value) {
if (value == null) {
throw new IllegalArgumentException("Cannot set null value to the field");
}
for (Field field : getClass().getFields()) {
ForFixture forFixture = field.getAnnotation(ForFixture.class);
if (forFixture != null && field.getType().isAssignableFrom(value.getClass())) {
try {
field.set(this, value);
} catch (IllegalAccessException e) {
throw new IllegalStateException("Couldn't inject value to field " + field);
}
}
}
}
}