Giter Club home page Giter Club logo

antlr4test-maven-plugin's Introduction

CI Codacy Badge DepShield Badge

antlr4test-maven-plugin

Maven Mojo for testing Antlr4 Grammars

Maven Coordinates

<groupId>com.khubla.antlr</groupId>
<artifactId>antlr4test-maven-plugin</artifactId>
<version>1.18</version>
<packaging>jar</packaging>

Example usage

<plugin>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4test-maven-plugin</artifactId>
	<configuration>
		<verbose>true</verbose>
		<showTree>true</showTree>
		<entryPoint>equation</entryPoint>
		<grammarName>tnt</grammarName>
		<packageName></packageName>
		<testFileExtension>.txt</testFileExtension>
		<exampleFiles>src/test/resources/examples</exampleFiles>
		<grammarInitializer>com.my.package.MyGrammarInitializer</grammarInitializer>
	</configuration>
</plugin>

Parameters

grammarName

Required name of the grammar. This should match the name of the grammar defined in the grammar ".g4" file.

<grammarName>PHP</grammarName>

caseInsensitiveType

An optional enum parameter used to enable a caseInsensitive lexer for case-insensitive languages such as PHP, Pascal, T-SQL, etc.

Available values:

  • None - does not activate a case insensitive mode (by default).
  • lower - all token values should be written in lower-case: TOKEN: 'asdf'.
  • UPPER - all token values should be written in UPPER-case: TOKEN: 'ASDF'.
<caseInsensitiveType>UPPER</caseInsensitiveType>

entryPoint

Required name of the grammar rule to use as the test entry point

<entryPoint>htmlDocument</entryPoint>

binary

Optionally treat file as binary

<binary>true</binary>

enabled

Optional boolean enable-disable flag

<enabled>true</enabled>

verbose

Optionally produce verbose output

<verbose>true</verbose>

showTree

Optionally show the LISP grammar tree

<showTree>false</showTree>

exampleFiles

Required relative path to the example files

<exampleFiles>src/test/resources/examples/</exampleFiles>

packageName

Optional package name to find the Lexer and Parser classes in

<packageName></packageName>

testFileExtension

Optional file extension of test files

<testFileExtension>.php</testFileExtension>

fileEncoding

Optional file encoding. The default value is UTF-8.

<fileEncoding>Shift_JIS</fileEncoding>

grammarInitializer

Optional full qualified name of a Java class that implements com.khubla.antlr.antlr4test.GrammarInitializer interface.

<grammarInitializer>com.my.package.MyGrammarInitializer</grammarInitializer>

When used, allows the Lexer and/or Parser to be initialized before grammar test starts. This option is typically used when your grammar uses superClass antlr4 option to override/extend default Lexer and/or Parser behavior and need to be initialized somehow before use.

One instance will be created with default constructor for each file being parsed and initialize method will be called with the Lexer and Parser instances that will be used in the tests. The class that implements GrammarInitializer should implement the following signature.

public void initialize(Lexer lexer, Parser parser)

Multiple Test Scenarios

A new optional configuration style was created to allow multiple test scenarios for the grammar. A test scenario is a set of configuration parameters used to test a particular scenario. The same configuration parameters used in traditional style can be used within test scenarios.

Its particularly useful for grammars that allows multiple configuration options through the use of superClass antlr4 option. Test scenarios will probably be used in conjunction with grammarInitializer parameter, allowing tests for distinct sets of grammar options. All configuration parameters are allowed within a test scenario. Here is an example of this new configuration style.

<plugin>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4test-maven-plugin</artifactId>
	<configuration>
		<scenarios>
			<scenario>
				<scenarioName>Package-Without-Initialization</scenarioName>
				<verbose>false</verbose>
				<showTree>true</showTree>
				<entryPoint>attrib_list</entryPoint>
				<grammarName>TestGrammar</grammarName>
				<packageName>dummy</packageName>
				<testFileExtension>.txt</testFileExtension>
				<exampleFiles>src/test/resources/noInitializationScenario/</exampleFiles>
			</scenario>
			<scenario>
				<scenarioName>Package-Initialize-IgnoreSpaces</scenarioName>
				<verbose>true</verbose>
				<showTree>true</showTree>
				<entryPoint>attrib_list</entryPoint>
				<grammarName>TestGrammar</grammarName>
				<packageName>dummy</packageName>
				<testFileExtension>.txt</testFileExtension>
				<exampleFiles>src/test/resources/initializeIgnoreSpacesScenario/</exampleFiles>
				<grammarInitializer>dummy.TestGrammarInitializer</grammarInitializer>
			</scenario>
		</scenarios>
	</configuration>
</plugin>

