/**
* Copyright (C) 2012 - 2014 Eric Van Dewoestine
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.eclim.plugin.jdt.command.junit;
import java.io.File;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collections;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.BuildLogger;
import org.apache.tools.ant.DefaultLogger;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.optional.junit.BatchTest;
import org.apache.tools.ant.taskdefs.optional.junit.FormatterElement;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTask;
import org.apache.tools.ant.taskdefs.optional.junit.JUnitTest;
import org.apache.tools.ant.types.Commandline.Argument;
import org.apache.tools.ant.types.Environment.Variable;
import org.apache.tools.ant.types.FileSet;
import org.apache.tools.ant.types.Path;
import org.eclim.Services;
import org.eclim.annotation.Command;
import org.eclim.command.CommandLine;
import org.eclim.command.Options;
import org.eclim.plugin.core.command.AbstractCommand;
import org.eclim.plugin.core.util.ProjectUtils;
import org.eclim.plugin.jdt.util.ClasspathUtils;
import org.eclim.plugin.jdt.util.JavaUtils;
import org.eclim.util.StringUtils;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jdt.core.IAnnotation;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.internal.junit.launcher.JUnit4TestFinder;
import org.eclipse.jdt.junit.JUnitCore;
import org.osgi.framework.Bundle;
/**
* Command to handle execution of junit tests.
*
* @author Eric Van Dewoestine
*/
@Command(
name = "java_junit",
options =
"REQUIRED p project ARG," +
"OPTIONAL d debug NOARG," +
"OPTIONAL h halt NOARG," +
"OPTIONAL t test ARG," +
"OPTIONAL f file ARG," +
"OPTIONAL o offset ARG," +
"OPTIONAL e encoding ARG"
)
public class JUnitCommand
extends AbstractCommand
{
@Override
public Object execute(CommandLine commandLine)
throws Exception
{
String projectName = commandLine.getValue(Options.PROJECT_OPTION);
String testName = commandLine.getValue(Options.TEST_OPTION);
String file = commandLine.getValue(Options.FILE_OPTION);
int offset = getOffset(commandLine);
boolean debug = commandLine.hasOption(Options.DEBUG_OPTION);
boolean halt = commandLine.hasOption(Options.HALT_OPTION);
IProject project = ProjectUtils.getProject(projectName);
project.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, null);
IJavaProject javaProject = JavaUtils.getJavaProject(project);
JUnitTask junit = createJUnitTask(javaProject, debug, halt);
String[] vmargs =
getPreferences().getArrayValue(project, "org.eclim.java.junit.jvmargs");
for(String vmarg : vmargs){
if (!vmarg.startsWith("-")){
continue;
}
Argument a = junit.createJvmarg();
a.setValue(vmarg);
}
String[] props =
getPreferences().getArrayValue(project, "org.eclim.java.junit.sysprops");
for(String prop : props){
String[] sysprop = StringUtils.split(prop, "=", 2);
if (sysprop.length != 2){
continue;
}
if (sysprop[0].startsWith("-D")){
sysprop[0] = sysprop[0].substring(2);
}
Variable var = new Variable();
var.setKey(sysprop[0]);
var.setValue(sysprop[1]);
junit.addConfiguredSysproperty(var);
}
String[] envs =
getPreferences().getArrayValue(project, "org.eclim.java.junit.envvars");
for(String env : envs){
String[] envvar = StringUtils.split(env, "=", 2);
if (envvar.length != 2){
continue;
}
Variable var = new Variable();
var.setKey(envvar[0]);
var.setValue(envvar[1]);
junit.addEnv(var);
}
if (file != null){
ICompilationUnit src = JavaUtils.getCompilationUnit(javaProject, file);
IMethod method = null;
if (offset != -1){
IJavaElement element = src.getElementAt(offset);
if(element != null && element.getElementType() == IJavaElement.METHOD){
method = (IMethod)element;
}
}
JUnit4TestFinder finder = new JUnit4TestFinder();
IType type = src.getTypes()[0];
if (!finder.isTest(type)){
src = JUnitUtils.findTest(javaProject, type);
if (src == null){
println(Services.getMessage("junit.testing.test.not.found"));
return null;
}
if (method != null){
method = JUnitUtils.findTestMethod(src, method);
if (method == null){
println(Services.getMessage("junit.testing.test.method.not.found"));
return null;
}
}
}
JUnitTest test = new JUnitTest();
test.setName(JavaUtils.getFullyQualifiedName(src));
if (method != null){
IAnnotation testAnnotation = method.getAnnotation("Test");
if (testAnnotation == null || !testAnnotation.exists()){
println(Services.getMessage(
"junit.testing.test.method.not.annotated",
method.getElementName()));
return null;
}
test.setMethods(method.getElementName());
}
junit.addTest(test);
}else if (testName != null){
if (testName.indexOf('*') != -1){
createBatchTest(javaProject, junit, testName);
}else{
JUnitTest test = new JUnitTest();
test.setName(testName);
junit.addTest(test);
}
}else{
ArrayList<String> names = new ArrayList<String>();
IType[] types = JUnitCore.findTestTypes(javaProject, null);
for (IType type : types) {
names.add(type.getFullyQualifiedName());
}
Collections.sort(names);
for (String name : names){
JUnitTest test = new JUnitTest();
test.setName(name);
junit.addTest(test);
}
}
try{
junit.init();
junit.execute();
}catch(BuildException be){
if(debug){
be.printStackTrace(getContext().err);
}
}
return null;
}
private JUnitTask createJUnitTask(
IJavaProject javaProject, boolean debug, boolean halt)
throws Exception
{
Project antProject = new Project();
BuildLogger buildLogger = new DefaultLogger();
buildLogger.setEmacsMode(true);
buildLogger.setMessageOutputLevel(debug ? Project.MSG_DEBUG : Project.MSG_INFO);
buildLogger.setOutputPrintStream(getContext().out);
buildLogger.setErrorPrintStream(getContext().err);
antProject.addBuildListener(buildLogger);
antProject.setBasedir(ProjectUtils.getPath(javaProject.getProject()));
// construct classpath
Path classpath = new Path(antProject);
String[] paths = ClasspathUtils.getClasspath(javaProject);
for (String path : paths){
Path.PathElement pe = classpath.createPathElement();
pe.setPath(path);
}
// add some ant jar files otherwise ant will fail to load them.
Bundle bundle = Platform.getBundle("org.apache.ant");
String pathName = FileLocator.getBundleFile(bundle).getPath();
classpath.createPathElement().setPath(pathName + "/lib/ant.jar");
classpath.createPathElement().setPath(pathName + "/lib/ant-junit.jar");
classpath.createPathElement().setPath(pathName + "/lib/ant-junit4.jar");
bundle = Platform.getBundle("org.eclim.jdt");
pathName = FileLocator.getBundleFile(bundle).getPath();
classpath.createPathElement().setPath(pathName + "/eclim.jdt.jar");
JUnitTask junit = new JUnitTask();
junit.setProject(antProject);
junit.setTaskName("junit");
junit.setFork(true);
IProject project = javaProject.getProject();
String cwd = getPreferences().getValue(project, "org.eclim.java.junit.cwd");
junit.setDir(new File(
cwd != null && cwd.trim().length() > 0 ? cwd :
ProjectUtils.getPath(project)));
junit.setHaltonerror(halt);
junit.setHaltonfailure(halt);
junit.createClasspath().append(classpath);
// we need to add ant.jar to the classpath for the ant test runner to work,
// but then JUnitTask will complain about multiple ant jars, so prevent
// that.
Field forkedPathChecked =
JUnitTask.class.getDeclaredField("forkedPathChecked");
forkedPathChecked.setAccessible(true);
forkedPathChecked.set(junit, true);
FormatterElement formatter = new FormatterElement();
junit.addFormatter(formatter);
formatter.setClassname("org.eclim.plugin.jdt.command.junit.ResultFormatter");
formatter.setUseFile(false);
return junit;
}
private void createBatchTest(
IJavaProject javaProject, JUnitTask junit, String pattern)
throws Exception
{
if (!pattern.endsWith(".java")){
pattern += ".java";
}
BatchTest batch = junit.createBatchTest();
IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
for (IClasspathEntry entry : entries){
if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE){
String path = ProjectUtils.getFilePath(
javaProject.getProject(), entry.getPath().toOSString());
FileSet fileset = new FileSet();
fileset.setDir(new File(path));
fileset.setIncludes(pattern);
batch.addFileSet(fileset);
}
}
}
}