Testing a Parser
Be sure to define a subclass of IANTLRFrontEnd
and
to declare an ANTLRTester
in your test-case class.
(See the usage page for further
instructions.)
Also, test your lexer first.
AST Assertions
It's harder to make simple assertions about a whole AST (Abstract Syntax Tree) compared to making assertions on tokens.
The helpful method from org.norecess.antlr.Assert
is assertTree
. You now make assertions on
- the type of the root of the AST, and
- the preorder traversal of the AST with heavily parenthesized text.
Here's an example parsing an infix +
expression:
assertTree(MyOwnParser.EXPRESSION, "(+(1)(x))", myTester.scanInput("1 + x").parseAs("expression"));
The parseAs("expression")
takes the token stream
from the scanned input and parses that stream starting (in this
case) with the expression
production. This allows you
to test your grammar at the finest detail without having
extraordinary input and preorder traversals.
MyOwnParser.EXPRESSION
is the type of the root of
the expected AST. You can always refer to these types from your
parser class whether their imaginary or lexer tokens.
(+(1)(x))
is the preorder traversal built up with
lots of parentheses and the tokens' texts.
Examples
Here I test various ways to build up a tuple:
@Test public void shouldRecognizeATupleAsAProgram() { assertTree(MyOwnParser.TUPLE, "(TUPLE)", myTester.scanInput("()") .parseAs("program")); assertTree(MyOwnParser.TUPLE, "(TUPLE(1))", myTester.scanInput( "(1)").parseAs("program")); assertTree(MyOwnParser.TUPLE, "(TUPLE(1)(2)(3))", myTester .scanInput("(1,2, 3)").parseAs("program")); }
Note that the commas are recognized by the parser in the last assertion, but they are not included in the AST (as evidenced by the preorder traversal).
Testing failures is a bit clumsy:
@Test(expected = Exception.class) public void shouldFailOnInitialComma() { myTester.scanInput("(,2, 3)").parseAs("program"); }