In the example we can see a first test scenario where no initialization is made and another test scenario where a "Ignore Space" grammar option is initialized before tests takes place. You can point to distinct example files directory in each test scenario. You can even use distinct grammars in each scenario. One should not assume any particular order of execution for each scenario.

Mixing Configuration Styles

You can mix traditional configuration style with test scenario style. In this case, the set of parameters created within traditional configuration style scope will be created within a "Default Scenario" scenario.

The following two configurations are completely equivalent.

  • Traditional Configuration Style
<plugin>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4test-maven-plugin</artifactId>
	<configuration>
		<verbose>true</verbose>
		<showTree>true</showTree>
		<entryPoint>equation</entryPoint>
		<grammarName>tnt</grammarName>
		<testFileExtension>.txt</testFileExtension>
		<exampleFiles>src/test/resources/examples</exampleFiles>
		<grammarInitializer>com.my.package.MyGrammarInitializer</grammarInitializer>
	</configuration>
</plugin>
  • Test Scenario Configuration Style
<plugin>
	<groupId>org.antlr</groupId>
	<artifactId>antlr4test-maven-plugin</artifactId>
	<configuration>
		<scenarios>
			<scenario>
				<scenarioName>Default Scenario</scenarioName>
				<verbose>true</verbose>
				<showTree>true</showTree>
				<entryPoint>equation</entryPoint>
				<grammarName>tnt</grammarName>
				<testFileExtension>.txt</testFileExtension>
				<exampleFiles>src/test/resources/examples</exampleFiles>
				<grammarInitializer>com.my.package.MyGrammarInitializer</grammarInitializer>
			</scenario>
		</scenarios>
	</configuration>
</plugin>

Checking parsed tree

Sometimes you want to assure that a given input file generates an specific parsed tree. To do so, you can create sibling files to the parsed examples provided adding the .tree extension to the full name of the parsed file to ask the plugin to check if the parsed tree obtained from the file matchs an expected tree.

For example, if you have an 'examples/fileToBeParsed.txt' file, you can create a 'examples/fileToBeParsed.txt.tree' file containing the LISP style tree expected to be parsed from you file.

The checking is done by taking the parsed tree and transforming it to LISP style tree with toStringTree(parserRuleContext, parser) of class org.antlr.v4.runtime.tree.Trees. If they match, everything is fine. If don't, a Diff is generated to show where differences was found.

Here is the code snippet that checks the parsed tree against the expected one:

		final File treeFile = new File(grammarFile.getAbsolutePath() + GrammarTestMojo.TREE_SUFFIX);
		if (treeFile.exists()) {
			final String lispTree = Trees.toStringTree(parserRuleContext, parser);
			if (null != lispTree) {
				final String treeFileData = FileUtils.fileRead(treeFile, scenario.getFileEncoding());
				if (null != treeFileData) {
					if (0 != treeFileData.compareTo(lispTree)) {
						StringBuilder sb = new StringBuilder(
								"Parse tree does not match '" + treeFile.getName() + "'. Differences: ");
						for (DiffMatchPatch.Diff diff : new DiffMatchPatch().diffMain(treeFileData, lispTree)) {
							sb.append(diff.toString());
							sb.append(", ");
						}
						throw new Exception(sb.toString());
					} else {
						log.info("Parse tree for '" + grammarFile.getName() + "' matches '" + treeFile.getName() + "'");
					}
				}
			}
		}

A tip to use this feature is to configure the plugin to shows the parsed tree using true option. Then you can check the log output manually to see if the generated tree is the expected one. If it is ok, you can copy/paste the parsed tree (only the parsed tree with no other message accessories) to the .tree file.

Checking expected errors

Sometimes you want to check if specific input files generate parsing errors. This can be done with the plugin by adding a new file sibling to the parsed one with .errors extension. Each line is interpreted as an expected parsing error, and the message in the file is compared to the parsed results. If they match, everything is ok, otherwise a test error is raised.

For example, if you have an 'examples/fileToBeParsed.txt' file, you can create a 'examples/fileToBeParsed.txt.errors' file containing the expected parse error messages.

A tip to use this feature is to configure the plugin to shows the errors using true option. Then you can check the log output manually to see exact error message generated and copy/paste the error messages (only the parsed tree with no other message accessories) to the .errors file.

antlr4test-maven-plugin's People

Contributors

airstone42 avatar bhamiltoncx avatar bleis-tift avatar dependabot[bot] avatar gilcesarf avatar kvanttt avatar mario-s avatar parrt avatar teverett avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

antlr4test-maven-plugin's Issues

How can i make ".errors" file with '\n' inside?

When I try to test my grammar I get this error exception:

