package org.gradle.plugins.easyb;
import org.easyb.BehaviorRunner;
import org.easyb.Configuration;
import org.easyb.domain.GroovyShellConfiguration;
import org.easyb.report.*;
import org.gradle.api.GradleException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.internal.ConventionTask;
import org.gradle.api.tasks.*;
import java.io.File;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.*;
public class Easyb extends ConventionTask implements VerificationTask {
private boolean ignoreFailures;
private File behaviorsDir;
private File reportsDir;
private List<String> suffixes;
private List<String> reportFormats;
FileCollection classpath;
private static final Map<String, ReportConfig> REPORT_CONFIGURATION = new LinkedHashMap<String, ReportConfig>();
static {
REPORT_CONFIGURATION.put("story", new ReportConfig("plain", "easyb-stories.txt", TxtStoryReportWriter.class));
REPORT_CONFIGURATION.put("spec", new ReportConfig("plain", "easyb-specifications.txt", TxtSpecificationReportWriter.class));
REPORT_CONFIGURATION.put("html", new ReportConfig("html", "easyb-reports.html", HtmlReportWriter.class));
REPORT_CONFIGURATION.put("xml", new ReportConfig("xml", "easyb-reports.xml", XmlReportWriter.class));
REPORT_CONFIGURATION.put("junit", new ReportConfig("junit", "", JUnitReportWriter.class));
}
@TaskAction
public void easyb() {
String[] filePaths = filePaths();
List<URL> urls = new ArrayList<URL>();
for (File file : getClasspath()) {
try {
URL url = file.toURI().toURL();
urls.add(url);
} catch (MalformedURLException e) {
getLogger().error("could not get URL for file "+ file.getAbsolutePath(), e);
}
}
try {
ClassLoader easybAndRuntime = new URLClassLoader(urls.toArray(new URL[urls.size()]),EasybPlugin.class.getClassLoader());
GroovyShellConfiguration gsh = new GroovyShellConfiguration(easybAndRuntime, Collections.<String, Object>emptyMap());
Configuration config = new Configuration(filePaths, reportWriters(easybAndRuntime));
BehaviorRunner runner = new BehaviorRunner(config);
runner.runBehaviors(BehaviorRunner.getBehaviors(gsh, filePaths, config));
} catch (Exception e) {
throw new GradleException("BehaviourExecution failed", e);
}
}
private List<ReportWriter> reportWriters(ClassLoader parentClassloader) {
List<ReportWriter> reportWriters = new ArrayList<ReportWriter>();
for (String reportFormat : getReportFormats()) {
ReportConfig reportConfig = REPORT_CONFIGURATION.get(reportFormat);
reportWriters.add(reportConfig.newReportWriterInstance(reportConfig.getWriterClass(), getReportsDir(), parentClassloader));
}
return reportWriters;
}
private String[] filePaths() {
List<String> paths = new ArrayList<String>();
System.out.println("behaviour dir is " + String.valueOf(getBehaviorsDir()));
listFiles(getBehaviorsDir(), paths);
return paths.toArray(new String[paths.size()]);
}
private void listFiles(File dir, List<String> files) {
//check whether this is a valid directory at all
File[] filesInDirectory = dir.listFiles();
if (filesInDirectory != null) {
for (File file : filesInDirectory) {
if (file.isDirectory()) {
listFiles(file, files);
} else if (isBehavior(file)) {
files.add(file.getAbsolutePath());
}
}
} else {
// TODO use logger, fail build?!
System.err.println("Could not find any behaviour/story files in " + dir + ", maybe IDE prefix (working dir) is wrong?");
}
}
private boolean isBehavior(File file) {
for (String pattern : getSuffixes()) {
if (file.getName().endsWith(pattern)) return true;
}
return false;
}
public List<String> getReportFormats() {
return reportFormats;
}
public void setReportFormats(List<String> reportFormats) {
this.reportFormats = reportFormats;
}
@OutputDirectory
public File getReportsDir() {
return reportsDir;
}
public void setReportsDir(File reportsDir) {
this.reportsDir = reportsDir;
}
@Input
public List<String> getSuffixes() {
return suffixes;
}
public void setSuffixes(List<String> suffixes) {
this.suffixes = suffixes;
}
@InputDirectory
public File getBehaviorsDir() {
return behaviorsDir;
}
public void setBehaviorsDir(File behaviorsDir) {
this.behaviorsDir = behaviorsDir;
}
public Easyb setIgnoreFailures(boolean ignoreFailures) {
this.ignoreFailures = ignoreFailures;
return this;
}
public boolean isIgnoreFailures() {
return ignoreFailures;
}
/**
* Returns the classpath containing the compiled classes for the source files to be inspected.
*
* @return The classpath.
*/
@InputFiles
public FileCollection getClasspath() {
return classpath;
}
/**
* Specified the classpath containing the compiled classes for the source file to be inspected.
*
* @param classpath The classpath. Must not be null.
*/
public void setClasspath(FileCollection classpath) {
getLogger().info("setting classpath for easyb", classpath);
this.classpath = classpath;
}
private static class ReportConfig {
private final String dirName;
private final String fileName;
private final Class<? extends ReportWriter> reportClassName;
private ReportConfig(String dirName, String fileName, Class<? extends ReportWriter> reportClassName) {
this.dirName = dirName;
this.fileName = fileName;
this.reportClassName = reportClassName;
}
public ReportWriter newReportWriterInstance(Class<? extends ReportWriter> reportClass, File reportsDir, final ClassLoader parentClassloader) {
File reportDir = new File(reportsDir.getAbsolutePath(), dirName);
reportDir.mkdirs();
try {
ReportWriter reportWriter = reportClass.getDeclaredConstructor(String.class).newInstance(reportDir.getAbsolutePath() + File.separator + fileName);
Method[] declaredMethods = reportWriter.getClass().getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
if(Arrays.asList(declaredMethod.getParameterTypes()).contains(ClassLoader.class)){
declaredMethod.invoke(reportWriter,parentClassloader);
}
}
return reportWriter;
} catch (Exception e) {
throw new IllegalArgumentException(e);
}
}
public Class<? extends ReportWriter> getWriterClass() {
return reportClassName;
}
}
}