ANLTR 4(Java)出于测试目的捕获解析器错误/期望

时间:2019-04-16 10:57:55

标签: java antlr antlr4 junit5

我正在研究ANTLR解析器,现在正在为解析器编写测试。

我已经找到了一种“正向”测试解析器的方法,但是现在还想测试在输入错误的情况下解析器也会失败(负测试?)。

我想要的是一种使用JUnits Assertions.assertThrows()来生成NoViableAltException或解析器抛出的其他异常的方法。

我已经研究了ANTLRErrorListener及其实现,但是在那里没有找到解决方案。

到目前为止,这是我的测试用例:

@Test
    public void test_short_negative() {

        String[] string_values = new String[]{"{", "<EOF>"};
        int[] id_values = new int[]{MyLexer.CBRACKET_OPEN, MyLexer.EOF};

        ArrayList<TestToken> tokens = new ArrayList<>();

        for (int i = 0; i < id_values.length; i++) tokens.add(new TestToken(string_values[i], id_values[i]));

        ListTokenSource source = new ListTokenSource(tokens);
        for(TestToken t: tokens) t.setTokenSource(source);

        TestErrorListener errorListener = new TestErrorListener(true);
        MyParser pars = createParser(new ListTokenSource(tokens), errorListener);
        pars.stmt_block();
    }

public class TestErrorListener extends BaseErrorListener {
    private boolean hadError = false;
    private TestToken lastOffendingSymbol;

    private boolean doPrint;

    public TestErrorListener(boolean doPrint){
        this.doPrint = doPrint;
    }

    public boolean hadError() {
        return hadError;
    }

    public TestToken getLastOffendingSymbol() {
        return lastOffendingSymbol;
    }

    @Override
    public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
        if(doPrint) System.out.println("Syntax error at " + line + ":" + charPositionInLine + ". Symbol: '" + ((TestToken) offendingSymbol).getText() + "' could not be parsed.");
        hadError = true;
        lastOffendingSymbol = (TestToken) offendingSymbol;
    }

    @Override
    public void reportAmbiguity(Parser recognizer, DFA dfa, int startIndex, int stopIndex, boolean exact, BitSet ambigAlts, ATNConfigSet configs) {
        if(doPrint) System.out.println("Ambiguity found at [" + startIndex + ":" + stopIndex + "]!");
    }


}

库版本:

  • ANTLR4 :4.7.2
  • JUnit :5.5.0-m1

感谢所有帮助^^

1 个答案:

答案 0 :(得分:1)

  

还希望测试在提供错误输入时解析器是否也会失败

在这种情况下,“失败”的含义还不清楚,但是我认为您的意思是“我怎么知道语法错误发生了?”。由于ANTLR解析器可以从某些语法错误中恢复,因此跳过一些标记并继续进行解析。

每次遇到语法错误时,您的syntaxError()的{​​{1}}方法都会被调用。

根据示例代码,每次发生错误时,都将TestErrorListener标志设置为true,这意味着在解析之后,您可以针对输入令牌测试此标志为true还是false。

此外,您可以通过提供错误处理程序,使ANTLR立即引发异常并在发生错误时停止解析,即:

hadError

从现在开始,您的解析器将抛出pars.setErrorHandler(new BailErrorStrategy()); 。捕获并使用ParseCancellationException方法,您可以获得导致解析器停止的真正原因,包括getCause()

在后一种情况下,您要做的就是将NoViableAltExceptionpars.stmt_block();一起运行,并检查是否抛出assertThrows()