All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.flexmojos.oss.plugin.test.TestCompilerMojo Maven / Gradle / Ivy

Go to download

With this maven plugin Flex3/AS3 sources can be compiled into a SWC or SWF package.

There is a newer version: 7.1.1
Show newest version
/**
 * Flexmojos is a set of maven goals to allow maven users to compile, optimize and test Flex SWF, Flex SWC, Air SWF and Air SWC.
 * Copyright (C) 2008-2012  Marvin Froeder 
 *
 * 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 .
 */
package net.flexmojos.oss.plugin.test;

import flex2.compiler.common.SinglePathResolver;
import net.flexmojos.oss.compiler.IRuntimeSharedLibraryPath;
import net.flexmojos.oss.compiler.MxmlcConfigurationHolder;
import net.flexmojos.oss.compiler.command.Result;
import net.flexmojos.oss.plugin.common.FlexClassifier;
import net.flexmojos.oss.plugin.common.flexbridge.MavenPathResolver;
import net.flexmojos.oss.plugin.compiler.MxmlcMojo;
import net.flexmojos.oss.plugin.compiler.attributes.MavenRuntimeException;
import net.flexmojos.oss.plugin.test.scanners.FlexClassScanner;
import net.flexmojos.oss.plugin.utilities.MavenUtils;
import net.flexmojos.oss.util.CollectionUtils;
import net.flexmojos.oss.util.PathUtil;
import net.flexmojos.oss.util.SocketUtil;
import org.apache.commons.io.IOUtils;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.model.FileSet;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;

import java.io.*;
import java.util.*;

import static java.util.Arrays.asList;
import static net.flexmojos.oss.matcher.artifact.ArtifactMatcher.*;
import static net.flexmojos.oss.plugin.common.FlexExtension.*;
import static net.flexmojos.oss.plugin.common.FlexScopes.*;
import static net.flexmojos.oss.util.PathUtil.*;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.Matchers.startsWith;

