// Copyright 2017 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.rules.android;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.truth.Truth;
import com.google.devtools.build.lib.actions.Action;
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.OutputFileConfiguredTarget;
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.SpawnAction;
import com.google.devtools.build.lib.analysis.config.BuildConfiguration;
import com.google.devtools.build.lib.cmdline.Label;
import com.google.devtools.build.lib.cmdline.RepositoryName;
import com.google.devtools.build.lib.collect.nestedset.NestedSet;
import com.google.devtools.build.lib.rules.android.AndroidIdeInfoProvider.SourceDirectory;
import com.google.devtools.build.lib.rules.java.JavaCompilationArgsProvider;
import com.google.devtools.build.lib.rules.java.JavaCompileAction;
import com.google.devtools.build.lib.rules.java.JavaExportsProvider;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.vfs.PathFragment;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* Tests for {@link AndroidLibrary}.
*/
@RunWith(JUnit4.class)
public class AndroidLibraryTest extends AndroidBuildViewTestCase {
@Test
public void testSimpleLibrary() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'a',",
" srcs = ['A.java'],",
" )");
getConfiguredTarget("//java/android:a");
}
@Test
public void testBaselineCoverageArtifacts() throws Exception {
useConfiguration("--collect_code_coverage");
ConfiguredTarget target = scratchConfiguredTarget("java/a", "a",
"android_library(name='a', srcs=['A.java'], deps=[':b'])",
"android_library(name='b', srcs=['B.java'])");
assertThat(baselineCoverageArtifactBasenames(target)).containsExactly("A.java", "B.java");
}
// regression test for #3169099
@Test
public void testLibrarySrcs() throws Exception {
scratch.file("java/srcs/a.foo", "foo");
scratch.file("java/srcs/BUILD",
"android_library(name = 'valid', srcs = ['a.java', 'b.srcjar', ':gvalid', ':gmix'])",
"android_library(name = 'invalid', srcs = ['a.foo', ':ginvalid'])",
"android_library(name = 'mix', srcs = ['a.java', 'a.foo'])",
"genrule(name = 'gvalid', srcs = ['a.java'], outs = ['b.java'], cmd = '')",
"genrule(name = 'ginvalid', srcs = ['a.java'], outs = ['b.foo'], cmd = '')",
"genrule(name = 'gmix', srcs = ['a.java'], outs = ['c.java', 'c.foo'], cmd = '')"
);
assertSrcsValidityForRuleType("//java/srcs", "android_library",
".java or .srcjar");
}
// regression test for #3169095
@Test
public void testXmbInSrcsDoesNotThrow() throws Exception {
reporter.removeHandler(failFastHandler);
scratchConfiguredTarget("java/xmb", "a", "android_library(name = 'a', srcs = ['a.xmb'])");
}
@Test
public void testSlashInIdlImportRoot() throws Exception {
scratchConfiguredTarget("java/com/google/android", "avocado",
"android_library(name='avocado',",
" idl_parcelables=['tropical/fruit/Avocado.aidl'],",
" idl_import_root='tropical/fruit')");
}
@Test
public void testAndroidLibraryWithIdlImportAndNoIdls() throws Exception {
checkError("java/com/google/android", "lib",
"Neither idl_srcs nor idl_parcelables were specified, "
+ "but 'idl_import_root' attribute was set",
"android_library(name = 'lib',",
" srcs = ['Dummy.java'],",
" idl_import_root = 'src')");
}
@Test
public void testAndroidLibraryWithIdlImportAndIdlSrcs() throws Exception {
scratchConfiguredTarget("java/com/google/android", "lib",
"android_library(name = 'lib',",
" idl_srcs = ['Dummy.aidl'],",
" idl_import_root = 'src')");
}
@Test
public void testAndroidLibraryWithIdlImportAndIdlParcelables() throws Exception {
scratchConfiguredTarget("java/com/google/android", "lib",
"android_library(name = 'lib',",
" idl_parcelables = ['src/android/DummyParcelable.aidl'],",
" idl_import_root = 'src')");
}
@Test
public void testAndroidLibraryWithIdlImportAndBothIdlTypes() throws Exception {
scratchConfiguredTarget("java/com/google/android", "lib",
"android_library(name = 'lib',",
" idl_srcs = ['src/android/Dummy.aidl'],",
" idl_parcelables = ['src/android/DummyParcelable.aidl'],",
" idl_import_root = 'src')");
}
@Test
public void testAndroidLibraryWithIdlImportAndEmptyLists() throws Exception {
scratchConfiguredTarget("java/com/google/android", "lib",
"android_library(name = 'lib',",
" idl_srcs = [],",
" idl_parcelables = [],",
" idl_import_root = 'src')");
}
@Test
public void testCommandLineContainsTargetLabelAndRuleKind() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'a', srcs = ['A.java'])");
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingActionForLabel("//java/android:liba.jar");
String commandLine = Iterables.toString(javacAction.buildCommandLine());
assertThat(commandLine).contains("--rule_kind, android_library");
assertThat(commandLine).contains("--target_label, //java/android:a");
}
@Test
public void testStrictAndroidDepsOff() throws Exception {
useConfiguration("--strict_java_deps=OFF");
scratch.file("java/android/strict/BUILD",
"android_library(name = 'b', srcs = ['B.java'])");
Artifact artifact = getFileConfiguredTarget("//java/android/strict:libb.jar").getArtifact();
JavaCompileAction compileAction = (JavaCompileAction) getGeneratingAction(artifact);
assertEquals(BuildConfiguration.StrictDepsMode.OFF, compileAction.getStrictJavaDepsMode());
}
@Test
public void testStrictAndroidDepsOn() throws Exception {
scratch.file("java/android/strict/BUILD",
"android_library(name = 'b', srcs = ['B.java'])");
Artifact artifact = getFileConfiguredTarget("//java/android/strict:libb.jar").getArtifact();
JavaCompileAction compileAction = (JavaCompileAction) getGeneratingAction(artifact);
assertEquals(BuildConfiguration.StrictDepsMode.ERROR, compileAction.getStrictJavaDepsMode());
}
@Test
public void testStrictAndroidDepsWarn() throws Exception {
useConfiguration("--strict_android_deps=WARN");
scratch.file("java/android/strict/BUILD",
"android_library(name = 'b', srcs = ['B.java'])");
Artifact artifact = getFileConfiguredTarget("//java/android/strict:libb.jar").getArtifact();
JavaCompileAction compileAction = (JavaCompileAction) getGeneratingAction(artifact);
assertEquals(BuildConfiguration.StrictDepsMode.WARN, compileAction.getStrictJavaDepsMode());
}
@Test
public void testJavaPluginProcessorPath() throws Exception {
scratch.file("java/test/BUILD",
"java_library(name = 'plugin_dep',",
" srcs = [ 'ProcessorDep.java'])",
"java_plugin(name = 'plugin',",
" srcs = ['AnnotationProcessor.java'],",
" processor_class = 'com.google.process.stuff',",
" deps = [ ':plugin_dep' ])",
"android_library(name = 'to_be_processed',",
" plugins = [':plugin'],",
" srcs = ['ToBeProcessed.java'])");
ConfiguredTarget target = getConfiguredTarget("//java/test:to_be_processed");
OutputFileConfiguredTarget output = (OutputFileConfiguredTarget)
getFileConfiguredTarget("//java/test:libto_be_processed.jar");
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingAction(output.getArtifact());
assertThat(javacAction.getProcessorNames()).contains("com.google.process.stuff");
assertThat(javacAction.getProcessorNames()).hasSize(1);
assertEquals("libplugin.jar libplugin_dep.jar", ActionsTestUtil.baseNamesOf(
javacAction.getProcessorpath()));
assertEquals("ToBeProcessed.java AnnotationProcessor.java ProcessorDep.java",
actionsTestUtil().predecessorClosureOf(getFilesToBuild(target),
JavaSemantics.JAVA_SOURCE));
}
// Same test as above, enabling the plugin through the command line.
@Test
public void testPluginCommandLine() throws Exception {
scratch.file("java/test/BUILD",
"java_library(name = 'plugin_dep',",
" srcs = [ 'ProcessorDep.java'])",
"java_plugin(name = 'plugin',",
" srcs = ['AnnotationProcessor.java'],",
" processor_class = 'com.google.process.stuff',",
" deps = [ ':plugin_dep' ])",
"android_library(name = 'to_be_processed',",
" srcs = ['ToBeProcessed.java'])");
useConfiguration("--plugin=//java/test:plugin");
ConfiguredTarget target = getConfiguredTarget("//java/test:to_be_processed");
OutputFileConfiguredTarget output =
(OutputFileConfiguredTarget) getFileConfiguredTarget("//java/test:libto_be_processed.jar");
JavaCompileAction javacAction = (JavaCompileAction) getGeneratingAction(output.getArtifact());
assertThat(javacAction.getProcessorNames()).contains("com.google.process.stuff");
assertThat(javacAction.getProcessorNames()).hasSize(1);
assertEquals("libplugin.jar libplugin_dep.jar",
ActionsTestUtil.baseNamesOf(javacAction.getProcessorpath()));
assertEquals("ToBeProcessed.java AnnotationProcessor.java ProcessorDep.java",
actionsTestUtil().predecessorClosureOf(getFilesToBuild(target),
JavaSemantics.JAVA_SOURCE));
}
@Test
public void testInvalidPlugin() throws Exception {
checkError("java/test", "lib",
// error:
getErrorMsgMisplacedRules("plugins", "android_library",
"//java/test:lib", "java_library", "//java/test:not_a_plugin"),
// BUILD file:
"java_library(name = 'not_a_plugin',",
" srcs = [ 'NotAPlugin.java'])",
"android_library(name = 'lib',",
" plugins = [':not_a_plugin'],",
" srcs = ['Lib.java'])");
}
@Test
public void testDisallowDepsWithoutSrcs() throws Exception {
useConfiguration("--experimental_allow_android_library_deps_without_srcs=false");
checkError("android/deps", "b",
// message:
"deps not allowed without srcs; move to exports?",
// build file
"android_library(name = 'a', srcs = ['a.java'])",
"android_library(name = 'b', deps = [':a'])");
}
@Test
public void testAlwaysAllowDepsWithoutSrcsIfLocalResources() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'a', srcs = ['a.java'])",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = glob(['res/**']),",
" deps = [':a'])");
scratch.file("java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
useConfiguration("--experimental_allow_android_library_deps_without_srcs=false");
getConfiguredTarget("//java/android:r");
assertNoEvents();
}
@Test
public void testTransitiveDependencyThroughExports() throws Exception {
scratch.file("java/test/BUILD",
"android_library(name = 'somelib',",
" srcs = ['Lib.java'],",
" deps = [':somealias'])",
"android_library(name = 'somealias',",
" exports = [':somedep'])",
"android_library(name = 'somedep',",
" srcs = ['Dependency.java'],",
" deps = [ ':otherdep' ])",
"android_library(name = 'otherdep',",
" srcs = ['OtherDependency.java'])");
ConfiguredTarget libTarget = getConfiguredTarget("//java/test:somelib");
assertThat(actionsTestUtil().predecessorClosureAsCollection(getFilesToBuild(libTarget),
JavaSemantics.JAVA_SOURCE)).containsExactly(
"Lib.java", "Dependency.java", "OtherDependency.java");
assertNoEvents();
}
@Test
public void testTransitiveStrictDeps() throws Exception {
scratch.file("java/peach/BUILD",
"android_library(name='a', exports=[':b'])",
"android_library(name='b', srcs=['B.java'], deps=[':c'])",
"android_library(name='c', srcs=['C.java'])");
useConfiguration("--strict_java_deps=ERROR");
ConfiguredTarget a = getConfiguredTarget("//java/peach:a");
Iterable<String> compileTimeJars = ActionsTestUtil.baseArtifactNames(
a.getProvider(JavaCompilationArgsProvider.class)
.getJavaCompilationArgs().getCompileTimeJars());
assertThat(compileTimeJars).contains("libb-hjar.jar");
assertThat(compileTimeJars).doesNotContain("libc-hjar.jar");
assertNoEvents();
}
@Test
public void testEmitOutputDeps() throws Exception {
scratch.file("java/deps/BUILD",
"android_library(name = 'a', exports = [':b'])",
"android_library(name = 'b', srcs = ['B.java'])");
useConfiguration("--java_deps");
JavaCompileAction aAction = (JavaCompileAction) getGeneratingActionForLabel(
"//java/deps:liba.jar");
List<String> aOutputs = ActionsTestUtil.prettyArtifactNames(aAction.getOutputs());
assertThat(aOutputs).doesNotContain("java/deps/liba.jdeps");
JavaCompileAction bAction = (JavaCompileAction) getGeneratingActionForLabel(
"//java/deps:libb.jar");
List<String> bOutputs = ActionsTestUtil.prettyArtifactNames(bAction.getOutputs());
assertThat(bOutputs).contains("java/deps/libb.jdeps");
assertNoEvents();
}
@Test
public void testDependencyArtifactsWithExports() throws Exception {
scratch.file("java/classpath/BUILD",
"android_library(name = 'a', srcs = ['A.java'], deps = [':b', ':c'])",
"android_library(name = 'b', exports = [':d'])",
"android_library(name = 'c', srcs = ['C.java'], exports = [':e'])",
"android_library(name = 'd', srcs = ['D.java'])",
"android_library(name = 'e', srcs = ['E.java'])");
JavaCompileAction aAction = (JavaCompileAction) getGeneratingActionForLabel(
"//java/classpath:liba.jar");
List<String> deps =
ActionsTestUtil.prettyArtifactNames(aAction.getCompileTimeDependencyArtifacts());
assertThat(deps)
.containsExactly(
"java/classpath/libc-hjar.jdeps",
"java/classpath/libd-hjar.jdeps",
"java/classpath/libe-hjar.jdeps");
assertNoEvents();
}
@Test
public void testSrcsLessExportsAreStillDirect() throws Exception {
scratch.file("java/exports/BUILD",
"android_library(name = 'a', srcs = ['a.java'])",
"android_library(name = 'b', deps = ['a'])",
"android_library(name = 'c', srcs = ['c.java'], deps = [':b'])");
ConfiguredTarget bTarget = getConfiguredTarget("//java/exports:b");
ConfiguredTarget cTarget = getConfiguredTarget("//java/exports:c");
assertEquals(Arrays.asList("liba.jar"),
ActionsTestUtil.baseArtifactNames(getDefaultRunfiles(bTarget).getArtifacts()));
assertEquals(Arrays.asList("liba.jar", "libc.jar"),
ActionsTestUtil.baseArtifactNames(getDefaultRunfiles(cTarget).getArtifacts()));
assertNoEvents();
}
@Test
public void testExportsWithStrictJavaDepsFlag() throws Exception {
scratch.file("java/exports/BUILD",
"android_library(name = 'a', srcs = ['a.java'])",
"android_library(name = 'b', srcs = ['b.java'], exports = ['a'])",
"android_library(name = 'c', srcs = ['c.java'], deps = [':b'])");
useConfiguration("--strict_java_deps=WARN");
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingActionForLabel("//java/exports:libc.jar");
assertThat(ActionsTestUtil.prettyArtifactNames(javacAction.getDirectJars()))
.containsExactly("java/exports/libb-hjar.jar", "java/exports/liba-hjar.jar");
assertNoEvents();
}
@Test
public void testExportsRunfiles() throws Exception {
scratch.file("java/exports/BUILD",
"android_library(name = 'a', srcs = ['a.java'], data = ['data.txt'])",
"android_library(name = 'b', srcs = ['b.java'], exports = [':a'])");
ConfiguredTarget bTarget = getConfiguredTarget("//java/exports:b");
assertEquals(
ActionsTestUtil.baseArtifactNames(getDefaultRunfiles(bTarget).getArtifacts()),
Arrays.asList("data.txt", "liba.jar", "libb.jar"));
assertNoEvents();
}
@Test
public void testTransitiveExports() throws Exception {
scratch.file("java/com/google/exports/BUILD",
"android_library(name = 'dummy',",
" srcs = ['dummy.java'],",
" exports = [':dummy2'])",
"android_library(name = 'dummy2',",
" srcs = ['dummy2.java'],",
" exports = [':dummy3'])",
"android_library(name = 'dummy3',",
" srcs = ['dummy3.java'],",
" exports = [':dummy4'])",
"android_library(name = 'dummy4',",
" srcs = ['dummy4.java'])");
ConfiguredTarget target = getConfiguredTarget("//java/com/google/exports:dummy");
List<Label> exports = ImmutableList.copyOf(
target.getProvider(JavaExportsProvider.class).getTransitiveExports());
assertThat(exports).containsExactly(Label.parseAbsolute("//java/com/google/exports:dummy2"),
Label.parseAbsolute("//java/com/google/exports:dummy3"),
Label.parseAbsolute("//java/com/google/exports:dummy4"));
assertNoEvents();
}
@Test
public void testSimpleIdl() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'idl',",
" idl_srcs = ['a.aidl'])");
getConfiguredTarget("//java/android:idl");
assertNoEvents();
}
@Test
public void testIdlSrcsFromAnotherPackageFails() throws Exception {
reporter.removeHandler(failFastHandler);
scratch.file("java/android/a/BUILD",
"exports_files(['A.aidl'])");
scratch.file("java/android/BUILD",
"android_library(name = 'idl',",
" idl_srcs = ['//java/android/a:A.aidl'])");
getConfiguredTarget("//java/android:idl");
assertContainsEvent("do not import '//java/android/a:A.aidl' directly. You should either"
+ " move the file to this package or depend on an appropriate rule there");
}
@Test
public void testIdlClassJarAction() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'idl',",
" idl_srcs = ['a.aidl', 'b.aidl', 'c.aidl'])");
ConfiguredTarget idlTarget =
getConfiguredTarget("//java/android:idl");
NestedSet<Artifact> outputGroup =
getOutputGroup(idlTarget, AndroidSemantics.IDL_JARS_OUTPUT_GROUP);
SpawnAction classJarAction = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith(
actionsTestUtil().artifactClosureOf(outputGroup), "libidl-idl.jar");
SpawnAction sourceJarAction = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith(
actionsTestUtil().artifactClosureOf(outputGroup), "libidl-idl.srcjar");
assertSame(classJarAction, sourceJarAction);
PathFragment genfilesPath =
getTargetConfiguration()
.getOutputDirectory(RepositoryName.MAIN)
.getExecPath()
.getRelative("genfiles/java/android/idl_aidl/java/android");
assertThat(classJarAction.getArguments()).containsAllOf(
genfilesPath.getRelative("a.java").getPathString(),
genfilesPath.getRelative("b.java").getPathString(),
genfilesPath.getRelative("c.java").getPathString());
}
@Test
public void testIdlOutputGroupTransitivity() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'lib',",
" idl_srcs = ['a.aidl'],",
" deps = [':dep'])",
"android_library(name = 'dep',",
" idl_srcs = ['b.aidl'])");
ConfiguredTarget idlTarget =
getConfiguredTarget("//java/android:lib");
NestedSet<Artifact> outputGroup =
getOutputGroup(idlTarget, AndroidSemantics.IDL_JARS_OUTPUT_GROUP);
List<String> asString = Lists.newArrayList();
for (Artifact artifact : outputGroup) {
asString.add(artifact.getRootRelativePathString());
}
assertThat(asString).containsAllOf(
"java/android/libdep-idl.jar",
"java/android/libdep-idl.srcjar",
"java/android/liblib-idl.jar",
"java/android/liblib-idl.srcjar"
);
}
@Test
public void testNoJavaDir() throws Exception {
checkError("android/hello", "idl",
// message:
"Cannot determine java/javatests root for import android/hello/Import.aidl",
// build file:
"android_library(name = 'idl',",
" srcs = ['Import.java'],",
" idl_parcelables = ['Import.aidl'])");
}
@Test
public void testExportedPluginsAreInherited() throws Exception {
scratch.file(
"java/test/BUILD",
"java_plugin(name = 'plugin',",
" srcs = [ 'Plugin.java' ],",
" processor_class = 'com.google.process.stuff')",
"android_library(name = 'exporting_lib',",
" srcs = [ 'ExportingLib.java' ],",
" exported_plugins = [ ':plugin' ])",
"android_library(name = 'consuming_lib',",
" srcs = [ 'ConsumingLib.java' ],",
" deps = [ ':exporting_lib' ])",
"android_library(name = 'leaf_lib',",
" srcs = [ 'LeafLib.java' ],",
" deps = [ ':consuming_lib' ])");
getConfiguredTarget("//java/test:consuming_lib");
getConfiguredTarget("//java/test:leaf_lib");
// libconsuming_lib should include the plugin, since it directly depends on exporting_lib
assertThat(getProcessorNames("//java/test:libconsuming_lib.jar"))
.containsExactly("com.google.process.stuff");
// but libleaf_lib should not, because its dependency is transitive.
assertThat(getProcessorNames("//java/test:libleaf_lib.jar")).isEmpty();
}
@Test
public void testAidlLibAddsProguardSpecs() throws Exception {
scratch.file("sdk/BUILD",
"android_sdk(name = 'sdk',",
" aapt = 'aapt',",
" adb = 'adb',",
" aidl = 'aidl',",
" aidl_lib = ':aidl_lib',",
" android_jar = 'android.jar',",
" annotations_jar = 'annotations_jar',",
" apksigner = 'apksigner',",
" dx = 'dx',",
" framework_aidl = 'framework_aidl',",
" main_dex_classes = 'main_dex_classes',",
" main_dex_list_creator = 'main_dex_list_creator',",
" proguard = 'proguard',",
" shrinked_android_jar = 'shrinked_android_jar',",
" zipalign = 'zipalign',",
" resource_extractor = 'resource_extractor')",
"java_library(name = 'aidl_lib',",
" srcs = ['AidlLib.java'],",
" proguard_specs = ['aidl_lib.cfg'])");
scratch.file("java/com/google/android/hello/BUILD",
"android_library(name = 'library',",
" srcs = ['MainActivity.java'],",
" idl_srcs = ['IMyInterface.aidl'])",
"android_library(name = 'library_no_idl',",
" srcs = ['MainActivity.java'])",
"android_binary(name = 'binary',",
" deps = [':library'],",
" manifest = 'AndroidManifest.xml',",
" proguard_specs = ['proguard-spec.pro'])",
"android_binary(name = 'binary_no_idl',",
" deps = [':library_no_idl'],",
" manifest = 'AndroidManifest.xml',",
" proguard_specs = ['proguard-spec.pro'])");
useConfiguration("--android_sdk=//sdk:sdk");
// Targets with AIDL-generated sources also get AIDL support lib Proguard specs
ConfiguredTarget binary = getConfiguredTarget("//java/com/google/android/hello:binary");
Action action = actionsTestUtil().getActionForArtifactEndingWith(
getFilesToBuild(binary), "_proguard.jar");
assertNotNull(ActionsTestUtil.getFirstArtifactEndingWith(action.getInputs(),
"sdk/aidl_lib.cfg_valid"));
// Targets without AIDL-generated sources don't care
ConfiguredTarget binaryNoIdl =
getConfiguredTarget("//java/com/google/android/hello:binary_no_idl");
Action actionNoIdl = actionsTestUtil().getActionForArtifactEndingWith(
getFilesToBuild(binaryNoIdl), "_proguard.jar");
assertNull(ActionsTestUtil.getFirstArtifactEndingWith(actionNoIdl.getInputs(),
"sdk/aidl_lib.cfg_valid"));
}
private List<String> getTransitiveDependentResourceDirs(
ConfiguredTarget target, List<String> actualArgs) {
assertThat(actualArgs).contains("--data");
String actualFlagValue = actualArgs.get(actualArgs.indexOf("--data") + 1);
return getDependentResourceDirs(target, actualFlagValue);
}
private List<String> getDirectDependentResourceDirs(
ConfiguredTarget target, List<String> actualArgs) {
assertThat(actualArgs).contains("--directData");
String actualFlagValue = actualArgs.get(actualArgs.indexOf("--directData") + 1);
return getDependentResourceDirs(target, actualFlagValue);
}
private List<String> getDependentResourceDirs(
ConfiguredTarget target, String actualFlagValue) {
ImmutableList.Builder<String> actualPaths = ImmutableList.builder();
for (String resourceDependency : actualFlagValue.split(",")) {
if (target
.getConfiguration()
.getFragment(AndroidConfiguration.class)
.useParallelResourceProcessing()) {
assertThat(actualFlagValue).matches("[^;]*;[^;]*;[^;]*;.*");
actualPaths.add(resourceDependency.split(";")[0].split("#"));
} else {
assertThat(actualFlagValue).matches("[^:]*:[^:]*:[^:]*:.*");
actualPaths.add(resourceDependency.split(":")[0].split("#"));
}
}
return actualPaths.build();
}
private List<String> getDependentAssetDirs(
ConfiguredTarget target, String flag, List<String> actualArgs) {
assertThat(actualArgs).contains(flag);
String actualFlagValue = actualArgs.get(actualArgs.indexOf(flag) + 1);
ImmutableList.Builder<String> actualPaths = ImmutableList.builder();
for (String resourceDependency : actualFlagValue.split(",")) {
if (target
.getConfiguration()
.getFragment(AndroidConfiguration.class)
.useParallelResourceProcessing()) {
assertThat(actualFlagValue).matches("[^;]*;[^;]*;[^;]*;.*");
actualPaths.add(resourceDependency.split(";")[1].split("#"));
} else {
assertThat(actualFlagValue).matches("[^:]*:[^:]*:[^:]*:.*");
actualPaths.add(resourceDependency.split(":")[1].split("#"));
}
}
return actualPaths.build();
}
@Test
public void testResourcesMultipleDirectoriesFromPackage() throws Exception {
scratch.file("c/b/m/a/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" custom_package = 'com.google.android.apps.a',",
" resource_files = [",
" 'b_/res/values/strings.xml',",
" ]",
" )");
scratch.file("c/b/m/a/b_/res",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
ConfiguredTarget resource = getConfiguredTarget("//c/b/m/a:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("c/b/m/a/b_/res"), args);
}
@Test
public void testSimpleResources() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = glob(['res/**']),",
" )");
scratch.file("java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/android/res"), args);
}
@Test
public void testResourcesWithConfigurationQualifier() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = glob(['res/**']),",
" )");
scratch.file("java/android/res/values-en/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
scratch.file("java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/android/res"), args);
}
@Test
public void testResourcesInOtherPackage_exported() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['//java/other:res/values/strings.xml'],",
" )");
scratch.file("java/other/BUILD",
"exports_files(['res/values/strings.xml'])");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/other/res"), args);
assertNoEvents();
}
@Test
public void testResourcesInOtherPackage_filegroup() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['//java/other:fg'],",
" )");
scratch.file("java/other/BUILD",
"filegroup(name = 'fg',",
" srcs = ['res/values/strings.xml'],",
")");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/other/res"), args);
assertNoEvents();
}
// Regression test for b/11924769
@Test
public void testResourcesInOtherPackage_filegroupWithExternalSources() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = [':fg'],",
" )",
"filegroup(name = 'fg',",
" srcs = ['//java/other:res/values/strings.xml'])");
scratch.file("java/other/BUILD",
"exports_files(['res/values/strings.xml'])");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/other/res"), args);
assertNoEvents();
}
// Regression test for b/11924769
@Test
public void testResourcesInOtherPackage_doubleFilegroup() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = [':fg'],",
" )",
"filegroup(name = 'fg',",
" srcs = ['//java/other:fg'])");
scratch.file("java/other/BUILD",
"filegroup(name = 'fg',",
" srcs = ['res/values/strings.xml'],",
")");
ConfiguredTarget resource = getConfiguredTarget("//java/android:r");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/other/res"), args);
assertNoEvents();
}
@Test
public void testManifestMissingFails() throws Exception {
checkError("java/android", "r",
"is required when resource_files or assets are defined.",
"filegroup(name = 'b')",
"android_library(name = 'r',",
" resource_files = [':b'],",
" )");
}
@Test
public void testResourcesDoesNotMatchDirectoryLayout_BadFile() throws Exception {
checkError("java/android", "r",
"'java/android/res/somefile.xml' is not in the expected resource directory structure of"
+ " <resource directory>/{"
+ Joiner.on(',').join(LocalResourceContainer.Builder.RESOURCE_DIRECTORY_TYPES) + "}",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/somefile.xml', 'r/t/f/m/raw/fold']",
" )");
}
@Test
public void testResourcesDoesNotMatchDirectoryLayout_BadDirectory() throws Exception {
checkError("java/android", "r",
"'java/android/res/other/somefile.xml' is not in the expected resource directory structure"
+ " of <resource directory>/{"
+ Joiner.on(',').join(LocalResourceContainer.Builder.RESOURCE_DIRECTORY_TYPES) + "}",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/other/somefile.xml', 'r/t/f/m/raw/fold']",
" )");
}
@Test
public void testResourcesNotUnderCommonDirectoryFails() throws Exception {
checkError("java/android", "r",
"'java/android/r/t/f/m/raw/fold' (generated by '//java/android:r/t/f/m/raw/fold') is not"
+ " in the same directory 'res' (derived from java/android/res/raw/speed). All"
+ " resources must share a common directory.",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/raw/speed', 'r/t/f/m/raw/fold']",
" )");
}
@Test
public void testAssetsDirAndNoAssetsFails() throws Exception {
checkError("cpp/android", "r",
"'assets' and 'assets_dir' should be either both empty or both non-empty",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" assets_dir = 'assets',",
" )");
}
@Test
public void testAssetsNotUnderAssetsDirFails() throws Exception {
checkError("java/android", "r",
"'java/android/r/t/f/m' (generated by '//java/android:r/t/f/m') is not beneath 'assets'",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" assets_dir = 'assets',",
" assets = ['assets/valuable', 'r/t/f/m']",
" )");
}
@Test
public void testAssetsAndNoAssetsDirFails() throws Exception {
scratch.file("java/android/assets/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
checkError("java/android", "r",
"'assets' and 'assets_dir' should be either both empty or both non-empty",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" assets = glob(['assets/**']),",
" )");
}
@Test
public void testFileLocation() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" )");
ConfiguredTarget foo = getConfiguredTarget("//java/android:r");
assertEquals(getTargetConfiguration().getBinDirectory(RepositoryName.MAIN),
ActionsTestUtil.getFirstArtifactEndingWith(getFilesToBuild(foo), "r.srcjar").getRoot());
}
// regression test for #3294893
@Test
public void testNoJavaPathFoundDoesNotThrow() throws Exception {
checkError("third_party/java_src/android/app", "r",
"The location of your BUILD file determines the Java package used for Android resource "
+ "processing. A directory named \"java\" or \"javatests\" will be used as your Java "
+ "source root and the path of your BUILD file relative to the Java source root will "
+ "be used as the package for Android resource processing. The Java source root could "
+ "not be determined for \"third_party/java_src/android/app\". Move your BUILD file "
+ "under a java or javatests directory, or set the 'custom_package' attribute.",
"licenses(['notice'])",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" )");
}
@Test
public void testWithRenameManifestPackage() throws Exception {
scratch.file("a/r/BUILD",
"android_library(name = 'r',",
" srcs = ['Foo.java'],",
" custom_package = 'com.google.android.bar',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/values/strings.xml'],",
" )");
ConfiguredTarget r = getConfiguredTarget("//a/r:r");
assertNoEvents();
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(r))).getArguments();
assertContainsSublist(args,
ImmutableList.of("--packageForR", "com.google.android.bar"));
}
@Test
public void testDebugConfiguration() throws Exception {
scratch.file("java/apps/android/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" )");
checkDebugMode("//java/apps/android:r", true);
useConfiguration("--compilation_mode=opt");
checkDebugMode("//java/apps/android:r", false);
}
@Test
public void testNeverlinkResources_AndroidResourcesProvider() throws Exception {
scratch.file("java/apps/android/BUILD",
"android_library(name = 'foo',",
" manifest = 'AndroidManifest.xml',",
" deps = [':lib', ':lib_neverlink'])",
"android_library(name = 'lib_neverlink',",
" neverlink = 1,",
" manifest = 'AndroidManifest.xml',",
" deps = [':bar'])",
"android_library(name = 'lib',",
" manifest = 'AndroidManifest.xml',",
" deps = [':bar'])",
"android_library(name = 'bar',",
" manifest = 'AndroidManifest.xml')");
Function<ResourceContainer, Label> getLabel = new Function<ResourceContainer, Label>() {
@Override
public Label apply(ResourceContainer container) {
return container.getLabel();
}
};
ConfiguredTarget foo = getConfiguredTarget("//java/apps/android:foo");
assertThat(Iterables.transform(
foo.getProvider(AndroidResourcesProvider.class).getTransitiveAndroidResources(), getLabel))
.containsExactly(
Label.parseAbsolute("//java/apps/android:lib"),
Label.parseAbsolute("//java/apps/android:bar"));
assertThat(Iterables.transform(
foo.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources(), getLabel))
.containsExactly(Label.parseAbsolute("//java/apps/android:foo"));
ConfiguredTarget lib = getConfiguredTarget("//java/apps/android:lib");
assertThat(Iterables.transform(
lib.getProvider(AndroidResourcesProvider.class).getTransitiveAndroidResources(), getLabel))
.containsExactly(Label.parseAbsolute("//java/apps/android:bar"));
assertThat(Iterables.transform(
lib.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources(), getLabel))
.containsExactly(Label.parseAbsolute("//java/apps/android:lib"));
ConfiguredTarget libNeverlink = getConfiguredTarget("//java/apps/android:lib_neverlink");
assertThat(libNeverlink.getProvider(AndroidResourcesProvider.class)
.getTransitiveAndroidResources())
.isEmpty();
assertThat(libNeverlink.getProvider(AndroidResourcesProvider.class)
.getDirectAndroidResources())
.isEmpty();
}
@Test
public void testNeverlinkResources_JavaCompileAction() throws Exception {
scratch.file("java/apps/android/BUILD",
"android_library(name = 'foo',",
" manifest = 'AndroidManifest.xml',",
" deps = [':lib', ':lib_neverlink'])",
"android_library(name = 'lib_neverlink',",
" neverlink = 1,",
" manifest = 'AndroidManifest.xml',",
" deps = [':bar'])",
"android_library(name = 'lib',",
" manifest = 'AndroidManifest.xml',",
" deps = [':bar'])",
"android_library(name = 'bar',",
" manifest = 'AndroidManifest.xml')");
ConfiguredTarget foo = getConfiguredTarget("//java/apps/android:foo");
JavaCompilationArgsProvider argsProvider = foo.getProvider(JavaCompilationArgsProvider.class);
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingActionForLabel("//java/apps/android:libfoo.jar");
assertThat(argsProvider.getJavaCompilationArgs().getCompileTimeJars())
.contains(ActionsTestUtil.getFirstArtifactEndingWith(
javacAction.getInputs(), "lib_neverlink_resources.jar"));
assertThat(argsProvider.getJavaCompilationArgs().getRuntimeJars())
.doesNotContain(ActionsTestUtil.getFirstArtifactEndingWith(
javacAction.getInputs(), "lib_neverlink_resources.jar"));
}
@Test
public void testResourceMergeAndProcessParallel() throws Exception {
// Test that for android_library, we can divide the resource processing action into
// smaller actions.
useConfiguration("--experimental_use_parallel_android_resource_processing");
scratch.file(
"java/android/app/foo/BUILD",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" resource_files = glob(['res/**']),",
" )");
scratch.file(
"java/android/app/foo/res/values/strings.xml",
"<resources>",
"<string name='hello'>Aloha!</string>",
"<string name='goodbye'>Aloha!</string>",
"</resources>");
ConfiguredTarget target = getConfiguredTarget("//java/android/app/foo:r");
NestedSet<Artifact> filesToBuild = getFilesToBuild(target);
Set<Artifact> artifacts = actionsTestUtil().artifactClosureOf(filesToBuild);
ResourceContainer resources =
Iterables.getOnlyElement(
target.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources());
SpawnAction resourceParserAction =
(SpawnAction)
actionsTestUtil()
.getActionForArtifactEndingWith(artifacts,
"/" + resources.getSymbols().getFilename());
SpawnAction resourceClassJarAction =
(SpawnAction)
actionsTestUtil()
.getActionForArtifactEndingWith(artifacts,
"/" + resources.getJavaClassJar().getFilename());
SpawnAction resourceSrcJarAction =
(SpawnAction)
actionsTestUtil()
.getActionForArtifactEndingWith(artifacts,
"/" + resources.getJavaSourceJar().getFilename());
assertThat(resourceParserAction.getMnemonic()).isEqualTo("AndroidResourceParser");
assertThat(resourceClassJarAction.getMnemonic()).isEqualTo("AndroidResourceMerger");
assertThat(resourceSrcJarAction.getMnemonic()).isEqualTo("AndroidResourceValidator");
// Validator also generates an R.txt.
assertThat(resourceSrcJarAction.getOutputs()).contains(resources.getRTxt());
}
private void checkDebugMode(String target, boolean isDebug) throws Exception {
ConfiguredTarget foo = getConfiguredTarget(target);
SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith(
getFilesToBuild(foo), "r.srcjar");
assertEquals(isDebug, action.getArguments().contains("--debug"));
}
@Test
public void testGeneratedManifestPackage() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'l',",
" srcs = ['foo.java'])",
"android_library(name = 'l2',",
" custom_package = 'foo',",
" srcs = ['foo.java'])");
scratch.file("third_party/android/BUILD",
"licenses(['notice'])",
"android_library(name = 'l',",
" srcs = ['foo.java'])");
ConfiguredTarget target = getConfiguredTarget("//java/android:l");
Artifact manifest = getBinArtifact("l_generated/l/AndroidManifest.xml", target);
FileWriteAction action = (FileWriteAction) getGeneratingAction(manifest);
assertThat(action.getFileContents()).contains("package=\"android\"");
target = getConfiguredTarget("//java/android:l2");
manifest = getBinArtifact("l2_generated/l2/AndroidManifest.xml", target);
action = (FileWriteAction) getGeneratingAction(manifest);
assertThat(action.getFileContents()).contains("package=\"foo\"");
target = getConfiguredTarget("//third_party/android:l");
manifest = getBinArtifact("l_generated/l/AndroidManifest.xml", target);
action = (FileWriteAction) getGeneratingAction(manifest);
assertThat(action.getFileContents()).contains("package=\"third_party.android\"");
}
@Test
public void testGeneratedIdlSrcs() throws Exception {
scratch.file("java/android/BUILD",
"genrule(name = 'idl',",
" outs = ['MyInterface.aidl'],",
" cmd = 'touch $@')",
"android_library(name = 'lib',",
" idl_srcs = [':idl'],",
" idl_parcelables = ['MyParcelable.aidl'])");
ConfiguredTarget target = getConfiguredTarget("//java/android:lib");
PathFragment genfilesJavaPath =
getTargetConfiguration()
.getOutputDirectory(RepositoryName.MAIN)
.getExecPath()
.getRelative("genfiles/java");
SpawnAction action = (SpawnAction) actionsTestUtil().getActionForArtifactEndingWith(
actionsTestUtil().artifactClosureOf(getFilesToBuild(target)), "MyInterface.java");
assertThat(action.getArguments())
.containsAllIn(ImmutableList.of("-Ijava", "-I" + genfilesJavaPath.getPathString()));
}
@Test
public void testMultipleLibsSameIdls() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'idl1',",
" idl_srcs = ['MyInterface.aidl'])",
"android_library(name = 'idl2',",
" idl_srcs = ['MyInterface.aidl'])");
getConfiguredTarget("//java/android:idl1");
getConfiguredTarget("//java/android:idl2");
}
@Test
public void testIdeInfoProvider() throws Exception {
scratch.file("java/android/BUILD",
"genrule(name='genrule', srcs=[], outs=['assets/genrule.so'], cmd='')",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" idl_srcs = [ 'MyInterface.aidl' ],",
" resource_files = glob(['res/**']),",
" assets_dir = 'assets',",
" assets = glob(['assets/**']) + [':genrule']",
" )");
scratch.file("java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
scratch.file("java/android/assets/values/orc.txt",
"Nabu nabu!");
ConfiguredTarget target = getConfiguredTarget("//java/android:r");
final AndroidIdeInfoProvider provider = target.getProvider(AndroidIdeInfoProvider.class);
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android/assets")),
SourceDirectory.fromRoot(
targetConfig.getGenfilesDirectory(RepositoryName.MAIN),
PathFragment.create("java/android/assets"))),
provider.getAssetDirs());
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android/res"))),
provider.getResourceDirs());
assertEquals(ImmutableList.of(SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android")
)), provider.getIdlImports());
Set<Artifact> artifactClosure = actionsTestUtil().artifactClosureOf(getFilesToBuild(target));
assertEquals(
ActionsTestUtil.getFirstArtifactEndingWith(artifactClosure,
"java/android/AndroidManifest.xml"),
provider.getManifest());
ResourceContainer resources = getOnlyElement(getConfiguredTarget("//java/android:r")
.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources());
assertEquals(resources.getManifest(),
provider.getGeneratedManifest());
}
@Test
public void testIdeInfoProviderOutsideJavaRoot() throws Exception {
String rootPath = "research/handwriting/java/com/google/research/handwriting/";
scratch.file(rootPath + "BUILD",
"genrule(name='genrule', srcs=[], outs=['assets/genrule.so'], cmd='')",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" idl_srcs = [ 'MyInterface.aidl' ],",
" resource_files = glob(['res/**']),",
" assets_dir = 'assets',",
" assets = glob(['assets/**']) + [':genrule']",
" )");
scratch.file(rootPath + "res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
scratch.file(rootPath + "/assets/values/orc.txt",
"Nabu nabu!");
ConfiguredTarget target = getConfiguredTarget(
"//research/handwriting/java/com/google/research/handwriting:r");
final AndroidIdeInfoProvider provider = target.getProvider(AndroidIdeInfoProvider.class);
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create(
"research/handwriting/java/com/google/research/handwriting/assets")
),
SourceDirectory.fromRoot(
targetConfig.getGenfilesDirectory(RepositoryName.MAIN),
PathFragment.create(
"research/handwriting/java/com/google/research/handwriting/assets")
)
),
provider.getAssetDirs());
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("research/handwriting/java/com/google/research/handwriting/res")
)
),
provider.getResourceDirs());
assertEquals(ImmutableList.of(SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("research/handwriting/java/com/google/research/handwriting")
)), provider.getIdlImports());
Set<Artifact> artifactClosure = actionsTestUtil().artifactClosureOf(getFilesToBuild(target));
assertEquals(
ActionsTestUtil.getFirstArtifactEndingWith(artifactClosure,
"handwriting/AndroidManifest.xml"),
provider.getManifest());
ResourceContainer resources = getOnlyElement(
getConfiguredTarget("//research/handwriting/java/com/google/research/handwriting:r")
.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources());
assertEquals(resources.getManifest(),
provider.getGeneratedManifest());
}
@Test
public void testIdeInfoProviderGeneratedIdl() throws Exception {
scratch.file("java/android/BUILD",
"genrule(name='genrule', srcs=[], outs=['assets/genrule.so'], cmd='')",
"genrule(name = 'idl',",
" outs = ['MyGeneratedInterface.aidl'],",
" cmd = 'touch $@')",
"android_library(name = 'r',",
" manifest = 'AndroidManifest.xml',",
" idl_srcs = [ ':idl' ],",
" idl_parcelables = [ 'MyInterface.aidl' ],",
" resource_files = glob(['res/**']),",
" assets_dir = 'assets',",
" assets = glob(['assets/**']) + [':genrule']",
" )");
scratch.file("java/android/res/values/strings.xml",
"<resources><string name = 'hello'>Hello Android!</string></resources>");
scratch.file("java/android/assets/values/orc.txt",
"Nabu nabu!");
ConfiguredTarget target = getConfiguredTarget("//java/android:r");
final AndroidIdeInfoProvider provider = target.getProvider(AndroidIdeInfoProvider.class);
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android/assets")),
SourceDirectory.fromRoot(
targetConfig.getGenfilesDirectory(RepositoryName.MAIN),
PathFragment.create("java/android/assets"))
),
provider.getAssetDirs());
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android/res"))
),
provider.getResourceDirs());
assertEquals(
ImmutableList.of(
SourceDirectory.fromSourceRoot(
rootDirectory.asFragment(),
PathFragment.create("java/android")),
SourceDirectory.fromRoot(
targetConfig.getGenfilesDirectory(RepositoryName.MAIN),
PathFragment.create("java/android"))
),
provider.getIdlImports());
Set<Artifact> artifactClosure = actionsTestUtil().artifactClosureOf(getFilesToBuild(target));
assertEquals(
ActionsTestUtil.getFirstArtifactEndingWith(artifactClosure,
"java/android/AndroidManifest.xml"),
provider.getManifest());
ResourceContainer resources = getOnlyElement(getConfiguredTarget("//java/android:r")
.getProvider(AndroidResourcesProvider.class).getDirectAndroidResources());
assertEquals(resources.getManifest(),
provider.getGeneratedManifest());
}
@Test
public void testAndroidLibraryWithMessagesDoNotCrash() throws Exception {
scratch.file("java/com/google/atest/BUILD",
"filegroup(name = 'sources',",
" srcs = ['source.java', 'message.xmb'])",
"android_library(name = 'alib',",
" srcs = [':sources'])");
getConfiguredTarget("//java/com/google/atest:alib");
}
@Test
public void testMultipleDirectDependentResourceDirectories_LocalResources()
throws Exception {
scratch.file("java/android/resources/d1/BUILD",
"android_library(name = 'd1',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['d1-res/values/strings.xml'],",
" assets = ['assets-d1/some/random/file'],",
" assets_dir = 'assets-d1',",
" deps = ['//java/android/resources/d2:d2'])");
scratch.file("java/android/resources/d2/BUILD",
"android_library(name = 'd2',",
" manifest = 'AndroidManifest.xml',",
" assets = ['assets-d2/some/random/file'],",
" assets_dir = 'assets-d2',",
" resource_files = ['d2-res/values/strings.xml'],",
" )");
ConfiguredTarget resource = getConfiguredTarget("//java/android/resources/d1:d1");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(resource, ImmutableList.of("java/android/resources/d1/d1-res"), args);
Truth.assertThat(getDirectDependentResourceDirs(resource, args))
.contains("java/android/resources/d2/d2-res");
Truth.assertThat(getDependentAssetDirs(resource, "--directData", args))
.contains("java/android/resources/d2/assets-d2");
assertNoEvents();
}
@Test
public void testTransitiveDependentResourceDirectories_LocalResources()
throws Exception {
scratch.file("java/android/resources/d1/BUILD",
"android_library(name = 'd1',",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['d1-res/values/strings.xml'],",
" assets = ['assets-d1/some/random/file'],",
" assets_dir = 'assets-d1',",
" deps = ['//java/android/resources/d2:d2'])");
scratch.file("java/android/resources/d2/BUILD",
"android_library(name = 'd2',",
" manifest = 'AndroidManifest.xml',",
" assets = ['assets-d2/some/random/file'],",
" assets_dir = 'assets-d2',",
" resource_files = ['d2-res/values/strings.xml'],",
" deps = ['//java/android/resources/d3:d3'],",
" )");
scratch.file("java/android/resources/d3/BUILD",
"android_library(name = 'd3',",
" manifest = 'AndroidManifest.xml',",
" assets = ['assets-d3/some/random/file'],",
" assets_dir = 'assets-d3',",
" resource_files = ['d3-res/values/strings.xml'],",
" )");
ConfiguredTarget resource = getConfiguredTarget("//java/android/resources/d1:d1");
List<String> args = ((SpawnAction) getGeneratingAction(getResourceArtifact(resource)))
.getArguments();
assertPrimaryResourceDirs(
resource, ImmutableList.of("java/android/resources/d1/d1-res"), args);
Truth.assertThat(getDirectDependentResourceDirs(resource, args))
.contains("java/android/resources/d2/d2-res");
Truth.assertThat(getDependentAssetDirs(resource, "--directData", args))
.contains("java/android/resources/d2/assets-d2");
Truth.assertThat(getTransitiveDependentResourceDirs(resource, args))
.contains("java/android/resources/d3/d3-res");
Truth.assertThat(getDependentAssetDirs(resource, "--data", args))
.contains("java/android/resources/d3/assets-d3");
assertNoEvents();
}
@Test
public void testCustomJavacopts() throws Exception {
scratch.file("java/android/BUILD",
"android_library(name = 'a',",
" srcs = ['A.java'],",
" javacopts = ['-g:lines,source'],",
" )");
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingActionForLabel("//java/android:liba.jar");
assertThat(javacAction.buildCommandLine()).contains("-g:lines,source");
}
// Regression test for b/23079127
@Test
public void testSrcjarStrictDeps() throws Exception {
scratch.file("java/strict/BUILD",
"android_library(name='a', srcs=['A.java'], deps=[':b'])",
"android_library(name='b', srcs=['b.srcjar'], deps=[':c'])",
"android_library(name='c', srcs=['C.java'])");
JavaCompileAction javacAction =
(JavaCompileAction) getGeneratingActionForLabel("//java/strict:liba.jar");
assertThat(ActionsTestUtil.prettyArtifactNames(javacAction.getDirectJars()))
.containsExactly("java/strict/libb-hjar.jar");
}
@Test
public void testDisallowPrecompiledJars() throws Exception {
checkError("java/precompiled", "library",
// messages:
"does not produce any android_library srcs files (expected .java or .srcjar)",
// build file:
"android_library(name = 'library',",
" srcs = [':jar'])",
"filegroup(name = 'jar',",
" srcs = ['lib.jar'])");
}
@Test
public void hjarPredecessors() throws Exception {
scratch.file(
"java/test/BUILD",
"android_library(name = 'a', srcs = ['A.java'], deps = [':b'])",
"android_library(name = 'b', srcs = ['B.java'])");
useConfiguration("--java_header_compilation");
Action a = getGeneratingActionForLabel("//java/test:liba.jar");
List<String> inputs = ActionsTestUtil.prettyArtifactNames(a.getInputs());
assertThat(inputs).doesNotContain("java/test/libb.jdeps");
assertThat(inputs).contains("java/test/libb-hjar.jdeps");
}
@Test
public void resourcesFromRuntimeDepsAreIncluded() throws Exception {
scratch.file(
"java/android/BUILD",
"android_library(name = 'dummyParentLibrary',",
" deps = [':dummyLibraryOne', ':dummyLibraryTwo'],",
" srcs = ['libraryParent.java'])",
"",
"android_library(name = 'dummyLibraryOne',",
" exports_manifest = 1,",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/drawable/dummyResource1.png'],",
" srcs = ['libraryOne.java'])",
"",
"android_library(name = 'dummyLibraryTwo',",
" exports_manifest = 1,",
" neverlink = 1,",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/drawable/dummyResource2.png'],",
" deps = ['dummyLibraryNested'],",
" srcs = ['libraryTwo.java'])",
"",
"android_library(name = 'dummyLibraryNested',",
" exports_manifest = 1,",
" manifest = 'AndroidManifest.xml',",
" resource_files = ['res/drawable/dummyResource1.png'],",
" srcs = ['libraryOne.java'])");
ConfiguredTarget target = getConfiguredTarget("//java/android:dummyLibraryOne");
AndroidLibraryAarProvider provider = target.getProvider(AndroidLibraryAarProvider.class);
assertThat(provider).isNotNull();
target = getConfiguredTarget("//java/android:dummyLibraryTwo");
provider = target.getProvider(AndroidLibraryAarProvider.class);
assertThat(provider).isNull();
target = getConfiguredTarget("//java/android:dummyParentLibrary");
provider = target.getProvider(AndroidLibraryAarProvider.class);
assertThat(provider).isNotNull();
assertThat(provider.getTransitiveAars()).hasSize(1);
}
@Test
public void testAndroidLibraryWithTestOnlySetsTestOnly() throws Exception {
scratch.file(
"java/com/google/android/foo/BUILD",
"android_library(",
" name = 'foo',",
" srcs = ['Foo.java'],",
" testonly = 1,",
")");
JavaCompileAction javacAction =
(JavaCompileAction)
getGeneratingAction(
getBinArtifact("libfoo.jar", getConfiguredTarget("//java/com/google/android/foo")));
assertThat(javacAction.buildCommandLine()).contains("--testonly");
}
@Test
public void testAndroidLibraryWithoutTestOnlyDoesntSetTestOnly() throws Exception {
scratch.file(
"java/com/google/android/foo/BUILD",
"android_library(",
" name = 'foo',",
" srcs = ['Foo.java'],",
")");
JavaCompileAction javacAction =
(JavaCompileAction)
getGeneratingAction(
getBinArtifact("libfoo.jar", getConfiguredTarget("//java/com/google/android/foo")));
assertThat(javacAction.buildCommandLine()).doesNotContain("--testonly");
}
}