From 345b58004cb7c50b782bf074c662cc2b465b9e79 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 13 Feb 2025 09:35:59 +0300 Subject: [PATCH 1/2] #168 Refactor Java port tests Signed-off-by: vityaman --- ports/java/.devcontainer/devcontainer.json | 15 ++++ .../antlr4c3/CountingErrorListener.java | 16 +++++ ...tCodeCompletionCore.java => ExprTest.java} | 71 ++++++------------- 3 files changed, 54 insertions(+), 48 deletions(-) create mode 100644 ports/java/.devcontainer/devcontainer.json create mode 100644 ports/java/src/test/java/com/vmware/antlr4c3/CountingErrorListener.java rename ports/java/src/test/java/com/vmware/antlr4c3/{TestCodeCompletionCore.java => ExprTest.java} (75%) diff --git a/ports/java/.devcontainer/devcontainer.json b/ports/java/.devcontainer/devcontainer.json new file mode 100644 index 0000000..100a351 --- /dev/null +++ b/ports/java/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +{ + "image": "maven:3.9.9-eclipse-temurin-23", + "customizations": { + "vscode": { + "extensions": [ + "redhat.java", + "vscjava.vscode-java-debug", + "vscjava.vscode-java-test", + "vscjava.vscode-maven", + "vscjava.vscode-java-dependency", + "VisualStudioExptTeam.vscodeintellicode" + ] + } + } +} \ No newline at end of file diff --git a/ports/java/src/test/java/com/vmware/antlr4c3/CountingErrorListener.java b/ports/java/src/test/java/com/vmware/antlr4c3/CountingErrorListener.java new file mode 100644 index 0000000..b7c9cc5 --- /dev/null +++ b/ports/java/src/test/java/com/vmware/antlr4c3/CountingErrorListener.java @@ -0,0 +1,16 @@ +package com.vmware.antlr4c3; + +import org.antlr.v4.runtime.BaseErrorListener; +import org.antlr.v4.runtime.RecognitionException; +import org.antlr.v4.runtime.Recognizer; + +public class CountingErrorListener extends BaseErrorListener { + public int errorCount = 0; + + @Override + public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, + String msg, RecognitionException e) { + super.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e); + errorCount++; + } +} diff --git a/ports/java/src/test/java/com/vmware/antlr4c3/TestCodeCompletionCore.java b/ports/java/src/test/java/com/vmware/antlr4c3/ExprTest.java similarity index 75% rename from ports/java/src/test/java/com/vmware/antlr4c3/TestCodeCompletionCore.java rename to ports/java/src/test/java/com/vmware/antlr4c3/ExprTest.java index 5c4afcc..940cad1 100644 --- a/ports/java/src/test/java/com/vmware/antlr4c3/TestCodeCompletionCore.java +++ b/ports/java/src/test/java/com/vmware/antlr4c3/ExprTest.java @@ -12,43 +12,16 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.logging.Logger; - -import org.antlr.v4.runtime.BaseErrorListener; import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.RecognitionException; -import org.antlr.v4.runtime.Recognizer; import org.antlr.v4.runtime.atn.PredictionMode; import org.junit.Test; import static org.junit.Assert.*; -/** - * Unit tests for CodeCompletionCore - */ -public class TestCodeCompletionCore { - - private static final Logger logger = Logger.getLogger(TestCodeCompletionCore.class.getName()); - - public static class CountingErrorListener extends BaseErrorListener { - - public int errorCount = 0; - - @Override - public void syntaxError(Recognizer recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) { - super.syntaxError(recognizer, offendingSymbol, line, charPositionInLine, msg, e); - errorCount++; - - } - } - +public class ExprTest { @Test - public void test1_simpleExpressionTest() throws Exception { - - System.out.println(); - System.out.println("simpleExpressionTest"); - + public void simpleExpressionTest() throws Exception { String expression = "var c = a + b()"; ExprLexer lexer = new ExprLexer(CharStreams.fromString(expression)); CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -76,14 +49,15 @@ public void test1_simpleExpressionTest() throws Exception { assertTrue(candidates.tokens.containsKey(ExprLexer.ID)); { // TS: expected [ExprLexer.ID, ExprLexer.EQUAL], here got [] - assertEquals(Arrays.asList(new Integer[]{}), candidates.tokens.get(ExprLexer.VAR)); - assertEquals(Arrays.asList(new Integer[]{}), candidates.tokens.get(ExprLexer.LET)); + assertEquals(Arrays.asList(new Integer[] {}), candidates.tokens.get(ExprLexer.VAR)); + assertEquals(Arrays.asList(new Integer[] {}), candidates.tokens.get(ExprLexer.LET)); } - assertEquals(Arrays.asList(new Integer[]{}), candidates.tokens.get(ExprLexer.ID)); + assertEquals(Arrays.asList(new Integer[] {}), candidates.tokens.get(ExprLexer.ID)); - // 2) On the first whitespace. In real implementations you would do some additional checks where in the whitespace - // the caret is, as the outcome is different depending on that position. + // 2) On the first whitespace. In real implementations you would do some + // additional checks where in the whitespace + // the caret is, as the outcome is different depending on that position. candidates = core.collectCandidates(1, null); assertEquals(1, candidates.tokens.size()); assertTrue(candidates.tokens.containsKey(ExprLexer.ID)); @@ -98,14 +72,16 @@ public void test1_simpleExpressionTest() throws Exception { assertEquals(1, candidates.tokens.size()); assertTrue(candidates.tokens.containsKey(ExprLexer.EQUAL)); - // 5) On the variable reference 'a'. But since we have not configure the c3 engine to return us var refs - // (or function refs for that matter) we only get an ID here. + // 5) On the variable reference 'a'. But since we have not configure the c3 + // engine to return us var refs + // (or function refs for that matter) we only get an ID here. candidates = core.collectCandidates(6, null); assertEquals(1, candidates.tokens.size()); assertTrue(candidates.tokens.containsKey(ExprLexer.ID)); - // 6) On the '+' operator. Usually you would not show operators as candidates, but we have not set up the c3 engine - // yet to not return them. + // 6) On the '+' operator. Usually you would not show operators as candidates, + // but we have not set up the c3 engine + // yet to not return them. candidates = core.collectCandidates(8, null); assertEquals(5, candidates.tokens.size()); assertTrue(candidates.tokens.containsKey(ExprLexer.PLUS)); @@ -116,11 +92,7 @@ public void test1_simpleExpressionTest() throws Exception { } @Test - public void test2_typicalExpressionTest() throws Exception { - - System.out.println(); - System.out.println("typicalExpressionTest"); - + public void typicalExpressionTest() throws Exception { String expression = "var c = a + b"; ExprLexer lexer = new ExprLexer(CharStreams.fromString(expression)); CommonTokenStream tokens = new CommonTokenStream(lexer); @@ -137,8 +109,10 @@ public void test2_typicalExpressionTest() throws Exception { assertEquals(0, errorListener.errorCount); - // Tell the engine to return certain rules to us, which we could use to look up values in a symbol table. - Set preferredRules = new HashSet<>(Arrays.asList(ExprParser.RULE_functionRef, ExprParser.RULE_variableRef)); + // Tell the engine to return certain rules to us, which we could use to look up + // values in a symbol table. + Set preferredRules = new HashSet<>( + Arrays.asList(ExprParser.RULE_functionRef, ExprParser.RULE_variableRef)); // Ignore operators and the generic ID token. Set ignoredTokens = new HashSet<>(Arrays.asList(ExprLexer.ID, @@ -153,8 +127,8 @@ public void test2_typicalExpressionTest() throws Exception { assertTrue(candidates.tokens.containsKey(ExprLexer.VAR)); assertTrue(candidates.tokens.containsKey(ExprLexer.LET)); - assertEquals(Arrays.asList(new Integer[]{}), candidates.tokens.get(ExprLexer.VAR)); - assertEquals(Arrays.asList(new Integer[]{}), candidates.tokens.get(ExprLexer.LET)); + assertEquals(Arrays.asList(new Integer[] {}), candidates.tokens.get(ExprLexer.VAR)); + assertEquals(Arrays.asList(new Integer[] {}), candidates.tokens.get(ExprLexer.LET)); // 2) On the variable name ('c'). candidates = core.collectCandidates(2, null); @@ -169,7 +143,8 @@ public void test2_typicalExpressionTest() throws Exception { assertEquals(0, candidates.tokens.size()); assertEquals(2, candidates.rules.size()); - // Here we get 2 rule indexes, derived from 2 different IDs possible at this caret position. + // Here we get 2 rule indexes, derived from 2 different IDs possible at this + // caret position. // These are what we told the engine above to be preferred rules for us. int found = 0; for (Map.Entry> candidate : candidates.rules.entrySet()) { From 40481bc90179cfc4af9e6bb54dceac5d04e00961 Mon Sep 17 00:00:00 2001 From: vityaman Date: Thu, 13 Feb 2025 09:54:38 +0300 Subject: [PATCH 2/2] #168 Translate tests to Java Signed-off-by: vityaman --- .../antlr4/com/vmware/antlr4c3/Whitebox.g4 | 47 ++++++ .../com/vmware/antlr4c3/WhiteboxTest.java | 142 ++++++++++++++++++ 2 files changed, 189 insertions(+) create mode 100644 ports/java/src/test/antlr4/com/vmware/antlr4c3/Whitebox.g4 create mode 100644 ports/java/src/test/java/com/vmware/antlr4c3/WhiteboxTest.java diff --git a/ports/java/src/test/antlr4/com/vmware/antlr4c3/Whitebox.g4 b/ports/java/src/test/antlr4/com/vmware/antlr4c3/Whitebox.g4 new file mode 100644 index 0000000..2b49c9b --- /dev/null +++ b/ports/java/src/test/antlr4/com/vmware/antlr4c3/Whitebox.g4 @@ -0,0 +1,47 @@ +grammar Whitebox; + +@eader { +/* eslint-disable @typescript-eslint/no-unused-vars, no-useless-escape */ +} + +test1: rule1 ADIPISCING ; +rule1: rule2 CONSECTETUR ; +rule2: LOREM rule3 rule5 SIT* AMET? ; +rule3: rule4 DOLOR? ; +rule4: IPSUM? ; +rule5: ; + +test2: rule7 ADIPISCING ; +rule7: rule8 CONSECTETUR ; +rule8: LOREM rule11 rule9 SIT* AMET? ; +rule9: rule10 DOLOR? ; +rule10: IPSUM? ; +rule11: ; + +test3: LOREM IPSUM? rule13 AMET+ CONSECTETUR ; +rule13: (DOLOR | SIT)* ; + +test4: LOREM (rule15 | rule16) ; +rule15: IPSUM DOLOR SIT ; +rule16: IPSUM DOLOR AMET ; + +test5: LOREM (rule15 | rule16) ; +rule18: IPSUM DOLOR (SIT | CONSECTETUR) ; +rule19: IPSUM DOLOR AMET ; + +test6: LOREM (rule15 | rule16) ; +rule21: IPSUM DOLOR SIT ; +rule22: IPSUM DOLOR (AMET | CONSECTETUR) ; + +test7: LOREM (IPSUM DOLOR SIT | IPSUM DOLOR AMET) ; + +test8: LOREM (IPSUM DOLOR SIT AMET | IPSUM DOLOR SIT CONSECTETUR) ; + +LOREM: 'LOREM'; +IPSUM: 'IPSUM'; +DOLOR: 'DOLOR'; +SIT: 'SIT'; +AMET: 'AMET'; +CONSECTETUR: 'CONSECTETUR'; +ADIPISCING: 'ADIPISCING'; +WS: [ \n\r\t] -> skip; diff --git a/ports/java/src/test/java/com/vmware/antlr4c3/WhiteboxTest.java b/ports/java/src/test/java/com/vmware/antlr4c3/WhiteboxTest.java new file mode 100644 index 0000000..1634655 --- /dev/null +++ b/ports/java/src/test/java/com/vmware/antlr4c3/WhiteboxTest.java @@ -0,0 +1,142 @@ +package com.vmware.antlr4c3; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import java.util.Set; + +import org.antlr.v4.runtime.CharStream; +import org.antlr.v4.runtime.CharStreams; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.ParserRuleContext; +import org.junit.Test; + +public class WhiteboxTest { + @Test + public void caretAtTransitionToRuleWithNonExhaustiveFollowSetTest() { + CharStream inputStream = CharStreams.fromString("LOREM "); + + WhiteboxLexer lexer = new WhiteboxLexer(inputStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + WhiteboxParser parser = new WhiteboxParser(tokenStream); + CountingErrorListener errorListener = new CountingErrorListener(); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + + ParserRuleContext ctx = parser.test1(); + + assertEquals(1, errorListener.errorCount); + + CodeCompletionCore core = new CodeCompletionCore(parser, null, null); + CodeCompletionCore.CandidatesCollection candidates = core.collectCandidates(1, ctx); + + assertEquals(5, candidates.tokens.size()); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.IPSUM)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.DOLOR)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.SIT)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.AMET)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.CONSECTETUR)); + } + + @Test + public void caretAtTransitionToRuleWithEmptyFollowSetTest() { + CharStream inputStream = CharStreams.fromString("LOREM "); + WhiteboxLexer lexer = new WhiteboxLexer(inputStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + WhiteboxParser parser = new WhiteboxParser(tokenStream); + CountingErrorListener errorListener = new CountingErrorListener(); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + + ParserRuleContext ctx = parser.test2(); + assertEquals(1, errorListener.errorCount); + + CodeCompletionCore core = new CodeCompletionCore(parser, null, null); + CodeCompletionCore.CandidatesCollection candidates = core.collectCandidates(1, ctx); + + assertEquals(5, candidates.tokens.size()); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.IPSUM)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.DOLOR)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.SIT)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.AMET)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.CONSECTETUR)); + } + + @Test + public void caretAtOptionalTokenTest() { + CharStream inputStream = CharStreams.fromString("LOREM "); + WhiteboxLexer lexer = new WhiteboxLexer(inputStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + WhiteboxParser parser = new WhiteboxParser(tokenStream); + CountingErrorListener errorListener = new CountingErrorListener(); + parser.removeErrorListeners(); + parser.addErrorListener(errorListener); + + ParserRuleContext ctx = parser.test3(); + assertEquals(1, errorListener.errorCount); + + CodeCompletionCore core = new CodeCompletionCore(parser, null, null); + CodeCompletionCore.CandidatesCollection candidates = core.collectCandidates(1, ctx); + + assertEquals(4, candidates.tokens.size()); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.IPSUM)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.DOLOR)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.SIT)); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.AMET)); + } + + @Test + public void caretAtOneOfMultiplePossibleStatesTest() { + for (int index : new int[] { 4, 5, 6, 7 }) { + CharStream inputStream = CharStreams.fromString("LOREM IPSUM "); + WhiteboxLexer lexer = new WhiteboxLexer(inputStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + WhiteboxParser parser = new WhiteboxParser(tokenStream); + ParserRuleContext ctx; + switch (index) { + case 4: + ctx = parser.test4(); + break; + case 5: + ctx = parser.test5(); + break; + case 6: + ctx = parser.test6(); + break; + case 7: + ctx = parser.test7(); + break; + default: + throw new IllegalStateException(); + } + + CodeCompletionCore core = new CodeCompletionCore(parser, null, null); + CodeCompletionCore.CandidatesCollection candidates = core.collectCandidates(2, ctx); + + assertEquals(Set.of(WhiteboxLexer.DOLOR), candidates.tokens.keySet()); + assertTrue(candidates.tokens.get(WhiteboxLexer.DOLOR).isEmpty()); + } + } + + @Test + public void caretAtOneOfMultiplePossibleStatesWithCommonFollowListTest() { + CharStream inputStream = CharStreams.fromString("LOREM IPSUM "); + WhiteboxLexer lexer = new WhiteboxLexer(inputStream); + CommonTokenStream tokenStream = new CommonTokenStream(lexer); + + WhiteboxParser parser = new WhiteboxParser(tokenStream); + ParserRuleContext ctx = parser.test8(); + + CodeCompletionCore core = new CodeCompletionCore(parser, null, null); + CodeCompletionCore.CandidatesCollection candidates = core.collectCandidates(2, ctx); + + assertEquals(1, candidates.tokens.size()); + assertTrue(candidates.tokens.containsKey(WhiteboxLexer.DOLOR)); + assertEquals(List.of(WhiteboxLexer.SIT), candidates.tokens.get(WhiteboxLexer.DOLOR)); + } +}