/**
 * 

* Goal which compiles the Flex test into a runnable application *

* * @author Marvin Herman Froeder ([email protected]) * @since 1.0 * @goal test-compile * @requiresDependencyResolution test * @phase test-compile * @threadSafe */ public class TestCompilerMojo extends MxmlcMojo { public static final String FLEXMOJOS_TEST_CONTROL_PORT = "flexmojos_test_control_port"; public static final String FLEXMOJOS_TEST_PORT = "flexmojos_test_port"; /** * Uses instruments the bytecode (using apparat) to create test coverage report. Only the test-swf is affected by * this. * * @parameter expression="${flex.coverage}" */ private boolean coverage; /** * Classes that shouldn't be include on code coverage analysis. * * @parameter */ private String[] coverageExclusions; /** * The strategy used by flexmojos do determine which files should be taken into account when calculating code * coverage. So far there are 4 valid values: 'all', 'disabled', 'link-report' and 'as3Content'
  • *
      * 'all' is the default implementation, includes all .as and .mxml available on source folders, is the fastest but * has potential problems with as3 inclusion. This ensures all classes available on source folder are taken into * account when calculating code coverage. *
    *
      * 'disabled' it will produce wrong coverage reports *
    *
      * 'link-report' will use the application link-report in other to know which classes need to be included on coverage * reports, basically mean that all files on your swf/swc will be on the coverage report, but not necessarily all * files present on your source folders. *
    *
      * 'as3Content' will scan all .as and .mxml file contents and will handle they properly, this ensures all classes * available on source folder are taken into account when calculating code coverage. *
    *
  • * * @parameter default-value="all" expression="${flex.coverageStrategy}" */ private String coverageStrategy; /** * Files to exclude from testing. If not defined, assumes no exclusions * * @parameter */ private List excludeTestFiles; /** * File to be tested. If not defined assumes Test*.as and *Test.as * * @parameter */ private List includeTestFiles; /** * @readonly */ private FlexClassScanner scanner; /** * @component role='net.flexmojos.oss.plugin.test.scanners.FlexClassScanner' */ private Map scanners; /** * Set this to 'true' to bypass unit tests entirely. Its use is NOT RECOMMENDED, but quite convenient on occasion. * * @parameter expression="${maven.test.skip}" */ private boolean skipTests; /** * Specify this parameter to run individual tests by file name, overriding the includes/excludes parameters. Each * pattern you specify here will be used to create an include pattern formatted like **\/${test}.as and * **\/${test}.mxml, so you can just type "-Dtest=MyTest" to run a single test called "foo/MyTest.as" and * "bar/MyTest.mxml". *

    * This mimic surefire test configuration. http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html#test *

    * * @parameter expression="${test}" */ private String test; /** * The maven compile source roots *

    * Equivalent to -compiler.source-path *

    * List of path elements that form the roots of ActionScript class * * @parameter expression="${project.testCompileSourceRoots}" * @required * @readonly */ private List testCompileSourceRoots; /** * If specified, the testrunner swf will be compiled to use this value as the control port to open during test runs. * * @parameter expression="${flex.testControlPort}" */ private Integer testControlPort; /** * @parameter expression="${project.build.testOutputDirectory}" * @required * @readonly */ private File testOutputDirectory; /** * If specified, the testrunner swf will be compiled to use this value as the port to open during test runs. * * @parameter expression="${flex.testPort}" */ private Integer testPort; /** * The maven test resources * * @parameter expression="${project.build.testResources}" * @required * @readonly */ protected List testResources; /** * @parameter */ private File testRunnerTemplate; public Result buildTest( String testFilename, List testClasses, Integer testControlPort, Integer testPort ) throws MojoExecutionException, MojoFailureException { getLog().info( "Compiling test class: " + testClasses ); File testMxml; try { testMxml = generateTester( testClasses, testFilename, testControlPort, testPort ); } catch ( Exception e ) { throw new MojoExecutionException( "Unable to generate tester class.", e ); } TestCompilerMojo cfg = this.clone(); cfg.finalName = testFilename; return executeCompiler( new MxmlcConfigurationHolder( cfg, testMxml ), fullSynchronization ); } public void buildTests( List testClasses ) throws MojoFailureException, MojoExecutionException { String testFilename = "TestRunner"; if ( testControlPort == null ) { testControlPort = freePort(); } if ( testPort == null ) { testPort = freePort(); } putPluginContext( FLEXMOJOS_TEST_CONTROL_PORT, testControlPort ); putPluginContext( FLEXMOJOS_TEST_PORT, testPort ); getLog().debug( "Flexmojos test port: " + testPort + " - control: " + testControlPort ); checkResult( buildTest( testFilename, testClasses, testControlPort, testPort ) ); } @Override public TestCompilerMojo clone() { return (TestCompilerMojo) super.clone(); } public void fmExecute() throws MojoExecutionException, MojoFailureException { if ( skipTests ) { getLog().warn( "Skipping test phase." ); return; } if ( !PathUtil.existAll( testCompileSourceRoots ) ) { getLog().info( "Skipping compiler, test source path doesn't exist." ); return; } initializeIncludes(); if ( !testOutputDirectory.exists() ) { testOutputDirectory.mkdirs(); } List testClasses = getTestClasses(); if ( testClasses == null || testClasses.isEmpty() ) { getLog().warn( "Skipping test compiler, no test class found." ); return; } buildTests( testClasses ); } protected Integer freePort() { try { return SocketUtil.freePort(); } catch ( IOException e ) { throw new MavenRuntimeException( "Failed to allocate socket port", e ); } } private File generateTester( List testClasses, String testFilename, Integer testControlPort, Integer testPort ) throws Exception { // can't use velocity, got: // java.io.InvalidClassException: // org.apache.velocity.runtime.parser.node.ASTprocess; class invalid for // deserialization StringBuilder imports = getImports( testClasses ); StringBuilder includes = getExtraIncludes( testOutputDirectory ); StringBuilder classes = getClasses( testClasses ); InputStream templateSource = getTemplate(); String sourceString = IOUtils.toString( templateSource ); sourceString = sourceString.replace( "$imports", imports ); sourceString = sourceString.replace( "$includes", includes ); sourceString = sourceString.replace( "$testClasses", classes ); sourceString = sourceString.replace( "$port", testPort.toString() ); sourceString = sourceString.replace( "$controlPort", String.valueOf( testControlPort ) ); File testSourceFile = new File( testOutputDirectory, testFilename + ".mxml" ); FileWriter fileWriter = new FileWriter( testSourceFile ); IOUtils.write( sourceString, fileWriter ); fileWriter.flush(); fileWriter.close(); return testSourceFile; } private StringBuilder getClasses( List testClasses ) { StringBuilder classes = new StringBuilder(); for ( String testClass : testClasses ) { testClass = testClass.substring( testClass.lastIndexOf( '.' ) + 1 ); classes.append( "addTest( " ); classes.append( testClass ); classes.append( ");" ); classes.append( '\n' ); } return classes; } @Override public Boolean getDebug() { return true; } @SuppressWarnings( "unchecked" ) @Override public File[] getExternalLibraryPath() { return MavenUtils.getFiles( getGlobalArtifactCollection() ); } private StringBuilder getExtraIncludes( File testOutputDirectory ) { StringBuilder includes = new StringBuilder(); if ( coverage ) { FlexClassScanner scanner = getFlexClassScanner(); for ( String snippet : scanner.getAs3Snippets() ) { // as3 include "sampleInclude.as"; // includes.append( "include \"" ); // includes.append( snippets.replace( '\\', '/' ) ); // includes.append( "\";\n" ); // mxml includes.append( "\n" ); } } return includes; } private FlexClassScanner getFlexClassScanner() { if ( this.scanner == null ) { File[] sp = existingFiles( getSourcePath() ); scanner = scanners.get( coverageStrategy ); if ( scanner == null ) { throw new IllegalArgumentException( "Invalid coverageFlexClassScanner: '" + coverageStrategy + "'" ); } Map context = new LinkedHashMap(); // TODO need a better idea to resolve link report file context.put( FlexClassifier.LINK_REPORT, file( project.getBuild().getFinalName() + "-" + FlexClassifier.LINK_REPORT + "." + XML, project.getBuild().getDirectory() ) ); scanner.scan( sp, coverageExclusions, context ); } return scanner; } protected Artifact getFlexmojosTestArtifact( String artifactId ) { return getFlexmojosTestArtifact( artifactId, null ); } protected Artifact getFlexmojosTestArtifact( String artifactId, String classifier ) { Artifact artifact = resolve( "net.flexmojos.oss", artifactId, MavenUtils.getFlexMojosVersion(), classifier, "swc" ); return artifact; } @SuppressWarnings( "unchecked" ) protected Artifact getFlexmojosUnittestFrameworkIntegrationLibrary() { if ( getDependency( groupId( "com.adobe.flexunit" ), artifactId( "flexunit" ), version( startsWith( "0" ) ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-flexunit" ); } else if ( getDependency( groupId( "com.adobe.flexunit" ), artifactId( "flexunit" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-flexunit4" ); } else if ( getDependency( groupId( "org.flexunit" ), artifactId( "flexunit" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-flexunit4" ); } else if ( getDependency( groupId( "advancedflex" ), artifactId( "debugger" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-advancedflex" ); } else if ( getDependency( groupId( "com.asunit" ), artifactId( "asunit" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-asunit" ); } else if ( getDependency( groupId( "net.digitalprimates" ), artifactId( "fluint" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-fluint" ); } else if ( getDependency( groupId( "org.funit" ), artifactId( "funit" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-funit" ); } else if ( getDependency( groupId( "org.apache.flex.flexunit" ), artifactId( "flexunit-flex" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-flexunit4" ); } else if ( getDependency( groupId( "org.apache.flex.flexunit" ), artifactId( "flexunit-as3" ) ) != null ) { return getFlexmojosTestArtifact( "flexmojos-unittest-flexunit4" ); } else { if ( getLog().isDebugEnabled() ) { getLog().debug( "Unable to find test dependency among this: " + getDependencies() ); } throw new IllegalStateException( "Not found any compatible unit test framework" + "\n\thttp://docs.sonatype.org/display/FLEXMOJOS/Running+unit+tests" ); } } private Artifact getFlexmojosUnittestSupport() { return getFlexmojosTestArtifact( "flexmojos-unittest-support", getIsAirProject() ? "air" : "flex" ); } private StringBuilder getImports( List testClasses ) { StringBuilder imports = new StringBuilder(); for ( String testClass : testClasses ) { imports.append( "import " ); imports.append( testClass ); imports.append( "; " ); if ( testClass.indexOf( '.' ) != -1 ) { imports.append( testClass.substring( testClass.lastIndexOf( '.' ) + 1 ) ); } else { imports.append( testClass ); } imports.append( ";" ); imports.append( '\n' ); } return imports; } @SuppressWarnings( "unchecked" ) @Override public File[] getIncludeLibraries() { Collection coverArtifact = (Collection) ( coverage ? Collections.singletonList( getFlexmojosTestArtifact( "flexmojos-test-coverage" ) ) : Collections.emptyList() ); return MavenUtils.getFiles( coverArtifact, Collections.singletonList( getFlexmojosUnittestSupport() ), Collections.singletonList( getFlexmojosUnittestFrameworkIntegrationLibrary() ), getDependencies( anyOf( type( SWC ), type( ANE ) ), // anyOf( scope( INTERNAL ), scope( RSL ), scope( CACHING ), scope( TEST ) ),// not( GLOBAL_MATCHER ) ) ); } @Override public List getIncludes() { if ( !coverage ) { return super.getIncludes(); } List includes = super.getIncludes(); if ( includes == null ) { includes = new ArrayList(); } else { includes = new ArrayList( includes ); } FlexClassScanner scanner = getFlexClassScanner(); for ( String testFile : scanner.getAs3Classes() ) { String include = toClass( testFile ); includes.add( include ); } return includes; } @SuppressWarnings( "unchecked" ) @Override public File[] getLibraryPath() { return MavenUtils.getFiles( getDependencies( type( SWC ),// anyOf( scope( MERGED ), scope( EXTERNAL ), scope( COMPILE ), scope( nullValue( String.class ) ) ),// not( GLOBAL_MATCHER ) ),// getCompiledResouceBundles() ); } @Override public String[] getLoadExterns() { return null; } @Override public String[] getLocale() { return CollectionUtils.merge( super.getLocalesRuntime(), super.getLocale() ); } @Override public String[] getLocalesRuntime() { return null; } @Override public SinglePathResolver getMavenPathResolver() { List resources = new ArrayList(); resources.addAll( this.testResources ); resources.addAll( this.resources ); return new MavenPathResolver( resources ); } @Override public Boolean getOptimize() { return false; } @Override public String getOutput() { return PathUtil.path( new File( getTargetDirectory(), getFinalName() + "." + getProjectType() ) ); } @Override public IRuntimeSharedLibraryPath[] getRuntimeSharedLibraryPath() { return null; } @Override protected File getSourceFile() { throw new UnsupportedOperationException(); } @Override public File[] getSourcePath() { Set files = new LinkedHashSet(); files.addAll( PathUtil.existingFilesList( testCompileSourceRoots ) ); files.addAll( Arrays.asList( super.getSourcePath() ) ); if ( getLocale() != null ) { if ( localesSourcePath.getParentFile().exists() ) { files.add( localesSourcePath ); } } return files.toArray( new File[0] ); } @Override public File getTargetDirectory() { testOutputDirectory.mkdirs(); return testOutputDirectory; } public InputStream getTemplate() throws MojoExecutionException { if ( testRunnerTemplate == null ) { if ( getIsAirProject() ) { return getClass().getResourceAsStream( "/templates/test/Air-TestRunner.vm" ); } return getClass().getResourceAsStream( "/templates/test/TestRunner.vm" ); } else if ( !testRunnerTemplate.exists() ) { throw new MojoExecutionException( "Template file not found: " + testRunnerTemplate ); } else { try { return new FileInputStream( testRunnerTemplate ); } catch ( FileNotFoundException e ) { // Never should happen throw new MojoExecutionException( "Error reading template file", e ); } } } protected List getTestClasses() { getLog().debug( "Scanning for tests at " + testCompileSourceRoots + " for " + includeTestFiles + " but " + excludeTestFiles ); FileSet fs = new FileSet(); fs.setIncludes( includeTestFiles ); fs.setExcludes( excludeTestFiles ); List testClasses = filterClasses( asList( fs ), files( testCompileSourceRoots ) ); getLog().debug( "Test classes: " + testClasses ); return testClasses; } protected void initializeIncludes() { if ( test != null ) { includeTestFiles = asList( test ); excludeTestFiles = null; } if ( includeTestFiles == null || includeTestFiles.isEmpty() ) { includeTestFiles = asList( "**/Test*.as", "**/*Test.as", "**/Test*.mxml", "**/*Test.mxml" ); } } @Override public boolean isUpdateSecuritySandbox() { // not optional for tests, flexmojos needs sandbox security disabled return true; } }




    © 2015 - 2025 Weber Informatics LLC | Privacy Policy