/* * Copyright 2012 James Moger * * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0 * * 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 org.moxie.ant; import java.io.File; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.types.Environment; import org.apache.tools.ant.types.FileSet; import org.apache.tools.ant.types.Path; import org.apache.tools.ant.types.Reference; import org.moxie.Build; import org.moxie.BuildConfig; import org.moxie.MoxieException; import org.moxie.Scope; import org.moxie.Toolkit.Key; import org.moxie.maxml.MaxmlMap; import org.moxie.mxtest.Cobertura; import org.moxie.mxtest.Emma; import org.moxie.mxtest.JUnit; import org.moxie.mxtest.Jacoco; import org.moxie.mxtest.TestNG; import org.moxie.utils.FileUtils; public class MxTest extends MxTask { File unitTestOutputDirectory; File testReports; File coverageReports; File instrumentedBuild; File coberturaData; File emmaData; File jacocoData; File classesDirectory; File testClassesDirectory; Path unitTestClasspath; FileSet unitTests; String failureProperty; boolean failOnError; public MxTest() { super(); setTaskName("mx:test"); } public File getUnitTestOutputDir() { return unitTestOutputDirectory; } public File getTestReports() { return testReports; } public File getCoverageReports() { return coverageReports; } public File getInstrumentedBuild() { return instrumentedBuild; } public File getCoberturaData() { return coberturaData; } public File getEmmaData() { return emmaData; } public File getJaCoCoData() { return jacocoData; } public File getClassesDir() { return classesDirectory; } public File getTestClassesDir() { return testClassesDirectory; } public Path getUnitTestClasspath() { return unitTestClasspath; } public FileSet getUnitTests() { return unitTests; } public String getFailureProperty() { return failureProperty; } public boolean getFailOnError() { return failOnError; } public void setFailOnError(boolean value) { this.failOnError = value; } public Environment.Variable getCoberturaFileProperty() { return newFile("net.sourceforge.cobertura.datafile", coberturaData.getAbsolutePath()); } public Environment.Variable getEmmaFileProperty() { return newFile("emma.coverage.out.file", emmaData.getAbsolutePath()); } public Environment.Variable getEmmaMergeProperty() { return newValue("emma.coverage.out.merge", "true"); } public static Environment.Variable newValue(String key, String value) { Environment.Variable v = new Environment.Variable(); v.setKey(key); v.setValue(value); return v; } public static Environment.Variable newFile(String key, String value) { Environment.Variable v = new Environment.Variable(); v.setKey(key); v.setFile(new File(value)); return v; } @Override public void execute() throws BuildException { /* * Prepare all variables and state. */ Build build = getBuild(); BuildConfig config = build.getConfig(); // generate unit test info into build/tests unitTestOutputDirectory = new File(config.getOutputDirectory(null), "tests"); FileUtils.delete(unitTestOutputDirectory); unitTestOutputDirectory.mkdirs(); // generate unit test info into target/tests testReports = new File(config.getReportsTargetDirectory(), "tests"); FileUtils.delete(testReports); testReports.mkdirs(); // instrument classes for code coverages into build/instrumented-classes instrumentedBuild = new File(config.getOutputDirectory(null), "instrumented-classes"); FileUtils.delete(instrumentedBuild); instrumentedBuild.mkdirs(); // generate code coverage report into target/coverage coverageReports = new File(config.getReportsTargetDirectory(), "coverage"); FileUtils.delete(coverageReports); coverageReports.mkdirs(); // delete Corbertura metadata coberturaData = new File(config.getOutputDirectory(null), "cobertura.ser"); coberturaData.delete(); // delete EMMA metadata emmaData = new File(config.getOutputDirectory(null), "metadata.emma"); emmaData.delete(); // delete JaCoCo metadata jacocoData = new File(config.getOutputDirectory(null), "jacoco.exec"); jacocoData.delete(); classesDirectory = config.getOutputDirectory(Scope.compile); testClassesDirectory = config.getOutputDirectory(Scope.test); // define the test class fileset unitTests = new FileSet(); unitTests.setProject(getProject()); unitTests.setDir(testClassesDirectory); MaxmlMap attributes = config.getTaskAttributes(getTaskName()); failureProperty = attributes.getString("failureProperty", "unit.test.failed"); failOnError = attributes.getBoolean("failOnError", false); unitTests.createInclude().setName(attributes.getString("include", "**/*Test.class")); // classpath for tests // instrumented classes, unit test classes, and unit test libraries unitTestClasspath = new Path(getProject()); unitTestClasspath.createPathElement().setPath(instrumentedBuild.getAbsolutePath()); unitTestClasspath.createPath().setRefid(new Reference(getProject(), Key.testClasspath.referenceId())); unitTestClasspath.createPath().setRefid(new Reference(getProject(), Key.buildClasspath.referenceId())); unitTestClasspath.createPathElement().setPath(testClassesDirectory.getAbsolutePath()); // log the unit test classpath to the console in debug mode build.getConsole().debug("unit test classpath"); for (String element : unitTestClasspath.toString().split(File.pathSeparator)) { build.getConsole().debug(1, element); } /* * Do the work. */ // compile the code and unit test classes MxJavac compile = new MxJavac(); compile.setProject(getProject()); compile.setScope(Scope.test.name()); compile.execute(); // instrument code classes if (hasClass("net.sourceforge.cobertura.ant.InstrumentTask")) { Cobertura.instrument(this); } else if (hasClass("com.vladium.emma.emmaTask")) { Emma.instrument(this); } else if (hasClass("org.jacoco.ant.AbstractCoverageTask")) { // jacoco wraps unit test tasks } else { build.getConsole().warn("SKIPPING code-coverage!"); build.getConsole().warn("add \"- build jacoco\", \"- build cobertura\", or \"- build emma\" to your dependencies for code-coverage."); } // optional jvmarg for running unit tests String jvmarg = null; if (hasClass("org.jacoco.ant.AbstractCoverageTask")) { jvmarg = Jacoco.newJvmarg(this); } // execute unit tests if (hasClass("org.testng.TestNGAntTask")) { TestNG.test(this, jvmarg); } else if (hasClass("junit.framework.Test")) { JUnit.test(this, jvmarg); } else { build.getConsole().warn("SKIPPING unit tests!"); build.getConsole().warn("add \"- test junit\" or \"- test testng\" to your dependencies to execute unit tests."); } // generate code coverage reports if (hasClass("net.sourceforge.cobertura.ant.ReportTask")) { Cobertura.report(this); } else if (hasClass("com.vladium.emma.report.reportTask")) { Emma.report(this); } else if (hasClass("org.jacoco.ant.ReportTask")) { Jacoco.report(this); } if ((getProject().getProperty(getFailureProperty()) != null) && failOnError) { throw new MoxieException("{0} has failed unit tests! Build aborted!", build.getPom().getArtifactId()); } } }