FileDocCategorySizeDatePackage
JUnitLaunchConfigDelegate.javaAPI DocAndroid 1.5 API6544Wed May 06 22:41:10 BST 2009com.android.ide.eclipse.adt.launch

JUnitLaunchConfigDelegate

public class JUnitLaunchConfigDelegate extends org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate

For Android projects, android.jar gets added to the launch configuration of JUnit tests as a bootstrap entry. This breaks JUnit tests as android.jar contains a skeleton version of JUnit classes and the JVM will stop with an error similar to:

Error occurred during initialization of VM java/lang/NoClassDefFoundError: java/lang/ref/FinalReference

At compile time, Eclipse does not know that there is no valid junit.jar in the classpath since it can find a correct reference to all the necessary org.junit.* classes in the android.jar so it does not prompt the user to add the JUnit3 or JUnit4 jar.

This delegates removes the android.jar from the bootstrap path and if necessary also puts back the junit.jar in the user classpath.

This delegate will be present for both Java and Android projects (delegates setting instead of only the current project) but the behavior for Java projects should be neutral since:

  1. Java tests can only compile (and then run) when a valid junit.jar is present
  2. There is no android.jar in Java projects

Fields Summary
private static final String
JUNIT_JAR
Constructors Summary
Methods Summary
public static java.lang.String[][]fixBootpathExt(java.lang.String[][] bootpath)
Removes the android.jar from the bootstrap path if present.

param
bootpath Array of Arrays of bootstrap class paths
return
a new modified (if applicable) bootpath

        for (int i = 0; i < bootpath.length; i++) {
            if (bootpath[i] != null) {
                // we assume that the android.jar can only be present in the
                // bootstrap path of android tests
                if (bootpath[i][0].endsWith(SdkConstants.FN_FRAMEWORK_LIBRARY)) {
                    bootpath[i] = null;
                }
            }
        }
        return bootpath;
    
public static java.lang.String[]fixClasspath(java.lang.String[] classpath, java.lang.String projectName)
Add the junit.jar to the user classpath; since Eclipse was relying on android.jar to provide the appropriate org.junit classes, it does not know it actually needs the junit.jar.

param
classpath Array containing classpath
param
projectName The name of the project (for logging purposes)
return
a new modified (if applicable) classpath

        // search for junit.jar; if any are found return immediately
        for (int i = 0; i < classpath.length; i++) {
            if (classpath[i].endsWith(JUNIT_JAR)) { 
                return classpath;
            }
        }

        // This delegate being called without a junit.jar present is only
        // possible for Android projects. In a non-Android project, the test
        // would not compile and would be unable to run.
        try {
            // junit4 is backward compatible with junit3 and they uses the
            // same junit.jar from bundle org.junit:
            // When a project has mixed JUnit3 and JUnit4 tests, if JUnit3 jar
            // is added first it is then replaced by the JUnit4 jar when user is
            // prompted to fix the JUnit4 test failure
            String jarLocation = getJunitJarLocation();
            // we extend the classpath by one element and append junit.jar
            String[] newClasspath = new String[classpath.length + 1];
            System.arraycopy(classpath, 0, newClasspath, 0, classpath.length);
            newClasspath[newClasspath.length - 1] = jarLocation;
            classpath = newClasspath;
        } catch (IOException e) {
            // This should not happen as we depend on the org.junit
            // plugin explicitly; the error is logged here so that the user can
            // trace back the cause when the test fails to run
            AdtPlugin.log(e, "Could not find a valid junit.jar");
            AdtPlugin.printErrorToConsole(projectName,
                    "Could not find a valid junit.jar");
            // Return the classpath as-is (with no junit.jar) anyway because we
            // will let the actual launch config fails.
        }

        return classpath;
    
public java.lang.String[][]getBootpathExt(org.eclipse.debug.core.ILaunchConfiguration configuration)

 //$NON-NLS-1$

    
          
        String[][] bootpath = super.getBootpathExt(configuration);
        return fixBootpathExt(bootpath);
    
public java.lang.String[]getClasspath(org.eclipse.debug.core.ILaunchConfiguration configuration)

        String[] classpath = super.getClasspath(configuration);
        return fixClasspath(classpath, getJavaProjectName(configuration));
    
public static java.lang.StringgetJunitJarLocation()
Returns the path of the junit jar in the highest version bundle. (This is public only so that the test can call it)

return
the path as a string
throws
IOException

        Bundle bundle = Platform.getBundle("org.junit"); //$NON-NLS-1$
        if (bundle == null) {
            throw new IOException("Cannot find org.junit bundle");
        }
        URL jarUrl = bundle.getEntry(AndroidConstants.WS_SEP + JUNIT_JAR);
        return FileLocator.resolve(jarUrl).getFile();