com.android.ide.eclipse.adt.internal.launch.junit.AndroidJUnitLaunchConfigDelegate.java Source code

Java tutorial

Introduction

Here is the source code for com.android.ide.eclipse.adt.internal.launch.junit.AndroidJUnitLaunchConfigDelegate.java

Source

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Eclipse Public License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.eclipse.org/org/documents/epl-v10.php
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.ide.eclipse.adt.internal.launch.junit;

import com.android.SdkConstants;
import com.android.ddmlib.testrunner.IRemoteAndroidTestRunner.TestSize;
import com.android.ide.common.xml.ManifestData;
import com.android.ide.common.xml.ManifestData.Instrumentation;
import com.android.ide.eclipse.adt.AdtConstants;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.launch.AndroidLaunch;
import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchConfiguration;
import com.android.ide.eclipse.adt.internal.launch.AndroidLaunchController;
import com.android.ide.eclipse.adt.internal.launch.IAndroidLaunchAction;
import com.android.ide.eclipse.adt.internal.launch.LaunchConfigDelegate;
import com.android.ide.eclipse.adt.internal.launch.LaunchMessages;
import com.android.ide.eclipse.adt.internal.launch.junit.runtime.AndroidJUnitLaunchInfo;
import com.android.ide.eclipse.adt.internal.project.BaseProjectHelper;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants;
import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry;
import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants;
import org.eclipse.swt.widgets.Display;

/**
 * Run configuration that can execute JUnit tests on an Android platform.
 * <p/>
 * Will deploy apps on target Android platform by reusing functionality from ADT
 * LaunchConfigDelegate, and then run JUnits tests by reusing functionality from JDT
 * JUnitLaunchConfigDelegate.
 */
