/*
* Copyright 2017-present Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.facebook.buck.jvm.java.abi.source;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
import com.facebook.buck.jvm.java.plugin.adapter.BuckJavacPlugin;
import com.facebook.buck.jvm.java.plugin.adapter.BuckJavacTask;
import com.facebook.buck.jvm.java.plugin.adapter.TestTaskListener;
import com.facebook.buck.jvm.java.plugin.adapter.TestTaskListenerAdapter;
import com.facebook.buck.jvm.java.testutil.compiler.CompilerTreeApiParameterized;
import com.facebook.buck.util.RichStream;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.sun.source.tree.CompilationUnitTree;
import java.io.IOException;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(CompilerTreeApiParameterized.class)
public class FrontendOnlyJavacTaskTest extends CompilerTreeApiParameterizedTest {
@Test
public void testParseReturnsAllCompilationUnits() throws IOException {
initCompiler(
ImmutableMap.of(
"Foo.java",
"public class Foo { }",
"Bar.java",
"public class Bar { }",
"Baz.java",
"public class Baz { }"));
Iterable<? extends CompilationUnitTree> compilationUnits = testCompiler.parse();
List<String> fileNames =
RichStream.from(compilationUnits)
.map(
compilationUnit ->
Paths.get(compilationUnit.getSourceFile().getName()).getFileName().toString())
.toImmutableList();
assertThat(fileNames, Matchers.contains("Foo.java", "Bar.java", "Baz.java"));
}
@Test
public void testEnterReturnsTopLevelTypesOnly() throws Exception {
initCompiler(
ImmutableMap.of(
"Foo.java",
Joiner.on('\n')
.join(
"package com.facebook.foo;",
"public class Foo {",
" private Runnable field = new Runnable() {",
" public void run() { }",
" };",
" private void method() {",
" class Local { };",
" }",
" private class Inner { }",
"}",
"class Extra { }"),
"Bar.java",
Joiner.on('\n').join("package com.facebook.bar;", "class Bar { }"),
"package-info.java",
"package com.facebook.foo;"));
Iterable<? extends Element> actualElements = testCompiler.enter();
assertThat(
actualElements,
Matchers.containsInAnyOrder(
elements.getTypeElement("com.facebook.foo.Foo"),
elements.getTypeElement("com.facebook.foo.Extra"),
elements.getTypeElement("com.facebook.bar.Bar")));
}
@Test
public void testTaskListenersGetEvents() throws Exception {
assumeTrue(testingTrees());
final List<String> events = new ArrayList<>();
initCompiler(ImmutableMap.of("Foo.java", "public class Foo { }"));
testCompiler.addPlugin(
new BuckJavacPlugin() {
@Override
public String getName() {
return null;
}
@Override
public void init(BuckJavacTask task, String... args) {
TestTaskListenerAdapter.setTaskListener(
task,
new TestTaskListener() {
@Override
public void started(String event) {
events.add(String.format("%s started", event));
}
@Override
public void finished(String event) {
events.add(String.format("%s finished", event));
}
});
}
});
testCompiler.parse();
assertThat(events, Matchers.contains("PARSE started", "PARSE finished"));
events.clear();
testCompiler.enter();
assertThat(events, Matchers.contains("ENTER started", "ENTER finished"));
}
@Test
public void testTaskListenersCanWorkWithElements() throws Exception {
assumeTrue(testingTrees());
final AtomicBoolean listenerRan = new AtomicBoolean(false);
initCompiler(ImmutableMap.of("Foo.java", "public class Foo { }"));
final Elements elements = testCompiler.getElements();
testCompiler.addPlugin(
new BuckJavacPlugin() {
@Override
public String getName() {
return null;
}
@Override
public void init(BuckJavacTask task, String... args) {
TestTaskListenerAdapter.setTaskListener(
task,
new TestTaskListener() {
@Override
public void started(String event) {}
@Override
public void finished(String event) {
if (event.equals("ENTER")) {
TypeElement element = elements.getTypeElement("Foo");
assertNotNull(element);
listenerRan.set(true);
}
}
});
}
});
testCompiler.enter();
assertTrue(listenerRan.get());
}
@Test
public void testCompileRunsAllPhases() throws Exception {
final List<String> events = new ArrayList<>();
initCompiler(ImmutableMap.of("Foo.java", "public class Foo { }"));
TestTaskListenerAdapter.setTaskListener(
testCompiler.getJavacTask(),
new TestTaskListener() {
@Override
public void started(String event) {
events.add(String.format("%s started", event));
}
@Override
public void finished(String event) {
events.add(String.format("%s finished", event));
}
});
testCompiler.compile();
String[] javacEvents = {
"PARSE started",
"PARSE finished",
"ENTER started",
"ENTER finished",
"ANALYZE started",
"ANALYZE finished",
"GENERATE started",
"GENERATE finished",
};
String[] treesEvents = {
"PARSE started", "PARSE finished", "ENTER started", "ENTER finished",
};
assertThat(events, Matchers.contains(testingJavac() ? javacEvents : treesEvents));
}
@Test
public void testAnnotationProcessorGetsNewElementsEachRound() throws Exception {
final AtomicBoolean processorRan = new AtomicBoolean(false);
initCompiler(ImmutableMap.of("Foo.java", "public class Foo { }"));
testCompiler.setProcessors(
ImmutableList.of(
new AbstractProcessor() {
private Elements elementsFromEnvironment;
private TypeElement element;
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton("*");
}
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
super.init(processingEnv);
elementsFromEnvironment = processingEnv.getElementUtils();
}
@Override
public boolean process(
Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
TypeElement newElement = elementsFromEnvironment.getTypeElement("Foo");
assertNotNull(newElement);
assertNotSame(newElement, element);
element = newElement;
processorRan.set(roundEnv.processingOver());
return false;
}
}));
testCompiler.compile();
assertTrue(processorRan.get());
}
}