HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Unit test code for Antlr Grammar

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
antlrgrammarfortestcodeunit

Problem

I'm working on a grammar for the Visual Basic for Applications (VBA) programming language. I've discovered a way to make assertions about how a parse tree should be generated by using the Antlr ToStringTree method.

My method is this:

  • Create a parser and give it a code snippet.



  • Obtain the parse tree result and turn it into a string using ToStringTree.



  • Perform a string comparison ignoring whitespace.



What I'm thinking though, is that I may be a little too prescriptive in the final step. As an example, I'm working through the valid identifier use cases in my unit tests:

```
public class ModuleStatementTests
{
private readonly List ambiguousIdentifiers = new List()
{
"Access",
"Alias",
"Append",
"Base",
"Binary",
"ClassInit",
"ClassTerm",
"CLngLng",
"Compare",
"Database",
"DefLngLng",
"Error",
"Explicit",
"Lib",
"Line",
"LongLong",
"Mid",
"MidB",
"Module",
"Object",
"Output",
"Property",
"PtrSafe",
"Random",
"Read",
"Reset",
"Step",
"Text",
"Width"
};

[Fact]
public void CanParseAmbiguousIdentifierInVariableDeclaration()
{
const string variableDeclarationTemplate = "Dim {0} As String";
const string expectedVariableDeclaration =
"(variableDeclaration Dim (variableDclList (variableDcl (untypedVariableDcl (identifier {0}) (asClause (asType As (typeSpec (typeExpression (builtInType (reservedTypeIdentifier String))))))))))";

CanParseAllAmbiguousIdentifiers(variableDeclarationTemplate, expectedVariableDeclaration, p => p.variableDeclaration());
}

private void CanParseAllAmbiguousIdentifiers(string sourceTemplate, string expectedOutputTemplate, Func rule)
{
foreach (var id in ambiguousIdentifiers)
{
var source = string.

Solution

I wanted to post an idea I had to address my concern over the brittleness of my unit test(s). I realised that since I am performing a string comparison, that I could use Regular Expressions. Then I can ignore parts of the parse tree string that are not interesting. So I have this as a potential solution:

[Fact]
public void CanParseAmbiguousIdentifierInVariableDeclaration()
{
    const string variableDeclarationTemplate = "Dim {0} As String";
    const string regexTemplate = @"(\(variableDeclaration.*\(identifier {0}\).*\))";

    CanParseAllAmbiguousIdentifiersRegex(variableDeclarationTemplate, regexTemplate,
        p => p.variableDeclaration());
}

private void CanParseAllAmbiguousIdentifiersRegex(string sourceTemplate, string regexTemplate, Func rule)
{
    foreach (var id in ambiguousIdentifiers)
    {
        var source = string.Format(sourceTemplate, id);
        var regex = string.Format(regexTemplate, id);

        CanParseSourceRegex(source, regex, rule);
    }
}

private static void CanParseSourceRegex(string source, string regex, Func rule)
{
    var parser = VbaCompilerHelper.BuildVbaParser(source);

    var result = rule(parser);

    Assert.Null(result.exception);
    Assert.True(Regex.IsMatch(result.ToStringTree(parser), regex));
}

Code Snippets

[Fact]
public void CanParseAmbiguousIdentifierInVariableDeclaration()
{
    const string variableDeclarationTemplate = "Dim {0} As String";
    const string regexTemplate = @"(\(variableDeclaration.*\(identifier {0}\).*\))";

    CanParseAllAmbiguousIdentifiersRegex(variableDeclarationTemplate, regexTemplate,
        p => p.variableDeclaration());
}

private void CanParseAllAmbiguousIdentifiersRegex(string sourceTemplate, string regexTemplate, Func<VbaParser, ParserRuleContext> rule)
{
    foreach (var id in ambiguousIdentifiers)
    {
        var source = string.Format(sourceTemplate, id);
        var regex = string.Format(regexTemplate, id);

        CanParseSourceRegex(source, regex, rule);
    }
}

private static void CanParseSourceRegex(string source, string regex, Func<VbaParser, ParserRuleContext> rule)
{
    var parser = VbaCompilerHelper.BuildVbaParser(source);

    var result = rule(parser);

    Assert.Null(result.exception);
    Assert.True(Regex.IsMatch(result.ToStringTree(parser), regex));
}

Context

StackExchange Code Review Q#97293, answer score: 3

Revisions (0)

No revisions yet.