@SuppressWarnings("restriction")
public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate {

    /** Launch config attribute that stores instrumentation runner. */
    static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$

    /** Launch config attribute that stores the test size annotation to run. */
    static final String ATTR_TEST_SIZE = AdtPlugin.PLUGIN_ID + ".testSize"; //$NON-NLS-1$

    private static final String EMPTY_STRING = ""; //$NON-NLS-1$

    @Override
    protected void doLaunch(final ILaunchConfiguration configuration, final String mode,
            final IProgressMonitor monitor, final IProject project, final AndroidLaunch androidLaunch,
            final AndroidLaunchConfiguration config, final AndroidLaunchController controller,
            final IFile applicationPackage, final ManifestData manifestData) {

        String runner = getRunner(project, configuration, manifestData);
        if (runner == null) {
            AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle,
                    String.format(LaunchMessages.AndroidJUnitDelegate_NoRunnerMsg_s, project.getName()));
            androidLaunch.stopLaunch();
            return;
        }
        // get the target app's package
        final String targetAppPackage = getTargetPackage(manifestData, runner);
        if (targetAppPackage == null) {
            AdtPlugin.displayError(LaunchMessages.LaunchDialogTitle,
                    String.format(LaunchMessages.AndroidJUnitDelegate_NoTargetMsg_3s, project.getName(), runner,
                            SdkConstants.FN_ANDROID_MANIFEST_XML));
            androidLaunch.stopLaunch();
            return;
        }
        final String testAppPackage = manifestData.getPackage();
        AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, testAppPackage, runner);
        junitLaunchInfo.setTestClass(getTestClass(configuration));
        junitLaunchInfo.setTestPackage(getTestPackage(configuration));
        junitLaunchInfo.setTestMethod(getTestMethod(configuration));
        junitLaunchInfo.setLaunch(androidLaunch);
        junitLaunchInfo.setTestSize(getTestSize(configuration));
        final IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo);

        // launch on a separate thread if currently on the display thread
        if (Display.getCurrent() != null) {
            Job job = new Job("Junit Launch") { //$NON-NLS-1$
                @Override
                protected IStatus run(IProgressMonitor m) {
                    controller.launch(project, mode, applicationPackage, testAppPackage, targetAppPackage,
                            manifestData.getDebuggable(), manifestData.getMinSdkVersionString(), junitLaunch,
                            config, androidLaunch, monitor);
                    return Status.OK_STATUS;
                }
            };
            job.setPriority(Job.INTERACTIVE);
            job.schedule();
        } else {
            controller.launch(project, mode, applicationPackage, testAppPackage, targetAppPackage,
                    manifestData.getDebuggable(), manifestData.getMinSdkVersionString(), junitLaunch, config,
                    androidLaunch, monitor);
        }
    }

    /**
     * Get the target Android application's package for the given instrumentation runner, or
     * <code>null</code> if it could not be found.
     *
     * @param manifestParser the {@link ManifestData} for the test project
     * @param runner the instrumentation runner class name
     * @return the target package or <code>null</code>
     */
    private String getTargetPackage(ManifestData manifestParser, String runner) {
        for (Instrumentation instr : manifestParser.getInstrumentations()) {
            if (instr.getName().equals(runner)) {
                return instr.getTargetPackage();
            }
        }
        return null;
    }

    /**
     * Returns the test package stored in the launch configuration, or <code>null</code> if not
     * specified.
     *
     * @param configuration the {@link ILaunchConfiguration} to retrieve the test package info from
     * @return the test package or <code>null</code>.
     */
    private String getTestPackage(ILaunchConfiguration configuration) {
        // try to retrieve a package name from the JUnit container attribute
        String containerHandle = getStringLaunchAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER,
                configuration);
        if (containerHandle != null && containerHandle.length() > 0) {
            IJavaElement element = JavaCore.create(containerHandle);
            // containerHandle could be a IProject, check if its a java package
            if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) {
                return element.getElementName();
            }
        }
        return null;
    }

    /**
     * Returns the test class stored in the launch configuration.
     *
     * @param configuration the {@link ILaunchConfiguration} to retrieve the test class info from
     * @return the test class. <code>null</code> if not specified.
     */
    private String getTestClass(ILaunchConfiguration configuration) {
        return getStringLaunchAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, configuration);
    }

    /**
     * Returns the test method stored in the launch configuration.
     *
     * @param configuration the {@link ILaunchConfiguration} to retrieve the test method info from
     * @return the test method. <code>null</code> if not specified.
     */
    private String getTestMethod(ILaunchConfiguration configuration) {
        return getStringLaunchAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, configuration);
    }

    /**
     * Returns the test sizes to run as saved in the launch configuration.
     * @return {@link TestSize} if only tests of specific sizes should be run,
     *         null if all tests should be run
     */
    private TestSize getTestSize(ILaunchConfiguration configuration) {
        String testSizeAnnotation = getStringLaunchAttribute(AndroidJUnitLaunchConfigDelegate.ATTR_TEST_SIZE,
                configuration);
        if (AndroidJUnitLaunchConfigurationTab.SMALL_TEST_ANNOTATION.equals(testSizeAnnotation)) {
            return TestSize.SMALL;
        } else if (AndroidJUnitLaunchConfigurationTab.MEDIUM_TEST_ANNOTATION.equals(testSizeAnnotation)) {
            return TestSize.MEDIUM;
        } else if (AndroidJUnitLaunchConfigurationTab.LARGE_TEST_ANNOTATION.equals(testSizeAnnotation)) {
            return TestSize.LARGE;
        } else {
            return null;
        }
    }

    /**
     * Gets a instrumentation runner for the launch.
     * <p/>
     * If a runner is stored in the given <code>configuration</code>, will return that.
     * Otherwise, will try to find the first valid runner for the project.
     * If a runner can still not be found, will return <code>null</code>, and will log an error
     * to the console.
     *
     * @param project the {@link IProject} for the app
     * @param configuration the {@link ILaunchConfiguration} for the launch
     * @param manifestData the {@link ManifestData} for the project
     *
     * @return <code>null</code> if no instrumentation runner can be found, otherwise return
     *   the fully qualified runner name.
     */
    private String getRunner(IProject project, ILaunchConfiguration configuration, ManifestData manifestData) {
        try {
            String runner = getRunnerFromConfig(configuration);
            if (runner != null) {
                return runner;
            }
            final InstrumentationRunnerValidator instrFinder = new InstrumentationRunnerValidator(
                    BaseProjectHelper.getJavaProject(project), manifestData);
            runner = instrFinder.getValidInstrumentationTestRunner();
            if (runner != null) {
                AdtPlugin.printErrorToConsole(project,
                        String.format(LaunchMessages.AndroidJUnitDelegate_NoRunnerConfigMsg_s, runner));
                return runner;
            }
            AdtPlugin.printErrorToConsole(project,
                    String.format(LaunchMessages.AndroidJUnitDelegate_NoRunnerConsoleMsg_4s, project.getName(),
                            SdkConstants.CLASS_INSTRUMENTATION_RUNNER, AdtConstants.LIBRARY_TEST_RUNNER,
                            SdkConstants.FN_ANDROID_MANIFEST_XML));
            return null;
        } catch (CoreException e) {
            AdtPlugin.log(e, "Error when retrieving instrumentation info"); //$NON-NLS-1$
        }

        return null;
    }

    private String getRunnerFromConfig(ILaunchConfiguration configuration) {
        return getStringLaunchAttribute(ATTR_INSTR_NAME, configuration);
    }

    /**
     * Helper method to retrieve a string attribute from the launch configuration
     *
     * @param attributeName name of the launch attribute
     * @param configuration the {@link ILaunchConfiguration} to retrieve the attribute from
     * @return the attribute's value. <code>null</code> if not found.
     */
    private String getStringLaunchAttribute(String attributeName, ILaunchConfiguration configuration) {
        try {
            String attrValue = configuration.getAttribute(attributeName, EMPTY_STRING);
            if (attrValue.length() < 1) {
                return null;
            }
            return attrValue;
        } catch (CoreException e) {
            AdtPlugin.log(e, String.format("Error when retrieving launch info %1$s", //$NON-NLS-1$
                    attributeName));
        }
        return null;
    }

    /**
     * Helper method to set JUnit-related attributes expected by JDT JUnit runner
     *
     * @param config the launch configuration to modify
     */
    static void setJUnitDefaults(ILaunchConfigurationWorkingCopy config) {
        // set the test runner to JUnit3 to placate JDT JUnit runner logic
        config.setAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_RUNNER_KIND,
                TestKindRegistry.JUNIT3_TEST_KIND_ID);
    }
}