summaryrefslogtreecommitdiff
path: root/src/test/java/com/fivetran
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/java/com/fivetran')
-rw-r--r--src/test/java/com/fivetran/javac/AutocompleteTest.java86
-rw-r--r--src/test/java/com/fivetran/javac/CompilerProfiling.java85
-rw-r--r--src/test/java/com/fivetran/javac/Fixtures.java13
-rw-r--r--src/test/java/com/fivetran/javac/LinterTest.java167
-rw-r--r--src/test/java/com/fivetran/javac/ParserTest.java47
-rw-r--r--src/test/java/com/fivetran/javac/RequestResponseTest.java124
-rw-r--r--src/test/java/com/fivetran/javac/ResponseCollector.java17
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);
+ }
+}