/* * Copyright (c) 2012-2017 The ANTLR Project. All rights reserved. * Use of this file is governed by the BSD 3-clause license that * can be found in the LICENSE.txt file in the project root. */ package org.antlr.mojo.antlr4; import io.takari.maven.testing.TestMavenRuntime; import io.takari.maven.testing.TestResources; import org.apache.maven.execution.MavenSession; import org.apache.maven.plugin.MojoExecution; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.project.MavenProject; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class Antlr4MojoTest { @Rule public ExpectedException thrown = ExpectedException.none(); @Rule public final TestResources resources = new TestResources(); @Rule public final TestMavenRuntime maven = new TestMavenRuntime(); @Test public void importTokens() throws Exception { Path baseDir = resources.getBasedir("importTokens").toPath(); Path antlrDir = baseDir.resolve("src/main/antlr4"); Path generatedSources = baseDir.resolve("target/generated-sources/antlr4"); Path genParser = generatedSources.resolve("test/SimpleParser.java"); Path tokens = antlrDir.resolve("imports/SimpleLexer.tokens"); MavenProject project = maven.readMavenProject(baseDir.toFile()); MavenSession session = maven.newMavenSession(project); MojoExecution exec = maven.newMojoExecution("antlr4"); //////////////////////////////////////////////////////////////////////// // 1st - all grammars have to be processed //////////////////////////////////////////////////////////////////////// assertFalse(Files.exists(genParser)); maven.executeMojo(session, project, exec); assertTrue(Files.exists(genParser)); //////////////////////////////////////////////////////////////////////// // 2nd - nothing has been modified, no grammars have to be processed //////////////////////////////////////////////////////////////////////// { byte[] sum = checksum(genParser); maven.executeMojo(session, project, exec); assertTrue(Arrays.equals(sum, checksum(genParser))); } //////////////////////////////////////////////////////////////////////// // 3rd - the imported grammar changed, every dependency has to be processed //////////////////////////////////////////////////////////////////////// try(Change change = Change.of(tokens, "DOT=4")) { byte[] sum = checksum(genParser); maven.executeMojo(session, project, exec); assertFalse(Arrays.equals(sum, checksum(genParser))); } } @Test public void importsCustomLayout() throws Exception { Path baseDir = resources.getBasedir("importsCustom").toPath(); Path antlrDir = baseDir.resolve("src/main/antlr4"); Path generatedSources = baseDir.resolve("src/main/java"); Path genTestLexer = generatedSources.resolve("foo/TestLexer.java"); Path genTestParser = generatedSources.resolve("foo/TestParser.java"); Path genHello = generatedSources.resolve("foo/HelloParser.java"); Path baseGrammar = antlrDir.resolve("imports/TestBaseLexer.g4"); Path lexerGrammar = antlrDir.resolve("TestLexer.g4"); Path parserGrammar = antlrDir.resolve("TestParser.g4"); Xpp3Dom outputDirectory = TestMavenRuntime.newParameter("outputDirectory", "src/main/java/foo"); Xpp3Dom arguments = new Xpp3Dom("arguments"); arguments.addChild(TestMavenRuntime.newParameter("argument", "-package")); arguments.addChild(TestMavenRuntime.newParameter("argument", "foo")); MavenProject project = maven.readMavenProject(baseDir.toFile()); MavenSession session = maven.newMavenSession(project); MojoExecution exec = maven.newMojoExecution("antlr4", outputDirectory, arguments); //////////////////////////////////////////////////////////////////////// // 1st - all grammars have to be processed //////////////////////////////////////////////////////////////////////// assertFalse(Files.exists(genHello)); assertFalse(Files.exists(genTestParser)); assertFalse(Files.exists(genTestLexer)); maven.executeMojo(session, project, exec); assertTrue(Files.exists(genHello)); assertTrue(Files.exists(genTestParser)); assertTrue(Files.exists(genTestLexer)); //////////////////////////////////////////////////////////////////////// // 2nd - nothing has been modified, no grammars have to be processed //////////////////////////////////////////////////////////////////////// { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertTrue(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 3rd - the imported grammar changed, every dependency has to be processed //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(baseGrammar, "DOT: '.' ;")) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 4th - the lexer grammar changed, the parser grammar has to be processed as well //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(lexerGrammar, "fragment DOT : '.';")) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 5th - the parser grammar changed, no other grammars have to be processed //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(parserGrammar, " t : WS* ;")) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } } @Test public void importsStandardLayout() throws Exception { Path baseDir = resources.getBasedir("importsStandard").toPath(); Path antlrDir = baseDir.resolve("src/main/antlr4"); Path generatedSources = baseDir.resolve("target/generated-sources/antlr4"); Path genTestLexer = generatedSources.resolve("test/TestLexer.java"); Path genTestParser = generatedSources.resolve("test/TestParser.java"); Path genHello = generatedSources.resolve("test/HelloParser.java"); Path baseGrammar = antlrDir.resolve("imports/TestBaseLexer.g4"); Path lexerGrammar = antlrDir.resolve("test/TestLexer.g4"); Path parserGrammar = antlrDir.resolve("test/TestParser.g4"); MavenProject project = maven.readMavenProject(baseDir.toFile()); MavenSession session = maven.newMavenSession(project); MojoExecution exec = maven.newMojoExecution("antlr4"); //////////////////////////////////////////////////////////////////////// // 1st - all grammars have to be processed //////////////////////////////////////////////////////////////////////// assertFalse(Files.exists(genHello)); assertFalse(Files.exists(genTestParser)); assertFalse(Files.exists(genTestLexer)); maven.executeMojo(session, project, exec); assertTrue(Files.exists(genHello)); assertTrue(Files.exists(genTestParser)); assertTrue(Files.exists(genTestLexer)); //////////////////////////////////////////////////////////////////////// // 2nd - nothing has been modified, no grammars have to be processed //////////////////////////////////////////////////////////////////////// { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertTrue(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 3rd - the imported grammar changed, every dependency has to be processed //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(baseGrammar, "DOT: '.' ;")) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 4th - the lexer grammar changed, the parser grammar has to be processed as well //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(lexerGrammar)) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertFalse(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } //////////////////////////////////////////////////////////////////////// // 5th - the parser grammar changed, no other grammars have to be processed //////////////////////////////////////////////////////////////////////// // modify the grammar to make checksum comparison detect a change try(Change change = Change.of(parserGrammar, " t : WS* ;")) { byte[] testLexerSum = checksum(genTestLexer); byte[] testParserSum = checksum(genTestParser); byte[] helloSum = checksum(genHello); maven.executeMojo(session, project, exec); assertTrue(Arrays.equals(testLexerSum, checksum(genTestLexer))); assertFalse(Arrays.equals(testParserSum, checksum(genTestParser))); assertTrue(Arrays.equals(helloSum, checksum(genHello))); } } @Test public void processWhenDependencyRemoved() throws Exception { Path baseDir = resources.getBasedir("dependencyRemoved").toPath(); Path antlrDir = baseDir.resolve("src/main/antlr4"); Path baseGrammar = antlrDir.resolve("imports/HelloBase.g4"); MavenProject project = maven.readMavenProject(baseDir.toFile()); MavenSession session = maven.newMavenSession(project); MojoExecution exec = maven.newMojoExecution("antlr4"); maven.executeMojo(session, project, exec); try(Change temp = Change.of(baseGrammar)) { // if the base grammar no longer exists, processing must be performed Files.delete(baseGrammar); thrown.expect(MojoExecutionException.class); thrown.expectMessage("ANTLR 4 caught 1 build errors."); maven.executeMojo(session, project, exec); } } private byte[] checksum(Path path) throws IOException { return MojoUtils.checksum(path.toFile()); } private static class Change implements AutoCloseable { final Path file; final byte[] original; public Change(Path file, String change) { this.file = file; try { original = Files.readAllBytes(file); } catch (IOException ex) { throw new RuntimeException("Could not read file " + file); } String text = new String(original, StandardCharsets.UTF_8) + change; write(file, text.getBytes(StandardCharsets.UTF_8)); } private void write(Path file, byte[] data) { try { Files.write(file, data); } catch (IOException ex) { throw new RuntimeException("Could not write file " + file); } } public static Change of(Path file, String change) { return new Change(file, change); } public static Change of(Path file) { return new Change(file, "\n"); } @Override public void close() { write(file, original); } } }