Package org.antlr.mojo.antlr3

Source Code of org.antlr.mojo.antlr3.GUnitExecuteMojo$Result

package org.antlr.mojo.antlr3;

import java.util.List;
import java.util.Set;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.Collections;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.io.FileWriter;
import java.io.BufferedWriter;
import java.net.URL;
import java.net.MalformedURLException;
import java.net.URLClassLoader;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.DependencyResolutionRequiredException;
import org.apache.maven.artifact.versioning.ArtifactVersion;
import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.FileUtils;
import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
import org.antlr.runtime.ANTLRFileStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.gunit.GrammarInfo;
import org.antlr.gunit.gUnitExecutor;
import org.antlr.gunit.AbstractTest;
import org.antlr.gunit.Interp;

/**
* Takes gUnit scripts and directly performs testing.
*
* @goal gunit
*
* @phase test
* @requiresDependencyResolution test
* @requiresProject true
*
* @author Steve Ebersole
*/
public class GUnitExecuteMojo extends AbstractMojo {
  public static final String ANTLR_GROUP_ID = "org.antlr";
  public static final String ANTLR_ARTIFACT_NAME = "antlr";
  public static final String ANTLR_RUNTIME_ARTIFACT_NAME = "antlr-runtime";

  /**
     * INTERNAL : The Maven Project to which we are attached
     *
     * @parameter expression="${project}"
     * @required
     */
    private MavenProject project;

  /**
   * INTERNAL : The artifacts associated to the dependencies defined as part
   * of our configuration within the project to which we are being attached.
   *
   * @parameter expression="${plugin.artifacts}"
     * @required
     * @readonly
   */
  private List<Artifact> pluginArtifacts;

  /**
     * Specifies the directory containing the gUnit testing files.
     *
     * @parameter expression="${basedir}/src/test/gunit"
     * @required
     */
    private File sourceDirectory;

    /**
     * A set of patterns for matching files from the sourceDirectory that
     * should be included as gUnit source files.
     *
     * @parameter
     */
    private Set<String> includes;

    /**
     * A set of exclude patterns.
     *
     * @parameter
     */
    private Set<String> excludes;

  /**
     * Specifies directory to which gUnit reports should get written.
     *
     * @parameter expression="${basedir}/target/gunit-report"
     * @required
     */
    private File reportDirectory;

  /**
   * Should gUnit functionality be completely by-passed?
   * <p>
   * By default we skip gUnit tests if the user requested that all testing be skipped using 'maven.test.skip'</p>
   *
   * @parameter expression="${maven.test.skip}"
   */
  private boolean skip;

  public Set<String> getIncludePatterns() {
    return includes == null || includes.isEmpty()
        ? Collections.singleton( "**/*.testsuite" )
        : includes;
  }

  public Set<String> getExcludePatterns() {
    return excludes == null
        ? Collections.<String>emptySet()
        : excludes;
  }


  public final void execute() throws MojoExecutionException, MojoFailureException {
    if ( skip ) {
      getLog().info( "Skipping gUnit processing" );
      return;
    }
    Artifact pluginAntlrArtifact = determinePluginAntlrArtifact();

    validateProjectsAntlrVersion( determineArtifactVersion( pluginAntlrArtifact ) );

    performExecution( determineProjectCompileScopeClassLoader( pluginAntlrArtifact ) );
  }

