/*
* The Kuali Financial System, a comprehensive financial management system for higher education.
*
* Copyright 2005-2014 The Kuali Foundation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.kuali.kfs.sys.suite;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.util.Arrays;
import junit.framework.TestCase;
import junit.framework.TestSuite;
/**
* This annotation marks test classes or methods as members of the listed test suites. This reverses the normal direction of the
* reference, from the test to the suite.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target( { ElementType.TYPE, ElementType.METHOD })
public @interface AnnotationTestSuite {
public Class<? extends Superclass>[] value();
/**
* Test suites using the enclosing annotation must extend this nested class. They should have a static method named "suite" that
* IDEs can run for convenience. That method should return getSuite() or getNegativeSuite() on an instance of the suite class.
*/
public static abstract class Superclass {
protected boolean pointsToThisClass(AnnotationTestSuite annotation) {
if (annotation != null) {
if (Arrays.asList(annotation.value()).contains(this.getClass().asSubclass(Superclass.class))) {
return true;
}
}
return false;
}
/**
* @return the suite of all test classes or methods listing this (sub)class in a AnnotationTestSuite annotation.
* @throws java.io.IOException if the directory containing the test class files cannot be scanned
*/
protected TestSuite getSuite() throws Exception {
TestSuiteBuilder.ClassCriteria classCriteria = new TestSuiteBuilder.ClassCriteria() {
public boolean includes(Class<? extends TestCase> testClass) {
return pointsToThisClass(testClass.getAnnotation(AnnotationTestSuite.class));
}
};
TestSuiteBuilder.MethodCriteria methodCriteria = new TestSuiteBuilder.MethodCriteria() {
public boolean includes(Method method) {
return pointsToThisClass(method.getAnnotation(AnnotationTestSuite.class));
}
};
TestSuite suite = TestSuiteBuilder.build(classCriteria, methodCriteria);
nameSuite(suite);
return suite;
}
private void nameSuite(TestSuite suite) {
suite.setName(this.getClass().getName());
}
/**
* @return the suite of all test methods (including those within test class sub-suites) which are not in the suite returned
* by {@link #getSuite()}.
* @throws java.io.IOException if the directory containing the test class files cannot be scanned
*/
protected TestSuite getNegativeSuite() throws Exception {
TestSuiteBuilder.MethodCriteria negativeMethodCriteria = new TestSuiteBuilder.MethodCriteria() {
public boolean includes(Method method) {
AnnotationTestSuite testClassAnnotation = method.getDeclaringClass().getAnnotation(AnnotationTestSuite.class);
return !pointsToThisClass(testClassAnnotation) && !pointsToThisClass(method.getAnnotation(AnnotationTestSuite.class));
}
};
TestSuite suite = TestSuiteBuilder.build(TestSuiteBuilder.NULL_CRITERIA, negativeMethodCriteria);
nameSuite(suite);
return suite;
}
}
}