package junit.runner;

import java.lang.reflect.*;
import junit.runner.*;
import junit.framework.*;

/**
 * An implementation of a TestCollector that loads
 * all classes on the class path and tests whether
 * it is assignable from Test or provides a static suite method.
 * @see TestCollector
 */
public class LoadingTestCollector extends ClassPathTestCollector {

    TestCaseClassLoader fLoader;

    public LoadingTestCollector() {
        fLoader= new TestCaseClassLoader();
    }

    protected boolean isTestClass(String classFileName) {
        try {
            if (classFileName.endsWith(".class")) {
                Class testClass= classFromFile(classFileName);
                return (testClass != null) && isTestClass(testClass);
            }
        }
        catch (ClassNotFoundException expected) {
        }
        catch (NoClassDefFoundError notFatal) {
        }
        return false;
    }

    Class classFromFile(String classFileName) throws ClassNotFoundException {
        String className= classNameFromFile(classFileName);
        if (!fLoader.isExcluded(className))
            return fLoader.loadClass(className, false);
        return null;
    }

    boolean isTestClass(Class testClass) {
        if (hasSuiteMethod(testClass))
            return true;
        if (Test.class.isAssignableFrom(testClass) &&
            Modifier.isPublic(testClass.getModifiers()) &&
            hasPublicConstructor(testClass))
            return true;
        return false;
    }

    boolean hasSuiteMethod(Class testClass) {
        try {
            testClass.getMethod(BaseTestRunner.SUITE_METHODNAME, new Class[0]);
         } catch(Exception e) {
             return false;
        }
        return true;
    }

    boolean hasPublicConstructor(Class testClass) {
        try {
            TestSuite.getTestConstructor(testClass);
        } catch(NoSuchMethodException e) {
            return false;
        }
        return true;
    }
}
