package org.codehaus.mojo.fit; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.net.MalformedURLException; import java.text.MessageFormat; import java.text.ParseException; import java.util.Arrays; import java.util.List; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.tools.ant.DirectoryScanner; import fit.Fixture; import fit.Parse; /** * Mojo to run Fit tests via a Fixture * * @author Mauro Talevi * @goal run * @phase integration-test * @requiresDependencyResolution test */ public class FitRunnerMojo extends AbstractMojo { private static final String COMMA = ","; private static final String WIKI_TAG = "wiki"; private static final String EXECUTION_PARAMETERS = "sourceDirectory={0}, caseSensitive={1}," + " sourceIncludes={2}, sourceExcludes={3}, parseTags={4}, outputDirectory={5}, ignoreFailures={6}"; /** * Classpath. * * @parameter expression="${project.testClasspathElements}" * @required */ List classpathElements; /** * The source directory containing the Fit fixtures * @parameter * @required */ String sourceDirectory; /** * Flag to indicate that path names are case sensitive * @parameter default-value="false" */ boolean caseSensitive; /** * The filter for source file includes, relative to the source directory, as CSV patterns. * @parameter */ String sourceIncludes; /** * The filter for source file excludes, relative to the source directory, as CSV patterns. * @parameter */ String sourceExcludes; /** * The parsee tags used to identify the Fit tables. * @parameter */ String[] parseTags = new String[] { "table", "tr", "td" }; /** * The output directory where the results of Fit processing is written to * @parameter * @required */ String outputDirectory; /** * The option to ignore fixture failures * * @parameter default-value="false" */ boolean ignoreFailures; /** * The scanner to list files */ private DirectoryScanner scanner = new DirectoryScanner(); public void execute() throws MojoExecutionException, MojoFailureException { final String executionParameters = MessageFormat.format( EXECUTION_PARAMETERS, new Object[] { sourceDirectory, Boolean.valueOf( caseSensitive ), sourceIncludes, sourceExcludes, Arrays.asList( parseTags ), outputDirectory, Boolean.valueOf( ignoreFailures )} ); getLog().debug( "Executing FitRunner with parameters " + executionParameters ); try { run( sourceDirectory, caseSensitive, sourceIncludes, sourceExcludes, outputDirectory ); } catch ( Exception e ) { throw new MojoExecutionException( "Failed to execute FitRunner with parameters " + executionParameters, e ); } } protected Fixture createFixture() throws MalformedURLException { Fixture fixture = new ClassLoaderFixture( new FixtureClassLoader( classpathElements) ); getLog().debug( "Created " + ClassLoaderFixture.class.getName() + " with classpathElements " + classpathElements ); return fixture; } protected String toPath( String directory, String name ) { return new File( directory, name ).getPath(); } protected String[] listFiles( String sourceDirectory, boolean caseSensitive, String sourceIncludes, String sourceExcludes ) { scanner.setBasedir( new File( sourceDirectory ) ); getLog().debug( "Listing files from directory " + sourceDirectory ); getLog().debug( "Setting case sensitive " + caseSensitive ); scanner.setCaseSensitive( caseSensitive ); if ( sourceIncludes != null ) { getLog().debug( "Setting includes " + sourceIncludes ); scanner.setIncludes( sourceIncludes.split( COMMA ) ); } if ( sourceExcludes != null ) { getLog().debug( "Setting excludes " + sourceExcludes ); scanner.setExcludes( sourceExcludes.split( COMMA ) ); } scanner.scan(); String[] files = scanner.getIncludedFiles(); getLog().debug( "Files listed " + Arrays.asList( files ) ); return files; } protected void ensureDirectoryExists( String path ) throws IOException { File file = new File( path ); if ( !file.exists() ) { getLog().debug( "Creating directory " + file ); file.mkdirs(); } } protected void run( String sourceDirectory, boolean caseSensitive, String sourceIncludes, String sourceExcludes, String outputDirectory ) throws Exception { ensureDirectoryExists( outputDirectory ); String[] files = listFiles( sourceDirectory, caseSensitive, sourceIncludes, sourceExcludes ); for ( int i = 0; i < files.length; i++ ) { String inputPath = toPath( sourceDirectory, files[i] ); String outputPath = toPath( outputDirectory, files[i] ); run( inputPath, outputPath ); } } protected void run( String in, String out ) throws IOException, ParseException { run( new File( in ), new File( out ) ); } protected void run( File in, File out ) throws IOException, ParseException { getLog().info( "Running Fixture with input file " + in.getPath() + " and output file " + out.getPath() ); run( new FileReader( in ), new FileWriter( out ) ); } protected void run( Reader reader, Writer writer ) throws IOException, ParseException { String input = read( reader ); Parse tables = parse( input, parseTags ); Fixture fixture = createFixture(); fixture.doTables( tables ); PrintWriter output = new PrintWriter( writer ); tables.print( output ); output.flush(); if ( failed( fixture ) ) { String message = "Fixture failed with counts: " + fixture.counts(); if ( ignoreFailures ) { getLog().warn( message ); } else { throw new IllegalStateException( message ); } } } protected boolean failed( Fixture fixture ) { if ( fixture.counts.wrong > 0 || fixture.counts.exceptions > 0 ) { return true; } return false; } private Parse parse( String input, String[] parseTags ) throws ParseException { Parse tables = new Parse( input, parseTags ); if ( parseTags.length > 0 && WIKI_TAG.equals( parseTags[0] ) ) { getLog().debug( "Found parse tag " + WIKI_TAG + ". Processing contained tags." ); return tables.parts; } return tables; } protected String read( Reader in ) throws IOException { BufferedReader br = new BufferedReader( in ); StringBuffer sb = new StringBuffer(); String line = br.readLine(); while ( line != null ) { sb.append( line ); line = br.readLine(); } in.close(); return sb.toString(); } }