001: /*
002: * Copyright 2006-2007 The Kuali Foundation.
003: *
004: * Licensed under the Educational Community License, Version 1.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.opensource.org/licenses/ecl1.php
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.kuali.test.suite;
017:
018: import java.lang.annotation.ElementType;
019: import java.lang.annotation.Retention;
020: import java.lang.annotation.RetentionPolicy;
021: import java.lang.annotation.Target;
022: import java.lang.reflect.Method;
023: import java.util.Arrays;
024:
025: import junit.framework.TestCase;
026: import junit.framework.TestSuite;
027:
028: /**
029: * This annotation marks test classes or methods as members of the listed test suites. This reverses the normal direction of the
030: * reference, from the test to the suite.
031: */
032: @Retention(RetentionPolicy.RUNTIME)
033: @Target({ElementType.TYPE,ElementType.METHOD})
034: public @interface AnnotationTestSuite {
035:
036: public Class<? extends Superclass>[] value();
037:
038: /**
039: * Test suites using the enclosing annotation must extend this nested class. They should have a static method named "suite" that
040: * IDEs can run for convenience. That method should return getSuite() or getNegativeSuite() on an instance of the suite class.
041: */
042: public static abstract class Superclass {
043:
044: protected boolean pointsToThisClass(
045: AnnotationTestSuite annotation) {
046: if (annotation != null) {
047: if (Arrays.asList(annotation.value()).contains(
048: this .getClass().asSubclass(Superclass.class))) {
049: return true;
050: }
051: }
052: return false;
053: }
054:
055: /**
056: * @return the suite of all test classes or methods listing this (sub)class in a AnnotationTestSuite annotation.
057: * @throws java.io.IOException if the directory containing the test class files cannot be scanned
058: */
059: protected TestSuite getSuite() throws Exception {
060: TestSuiteBuilder.ClassCriteria classCriteria = new TestSuiteBuilder.ClassCriteria() {
061: public boolean includes(
062: Class<? extends TestCase> testClass) {
063: return pointsToThisClass(testClass
064: .getAnnotation(AnnotationTestSuite.class));
065: }
066: };
067: TestSuiteBuilder.MethodCriteria methodCriteria = new TestSuiteBuilder.MethodCriteria() {
068: public boolean includes(Method method) {
069: return pointsToThisClass(method
070: .getAnnotation(AnnotationTestSuite.class));
071: }
072: };
073: TestSuite suite = TestSuiteBuilder.build(classCriteria,
074: methodCriteria);
075: nameSuite(suite);
076: return suite;
077: }
078:
079: private void nameSuite(TestSuite suite) {
080: suite.setName(this .getClass().getName());
081: }
082:
083: /**
084: * @return the suite of all test methods (including those within test class sub-suites) which are not in the suite returned
085: * by {@link #getSuite()}.
086: * @throws java.io.IOException if the directory containing the test class files cannot be scanned
087: */
088: protected TestSuite getNegativeSuite() throws Exception {
089: TestSuiteBuilder.MethodCriteria negativeMethodCriteria = new TestSuiteBuilder.MethodCriteria() {
090: public boolean includes(Method method) {
091: AnnotationTestSuite testClassAnnotation = method
092: .getDeclaringClass().getAnnotation(
093: AnnotationTestSuite.class);
094: return !pointsToThisClass(testClassAnnotation)
095: && !pointsToThisClass(method
096: .getAnnotation(AnnotationTestSuite.class));
097: }
098: };
099: TestSuite suite = TestSuiteBuilder.build(
100: TestSuiteBuilder.NULL_CRITERIA,
101: negativeMethodCriteria);
102: nameSuite(suite);
103: return suite;
104: }
105: }
106: }
|