[ERROR] Failed to execute goal com.khubla.antlr:antlr4test-maven-plugin:1.11:test (VisualBasic6) on project matcher-core: Unable execute mojo: VB6_BACKDOOR_TIMEBOMB.vb.errors : expected (line 24:19 no viable alternative at input '
[ERROR] 
[ERROR] If Timer() < 1234 Then
[ERROR] 
[ERROR] End If
[ERROR] 
[ERROR] If Year(date)=2017 Then
[ERROR] \tactivateBackdoor();'), but was (line 24:19 no viable alternative at input '\n\nIf Timer() < 1234 Then\n    \nEnd If\n\nIf Year(date)=2017 Then\n\tactivateBackdoor();')

I don't understand how is it possible. '\n''s encoding like a newline but '\t''s not. And adding '\' before symbol '\n' in ".errors" file does't give any successful result (printed like '\').
I think something is wrong. Encoding file is 'utf-8', default value encoding in this plugin is 'utf-8' too.

Change owner for Travis-CI

It's necessary to include travis-ci to ANTLR organization and use https://travis-ci.org/antlr/antlr4test-maven-plugin instead of old https://travis-ci.org/teverett/antlr4test-maven-plugin.

Parsing tests for different runtimes

Some grammars contain actions designed for certain runtimes (due to ANTLR context-free grammar restrictions). For example, csharp and php grammars developed under C# runtime. Travis CI support for such grammars would be great.

ANTLRFileStream should not be used

It looks like ANTLRFileStream.LA(int) does not work on grammars-v4/php/examples/identifiers.php. See this. It should be replaced with CharStreams.fromFileName.

java.lang.ClassNotFoundException during GrammarInitializer instantiation

I have created a new scenario and configured a GrammarInitializer implemented inside my src/test/java root. A ClassNotFound exception was raised as at the end.

I investigated the problem and it is caused because of this snippet inside com.khubla.antlr.antlr4test.Scenario class:

public ClassLoader getClassLoader() throws MalformedURLException, ClassNotFoundException {
    final URL antlrGeneratedURL = new File(baseDir + "/target/classes").toURI().toURL();
    final URL[] urls = new URL[] { antlrGeneratedURL };
    return new URLClassLoader(urls, Thread.currentThread().getContextClassLoader());
}

This is the code used to get a classloader to load the Lexer and Parser. It points explicitly to "/target/classes". But when the GrammarInitializer is put inside /src/test/java, the corresponding .class gets compiled to "/target/test-classes", so it cannot be found.

Until I fix this, a possible workaround is to put the GrammarInitializer implementation inside the main source project root: src/main/java

This workaround solved the ClassNotFoundException. Its drawback is that GrammarInitializer class would be distributed with the .jar of the project.

java.lang.ClassNotFoundException: io.trustep.grammars.mysql.SmokeInitializer
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:466)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:563)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:496)
	at com.khubla.antlr.antlr4test.ScenarioExecutor.testGrammar(ScenarioExecutor.java:112)
	at com.khubla.antlr.antlr4test.ScenarioExecutor.testGrammars(ScenarioExecutor.java:72)
	at com.khubla.antlr.antlr4test.GrammarTestMojo.testScenarios(GrammarTestMojo.java:294)
	at com.khubla.antlr.antlr4test.GrammarTestMojo.execute(GrammarTestMojo.java:169)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

NullPointerException under certain conditions when using new Scenario configuration

Using the new scenario configuration, I have found a NPE only when using the verbose=true option. Digging into the code, I have found that baseDir does not get its default value if using the new Scenario configuration, as shown in log messages. Two possible workarounds: first, to setup manually the baseDir with . within the scenario; or second, to disable verbose option.

The problematic Scenario configuration:

<scenario>
	<scenarioName>Basic</scenarioName>
	<enabled>true</enabled>
	<verbose>false</verbose>
	<showTree>true</showTree>
	<entryPoint>query</entryPoint>
	<grammarName>MySQL</grammarName>
	<packageName>io.trustep.grammars.mysql</packageName>
	<caseInsensitiveType>None</caseInsensitiveType>
	<exampleFiles>src/test/antlr4/io/trustep/grammars/mysql/basic</exampleFiles>
	<fileEncoding>ISO-8859-1</fileEncoding>
	<testFileExtension>sql</testFileExtension>
</scenario>

The logged error:

