Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#168 Add Java port Whitebox test #170

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions ports/java/.devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -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"
]
}
}
}
47 changes: 47 additions & 0 deletions ports/java/src/test/antlr4/com/vmware/antlr4c3/Whitebox.g4
Original file line number Diff line number Diff line change
@@ -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;
Original file line number Diff line number Diff line change
@@ -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++;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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));
Expand All @@ -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));
Expand All @@ -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);
Expand All @@ -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<Integer> 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<Integer> preferredRules = new HashSet<>(
Arrays.asList(ExprParser.RULE_functionRef, ExprParser.RULE_variableRef));

// Ignore operators and the generic ID token.
Set<Integer> ignoredTokens = new HashSet<>(Arrays.asList(ExprLexer.ID,
Expand All @@ -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);
Expand All @@ -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<Integer, List<Integer>> candidate : candidates.rules.entrySet()) {
Expand Down
142 changes: 142 additions & 0 deletions ports/java/src/test/java/com/vmware/antlr4c3/WhiteboxTest.java
Original file line number Diff line number Diff line change
@@ -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));
}
}
Loading