Add JavaPluginConfiguredTargetTest.java

PiperOrigin-RevId: 407617271
diff --git a/src/test/java/com/google/devtools/build/lib/view/java/JavaPluginConfiguredTargetTest.java b/src/test/java/com/google/devtools/build/lib/view/java/JavaPluginConfiguredTargetTest.java
new file mode 100644
index 0000000..0c13492
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/view/java/JavaPluginConfiguredTargetTest.java
@@ -0,0 +1,272 @@
+// Copyright 2021 The Bazel Authors. All rights reserved.
+//
+// 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.google.devtools.build.lib.view.java;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
+import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames;
+import static com.google.devtools.build.lib.rules.java.JavaCompileActionTestHelper.getProcessorpath;
+
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.util.ActionsTestUtil;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.OutputGroupInfo;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.analysis.configuredtargets.FileConfiguredTarget;
+import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.rules.java.JavaCompileAction;
+import com.google.devtools.build.lib.rules.java.JavaInfo;
+import com.google.devtools.build.lib.rules.java.JavaPlugin;
+import com.google.devtools.build.lib.rules.java.JavaPluginInfo;
+import com.google.devtools.build.lib.rules.java.ProguardSpecProvider;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit test for {@link JavaPlugin} */
+@RunWith(JUnit4.class)
+public class JavaPluginConfiguredTargetTest extends BuildViewTestCase {
+
+  @Test
+  public void testNoConstraintsAttribute() throws Exception {
+    checkError(
+        "java/plugin",
+        "plugin",
+        "no such attribute 'constraints' in 'java_plugin'",
+        "java_plugin(name = 'plugin',",
+        "            srcs = ['A.java'],",
+        "            processor_class = 'xx',",
+        "            constraints = ['this_shouldnt_exist'])");
+  }
+
+  private void setupEmptyProcessorClass() throws Exception {
+    scratch.file(
+        "java/com/google/test/BUILD",
+        "java_library(name = 'deps',",
+        "    srcs = ['Deps.java'])",
+        "java_plugin(name = 'processor',",
+        "    processor_class = 'com.google.test.Processor',",
+        "    srcs = ['Processor.java'],",
+        "    deps = [':deps'])",
+        "java_plugin(name = 'bugchecker',",
+        "    srcs = ['BugChecker.java'],",
+        "    deps = [':deps'])",
+        "java_library(name = 'empty',",
+        "    plugins = [':bugchecker'])");
+  }
+
+  @Test
+  public void testNotEmptyProcessorClass() throws Exception {
+    setupEmptyProcessorClass();
+
+    ConfiguredTarget processorTarget = getConfiguredTarget("//java/com/google/test:processor");
+    assertThat(processorTarget.get(JavaPluginInfo.PROVIDER).plugins().processorClasses().toList())
+        .containsExactly("com.google.test.Processor");
+    assertThat(
+            prettyArtifactNames(
+                processorTarget.get(JavaPluginInfo.PROVIDER).plugins().processorClasspath()))
+        .containsExactly(
+            "java/com/google/test/libprocessor.jar", "java/com/google/test/libdeps.jar");
+  }
+
+  @Test
+  public void testEmptyProcessorClass() throws Exception {
+    setupEmptyProcessorClass();
+
+    ConfiguredTarget bugcheckerTarget = getConfiguredTarget("//java/com/google/test:bugchecker");
+    assertThat(bugcheckerTarget.get(JavaPluginInfo.PROVIDER).plugins().processorClasses().toList())
+        .isEmpty();
+
+    assertThat(
+            prettyArtifactNames(
+                bugcheckerTarget.get(JavaPluginInfo.PROVIDER).plugins().processorClasspath()))
+        .containsExactly(
+            "java/com/google/test/libbugchecker.jar", "java/com/google/test/libdeps.jar");
+  }
+
+  @Test
+  public void testEmptyProcessorClassTarget() throws Exception {
+    setupEmptyProcessorClass();
+    ConfiguredTarget bugcheckerTarget = getConfiguredTarget("//java/com/google/test:bugchecker");
+    FileConfiguredTarget emptyOutput =
+        getFileConfiguredTarget("//java/com/google/test:libempty.jar");
+    JavaCompileAction javacAction =
+        (JavaCompileAction) getGeneratingAction(emptyOutput.getArtifact());
+    assertThat(
+            Artifact.toRootRelativePaths(
+                bugcheckerTarget
+                    .get(JavaPluginInfo.PROVIDER)
+                    .plugins()
+                    .processorClasspath()
+                    .toList()))
+        .containsExactlyElementsIn(
+            Artifact.toRootRelativePaths(getInputs(javacAction, getProcessorpath(javacAction))));
+  }
+
+  @Test
+  public void testNeverlinkIsPopulated() throws Exception {
+    setBuildLanguageOptions("--experimental_builtins_injection_override=-java_plugin");
+    useConfiguration("--noincompatible_require_javaplugininfo_in_javacommon");
+    scratch.file(
+        "java/com/google/test/BUILD",
+        "java_plugin(name = 'processor',",
+        "    neverlink = 1,",
+        "    srcs = ['BugChecker.java'])");
+    ConfiguredTarget processorTarget = getConfiguredTarget("//java/com/google/test:processor");
+    JavaInfo javaInfo = (JavaInfo) processorTarget.get(JavaInfo.PROVIDER.getKey());
+    assertThat(javaInfo.isNeverlink()).isTrue();
+  }
+
+  @Test
+  public void testJavaPluginExportsTransitiveProguardSpecs() throws Exception {
+    scratch.file(
+        "java/com/google/android/hello/BUILD",
+        "java_plugin(name = 'plugin',",
+        "            srcs = ['Plugin.java'],",
+        "            proguard_specs = ['plugin.pro'])",
+        "java_library(name = 'dep',",
+        "             srcs = ['Dep.java'],",
+        "             proguard_specs = ['dep.pro'])",
+        "java_plugin(name = 'top',",
+        "            srcs = ['Top.java'],",
+        "            proguard_specs = ['top.pro'],",
+        "            plugins = [':plugin'],",
+        "            deps = [':dep'])");
+    NestedSet<Artifact> providedSpecs =
+        getConfiguredTarget("//java/com/google/android/hello:top")
+            .get(ProguardSpecProvider.PROVIDER)
+            .getTransitiveProguardSpecs();
+    assertThat(ActionsTestUtil.baseArtifactNames(providedSpecs))
+        .containsAtLeast("top.pro_valid", "dep.pro_valid", "plugin.pro_valid");
+  }
+
+  @Test
+  public void testJavaPluginValidatesProguardSpecs() throws Exception {
+    scratch.file(
+        "java/com/google/android/hello/BUILD",
+        "java_plugin(name = 'plugin',",
+        "            srcs = ['Plugin.java'],",
+        "            proguard_specs = ['plugin.pro'])");
+    SpawnAction action =
+        (SpawnAction)
+            actionsTestUtil()
+                .getActionForArtifactEndingWith(
+                    getOutputGroup(
+                        getConfiguredTarget("//java/com/google/android/hello:plugin"),
+                        OutputGroupInfo.HIDDEN_TOP_LEVEL),
+                    "plugin.pro_valid");
+    assertWithMessage("Proguard validate action").that(action).isNotNull();
+    assertWithMessage("Proguard validate action input")
+        .that(prettyArtifactNames(action.getInputs()))
+        .contains("java/com/google/android/hello/plugin.pro");
+  }
+
+  @Test
+  public void testJavaPluginValidatesTransitiveProguardSpecs() throws Exception {
+    scratch.file(
+        "java/com/google/android/hello/BUILD",
+        "java_library(name = 'transitive',",
+        "             srcs = ['Transitive.java'],",
+        "             proguard_specs = ['transitive.pro'])",
+        "java_plugin(name = 'plugin',",
+        "            srcs = ['Plugin.java'],",
+        "            deps = [':transitive'])");
+    SpawnAction action =
+        (SpawnAction)
+            actionsTestUtil()
+                .getActionForArtifactEndingWith(
+                    getOutputGroup(
+                        getConfiguredTarget("//java/com/google/android/hello:plugin"),
+                        OutputGroupInfo.HIDDEN_TOP_LEVEL),
+                    "transitive.pro_valid");
+    assertWithMessage("Proguard validate action").that(action).isNotNull();
+    assertWithMessage("Proguard validate action input")
+        .that(prettyArtifactNames(action.getInputs()))
+        .contains("java/com/google/android/hello/transitive.pro");
+  }
+
+  @Test
+  public void generatesApi() throws Exception {
+    scratch.file(
+        "java/com/google/test/BUILD",
+        "java_plugin(",
+        "    name = 'api_generating',",
+        "    srcs = ['ApiGeneratingPlugin.java'],",
+        "    processor_class = 'ApiGeneratingPlugin',",
+        "    generates_api = True,",
+        ")");
+
+    JavaPluginInfo plugin =
+        getConfiguredTarget("//java/com/google/test:api_generating").get(JavaPluginInfo.PROVIDER);
+    assertThat(plugin.plugins().processorClasses().toList()).containsExactly("ApiGeneratingPlugin");
+    assertThat(plugin.apiGeneratingPlugins().processorClasses().toList())
+        .containsExactly("ApiGeneratingPlugin");
+    assertThat(ActionsTestUtil.baseArtifactNames(plugin.plugins().processorClasspath()))
+        .containsExactly("libapi_generating.jar");
+    assertThat(
+            ActionsTestUtil.baseArtifactNames(plugin.apiGeneratingPlugins().processorClasspath()))
+        .containsExactly("libapi_generating.jar");
+  }
+
+  @Test
+  public void generatesImplementation() throws Exception {
+    scratch.file(
+        "java/com/google/test/BUILD",
+        "java_plugin(",
+        "    name = 'impl_generating',",
+        "    srcs = ['ImplGeneratingPlugin.java'],",
+        "    processor_class = 'ImplGeneratingPlugin',",
+        "    generates_api = False,",
+        ")");
+
+    JavaPluginInfo plugin =
+        getConfiguredTarget("//java/com/google/test:impl_generating").get(JavaPluginInfo.PROVIDER);
+    assertThat(plugin.plugins().processorClasses().toList())
+        .containsExactly("ImplGeneratingPlugin");
+    assertThat(plugin.apiGeneratingPlugins().processorClasses().toList()).isEmpty();
+    assertThat(ActionsTestUtil.baseArtifactNames(plugin.plugins().processorClasspath()))
+        .containsExactly("libimpl_generating.jar");
+    assertThat(
+            ActionsTestUtil.baseArtifactNames(plugin.apiGeneratingPlugins().processorClasspath()))
+        .isEmpty();
+  }
+
+  @Test
+  public void pluginData() throws Exception {
+    scratch.file(
+        "java/com/google/test/BUILD",
+        "java_plugin(",
+        "    name = 'impl_generating',",
+        "    srcs = ['ImplGeneratingPlugin.java'],",
+        "    processor_class = 'ImplGeneratingPlugin',",
+        "    generates_api = False,",
+        "    data = ['data.txt'],",
+        ")",
+        "java_library(",
+        "    name = 'lib',",
+        "    plugins = [':impl_generating'],",
+        ")");
+
+    JavaPluginInfo plugin =
+        getConfiguredTarget("//java/com/google/test:impl_generating").get(JavaPluginInfo.PROVIDER);
+    assertThat(prettyArtifactNames(plugin.plugins().data()))
+        .containsExactly("java/com/google/test/data.txt");
+    FileConfiguredTarget libJar = getFileConfiguredTarget("//java/com/google/test:liblib.jar");
+    JavaCompileAction javacAction = (JavaCompileAction) getGeneratingAction(libJar.getArtifact());
+    assertThat(prettyArtifactNames(javacAction.getInputs()))
+        .contains("java/com/google/test/data.txt");
+  }
+}