/*
* 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.plugin.adapter;
import static org.junit.Assert.assertThat;
import com.facebook.buck.jvm.java.testutil.compiler.CompilerTreeApiTestRunner;
import com.facebook.buck.jvm.java.testutil.compiler.TestCompiler;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.element.TypeElement;
import org.hamcrest.Matchers;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@RunWith(CompilerTreeApiTestRunner.class)
public class PostEnterTaskListenerTest {
@Rule public TestCompiler compiler = new TestCompiler();
private List<String> callbacksIssued = new ArrayList<>();
@Test
public void testCallbackIssuedAfterJustEnterWithoutAPs() throws IOException {
compiler.addSourceFileContents("Foo.java", "class Foo { }");
compiler.setProcessors(ImmutableList.of());
addCallback("callback");
compiler.enter();
assertThat(callbacksIssued, Matchers.contains("callback: Foo"));
}
@Test
public void testCallbackIssuedAfterEnterWithoutAPs() throws IOException {
compiler.addSourceFileContents("Foo.java", "class Foo { }");
compiler.setProcessors(ImmutableList.of());
addCallback("callback");
compiler.compile();
assertThat(callbacksIssued, Matchers.contains("callback: Foo"));
}
@Test
public void testCallbacksIssuedInOrderRegistered() throws IOException {
compiler.addSourceFileContents("Foo.java", "class Foo { }");
compiler.setProcessors(ImmutableList.of());
addCallback("4");
addCallback("3");
addCallback("2");
addCallback("1");
compiler.compile();
assertThat(callbacksIssued, Matchers.contains("4: Foo", "3: Foo", "2: Foo", "1: Foo"));
}
@Test
public void testCallbackIssuedForTopLevelTypesOnly() throws IOException {
compiler.addSourceFileContents(
"Foo.java", Joiner.on('\n').join("class Foo {", " class Inner { }", "}", "class Bar { }"));
compiler.setProcessors(ImmutableList.of());
addCallback("callback");
compiler.compile();
assertThat(callbacksIssued, Matchers.contains("callback: Foo, Bar"));
}
@Test
public void testCallbackIssuedAfterEnterWithAPs() throws IOException {
// We add an unrelated source file here to make the compiler do something
compiler.addSourceFileContents("Bar.java", "class Bar { }");
compiler.setProcessors(
ImmutableList.of(
new AbstractProcessor() {
@Override
public Set<String> getSupportedAnnotationTypes() {
return Collections.singleton("*");
}
@Override
public boolean process(
Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
if (roundEnv.processingOver()) {
Filer filer = processingEnv.getFiler();
// We wait until the last possible momemt to generate Foo; if the callback is able to
// get an element for it, that means it ran after the enter phase
try (OutputStream outputStream =
filer.createSourceFile("Foo").openOutputStream()) {
outputStream.write("class Foo { }".getBytes());
} catch (IOException e) {
throw new AssertionError(e);
}
}
return false;
}
}));
addCallback("callback");
compiler.compile();
assertThat(callbacksIssued, Matchers.contains("callback: Bar, Foo"));
}
private void addCallback(String name) {
compiler.addPostEnterCallback(
topLevelTypes ->
callbacksIssued.add(
String.format(
"%s: %s",
name,
topLevelTypes
.stream()
.map(TypeElement::getSimpleName)
.collect(Collectors.joining(", ")))));
}
}