gw.test.TestClass Maven / Gradle / Ivy
/*
* Copyright 2014 Guidewire Software, Inc.
*/
package gw.test;
import gw.lang.GosuShop;
import gw.lang.reflect.IAnnotationInfo;
import gw.lang.reflect.IConstructorInfo;
import gw.lang.reflect.IHasJavaClass;
import gw.lang.reflect.IMethodInfo;
import gw.lang.reflect.IType;
import gw.lang.reflect.Modifier;
import gw.lang.reflect.TypeSystem;
import gw.lang.reflect.java.IJavaType;
import gw.lang.reflect.java.JavaTypes;
import gw.testharness.IncludeInTestResults;
import gw.testharness.KnownBreak;
import gw.testharness.KnownBreakQualifier;
import gw.util.GosuExceptionUtil;
import gw.util.GosuObjectUtil;
import gw.util.GosuStringUtil;
import gw.util.Predicate;
import junit.framework.TestCase;
import junit.framework.TestResult;
import java.lang.annotation.Annotation;
import gw.util.Array;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class TestClass extends TestCase implements ITestWithMetadata {
private String _pkgName;
private String _className;
private TestExecutionManager _executionManager;
private static final ThreadLocal THREAD_LOCAL_EXECUTION_MANAGER = new ThreadLocal();
private List _metadata = new ArrayList();
private boolean _doNotRun;
private boolean _knownBreak;
private static final Map _numberOfInstancesCreatedByTypeName = new HashMap();
private boolean _isGosuTest;
protected TestClass() {
super();
initInternalData();
}
protected TestClass(String s) {
super(s);
initInternalData();
}
// This is a bit hacky: some subclasses might need to delay the call
// to the initInternalData() method until after the class performed some additional work
protected TestClass(boolean shouldInit) {
if (shouldInit) {
initInternalData();
}
}
// This is a bit hacky: some subclasses might need to delay the call
// to the init() method until after the class performed some additional work
protected TestClass(String s, boolean shouldInit) {
super(s);
if (shouldInit) {
initInternalData();
}
}
public boolean isGosuTest() {
return _isGosuTest;
}
public void setGosuTest(boolean gosuTest) {
_isGosuTest = gosuTest;
}
protected void initInternalData() {
String fullName = getFullClassNameInternal();
int lastDot = fullName.lastIndexOf(".");
_pkgName = fullName.substring(0, lastDot).replace("_proxy_.", "");
_className = fullName.substring(lastDot + 1, fullName.length()).replace('$', '.');
// When running from an IDE, we could be running just one method out of a class, or we could be running
// the entire class. Since we have no way to get ahold of the suite that the IDE has created, the only
// way for us to tell how many methods we're running out of a given class is to track how many instances
// of each class are created. We can then use that to determine when to run the afterClass() hook.
Integer numberOfInstances = _numberOfInstancesCreatedByTypeName.get(getTypeName());
if (numberOfInstances == null) {
_numberOfInstancesCreatedByTypeName.put(getTypeName(), 1);
} else {
_numberOfInstancesCreatedByTypeName.put(getTypeName(), numberOfInstances + 1);
}
}
protected String getFullClassNameInternal() {
return getClass().getName();
}
public static Integer getNumberOfInstancesOfTestClassCreated(String typeName) {
return _numberOfInstancesCreatedByTypeName.get(typeName);
}
@Override
protected final void setUp() throws Exception {
super.setUp();
if(!getType().getName().endsWith("Test")) {
throw new IllegalStateException("All subclasses of TestClass must have a name that ends with \"Test\"");
}
if ( _executionManager == null || _executionManager.assertionsMustBeEnabled()) {
try {
assert false;
throw new IllegalStateException("Assertions must be enabled for tests to be run properly.");
} catch (AssertionError ae) {
//ignore
}
}
}
public void setExecutionManager(TestExecutionManager executionManager) {
_executionManager = executionManager;
}
@Override
protected final void tearDown() throws Exception {
super.tearDown();
}
public void beforeTestClass(){
}
public void beforeTestMethod(){
}
public void afterTestMethod(Throwable possibleException){
}
public void afterTestClass(){
}
@Override
public void run(TestResult result) {
getExecutionManager().runTestClass(this, result);
}
public void reallyRun(TestResult result) {
super.run(result);
}
@Override
public void runBare() throws Throwable {
getExecutionManager().runTestClassBare(this);
}
public void reallyRunBare() throws Throwable {
initMetadata(getName());
super.runBare();
}
@Override
public String toString() {
return this.getName() + "(" + getTypeName() + ")";
}
@Override
public void setName(String name) {
super.setName(name);
}
@Override
public String getName() {
return super.getName();
}
protected TestExecutionManager getExecutionManager() {
if (_executionManager == null) {
return getThreadLocalExecutionManager();
} else {
return _executionManager;
}
}
//Provides a simple thread local execution manager for all the tests being run
//presumably from an IDE environment
private TestExecutionManager getThreadLocalExecutionManager() {
TestExecutionManager executionManager = THREAD_LOCAL_EXECUTION_MANAGER.get();
if (executionManager == null) {
executionManager = new TestExecutionManager();
executionManager.setEnvironment(createDefaultEnvironment());
THREAD_LOCAL_EXECUTION_MANAGER.set(executionManager);
// TODO - AHK - Set up the default classpath?
}
return executionManager;
}
public TestEnvironment createDefaultEnvironment() {
return new TestEnvironment();
}
@Override
protected final void runTest() throws Throwable {
// TODO - AHK - More properly log this, rather than using System.out
if (_knownBreak) {
System.out.println("**** Test method " + getName() + " is marked as a known break. Run tests with -Dgw.tests.skip.knownbreak=true to skip known breaks.");
}
if (_doNotRun) {
System.out.println("*** Skipping test method " + getName() + ", as it's marked @Disabled, @ManualTest, or @InProgress");
} else if (_knownBreak && skipKnownBreakTests()) {
System.out.println("*** Skipping test method " + getName() + ", as it's marked @KnownBreak and the gw.tests.skip.knownbreak system parameter is set to true.");
} else {
doRunTest( getName() );
}
}
private static Boolean _skipKnownBreakTests = null;
private static boolean skipKnownBreakTests() {
// And no, I don't really care about thread-safety here
if (_skipKnownBreakTests == null) {
String propValue = System.getProperty("gw.tests.skip.knownbreak");
if (propValue != null) {
_skipKnownBreakTests = Boolean.valueOf(propValue);
} else {
_skipKnownBreakTests = false;
}
}
return _skipKnownBreakTests;
}
protected void doRunTest( String name ) throws Throwable
{
IType type = getType();
Method runMethod;
if( type instanceof IJavaType && ((IHasJavaClass) getType()).getBackingClass() == null ) {
// Handle case where we are getting IJavaClassInfo from source (getBackingClass() returns null)
ClassLoader cl = type.getTypeLoader().getModule().getModuleTypeLoader().getDefaultTypeLoader().getGosuClassLoader().getActualLoader();
Class> testClass = Class.forName( type.getName(), true, cl );
runMethod = testClass.getMethod( name );
}
else {
runMethod = ((IHasJavaClass) getType()).getBackingClass().getMethod( name );
}
if (runMethod == null) {
fail("Method \"" + name + "\" not found");
}
if (!Modifier.isPublic(runMethod.getModifiers())) {
fail("Method \"" + name + "\" should be public");
}
try
{
runMethod.invoke(this);
}
catch( InvocationTargetException e )
{
throw GosuExceptionUtil.forceThrow( e.getTargetException() );
}
// IMethodInfo runMethod = null;
// runMethod = getType().getTypeInfo().getMethod( name );
// if (runMethod == null) {
// fail("Method \"" + name + "\" not found");
// }
// if (!runMethod.isPublic()) {
// fail("Method \"" + name + "\" should be public");
// }
// runMethod.getCallHandler().handleCall(this);
}
public IType getType() {
return TypeSystem.getFromObject(this);
}
public String getTypeName() {
return _pkgName + "." + _className;
}
//================================================================
// Utility Methods
//================================================================
public String getClassName() {
return _className;
}
public String getPackageName() {
return _pkgName;
}
//================================================================
// Assertion extensions
//================================================================
public interface EqualityTester {
boolean equals(Object expected, Object got);
}
public static void assertArrayEquals(Object[] expected, Object[] got) {
assertArrayEquals(expected, got, new EqualityTester() {
@Override
public boolean equals(Object expected, Object got) {
if (expected != null && got != null && expected.getClass().isArray() && got.getClass().isArray() && Array.getLength(expected) == Array.getLength(got)) {
int length = Array.getLength(expected);
for (int i = 0; i < length; i++) {
if (!equals(Array.get(expected, i), Array.get(got, i))) {
return false;
}
}
return true;
}
return GosuObjectUtil.equals(expected, got);
}
});
}
/**
* Compare two byte arrays, first the size then each byte.
* @param expected
* @param actual
*/
public static void assertArrayEquals(String message, byte[] expected, byte[] actual) {
if (expected.length != actual.length) {
fail(message+" - expected array length of "+expected.length+" but got "+actual.length);
for (int i=0; i hist = new HashMap
© 2015 - 2024 Weber Informatics LLC | Privacy Policy