Evaluating Scenario: Basic
baseDir: null
exampleFiles: src/test/antlr4/io/trustep/grammars/mysql/basic
java.lang.NullPointerException
	at com.khubla.antlr.antlr4test.GrammarTestMojo.testScenarios(GrammarTestMojo.java:284)
	at com.khubla.antlr.antlr4test.GrammarTestMojo.execute(GrammarTestMojo.java:169)
	at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:210)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:156)
	at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:148)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:117)
	at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:81)
	at org.apache.maven.lifecycle.internal.builder.singlethreaded.SingleThreadedBuilder.build(SingleThreadedBuilder.java:56)
	at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:128)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:305)
	at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:192)
	at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:105)
	at org.apache.maven.cli.MavenCli.execute(MavenCli.java:957)
	at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:289)
	at org.apache.maven.cli.MavenCli.main(MavenCli.java:193)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:564)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:282)
	at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:225)
	at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:406)
	at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:347)

Add instructions on how to use .tree and .errors files

Looking through the sources, I suppose it's possible to specify the expected tree outputs and expected errors for some test files. It would be very useful to have a documentation with examples describing how to use that files.
Also, when some of the test files contains an error (does not match grammar syntax), the plugin tries to open .errors file and throws an error if it doesn't exist:

Caused by: java.io.FileNotFoundException: /home/scadge/IdeaProjects/querysyntax/query-syntax/examples/dml_select.txt.errors (No such file or directory)

Though it's probably a subject to another issue, I thought it would be useful to also mention it here.

Using this plugin with a jar in the classpath or maven dependency

Error I'm getting:

baseDir: /tmp/testproject
exampleFiles: src/main/plsql/
Lexer classname is: PlSqlLexer
Parser classname is: PlSqlParser
java.lang.ClassNotFoundException: PlSqlLexer

I'm building an internal project with pom.xml like this and I'm wondering how to get a Lexer/Parser into the classpath of the test.

(We are building the standard PL/SQL grammar/lexer jar internally and uploading to an internal maven repo, thus the dependency below...)

  <build>
    <plugins>
      <plugin>
        <groupId>com.khubla.antlr</groupId>
        <artifactId>antlr4test-maven-plugin</artifactId>
        <version>1.9</version>
        <configuration>
          <verbose>true</verbose>
          <showTree>false</showTree>
          <entryPoint>sql_script</entryPoint>
          <grammarName>PlSql</grammarName>
          <caseInsensitiveType>UPPER</caseInsensitiveType>
          <packageName></packageName>
          <exampleFiles>src/main/plsql/</exampleFiles>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>test</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>com.antlr.grammarsv4</groupId>
      <artifactId>plsql</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>test</scope>
    </dependency>
  </dependencies>

Thank you for your time,

Stephen

New case insensitive options

I want to use not only lower case. but UPPER CASE for case insensitive lexers (such as SQL languages). So, I suggest to use the following options for caseInsensitive parameter:

  • false (by default)
  • UPPER
  • lower

Default parameters that oriented on grammars-v4 repository

  • grammars or includes - <grammarName>.g4 . If not found than <grammarName>Lexer.g4 and <grammarName>Parser.g4.
  • entryPoint - the first rule in separated or combined grammar.
  • exampleFiles - examples directory in root grammar dir (baseDir).

The plugin should be marked to be thread safe

If you start a build which contains antlr4test-maven-plugin with multi thread support (parallel build) you get the following warning:

[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ cql ---
[INFO] Building jar: ..../grammars-v4/cql/target/cql-1.0-SNAPSHOT.jar
[INFO] 
[INFO] ----------------------< org.antlr.grammars:cql3 >-----------------------
[INFO] Building Apache Cassandra CQL 3 grammar 1.0-SNAPSHOT            [34/256]
[INFO] --------------------------------[ jar ]---------------------------------
[WARNING] *****************************************************************
[WARNING] * Your build is requesting parallel execution, but project      *
[WARNING] * contains the following plugin(s) that have goals not marked   *
[WARNING] * as @threadSafe to support parallel building.                  *
[WARNING] * While this /may/ work fine, please look for plugin updates    *
[WARNING] * and/or request plugins be made thread-safe.                   *
[WARNING] * If reporting an issue, report it against the plugin in        *
[WARNING] * question, not against maven-core                              *
[WARNING] *****************************************************************
[WARNING] The following plugins are not marked @threadSafe in Apache Cassandra CQL 3 grammar:
[WARNING] com.khubla.antlr:antlr4test-maven-plugin:1.17
[WARNING] org.antlr:antlr4-maven-plugin:4.9.1
[WARNING] Enable debug to see more precisely which goals are not marked @threadSafe.
[WARNING] *****************************************************************
[INFO] 
[INFO] --- maven-clean-plugin:2.5:clean (default-clean) @ cql3 ---

It would be nice to mark the antlr4-maven-plugin threadSafe = true to suppress this warning.

Reuse lexer and parser between tests

Both Lexer and Parser have setInputStream method so they can be reused. We could add an option to reuse them between tests of the same grammar to make sure it works properly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.