  private Artifact determinePluginAntlrArtifact() throws MojoExecutionException {
    for ( Artifact artifact : pluginArtifacts ) {
      boolean match = ANTLR_GROUP_ID.equals( artifact.getGroupId() )
          && ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() );
      if ( match ) {
        return artifact;
      }
    }
    throw new MojoExecutionException(
        "Unexpected state : could not locate " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME +
            " in plugin dependencies"
    );
  }

  private ArtifactVersion determineArtifactVersion(Artifact artifact) throws MojoExecutionException {
    try {
      return artifact.getVersion() != null
          ? new DefaultArtifactVersion( artifact.getVersion() )
          : artifact.getSelectedVersion();
    }
    catch ( OverConstrainedVersionException e ) {
      throw new MojoExecutionException( "artifact [" + artifact.getId() + "] defined an overly constrained version range" );
    }
  }

  private void validateProjectsAntlrVersion(ArtifactVersion pluginAntlrVersion) throws MojoExecutionException {
    Artifact antlrArtifact = null;
    Artifact antlrRuntimeArtifact = null;

    if ( project.getCompileArtifacts() != null ) {
      for ( Object o : project.getCompileArtifacts() ) {
        final Artifact artifact = ( Artifact ) o;
        if ( ANTLR_GROUP_ID.equals( artifact.getGroupId() ) ) {
          if ( ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
            antlrArtifact = artifact;
            break;
          }
          if ( ANTLR_RUNTIME_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
            antlrRuntimeArtifact = artifact;
          }
        }
      }
    }

    validateBuildTimeArtifact( antlrArtifact, pluginAntlrVersion );
    validateRunTimeArtifact( antlrRuntimeArtifact, pluginAntlrVersion );
  }

  @SuppressWarnings(value = "unchecked")
  protected void validateBuildTimeArtifact(Artifact antlrArtifact, ArtifactVersion pluginAntlrVersion)
      throws MojoExecutionException {
    if ( antlrArtifact == null ) {
      validateMissingBuildtimeArtifact();
      return;
    }

    // otherwise, lets make sure they match...
    ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrArtifact );
    if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
      getLog().warn(
          "Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
              " which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
      );
    }
  }

  protected void validateMissingBuildtimeArtifact() {
    // generally speaking, its ok for the project to not define a dep on the build-time artifact...
  }

  @SuppressWarnings(value = "unchecked")
  protected void validateRunTimeArtifact(Artifact antlrRuntimeArtifact, ArtifactVersion pluginAntlrVersion)
      throws MojoExecutionException {
    if ( antlrRuntimeArtifact == null ) {
      // its possible, if the project instead depends on the build-time (or full) artifact.
      return;
    }

    ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrRuntimeArtifact );
    if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
      getLog().warn(
          "Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_RUNTIME_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
              " which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
      );
    }
  }

  /**
   * Builds the classloader to pass to gUnit.
   *
   * @param antlrArtifact The plugin's (our) Antlr dependency artifact.
   *
   * @return The classloader for gUnit to use
   *
   * @throws MojoExecutionException Problem resolving artifacts to {@link java.net.URL urls}.
   */
  private ClassLoader determineProjectCompileScopeClassLoader(Artifact antlrArtifact)
      throws MojoExecutionException {
    ArrayList<URL> classPathUrls = new ArrayList<URL>();
    getLog().info( "Adding Antlr artifact : " + antlrArtifact.getId() );
    classPathUrls.add( resolveLocalURL( antlrArtifact ) );

    for ( String path : classpathElements() ) {
      try {
        getLog().info( "Adding project compile classpath element : " + path );
        classPathUrls.add( new File( path ).toURI().toURL() );
      }
      catch ( MalformedURLException e ) {
        throw new MojoExecutionException( "Unable to build path URL [" + path + "]" );
      }
    }

    return new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ), getClass().getClassLoader() );
  }

  protected static URL resolveLocalURL(Artifact artifact) throws MojoExecutionException {
    try {
      return artifact.getFile().toURI().toURL();
    }
    catch ( MalformedURLException e ) {
      throw new MojoExecutionException( "Unable to resolve artifact url : " + artifact.getId(), e );
    }
  }

  @SuppressWarnings( "unchecked" )
  private List<String> classpathElements() throws MojoExecutionException {
    try {
      // todo : should we combine both compile and test scoped elements?
      return ( List<String> ) project.getTestClasspathElements();
    }
    catch ( DependencyResolutionRequiredException e ) {
      throw new MojoExecutionException( "Call to Project#getCompileClasspathElements required dependency resolution" );
    }
  }

  private void performExecution(ClassLoader projectCompileScopeClassLoader) throws MojoExecutionException {
    getLog().info( "gUnit report directory : " + reportDirectory.getAbsolutePath() );
    if ( !reportDirectory.exists() ) {
      boolean directoryCreated = reportDirectory.mkdirs();
      if ( !directoryCreated ) {
        getLog().warn( "mkdirs() reported problem creating report directory" );
      }
    }

    Result runningResults = new Result();
    ArrayList<String> failureNames = new ArrayList<String>();

    System.out.println();
    System.out.println( "-----------------------------------------------------------" );
    System.out.println( " G U N I T   R E S U L T S" );
    System.out.println( "-----------------------------------------------------------" );

    for ( File script : collectIncludedSourceGrammars() ) {
      final String scriptPath = script.getAbsolutePath();
      System.out.println( "Executing script " + scriptPath );
      try {
        String scriptBaseName = StringUtils.chompLast( FileUtils.basename( script.getName() ), "." );

        ANTLRFileStream antlrStream = new ANTLRFileStream( scriptPath );
        GrammarInfo grammarInfo = Interp.parse( antlrStream );
        gUnitExecutor executor = new gUnitExecutor(
            grammarInfo,
            projectCompileScopeClassLoader,
            script.getParentFile().getAbsolutePath()
        );

        String report = executor.execTest();
        writeReportFile( new File( reportDirectory, scriptBaseName + ".txt" ), report );

        Result testResult = new Result();
        testResult.tests = executor.numOfTest;
        testResult.failures = executor.numOfFailure;
        testResult.invalids = executor.numOfInvalidInput;

        System.out.println( testResult.render() );

        runningResults.add( testResult );
        for ( AbstractTest test : executor.failures ) {
          failureNames.add( scriptBaseName + "#" + test.getHeader() );
        }
      }
      catch ( IOException e ) {
        throw new MojoExecutionException( "Could not open specified script file", e );
      }
      catch ( RecognitionException e ) {
        throw new MojoExecutionException( "Could not parse gUnit script", e );
      }
    }

    System.out.println();
    System.out.println( "Summary :" );
    if ( ! failureNames.isEmpty() ) {
      System.out.println( "  Found " + failureNames.size() + " failures" );
      for ( String name : failureNames ) {
        System.out.println( "    - " + name );
      }
    }
    System.out.println( runningResults.render() );
    System.out.println();

    if ( runningResults.failures > 0 ) {
      throw new MojoExecutionException( "Found gUnit test failures" );
    }

    if ( runningResults.invalids > 0 ) {
      throw new MojoExecutionException( "Found invalid gUnit tests" );
    }
  }

  private Set<File> collectIncludedSourceGrammars() throws MojoExecutionException {
    SourceMapping mapping = new SuffixMapping( "g", Collections.<String>emptySet() );
        SourceInclusionScanner scan = new SimpleSourceInclusionScanner( getIncludePatterns(), getExcludePatterns() );
        scan.addSourceMapping( mapping );
    try {
      return scan.getIncludedSources( sourceDirectory, null );
    }
    catch ( InclusionScanException e ) {
      throw new MojoExecutionException( "Error determining gUnit sources", e );
    }
  }

  private void writeReportFile(File reportFile, String results) {
    try {
      Writer writer = new FileWriter( reportFile );
      writer = new BufferedWriter( writer );
      try {
        writer.write( results );
        writer.flush();
      }
      finally {
        try {
          writer.close();
        }
        catch ( IOException ignore ) {
        }
      }
    }
    catch ( IOException e ) {
      getLog().warn"Error writing gUnit report file", e );
    }
  }

  private static class Result {
    private int tests = 0;
    private int failures = 0;
    private int invalids = 0;

    public String render() {
      return String.format( "Tests run: %d,  Failures: %d,  Invalid: %d", tests, failures, invalids );
    }

    public void add(Result result) {
      this.tests += result.tests;
      this.failures += result.failures;
      this.invalids += result.invalids;
    }
  }

}
TOP

Related Classes of org.antlr.mojo.antlr3.GUnitExecuteMojo$Result

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.