PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/projects/antlr-3.4/gunit-maven-plugin/src/main/java/org/antlr/mojo/antlr3/GUnitExecuteMojo.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 410 lines | 293 code | 49 blank | 68 comment | 36 complexity | 8b9fff199fdeedc1b40b347441274317 MD5 | raw file
  1. package org.antlr.mojo.antlr3;
  2. import java.util.List;
  3. import java.util.Set;
  4. import java.util.HashSet;
  5. import java.util.ArrayList;
  6. import java.util.Collections;
  7. import java.io.File;
  8. import java.io.IOException;
  9. import java.io.Writer;
  10. import java.io.FileWriter;
  11. import java.io.BufferedWriter;
  12. import java.net.URL;
  13. import java.net.MalformedURLException;
  14. import java.net.URLClassLoader;
  15. import org.apache.maven.plugin.AbstractMojo;
  16. import org.apache.maven.plugin.MojoExecutionException;
  17. import org.apache.maven.plugin.MojoFailureException;
  18. import org.apache.maven.project.MavenProject;
  19. import org.apache.maven.artifact.Artifact;
  20. import org.apache.maven.artifact.DependencyResolutionRequiredException;
  21. import org.apache.maven.artifact.versioning.ArtifactVersion;
  22. import org.apache.maven.artifact.versioning.DefaultArtifactVersion;
  23. import org.apache.maven.artifact.versioning.OverConstrainedVersionException;
  24. import org.codehaus.plexus.util.StringUtils;
  25. import org.codehaus.plexus.util.FileUtils;
  26. import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
  27. import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;
  28. import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
  29. import org.codehaus.plexus.compiler.util.scan.SimpleSourceInclusionScanner;
  30. import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
  31. import org.antlr.runtime.ANTLRFileStream;
  32. import org.antlr.runtime.RecognitionException;
  33. import org.antlr.gunit.GrammarInfo;
  34. import org.antlr.gunit.gUnitExecutor;
  35. import org.antlr.gunit.AbstractTest;
  36. import org.antlr.gunit.Interp;
  37. /**
  38. * Takes gUnit scripts and directly performs testing.
  39. *
  40. * @goal gunit
  41. *
  42. * @phase test
  43. * @requiresDependencyResolution test
  44. * @requiresProject true
  45. *
  46. * @author Steve Ebersole
  47. */
  48. public class GUnitExecuteMojo extends AbstractMojo {
  49. public static final String ANTLR_GROUP_ID = "org.antlr";
  50. public static final String ANTLR_ARTIFACT_NAME = "antlr";
  51. public static final String ANTLR_RUNTIME_ARTIFACT_NAME = "antlr-runtime";
  52. /**
  53. * INTERNAL : The Maven Project to which we are attached
  54. *
  55. * @parameter expression="${project}"
  56. * @required
  57. */
  58. private MavenProject project;
  59. /**
  60. * INTERNAL : The artifacts associated to the dependencies defined as part
  61. * of our configuration within the project to which we are being attached.
  62. *
  63. * @parameter expression="${plugin.artifacts}"
  64. * @required
  65. * @readonly
  66. */
  67. private List<Artifact> pluginArtifacts;
  68. /**
  69. * Specifies the directory containing the gUnit testing files.
  70. *
  71. * @parameter expression="${basedir}/src/test/gunit"
  72. * @required
  73. */
  74. private File sourceDirectory;
  75. /**
  76. * A set of patterns for matching files from the sourceDirectory that
  77. * should be included as gUnit source files.
  78. *
  79. * @parameter
  80. */
  81. private Set includes;
  82. /**
  83. * A set of exclude patterns.
  84. *
  85. * @parameter
  86. */
  87. private Set excludes;
  88. /**
  89. * Specifies directory to which gUnit reports should get written.
  90. *
  91. * @parameter expression="${basedir}/target/gunit-report"
  92. * @required
  93. */
  94. private File reportDirectory;
  95. /**
  96. * Should gUnit functionality be completely by-passed?
  97. * <p/>
  98. * By default we skip gUnit tests if the user requested that all testing be skipped using 'maven.test.skip'
  99. *
  100. * @parameter expression="${maven.test.skip}"
  101. */
  102. private boolean skip;
  103. public Set getIncludePatterns() {
  104. return includes == null || includes.isEmpty()
  105. ? Collections.singleton( "**/*.testsuite" )
  106. : includes;
  107. }
  108. public Set getExcludePatterns() {
  109. return excludes == null
  110. ? Collections.emptySet()
  111. : excludes;
  112. }
  113. public final void execute() throws MojoExecutionException, MojoFailureException {
  114. if ( skip ) {
  115. getLog().info( "Skipping gUnit processing" );
  116. return;
  117. }
  118. Artifact pluginAntlrArtifact = determinePluginAntlrArtifact();
  119. validateProjectsAntlrVersion( determineArtifactVersion( pluginAntlrArtifact ) );
  120. performExecution( determineProjectCompileScopeClassLoader( pluginAntlrArtifact ) );
  121. }
  122. private Artifact determinePluginAntlrArtifact() throws MojoExecutionException {
  123. for ( Artifact artifact : pluginArtifacts ) {
  124. boolean match = ANTLR_GROUP_ID.equals( artifact.getGroupId() )
  125. && ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() );
  126. if ( match ) {
  127. return artifact;
  128. }
  129. }
  130. throw new MojoExecutionException(
  131. "Unexpected state : could not locate " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME +
  132. " in plugin dependencies"
  133. );
  134. }
  135. private ArtifactVersion determineArtifactVersion(Artifact artifact) throws MojoExecutionException {
  136. try {
  137. return artifact.getVersion() != null
  138. ? new DefaultArtifactVersion( artifact.getVersion() )
  139. : artifact.getSelectedVersion();
  140. }
  141. catch ( OverConstrainedVersionException e ) {
  142. throw new MojoExecutionException( "artifact [" + artifact.getId() + "] defined an overly constrained version range" );
  143. }
  144. }
  145. private void validateProjectsAntlrVersion(ArtifactVersion pluginAntlrVersion) throws MojoExecutionException {
  146. Artifact antlrArtifact = null;
  147. Artifact antlrRuntimeArtifact = null;
  148. if ( project.getCompileArtifacts() != null ) {
  149. for ( Object o : project.getCompileArtifacts() ) {
  150. final Artifact artifact = ( Artifact ) o;
  151. if ( ANTLR_GROUP_ID.equals( artifact.getGroupId() ) ) {
  152. if ( ANTLR_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
  153. antlrArtifact = artifact;
  154. break;
  155. }
  156. if ( ANTLR_RUNTIME_ARTIFACT_NAME.equals( artifact.getArtifactId() ) ) {
  157. antlrRuntimeArtifact = artifact;
  158. }
  159. }
  160. }
  161. }
  162. validateBuildTimeArtifact( antlrArtifact, pluginAntlrVersion );
  163. validateRunTimeArtifact( antlrRuntimeArtifact, pluginAntlrVersion );
  164. }
  165. @SuppressWarnings(value = "unchecked")
  166. protected void validateBuildTimeArtifact(Artifact antlrArtifact, ArtifactVersion pluginAntlrVersion)
  167. throws MojoExecutionException {
  168. if ( antlrArtifact == null ) {
  169. validateMissingBuildtimeArtifact();
  170. return;
  171. }
  172. // otherwise, lets make sure they match...
  173. ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrArtifact );
  174. if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
  175. getLog().warn(
  176. "Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
  177. " which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
  178. );
  179. }
  180. }
  181. protected void validateMissingBuildtimeArtifact() {
  182. // generally speaking, its ok for the project to not define a dep on the build-time artifact...
  183. }
  184. @SuppressWarnings(value = "unchecked")
  185. protected void validateRunTimeArtifact(Artifact antlrRuntimeArtifact, ArtifactVersion pluginAntlrVersion)
  186. throws MojoExecutionException {
  187. if ( antlrRuntimeArtifact == null ) {
  188. // its possible, if the project instead depends on the build-time (or full) artifact.
  189. return;
  190. }
  191. ArtifactVersion projectAntlrVersion = determineArtifactVersion( antlrRuntimeArtifact );
  192. if ( pluginAntlrVersion.compareTo( projectAntlrVersion ) != 0 ) {
  193. getLog().warn(
  194. "Encountered " + ANTLR_GROUP_ID + ':' + ANTLR_RUNTIME_ARTIFACT_NAME + ':' + projectAntlrVersion.toString() +
  195. " which did not match Antlr version used by plugin [" + pluginAntlrVersion.toString() + "]"
  196. );
  197. }
  198. }
  199. /**
  200. * Builds the classloader to pass to gUnit.
  201. *
  202. * @param antlrArtifact The plugin's (our) Antlr dependency artifact.
  203. *
  204. * @return The classloader for gUnit to use
  205. *
  206. * @throws MojoExecutionException Problem resolving artifacts to {@link java.net.URL urls}.
  207. */
  208. private ClassLoader determineProjectCompileScopeClassLoader(Artifact antlrArtifact)
  209. throws MojoExecutionException {
  210. ArrayList<URL> classPathUrls = new ArrayList<URL>();
  211. getLog().info( "Adding Antlr artifact : " + antlrArtifact.getId() );
  212. classPathUrls.add( resolveLocalURL( antlrArtifact ) );
  213. for ( String path : classpathElements() ) {
  214. try {
  215. getLog().info( "Adding project compile classpath element : " + path );
  216. classPathUrls.add( new File( path ).toURI().toURL() );
  217. }
  218. catch ( MalformedURLException e ) {
  219. throw new MojoExecutionException( "Unable to build path URL [" + path + "]" );
  220. }
  221. }
  222. return new URLClassLoader( classPathUrls.toArray( new URL[classPathUrls.size()] ), getClass().getClassLoader() );
  223. }
  224. protected static URL resolveLocalURL(Artifact artifact) throws MojoExecutionException {
  225. try {
  226. return artifact.getFile().toURI().toURL();
  227. }
  228. catch ( MalformedURLException e ) {
  229. throw new MojoExecutionException( "Unable to resolve artifact url : " + artifact.getId(), e );
  230. }
  231. }
  232. @SuppressWarnings( "unchecked" )
  233. private List<String> classpathElements() throws MojoExecutionException {
  234. try {
  235. // todo : should we combine both compile and test scoped elements?
  236. return ( List<String> ) project.getTestClasspathElements();
  237. }
  238. catch ( DependencyResolutionRequiredException e ) {
  239. throw new MojoExecutionException( "Call to Project#getCompileClasspathElements required dependency resolution" );
  240. }
  241. }
  242. private void performExecution(ClassLoader projectCompileScopeClassLoader) throws MojoExecutionException {
  243. getLog().info( "gUnit report directory : " + reportDirectory.getAbsolutePath() );
  244. if ( !reportDirectory.exists() ) {
  245. boolean directoryCreated = reportDirectory.mkdirs();
  246. if ( !directoryCreated ) {
  247. getLog().warn( "mkdirs() reported problem creating report directory" );
  248. }
  249. }
  250. Result runningResults = new Result();
  251. ArrayList<String> failureNames = new ArrayList<String>();
  252. System.out.println();
  253. System.out.println( "-----------------------------------------------------------" );
  254. System.out.println( " G U N I T R E S U L T S" );
  255. System.out.println( "-----------------------------------------------------------" );
  256. for ( File script : collectIncludedSourceGrammars() ) {
  257. final String scriptPath = script.getAbsolutePath();
  258. System.out.println( "Executing script " + scriptPath );
  259. try {
  260. String scriptBaseName = StringUtils.chompLast( FileUtils.basename( script.getName() ), "." );
  261. ANTLRFileStream antlrStream = new ANTLRFileStream( scriptPath );
  262. GrammarInfo grammarInfo = Interp.parse( antlrStream );
  263. gUnitExecutor executor = new gUnitExecutor(
  264. grammarInfo,
  265. projectCompileScopeClassLoader,
  266. script.getParentFile().getAbsolutePath()
  267. );
  268. String report = executor.execTest();
  269. writeReportFile( new File( reportDirectory, scriptBaseName + ".txt" ), report );
  270. Result testResult = new Result();
  271. testResult.tests = executor.numOfTest;
  272. testResult.failures = executor.numOfFailure;
  273. testResult.invalids = executor.numOfInvalidInput;
  274. System.out.println( testResult.render() );
  275. runningResults.add( testResult );
  276. for ( AbstractTest test : executor.failures ) {
  277. failureNames.add( scriptBaseName + "#" + test.getHeader() );
  278. }
  279. }
  280. catch ( IOException e ) {
  281. throw new MojoExecutionException( "Could not open specified script file", e );
  282. }
  283. catch ( RecognitionException e ) {
  284. throw new MojoExecutionException( "Could not parse gUnit script", e );
  285. }
  286. }
  287. System.out.println();
  288. System.out.println( "Summary :" );
  289. if ( ! failureNames.isEmpty() ) {
  290. System.out.println( " Found " + failureNames.size() + " failures" );
  291. for ( String name : failureNames ) {
  292. System.out.println( " - " + name );
  293. }
  294. }
  295. System.out.println( runningResults.render() );
  296. System.out.println();
  297. if ( runningResults.failures > 0 ) {
  298. throw new MojoExecutionException( "Found gUnit test failures" );
  299. }
  300. if ( runningResults.invalids > 0 ) {
  301. throw new MojoExecutionException( "Found invalid gUnit tests" );
  302. }
  303. }
  304. private Set<File> collectIncludedSourceGrammars() throws MojoExecutionException {
  305. SourceMapping mapping = new SuffixMapping( "g", Collections.EMPTY_SET );
  306. SourceInclusionScanner scan = new SimpleSourceInclusionScanner( getIncludePatterns(), getExcludePatterns() );
  307. scan.addSourceMapping( mapping );
  308. try {
  309. Set scanResults = scan.getIncludedSources( sourceDirectory, null );
  310. Set<File> results = new HashSet<File>();
  311. for ( Object result : scanResults ) {
  312. if ( result instanceof File ) {
  313. results.add( ( File ) result );
  314. }
  315. else if ( result instanceof String ) {
  316. results.add( new File( ( String ) result ) );
  317. }
  318. else {
  319. throw new MojoExecutionException( "Unexpected result type from scanning [" + result.getClass().getName() + "]" );
  320. }
  321. }
  322. return results;
  323. }
  324. catch ( InclusionScanException e ) {
  325. throw new MojoExecutionException( "Error determining gUnit sources", e );
  326. }
  327. }
  328. private void writeReportFile(File reportFile, String results) {
  329. try {
  330. Writer writer = new FileWriter( reportFile );
  331. writer = new BufferedWriter( writer );
  332. try {
  333. writer.write( results );
  334. writer.flush();
  335. }
  336. finally {
  337. try {
  338. writer.close();
  339. }
  340. catch ( IOException ignore ) {
  341. }
  342. }
  343. }
  344. catch ( IOException e ) {
  345. getLog().warn( "Error writing gUnit report file", e );
  346. }
  347. }
  348. private static class Result {
  349. private int tests = 0;
  350. private int failures = 0;
  351. private int invalids = 0;
  352. public String render() {
  353. return String.format( "Tests run: %d, Failures: %d, Invalid: %d", tests, failures, invalids );
  354. }
  355. public void add(Result result) {
  356. this.tests += result.tests;
  357. this.failures += result.failures;
  358. this.invalids += result.invalids;
  359. }
  360. }
  361. }