diff options
Diffstat (limited to 'src/test/java/com/fivetran')
-rw-r--r-- | src/test/java/com/fivetran/javac/AutocompleteTest.java | 86 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/CompilerProfiling.java | 85 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/Fixtures.java | 13 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/LinterTest.java | 167 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/ParserTest.java | 47 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/RequestResponseTest.java | 124 | ||||
-rw-r--r-- | src/test/java/com/fivetran/javac/ResponseCollector.java | 17 |
7 files changed, 539 insertions, 0 deletions
diff --git a/src/test/java/com/fivetran/javac/AutocompleteTest.java b/src/test/java/com/fivetran/javac/AutocompleteTest.java new file mode 100644 index 0000000..58a3e97 --- /dev/null +++ b/src/test/java/com/fivetran/javac/AutocompleteTest.java @@ -0,0 +1,86 @@ +package com.fivetran.javac; + +import com.fivetran.javac.message.RequestAutocomplete; +import org.junit.Ignore; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Set; +import java.util.logging.Logger; + +import static java.util.stream.Collectors.toSet; +import static org.hamcrest.Matchers.hasItems; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.assertThat; + +public class AutocompleteTest extends Fixtures { + private static final Logger LOG = Logger.getLogger(""); + + @Test + public void staticMember() throws IOException { + String file = "/AutocompleteStaticMember.java"; + + // Static method + Set<String> suggestions = autocomplete(file, 2, 33); + + assertThat(suggestions, hasItems("fieldStatic", "methodStatic", "class")); + assertThat(suggestions, not(hasItems("field", "method", "getClass"))); + } + + @Test + @Ignore + public void staticReference() throws IOException { + String file = "/AutocompleteStaticReference.java"; + + // Static method + Set<String> suggestions = autocomplete(file, 2, 37); + + assertThat(suggestions, hasItems("methodStatic")); + assertThat(suggestions, not(hasItems( "method", "new"))); + } + + @Test + public void member() throws IOException { + String file = "/AutocompleteMember.java"; + + // Static method + Set<String> suggestions = autocomplete(file, 2, 13); + + assertThat(suggestions, not(hasItems("fieldStatic", "methodStatic", "class"))); + assertThat(suggestions, hasItems("field", "method", "getClass")); + } + + @Test + @Ignore + public void reference() throws IOException { + String file = "/AutocompleteReference.java"; + + // Static method + Set<String> suggestions = autocomplete(file, 2, 14); + + assertThat(suggestions, not(hasItems("methodStatic"))); + assertThat(suggestions, hasItems("method", "getClass")); + } + + private Set<String> autocomplete(String file, int row, int column) throws IOException { + RequestAutocomplete request = new RequestAutocomplete(); + + request.path = path(file); + request.text = new String(Files.readAllBytes(Paths.get(path(file)))); + request.row = row; + request.column = column; + + return new Services().autocomplete(request).suggestions.stream().map(s -> s.text).collect(toSet()); + } + + private String path(String file) { + try { + return AutocompleteTest.class.getResource(file).toURI().getPath(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } +} diff --git a/src/test/java/com/fivetran/javac/CompilerProfiling.java b/src/test/java/com/fivetran/javac/CompilerProfiling.java new file mode 100644 index 0000000..bc7d296 --- /dev/null +++ b/src/test/java/com/fivetran/javac/CompilerProfiling.java @@ -0,0 +1,85 @@ +package com.fivetran.javac; + +import com.sun.source.tree.CompilationUnitTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.comp.CompileStates; +import org.junit.Ignore; +import org.junit.Test; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; +import java.util.logging.Logger; + +import static org.junit.Assert.assertNotNull; + +@Ignore +public class CompilerProfiling extends Fixtures { + private static final Logger LOG = Logger.getLogger(""); + + @Test + public void parsingSpeed() throws IOException, URISyntaxException { + StringFileObject file = fromResource("/LargeFile.java"); + + for (int i = 0; i < 10; i++) { + Duration duration = compileLargeFile(file); + + LOG.info(duration.toString()); + } + } + + private Duration compileLargeFile(StringFileObject file) { + long start = System.nanoTime(); + + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + GetCompilationUnit compilationUnit = new GetCompilationUnit(); + JavacTask task = JavacTaskBuilder.create() + .addFile(file) + .afterParse(compilationUnit) + .reportErrors(errors) + .stopIfError(CompileStates.CompileState.ENTER) + .stopIfNoError(CompileStates.CompileState.ENTER) + .build(); + + try { + task.call(); + } catch (RuntimeException e) { + if (e.getCause() instanceof AbortCompilation) + LOG.info("Aborted further stages"); + else + throw e; + } + + long finish = System.nanoTime(); + + assertNotNull(compilationUnit.result); + + return Duration.ofNanos(finish - start); + } + + private StringFileObject fromResource(String file) throws URISyntaxException, IOException { + Path path = Paths.get(LinterTest.class.getResource(file).toURI()); + String content = new String(Files.readAllBytes(path)); + return new StringFileObject(content, path); + } + + private static class GetCompilationUnit extends BridgeExpressionScanner { + private CompilationUnitTree result; + + @Override + protected void visitCompilationUnit(CompilationUnitTree node) { + this.result = node; + + throw new AbortCompilation(); + } + } + + private static class AbortCompilation extends RuntimeException { + + } +} diff --git a/src/test/java/com/fivetran/javac/Fixtures.java b/src/test/java/com/fivetran/javac/Fixtures.java new file mode 100644 index 0000000..3e5d8ab --- /dev/null +++ b/src/test/java/com/fivetran/javac/Fixtures.java @@ -0,0 +1,13 @@ +package com.fivetran.javac; + +import com.fivetran.javac.logging.LoggingFormat; +import org.junit.BeforeClass; + +import java.io.IOException; + +public class Fixtures { + @BeforeClass + public static void setup() throws IOException { + LoggingFormat.startLogging(); + } +} diff --git a/src/test/java/com/fivetran/javac/LinterTest.java b/src/test/java/com/fivetran/javac/LinterTest.java new file mode 100644 index 0000000..8f3de35 --- /dev/null +++ b/src/test/java/com/fivetran/javac/LinterTest.java @@ -0,0 +1,167 @@ +package com.fivetran.javac; + +import com.sun.source.tree.MethodTree; +import com.sun.source.util.JavacTask; +import com.sun.source.util.Trees; +import com.sun.tools.javac.code.Type; +import org.junit.Test; + +import javax.tools.Diagnostic; +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.logging.Logger; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.assertThat; + +public class LinterTest extends Fixtures { + private static final Logger LOG = Logger.getLogger(""); + + @Test + public void compile() throws IOException { + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + + JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/HelloWorld.java")) + .reportErrors(errors) + .build() + .call(); + } + + @Test + public void inspectTree() throws IOException { + CollectMethods scanner = new CollectMethods(); + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/HelloWorld.java")) + .reportErrors(errors) + .afterAnalyze(scanner) + .build(); + + task.call(); + + assertThat(scanner.methodNames, hasItem("main")); + } + + @Test + public void missingMethodBody() throws IOException { + CollectMethods scanner = new CollectMethods(); + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/MissingMethodBody.java")) + .reportErrors(errors) + .afterAnalyze(scanner) + .build(); + + task.call(); + + assertThat(scanner.methodNames, hasItem("test")); + assertThat(errors.getDiagnostics(), not(empty())); + } + + @Test + public void incompleteAssignment() throws IOException { + CollectMethods parsed = new CollectMethods(); + CollectMethods compiled = new CollectMethods(); + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/IncompleteAssignment.java")) + .reportErrors(errors) + .afterParse(parsed) + .afterAnalyze(compiled) + .build(); + + task.call(); + + assertThat(parsed.methodNames, hasItem("test")); // Error recovery should have worked + assertThat(compiled.methodNames, hasItem("test")); // Type error recovery should have worked + assertThat(errors.getDiagnostics(), not(empty())); + } + + @Test + public void undefinedSymbol() throws IOException { + CollectMethods scanner = new CollectMethods(); + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/UndefinedSymbol.java")) + .afterAnalyze(scanner) + .reportErrors(errors) + .build(); + + task.call(); + + assertThat(scanner.methodNames, hasItem("test")); // Type error, so parse tree is present + assertThat(errors.getDiagnostics(), not(empty())); + + Diagnostic<? extends JavaFileObject> d = errors.getDiagnostics().get(0); + + // Error position should span entire 'foo' symbol + assertThat(d.getLineNumber(), greaterThan(0L)); + assertThat(d.getStartPosition(), greaterThan(0L)); + assertThat(d.getEndPosition(), greaterThan(d.getStartPosition() + 1)); + } + + @Test + public void getType() { + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + MethodTypes scanner = new MethodTypes(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/FooString.java")) + .afterAnalyze(scanner) + .reportErrors(errors) + .build(); + + task.call(); + + assertThat(scanner.methodTypes, hasKey("test")); + + Type.MethodType type = scanner.methodTypes.get("test"); + + assertThat(type.getReturnType().toString(), equalTo("java.lang.String")); + assertThat(type.getParameterTypes(), hasSize(1)); + assertThat(type.getParameterTypes().get(0).toString(), equalTo("java.lang.String")); + } + + @Test + public void notJava() { + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + JavacTask task = JavacTaskBuilder.create() + .addFile(new GetResourceFileObject("/NotJava.java.txt")) + .reportErrors(errors) + .build(); + + task.call(); + + assertThat(errors.getDiagnostics(), not(empty())); + } + + public static class MethodTypes extends BridgeExpressionScanner { + public final Map<String, Type.MethodType> methodTypes = new HashMap<>(); + + @Override + protected void visitMethod(MethodTree node) { + super.visitMethod(node); + + Trees trees = Trees.instance(super.task); + Type.MethodType typeMirror = (Type.MethodType) trees.getTypeMirror(path()); + + methodTypes.put(node.getName().toString(), typeMirror); + } + } + + public static class CollectMethods extends BridgeExpressionScanner { + public final Set<String> methodNames = new HashSet<>(); + + @Override + protected void visitMethod(MethodTree node) { + super.visitMethod(node); + + methodNames.add(node.getName().toString()); + } + } +} diff --git a/src/test/java/com/fivetran/javac/ParserTest.java b/src/test/java/com/fivetran/javac/ParserTest.java new file mode 100644 index 0000000..2d90732 --- /dev/null +++ b/src/test/java/com/fivetran/javac/ParserTest.java @@ -0,0 +1,47 @@ +package com.fivetran.javac; + +import com.sun.source.tree.MethodTree; +import com.sun.source.util.JavacTask; +import com.sun.tools.javac.comp.CompileStates; +import org.junit.Test; + +import javax.tools.DiagnosticCollector; +import javax.tools.JavaFileObject; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.Matchers.hasItem; +import static org.junit.Assert.assertThat; + +public class ParserTest extends Fixtures { + @Test + public void missingSemicolon() throws IOException, URISyntaxException { + String test = "/MissingSemicolon.java"; + + List<String> methods = new ArrayList<>(); + DiagnosticCollector<JavaFileObject> errors = new DiagnosticCollector<>(); + Path path = Paths.get(ParserTest.class.getResource(test).toURI().getPath()); + JavaFileObject file = JavacTaskBuilder.STANDARD_FILE_MANAGER.getRegularFile(path.toFile()); + JavacTask task = JavacTaskBuilder.create() + .fuzzyParser() + .addFile(file) + .reportErrors(errors) + .afterParse(new BridgeExpressionScanner() { + @Override + protected void visitMethod(MethodTree node) { + methods.add(node.getName().toString()); + } + }) + .stopIfNoError(CompileStates.CompileState.PARSE) + .build(); + + task.call(); + + assertThat(methods, hasItem("methodWithMissingSemicolon")); + assertThat(methods, hasItem("methodAfterMissingSemicolon")); + } +} diff --git a/src/test/java/com/fivetran/javac/RequestResponseTest.java b/src/test/java/com/fivetran/javac/RequestResponseTest.java new file mode 100644 index 0000000..da219ab --- /dev/null +++ b/src/test/java/com/fivetran/javac/RequestResponseTest.java @@ -0,0 +1,124 @@ +package com.fivetran.javac; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.MappingIterator; +import com.fivetran.javac.message.*; +import org.junit.Test; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.Assert.assertThat; + +public class RequestResponseTest extends Fixtures { + + @Test + public void echo() throws IOException { + String request = "{\"requestId\":1,\"echo\":\"Hello world!\"}"; + List<Response> responses = responses(request); + + Response expected = new Response(1); + + expected.echo = Optional.of(Main.JSON.readTree("\"Hello world!\"")); + + assertThat(responses, hasItem(expected)); + + request = "{\"requestId\":2,\"echo\":\"Hello world!\"}"; + responses = responses(request); + + expected = new Response(2); + + expected.echo = Optional.of(Main.JSON.readTree("\"Hello world!\"")); + + assertThat(responses, hasItem(expected)); + } + + private List<Response> responses(String request) throws IOException { + JsonParser parser = Main.JSON.getFactory().createParser(request); + MappingIterator<Request> in = Main.JSON.readValues(parser, Request.class); + ResponseCollector out = new ResponseCollector(); + + new Main(in, out).run(); + + return out.responses; + } + + @Test + public void lintUndefinedSymbol() throws URISyntaxException, IOException { + Path file = Paths.get(RequestResponseTest.class.getResource("/UndefinedSymbol.java").toURI()); + + RequestLint lint = new RequestLint(); + lint.path = file.toString(); + + Request request = new Request(); + request.requestId = 2; + request.lint = Optional.of(lint); + + List<Response> responses = responses(request.toString()); + + ResponseLint responseLint = new ResponseLint(); + String message = "cannot find symbol\n symbol: variable foo\n location: class UndefinedSymbol"; + Range range = new Range(new Point(2, 15), new Point(2, 18)); + responseLint.messages.add(new LintMessage(LintMessage.Type.Error, message, lint.path, range)); + + Response expected = new Response(request.requestId); + expected.lint = Optional.of(responseLint); + + assertThat(responses, hasItem(expected)); + } + + @Test + public void lintSingleLineUndefinedSymbol() throws URISyntaxException, IOException { + Path file = Paths.get(RequestResponseTest.class.getResource("/SingleLineUndefinedSymbol.java").toURI()); + + RequestLint lint = new RequestLint(); + lint.path = file.toString(); + + Request request = new Request(); + request.requestId = 2; + request.lint = Optional.of(lint); + + List<Response> responses = responses(request.toString()); + + ResponseLint responseLint = new ResponseLint(); + String message = "cannot find symbol\n symbol: variable foo\n location: class SingleLineUndefinedSymbol"; + Range range = new Range(new Point(0, 71), new Point(0, 74)); + responseLint.messages.add(new LintMessage(LintMessage.Type.Error, message, lint.path, range)); + + Response expected = new Response(request.requestId); + expected.lint = Optional.of(responseLint); + + assertThat(responses, hasItem(expected)); + } + + @Test + public void lintNotJava() throws URISyntaxException, IOException { + Path file = Paths.get(RequestResponseTest.class.getResource("/NotJava.java.txt").toURI()); + + RequestLint lint = new RequestLint(); + lint.path = file.toString(); + + Request request = new Request(); + request.requestId = 2; + request.lint = Optional.of(lint); + + List<Response> responses = responses(request.toString()); + + assertThat(responses.toString(), containsString("Compilation unit is not of SOURCE kind")); + } + + @Test + public void lintNoSuchFile() throws URISyntaxException, IOException { + String request = "{\"requestId\":1,\"lint\":{\"path\":\"/NoSuchFile.java\"}}"; + + List<Response> responses = responses(request.toString()); + + assertThat(responses.toString(), containsString("NoSuchFileException: /NoSuchFile.java")); + } +} diff --git a/src/test/java/com/fivetran/javac/ResponseCollector.java b/src/test/java/com/fivetran/javac/ResponseCollector.java new file mode 100644 index 0000000..c8f043d --- /dev/null +++ b/src/test/java/com/fivetran/javac/ResponseCollector.java @@ -0,0 +1,17 @@ +package com.fivetran.javac; + +import com.fivetran.javac.message.Response; +import com.fivetran.javac.message.ResponseChannel; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class ResponseCollector implements ResponseChannel { + public final List<Response> responses = new ArrayList<>(); + + @Override + public void next(Response response) throws IOException { + responses.add(response); + } +} |