package de.retest.recheck;

import java.lang.reflect.Method;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.theories.Theory;

import com.google.common.base.Optional;

/**
 * This class is a duplicate of class TestCaseFinder in testutils module.
 */
public class TestCaseFinder {

	public static StackTraceElement findTestCaseMethodInStack() {
		for ( final StackTraceElement[] stack : Thread.getAllStackTraces().values() ) {
			final Optional<StackTraceElement> testCaseStackElement = findTestCaseMethodInStack( stack );
			if ( testCaseStackElement.isPresent() ) {
				return testCaseStackElement.get();
			}
		}
		return null;
	}

	private static Optional<StackTraceElement> findTestCaseMethodInStack( final StackTraceElement[] trace ) {
		boolean inTestCase = false;
		for ( int i = 0; i < trace.length; i++ ) {
			if ( isTestCase( trace[i] ) ) {
				inTestCase = true;
			} else if ( inTestCase ) {
				return Optional.of( trace[i - 1] );
			}
		}
		return Optional.absent();
	}

	private static boolean isTestCase( final StackTraceElement element ) {
		final Method method = tryToFindMethodForStackTraceElement( element );
		return method != null && (method.isAnnotationPresent( Test.class ) || method.isAnnotationPresent( Theory.class )
				|| method.isAnnotationPresent( Before.class ) || method.isAnnotationPresent( After.class )
				|| method.isAnnotationPresent( BeforeClass.class ) || method.isAnnotationPresent( AfterClass.class ));
	}

	private static Method tryToFindMethodForStackTraceElement( final StackTraceElement element ) {
		Class<?> clazz;
		Method method = null;

		try {
			clazz = Class.forName( element.getClassName() );
		} catch ( final ClassNotFoundException e ) {
			return null;
		}

		for ( final Method methodCandidate : clazz.getDeclaredMethods() ) {
			if ( methodCandidate.getName().equals( element.getMethodName() ) ) {
				if ( method == null ) {
					method = methodCandidate;
				} else {
					// two methods with same name found, can't determine correct one!
					return null;
				}
			}
		}
		return method;
	}

}

@@ -42,356 +42,532 @@
 ang.
-reflect.Method;%0A%0Aimport org.junit.After;%0Aimport org.junit.AfterClass;%0Aimport org.junit.Before;%0Aimport org.junit.BeforeClass;%0Aimport org.junit.Test;%0Aimport org.junit.experimental.theories.Theory;%0A%0Aimport com.google.common.base.Optional;%0A%0A/**%0A * This class is a duplicate of class TestCaseFinder in testutils module.%0A */%0Apublic class TestCaseFinder %7B
+annotation.Annotation;%0Aimport java.lang.reflect.Method;%0Aimport java.util.Arrays;%0Aimport java.util.HashSet;%0Aimport java.util.Set;%0A%0Aimport com.google.common.base.Optional;%0A%0A/**%0A * This class is a duplicate of class TestCaseFinder in testutils module.%0A */%0Apublic class TestCaseFinder %7B%0A%0A%09private static final Set%3CString%3E testCaseAnnotations = new HashSet%3CString%3E( Arrays.asList( //%0A%09%09%09%22org.junit.Test%22, // JUnit Vintage (v4)%0A%09%09%09%22org.junit.jupiter.api.Test%22, // JUnit Jupiter (v5)%0A%09%09%09%22org.testng.annotations.Test%22 ) ); // TestNG
 %0A%0A%09p
@@ -1418,22 +1418,20 @@
 ;%0A%09%09
-return
+if (
  method 
 != n
@@ -1430,307 +1430,328 @@
 hod 
-!
+=
 = null 
-&& (method.isAnnotationPresent( Test.class ) %7C%7C method.isAnnotationPresent( Theory.clas
+) %7B%0A%09%09%09return false;%0A%09%09%7D%0A%0A%09%09final Annotation%5B%5D annotations = method.getAnnotations();%0A%09%09for ( final Annotation annotation : annotation
 s )
+ %7B
 %0A%09%09%09
-%09%7C%7C method.isAnnotationPresent( Before.class ) %7C%7C method.isAnnotationPresent( After.class )%0A%09%09%09%09%7C%7C method.isAnnotationPresent( BeforeClass.class ) %7C%7C method.isAnnotationPresent( AfterClass.class ))
+final String annotationName = annotation.annotationType().getName();%0A%09%09%09if ( testCaseAnnotations.contains( annotationName ) ) %7B%0A%09%09%09%09return true;%0A%09%09%09%7D%0A%09%09%7D%0A%0A%09%09return false
 ;%0A%09%7D

Make test case finding more extensible