aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar dannark <dannark@google.com>2017-11-29 23:29:29 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2017-11-29 23:31:28 -0800
commit2874302e49f3e92bb455dd3ce11f67260b618746 (patch)
treef8d09546a2f6da81a1b711b2f44281c46de00548
parentc7633e582e49f8a4c47c8ea0060ac3c9b0b6d71b (diff)
Add android_local_test base class.
RELNOTES: None PiperOrigin-RevId: 177414939
-rw-r--r--src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java2
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java554
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBaseRule.java168
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/android/robolectric_properties_template.txt4
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/AbstractAndroidLocalTestTest.java84
-rw-r--r--src/test/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestTest.java116
6 files changed, 844 insertions, 84 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
index c6cd791be9..d8ae98d451 100644
--- a/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
+++ b/src/main/java/com/google/devtools/build/lib/bazel/rules/BazelRuleClassProvider.java
@@ -83,6 +83,7 @@ import com.google.devtools.build.lib.rules.android.AndroidBinaryOnlyRule;
import com.google.devtools.build.lib.rules.android.AndroidConfiguration;
import com.google.devtools.build.lib.rules.android.AndroidDeviceRule;
import com.google.devtools.build.lib.rules.android.AndroidLibraryBaseRule;
+import com.google.devtools.build.lib.rules.android.AndroidLocalTestBaseRule;
import com.google.devtools.build.lib.rules.android.AndroidNeverlinkAspect;
import com.google.devtools.build.lib.rules.android.AndroidRuleClasses;
import com.google.devtools.build.lib.rules.android.AndroidSkylarkCommon;
@@ -506,6 +507,7 @@ public class BazelRuleClassProvider {
builder.addRuleDefinition(new AarImportBaseRule());
builder.addRuleDefinition(new BazelAarImportRule());
builder.addRuleDefinition(new AndroidDeviceRule());
+ builder.addRuleDefinition(new AndroidLocalTestBaseRule());
builder.addSkylarkAccessibleTopLevels("android_common", new AndroidSkylarkCommon());
builder.addSkylarkAccessibleTopLevels("java_common",
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
new file mode 100644
index 0000000000..f76c01b928
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBase.java
@@ -0,0 +1,554 @@
+// 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;
+package com.google.devtools.build.lib.rules.android;
+
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.ConfiguredTarget;
+import com.google.devtools.build.lib.analysis.FileProvider;
+import com.google.devtools.build.lib.analysis.OutputGroupProvider;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetBuilder;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTargetFactory;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.Runfiles;
+import com.google.devtools.build.lib.analysis.RunfilesProvider;
+import com.google.devtools.build.lib.analysis.RunfilesSupport;
+import com.google.devtools.build.lib.analysis.TransitiveInfoCollection;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
+import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Substitution;
+import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction.Template;
+import com.google.devtools.build.lib.analysis.configuredtargets.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.rules.android.AndroidConfiguration.AndroidAaptVersion;
+import com.google.devtools.build.lib.rules.java.ClasspathConfiguredFragment;
+import com.google.devtools.build.lib.rules.java.JavaCommon;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArgs;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArgs.ClasspathType;
+import com.google.devtools.build.lib.rules.java.JavaCompilationArtifacts;
+import com.google.devtools.build.lib.rules.java.JavaCompilationHelper;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration.OneVersionEnforcementLevel;
+import com.google.devtools.build.lib.rules.java.JavaHelper;
+import com.google.devtools.build.lib.rules.java.JavaInfo;
+import com.google.devtools.build.lib.rules.java.JavaPrimaryClassProvider;
+import com.google.devtools.build.lib.rules.java.JavaRuleOutputJarsProvider;
+import com.google.devtools.build.lib.rules.java.JavaRunfilesProvider;
+import com.google.devtools.build.lib.rules.java.JavaRuntimeClasspathProvider;
+import com.google.devtools.build.lib.rules.java.JavaSemantics;
+import com.google.devtools.build.lib.rules.java.JavaSkylarkApiProvider;
+import com.google.devtools.build.lib.rules.java.JavaSourceInfoProvider;
+import com.google.devtools.build.lib.rules.java.JavaSourceJarsProvider;
+import com.google.devtools.build.lib.rules.java.JavaTargetAttributes;
+import com.google.devtools.build.lib.rules.java.JavaToolchainProvider;
+import com.google.devtools.build.lib.rules.java.OneVersionCheckActionBuilder;
+import com.google.devtools.build.lib.rules.java.ProguardHelper;
+import com.google.devtools.build.lib.rules.java.proto.GeneratedExtensionRegistryProvider;
+import com.google.devtools.build.lib.syntax.Type;
+import com.google.devtools.build.lib.util.OS;
+import com.google.devtools.build.lib.vfs.PathFragment;
+import java.util.ArrayList;
+import java.util.List;
+
+/** A base implementation for the "android_local_test" rule. */
+public abstract class AndroidLocalTestBase implements RuleConfiguredTargetFactory {
+
+ @Override
+ public ConfiguredTarget create(RuleContext ruleContext)
+ throws InterruptedException, RuleErrorException {
+
+ ruleContext.checkSrcsSamePackage(true);
+
+ JavaSemantics javaSemantics = createJavaSemantics();
+ AndroidSemantics androidSemantics = createAndroidSemantics();
+
+ final JavaCommon javaCommon = new JavaCommon(ruleContext, javaSemantics);
+ // Use the regular Java javacopts. Enforcing android-compatible Java
+ // (-source 7 -target 7 and no TWR) is unnecessary for robolectric tests
+ // since they run on a JVM, not an android device.
+ JavaTargetAttributes.Builder attributesBuilder =
+ getJavaTargetAttributes(ruleContext, javaCommon);
+
+ // Create the final merged manifest
+ ResourceDependencies resourceDependencies = getResourceDependencies(ruleContext);
+ ApplicationManifest applicationManifest =
+ getApplicationManifest(ruleContext, androidSemantics, resourceDependencies);
+ Artifact manifest = applicationManifest.getManifest();
+ String manifestLocation = manifest.getRunfilesPathString();
+
+ // Create merged resources and assets zip file
+ Artifact resourcesZip =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_ZIP);
+ String resourcesLocation = resourcesZip.getRunfilesPathString();
+
+ // Create the final merged R class
+ Artifact resourcesClassJar =
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
+ ResourceApk resourceApk =
+ applicationManifest.packBinaryWithDataAndResources(
+ ruleContext,
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_RESOURCES_APK),
+ resourceDependencies,
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_R_TXT),
+ ResourceFilterFactory.fromRuleContext(ruleContext),
+ ImmutableList.of(), /* list of uncompressed extensions */
+ false, /* crunch png */
+ ProguardHelper.getProguardConfigArtifact(ruleContext, ""),
+ null, /* mainDexProguardCfg */
+ false, /* conditionalKeepRules */
+ ruleContext.getImplicitOutputArtifact(AndroidRuleClasses.ANDROID_PROCESSED_MANIFEST),
+ resourcesZip,
+ DataBinding.isEnabled(ruleContext) ? DataBinding.getLayoutInfoFile(ruleContext) : null,
+ null, /* featureOfArtifact */
+ null /* featureAfterArtifact */);
+ compileResourceJar(ruleContext, resourceApk, resourcesClassJar);
+ attributesBuilder.addRuntimeClassPathEntry(resourcesClassJar);
+
+ // Exclude the Rs from the library from the runtime classpath.
+ NestedSet<Artifact> excludedRuntimeArtifacts = getLibraryResourceJars(ruleContext);
+ attributesBuilder.addExcludedArtifacts(excludedRuntimeArtifacts);
+
+ // Create robolectric test_config.properties file
+ String name = "_robolectric/" + ruleContext.getRule().getName() + "_test_config.properties";
+ Artifact propertiesFile = ruleContext.getGenfilesArtifact(name);
+
+ Template template =
+ Template.forResource(AndroidLocalTestBase.class, "robolectric_properties_template.txt");
+ List<Substitution> substitutions = new ArrayList<>();
+ substitutions.add(Substitution.of("%android_merged_manifest%", manifestLocation));
+ substitutions.add(
+ Substitution.of("%android_merged_resources%", "jar:file:" + resourcesLocation + "!/res"));
+ substitutions.add(
+ Substitution.of("%android_merged_assets%", "jar:file:" + resourcesLocation + "!/assets"));
+ substitutions.add(
+ Substitution.of(
+ "%android_custom_package%", resourceApk.getPrimaryResource().getJavaPackage()));
+
+ ruleContext.registerAction(
+ new TemplateExpansionAction(
+ ruleContext.getActionOwner(),
+ propertiesFile,
+ template,
+ substitutions,
+ false /* makeExecutable */));
+ // Add the properties file to the test jar as a java resource
+ attributesBuilder.addResource(
+ PathFragment.create("com/android/tools/test_config.properties"), propertiesFile);
+
+ String testClass =
+ getAndCheckTestClass(ruleContext, ImmutableList.copyOf(attributesBuilder.getSourceFiles()));
+ getAndCheckTestSupport(ruleContext);
+ javaSemantics.checkForProtoLibraryAndJavaProtoLibraryOnSameProto(ruleContext, javaCommon);
+ if (ruleContext.hasErrors()) {
+ return null;
+ }
+
+ Artifact srcJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_SOURCE_JAR);
+ JavaSourceJarsProvider.Builder javaSourceJarsProviderBuilder =
+ JavaSourceJarsProvider.builder()
+ .addSourceJar(srcJar)
+ .addAllTransitiveSourceJars(javaCommon.collectTransitiveSourceJars(srcJar));
+
+ Artifact classJar = ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_BINARY_CLASS_JAR);
+ JavaRuleOutputJarsProvider.Builder javaRuleOutputJarsProviderBuilder =
+ JavaRuleOutputJarsProvider.builder()
+ .addOutputJar(
+ classJar,
+ classJar,
+ srcJar == null ? ImmutableList.<Artifact>of() : ImmutableList.of(srcJar));
+
+ JavaCompilationArtifacts.Builder javaArtifactsBuilder = new JavaCompilationArtifacts.Builder();
+ JavaCompilationHelper helper =
+ getJavaCompilationHelperWithDependencies(
+ ruleContext, javaSemantics, javaCommon, attributesBuilder);
+ Artifact instrumentationMetadata =
+ helper.createInstrumentationMetadata(classJar, javaArtifactsBuilder);
+ Artifact executable; // the artifact for the rule itself
+ if (OS.getCurrent() == OS.WINDOWS
+ && ruleContext.getConfiguration().enableWindowsExeLauncher()) {
+ executable =
+ ruleContext.getImplicitOutputArtifact(ruleContext.getTarget().getName() + ".exe");
+ } else {
+ executable = ruleContext.createOutputArtifact();
+ }
+ NestedSetBuilder<Artifact> filesToBuildBuilder =
+ NestedSetBuilder.<Artifact>stableOrder().add(classJar).add(executable);
+
+ GeneratedExtensionRegistryProvider generatedExtensionRegistryProvider =
+ javaSemantics.createGeneratedExtensionRegistry(
+ ruleContext,
+ javaCommon,
+ filesToBuildBuilder,
+ javaArtifactsBuilder,
+ javaRuleOutputJarsProviderBuilder,
+ javaSourceJarsProviderBuilder);
+
+ String mainClass =
+ getMainClass(
+ ruleContext,
+ javaSemantics,
+ helper,
+ executable,
+ instrumentationMetadata,
+ javaArtifactsBuilder,
+ attributesBuilder);
+
+ // JavaCompilationHelper.getAttributes() builds the JavaTargetAttributes, after which the
+ // JavaTargetAttributes becomes immutable. This is an extra safety check to avoid inconsistent
+ // states (i.e. building the JavaTargetAttributes then modifying it again).
+ addJavaClassJarToArtifactsBuilder(javaArtifactsBuilder, helper.getAttributes(), classJar);
+
+ // The gensrc jar is created only if the target uses annotation processing. Otherwise,
+ // it is null, and the source jar action will not depend on the compile action.
+ Artifact manifestProtoOutput = helper.createManifestProtoOutput(classJar);
+
+ Artifact genClassJar = null;
+ Artifact genSourceJar = null;
+ if (helper.usesAnnotationProcessing()) {
+ genClassJar = helper.createGenJar(classJar);
+ genSourceJar = helper.createGensrcJar(classJar);
+ helper.createGenJarAction(classJar, manifestProtoOutput, genClassJar);
+ }
+ Artifact outputDepsProtoArtifact =
+ helper.createOutputDepsProtoArtifact(classJar, javaArtifactsBuilder);
+ javaRuleOutputJarsProviderBuilder.setJdeps(outputDepsProtoArtifact);
+
+ helper.createCompileAction(
+ classJar,
+ manifestProtoOutput,
+ genSourceJar,
+ outputDepsProtoArtifact,
+ instrumentationMetadata);
+ helper.createSourceJarAction(srcJar, genSourceJar);
+
+ setUpJavaCommon(javaCommon, helper, javaArtifactsBuilder.build());
+
+ Artifact launcher = JavaHelper.launcherArtifactForTarget(javaSemantics, ruleContext);
+
+ String javaExecutable;
+ if (javaSemantics.isJavaExecutableSubstitution()) {
+ javaExecutable = JavaCommon.getJavaBinSubstitution(ruleContext, launcher);
+ } else {
+ javaExecutable = JavaCommon.getJavaExecutableForStub(ruleContext, launcher);
+ }
+
+ javaSemantics.createStubAction(
+ ruleContext,
+ javaCommon,
+ getJvmFlags(ruleContext, testClass),
+ executable,
+ mainClass,
+ javaExecutable);
+
+ Artifact oneVersionOutputArtifact = null;
+ OneVersionEnforcementLevel oneVersionEnforcementLevel =
+ ruleContext.getFragment(JavaConfiguration.class).oneVersionEnforcementLevel();
+ if (oneVersionEnforcementLevel != OneVersionEnforcementLevel.OFF) {
+ oneVersionOutputArtifact =
+ OneVersionCheckActionBuilder.newBuilder()
+ .withEnforcementLevel(oneVersionEnforcementLevel)
+ .outputArtifact(
+ ruleContext.getImplicitOutputArtifact(JavaSemantics.JAVA_ONE_VERSION_ARTIFACT))
+ .useToolchain(JavaToolchainProvider.from(ruleContext))
+ .checkJars(
+ NestedSetBuilder.fromNestedSet(helper.getAttributes().getRuntimeClassPath())
+ .add(classJar)
+ .build())
+ .build(ruleContext);
+ }
+
+ NestedSet<Artifact> filesToBuild = filesToBuildBuilder.build();
+
+ Runfiles defaultRunfiles =
+ collectDefaultRunfiles(
+ ruleContext, javaCommon, filesToBuild, manifest, resourcesClassJar, resourcesZip);
+
+ RunfilesSupport runfilesSupport =
+ RunfilesSupport.withExecutable(
+ ruleContext, defaultRunfiles, executable, CustomCommandLine.EMPTY);
+
+ JavaSourceJarsProvider sourceJarsProvider = javaSourceJarsProviderBuilder.build();
+ NestedSet<Artifact> transitiveSourceJars = sourceJarsProvider.getTransitiveSourceJars();
+
+ RuleConfiguredTargetBuilder builder = new RuleConfiguredTargetBuilder(ruleContext);
+
+ if (generatedExtensionRegistryProvider != null) {
+ builder.addProvider(
+ GeneratedExtensionRegistryProvider.class, generatedExtensionRegistryProvider);
+ }
+
+ JavaRuleOutputJarsProvider ruleOutputJarsProvider = javaRuleOutputJarsProviderBuilder.build();
+
+ javaCommon.addTransitiveInfoProviders(builder, filesToBuild, classJar);
+ javaCommon.addGenJarsProvider(builder, genClassJar, genSourceJar);
+
+ // Just confirming that there are no aliases being used here.
+ AndroidFeatureFlagSetProvider.getAndValidateFlagMapFromRuleContext(ruleContext);
+
+ if (oneVersionOutputArtifact != null) {
+ builder.addOutputGroup(OutputGroupProvider.HIDDEN_TOP_LEVEL, oneVersionOutputArtifact);
+ }
+
+ NestedSet<Artifact> extraFilesToRun =
+ NestedSetBuilder.create(Order.STABLE_ORDER, runfilesSupport.getRunfilesMiddleman());
+
+ JavaInfo javaInfo =
+ JavaInfo.Builder.create()
+ .addProvider(JavaSourceJarsProvider.class, sourceJarsProvider)
+ .addProvider(JavaRuleOutputJarsProvider.class, ruleOutputJarsProvider)
+ .build();
+
+ return builder
+ .setFilesToBuild(filesToBuild)
+ .addSkylarkTransitiveInfo(
+ JavaSkylarkApiProvider.NAME, JavaSkylarkApiProvider.fromRuleContext())
+ .addNativeDeclaredProvider(javaInfo)
+ .addProvider(
+ RunfilesProvider.class,
+ RunfilesProvider.withData(
+ defaultRunfiles,
+ new Runfiles.Builder(ruleContext.getWorkspaceName())
+ .merge(runfilesSupport)
+ .build()))
+ .addFilesToRun(extraFilesToRun)
+ .setRunfilesSupport(runfilesSupport, executable)
+ .addProvider(
+ JavaRuntimeClasspathProvider.class,
+ new JavaRuntimeClasspathProvider(javaCommon.getRuntimeClasspath()))
+ .addProvider(JavaPrimaryClassProvider.class, new JavaPrimaryClassProvider(testClass))
+ .addProvider(
+ JavaSourceInfoProvider.class,
+ JavaSourceInfoProvider.fromJavaTargetAttributes(helper.getAttributes(), javaSemantics))
+ .addOutputGroup(JavaSemantics.SOURCE_JARS_OUTPUT_GROUP, transitiveSourceJars)
+ .build();
+ }
+
+ /** Creates the final merged R class with all of the transitive resources. */
+ private void compileResourceJar(
+ RuleContext ruleContext, ResourceApk resourceApk, Artifact resourceClassJar)
+ throws InterruptedException, RuleErrorException {
+
+ if (resourceApk.getResourceJavaClassJar() == null) {
+ new RClassGeneratorActionBuilder(ruleContext)
+ .targetAaptVersion(AndroidAaptVersion.chooseTargetAaptVersion(ruleContext))
+ .withPrimary(resourceApk.getPrimaryResource())
+ .withDependencies(resourceApk.getResourceDependencies())
+ .setClassJarOut(resourceClassJar)
+ .build();
+ } else {
+ Preconditions.checkArgument(resourceApk.getResourceJavaClassJar().equals(resourceClassJar));
+ }
+ }
+
+ /**
+ * Returns a merged {@link ApplicationManifest} for the rule. The final merged manifest will be
+ * merged into the manifest provided on the rule, or into a placeholder manifest if one is not
+ * provided
+ * @throws InterruptedException
+ * @throws RuleErrorException
+ */
+ private ApplicationManifest getApplicationManifest(
+ RuleContext ruleContext,
+ AndroidSemantics androidSemantics,
+ ResourceDependencies resourceDependencies)
+ throws InterruptedException, RuleErrorException {
+ ApplicationManifest applicationManifest;
+
+ if (LocalResourceContainer.definesAndroidResources(ruleContext.attributes())) {
+ LocalResourceContainer.validateRuleContext(ruleContext);
+ ApplicationManifest ruleManifest = androidSemantics.getManifestForRule(ruleContext);
+ applicationManifest = ruleManifest.mergeWith(ruleContext, resourceDependencies, false);
+ } else {
+ // we don't have a manifest, merge like android_library with a stub manifest
+ ApplicationManifest dummyManifest = ApplicationManifest.generatedManifest(ruleContext);
+ applicationManifest = dummyManifest.mergeWith(ruleContext, resourceDependencies, false);
+ }
+ return applicationManifest;
+ }
+
+ /** Returns the transitive closure of resource dependencies, including those specified on the rule
+ * if present. */
+ private ResourceDependencies getResourceDependencies(RuleContext ruleContext) {
+ return LocalResourceContainer.definesAndroidResources(ruleContext.attributes())
+ ? ResourceDependencies.fromRuleDeps(ruleContext, false /* neverlink */)
+ : ResourceDependencies.fromRuleResourceAndDeps(ruleContext, false /* neverlink */);
+ }
+
+ private static void setUpJavaCommon(
+ JavaCommon common,
+ JavaCompilationHelper helper,
+ JavaCompilationArtifacts javaCompilationArtifacts) {
+ common.setJavaCompilationArtifacts(javaCompilationArtifacts);
+ common.setClassPathFragment(
+ new ClasspathConfiguredFragment(
+ common.getJavaCompilationArtifacts(),
+ helper.getAttributes(),
+ false,
+ helper.getBootclasspathOrDefault()));
+ }
+
+ private void addJavaClassJarToArtifactsBuilder(
+ JavaCompilationArtifacts.Builder javaArtifactsBuilder,
+ JavaTargetAttributes attributes,
+ Artifact classJar) {
+ if (attributes.hasSources() || attributes.hasResources()) {
+ // We only want to add a jar to the classpath of a dependent rule if it has content.
+ javaArtifactsBuilder.addRuntimeJar(classJar);
+ }
+ }
+
+ private Runfiles collectDefaultRunfiles(
+ RuleContext ruleContext,
+ JavaCommon javaCommon,
+ NestedSet<Artifact> filesToBuild,
+ Artifact manifest,
+ Artifact resourcesClassJar,
+ Artifact resourcesZip)
+ throws RuleErrorException {
+
+ Runfiles.Builder builder = new Runfiles.Builder(ruleContext.getWorkspaceName());
+ builder.addTransitiveArtifacts(filesToBuild);
+ builder.addArtifacts(javaCommon.getJavaCompilationArtifacts().getRuntimeJars());
+
+ builder.addRunfiles(ruleContext, RunfilesProvider.DEFAULT_RUNFILES);
+ builder.add(ruleContext, JavaRunfilesProvider.TO_RUNFILES);
+
+ List<TransitiveInfoCollection> depsForRunfiles = new ArrayList<>();
+
+ if (ruleContext.isAttrDefined("$robolectric", LABEL_LIST)) {
+ depsForRunfiles.addAll(ruleContext.getPrerequisites("$robolectric", Mode.TARGET));
+ }
+ depsForRunfiles.addAll(ruleContext.getPrerequisites("runtime_deps", Mode.TARGET));
+
+ builder.addArtifacts(getRuntimeJarsForTargets(getAndCheckTestSupport(ruleContext)));
+
+ builder.addTargets(depsForRunfiles, JavaRunfilesProvider.TO_RUNFILES);
+ builder.addTargets(depsForRunfiles, RunfilesProvider.DEFAULT_RUNFILES);
+
+ if (ruleContext.getConfiguration().isCodeCoverageEnabled()) {
+ Artifact instrumentedJar = javaCommon.getJavaCompilationArtifacts().getInstrumentedJar();
+ if (instrumentedJar != null) {
+ builder.addArtifact(instrumentedJar);
+ }
+ }
+
+ // We assume that the runtime jars will not have conflicting artifacts
+ // with the same root relative path
+ builder.addTransitiveArtifactsWrappedInStableOrder(javaCommon.getRuntimeClasspath());
+
+ // Add the JDK files if it comes from P4 (see java_stub_template.txt).
+ TransitiveInfoCollection javabaseTarget = ruleContext.getPrerequisite(":jvm", Mode.TARGET);
+
+ if (javabaseTarget != null) {
+ builder.addTransitiveArtifacts(
+ javabaseTarget.getProvider(FileProvider.class).getFilesToBuild());
+ }
+
+ builder.addArtifact(manifest);
+ builder.addArtifact(resourcesClassJar);
+ builder.addArtifact(resourcesZip);
+
+ return builder.build();
+ }
+
+ private NestedSet<Artifact> getRuntimeJarsForTargets(TransitiveInfoCollection deps) {
+ // The dep may be a simple JAR and not a java rule, hence we can't simply do
+ // dep.getProvider(JavaCompilationArgsProvider.class).getRecursiveJavaCompilationArgs(),
+ // so we reuse the logic within JavaCompilationArgs to handle both scenarios.
+ JavaCompilationArgs args =
+ JavaCompilationArgs.builder()
+ .addTransitiveTargets(
+ ImmutableList.of(deps), /*recursive=*/ true, ClasspathType.RUNTIME_ONLY)
+ .build();
+ return args.getRuntimeJars();
+ }
+
+ private static String getAndCheckTestClass(
+ RuleContext ruleContext, ImmutableList<Artifact> sourceFiles) {
+ String testClass =
+ ruleContext.getRule().isAttrDefined("test_class", Type.STRING)
+ ? ruleContext.attributes().get("test_class", Type.STRING)
+ : "";
+
+ if (testClass.isEmpty()) {
+ testClass = JavaCommon.determinePrimaryClass(ruleContext, sourceFiles);
+ if (testClass == null) {
+ ruleContext.ruleError(
+ "cannot determine junit.framework.Test class "
+ + "(Found no source file '"
+ + ruleContext.getTarget().getName()
+ + ".java' and package name doesn't include 'java' or 'javatests'. "
+ + "You might want to rename the rule or add a 'test_class' "
+ + "attribute.)");
+ }
+ }
+ return testClass;
+ }
+
+ private static NestedSet<Artifact> getLibraryResourceJars(RuleContext ruleContext) {
+ Iterable<AndroidLibraryResourceClassJarProvider> libraryResourceJarProviders =
+ AndroidCommon.getTransitivePrerequisites(
+ ruleContext, Mode.TARGET, AndroidLibraryResourceClassJarProvider.class);
+
+ NestedSetBuilder<Artifact> libraryResourceJarsBuilder = NestedSetBuilder.naiveLinkOrder();
+ for (AndroidLibraryResourceClassJarProvider provider : libraryResourceJarProviders) {
+ libraryResourceJarsBuilder.addTransitive(provider.getResourceClassJars());
+ }
+ return libraryResourceJarsBuilder.build();
+ }
+
+ /** Get JavaSemantics */
+ protected abstract JavaSemantics createJavaSemantics();
+
+ /** Get AndroidSemantics */
+ protected abstract AndroidSemantics createAndroidSemantics();
+
+ /** Get JavaTargetAttributes Builder */
+ protected abstract JavaTargetAttributes.Builder getJavaTargetAttributes(
+ RuleContext ruleContext, JavaCommon javaCommon);
+
+ /** Set test and robolectric specific jvm flags */
+ protected abstract ImmutableList<String> getJvmFlags(RuleContext ruleContext, String testClass);
+
+ /** Return the testrunner main class */
+ protected abstract String getMainClass(
+ RuleContext ruleContext,
+ JavaSemantics javaSemantics,
+ JavaCompilationHelper helper,
+ Artifact executable,
+ Artifact instrumentationMetadata,
+ JavaCompilationArtifacts.Builder javaArtifactsBuilder,
+ JavaTargetAttributes.Builder attributesBuilder)
+ throws InterruptedException;
+
+ /**
+ * Add compilation dependencies to the java compilation helper.
+ * @throws RuleErrorException
+ */
+ protected abstract JavaCompilationHelper getJavaCompilationHelperWithDependencies(
+ RuleContext ruleContext,
+ JavaSemantics javaSemantics,
+ JavaCommon javaCommon,
+ JavaTargetAttributes.Builder javaTargetAttributesBuilder)
+ throws RuleErrorException;
+
+ /** Get the testrunner from the rule */
+ protected abstract TransitiveInfoCollection getAndCheckTestSupport(RuleContext ruleContext)
+ throws RuleErrorException;
+}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBaseRule.java b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBaseRule.java
new file mode 100644
index 0000000000..ef13513cda
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestBaseRule.java
@@ -0,0 +1,168 @@
+// 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;
+package com.google.devtools.build.lib.rules.android;
+
+import static com.google.devtools.build.lib.packages.Attribute.ConfigurationTransition.HOST;
+import static com.google.devtools.build.lib.packages.Attribute.attr;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_KEYED_STRING_DICT;
+import static com.google.devtools.build.lib.packages.BuildType.LABEL_LIST;
+import static com.google.devtools.build.lib.rules.android.AndroidRuleClasses.getAndroidSdkLabel;
+import static com.google.devtools.build.lib.syntax.Type.STRING;
+import static com.google.devtools.build.lib.syntax.Type.STRING_DICT;
+
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.analysis.RuleDefinition;
+import com.google.devtools.build.lib.analysis.RuleDefinitionEnvironment;
+import com.google.devtools.build.lib.packages.RuleClass;
+import com.google.devtools.build.lib.packages.RuleClass.Builder;
+import com.google.devtools.build.lib.packages.RuleClass.Builder.RuleClassType;
+import com.google.devtools.build.lib.rules.config.ConfigFeatureFlagProvider;
+import com.google.devtools.build.lib.rules.java.JavaConfiguration;
+import com.google.devtools.build.lib.rules.java.Jvm;
+import com.google.devtools.build.lib.util.FileTypeSet;
+
+/** Base rule definition for android_local_test */
+public class AndroidLocalTestBaseRule implements RuleDefinition {
+
+ @Override
+ public RuleClass build(Builder builder, RuleDefinitionEnvironment environment) {
+ return builder
+ .requiresConfigurationFragments(JavaConfiguration.class, Jvm.class)
+
+ // Update documentation for inherited attributes
+
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(deps) -->
+ The list of libraries to be tested as well as additional libraries to be linked
+ in to the target.
+ All resources, assets and manifest files declared in Android rules in the transitive
+ closure of this attribute are made available in the test.
+ <p>
+ The list of allowed rules in <code>deps</code> are <code>android_library</code>,
+ <code>aar_import</code>, <code>java_import</code>, <code>java_library</code>,
+ <code>java_lite_proto_library</code>, and <code>proto_library</code>.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(srcs) -->
+ The list of source files that are processed to create the target.
+ Required except in special case described below.
+ <p><code>srcs</code> files of type <code>.java</code> are compiled.
+ <em>For readability's sake</em>, it is not good to put the name of a
+ generated <code>.java</code> source file into the <code>srcs</code>.
+ Instead, put the depended-on rule name in the <code>srcs</code>, as
+ described below.
+ </p>
+
+ <p><code>srcs</code> files of type <code>.srcjar</code> are unpacked and
+ compiled. (This is useful if you need to generate a set of .java files with
+ a genrule or build extension.)
+ </p>
+
+ <p>All other files are ignored, as long as
+ there is at least one file of a file type described above. Otherwise an
+ error is raised.
+ </p>
+
+ <p>
+ The <code>srcs</code> attribute is required and cannot be empty, unless
+ <code>runtime_deps</code> is specified.
+ </p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+
+ .add(
+ attr(AndroidFeatureFlagSetProvider.FEATURE_FLAG_ATTR, LABEL_KEYED_STRING_DICT)
+ .undocumented("the feature flag feature has not yet been launched")
+ .allowedRuleClasses("config_feature_flag")
+ .allowedFileTypes()
+ .nonconfigurable("defines an aspect of configuration")
+ .mandatoryProviders(ImmutableList.of(ConfigFeatureFlagProvider.id())))
+ .add(AndroidFeatureFlagSetProvider.getWhitelistAttribute(environment))
+ // TODO(b/38314524): Move $android_resources_busybox and :android_sdk to a separate
+ // rule so they're not defined in multiple places
+ .add(
+ attr("$android_resources_busybox", LABEL)
+ .cfg(HOST)
+ .exec()
+ .value(environment.getToolsLabel(AndroidRuleClasses.DEFAULT_RESOURCES_BUSYBOX)))
+ .add(
+ attr(":android_sdk", LABEL)
+ .allowedRuleClasses("android_sdk", "filegroup")
+ .value(
+ getAndroidSdkLabel(environment.getToolsLabel(AndroidRuleClasses.DEFAULT_SDK))))
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(test_class) -->
+ The Java class to be loaded by the test runner.<br/>
+ <p>
+ This attribute specifies the name of a Java class to be run by
+ this test. It is rare to need to set this. If this argument is omitted, the Java class
+ whose name corresponds to the <code>name</code> of this
+ <code>android_local_test</code> rule will be used.
+ The test class needs to be annotated with <code>org.junit.runner.RunWith</code>.
+ </p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("test_class", STRING)) // every test class adds this
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(manifest_values) -->
+ A dictionary of values to be overridden in the manifest. Any instance of ${name} in the
+ manifest will be replaced with the value corresponding to name in this dictionary.
+ <code>applicationId</code>, <code>versionCode</code>, <code>versionName</code>,
+ <code>minSdkVersion</code>, <code>targetSdkVersion</code> and
+ <code>maxSdkVersion</code> will also override the corresponding attributes
+ of the manifest and
+ uses-sdk tags. <code>packageName</code> will be ignored and will be set from either
+ <code>applicationId</code> if
+ specified or the package in the manifest.
+ It is not necessary to have a manifest on the rule in order to use manifest_values.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("manifest_values", STRING_DICT))
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(manifest) -->
+ The name of the Android manifest file, normally <code>AndroidManifest.xml</code>.
+ Must be defined if resource_files or assets are defined or if any of the manifests from
+ the libraries under test have a <code>minSdkVersion</code> tag in them.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("manifest", LABEL).allowedFileTypes(FileTypeSet.ANY_FILE))
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(resource_files) -->
+ The list of test resources to be packaged. This is typically a <code>glob</code>
+ of all files under the <code>res</code> directory.
+ <p>
+ Generated files (from genrules) can be referenced by
+ <a href="../build-ref.html#labels">Label</a> here as well. The only restriction is that
+ the generated outputs must be under the same "<code>res</code>" directory as any other
+ resource files that are included. It is rare to need this.
+ </p>
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("resource_files", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(assets_dir) -->
+ The string giving the path to the files in <code>assets</code>.
+ The pair <code>assets</code> and <code>assets_dir</code> describe packaged
+ assets and either both attributes should be provided or neither of them.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("assets_dir", STRING))
+ /* <!-- #BLAZE_RULE($android_local_test_base).ATTRIBUTE(assets) -->
+ The list of test assets to be packaged. This is typically a <code>glob</code> of all files
+ under the <code>assets</code> directory. You can also reference other rules (any rule that
+ produces files) or exported files in the other packages, as long as all those files are
+ under the <code>assets_dir</code> directory in the corresponding package. It is rare to
+ need this.
+ <!-- #END_BLAZE_RULE.ATTRIBUTE --> */
+ .add(attr("assets", LABEL_LIST).allowedFileTypes(FileTypeSet.ANY_FILE))
+ .build();
+ }
+
+ @Override
+ public Metadata getMetadata() {
+ return RuleDefinition.Metadata.builder()
+ .name("$android_local_test_base")
+ .type(RuleClassType.ABSTRACT)
+ .build();
+ }
+} \ No newline at end of file
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/robolectric_properties_template.txt b/src/main/java/com/google/devtools/build/lib/rules/android/robolectric_properties_template.txt
new file mode 100644
index 0000000000..dba03448b2
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/robolectric_properties_template.txt
@@ -0,0 +1,4 @@
+android_merged_manifest=%android_merged_manifest%
+android_merged_resources=%android_merged_resources%
+android_merged_assets=%android_merged_assets%
+android_custom_package=%android_custom_package% \ No newline at end of file
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AbstractAndroidLocalTestTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AbstractAndroidLocalTestTest.java
index 83f72f10d2..0c790c63e0 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AbstractAndroidLocalTestTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AbstractAndroidLocalTestTest.java
@@ -16,27 +16,18 @@ package com.google.devtools.build.lib.rules.android;
import static com.google.common.truth.Truth.assertThat;
import static com.google.devtools.build.lib.actions.util.ActionsTestUtil.prettyArtifactNames;
-import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
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.FilesToRunProvider;
import com.google.devtools.build.lib.analysis.OutputGroupProvider;
import com.google.devtools.build.lib.analysis.RunfilesProvider;
-import com.google.devtools.build.lib.analysis.RunfilesSupport;
import com.google.devtools.build.lib.analysis.actions.FileWriteAction;
import com.google.devtools.build.lib.analysis.actions.TemplateExpansionAction;
import com.google.devtools.build.lib.analysis.util.BuildViewTestCase;
import com.google.devtools.build.lib.rules.java.JavaSemantics;
import com.google.devtools.build.lib.util.FileType;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.LinkedHashSet;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -174,81 +165,6 @@ public abstract class AbstractAndroidLocalTestTest extends BuildViewTestCase {
}
@Test
- public void testResourcesFromRuntimeDepsAreIncluded() throws Exception {
- writeFile(
- "java/android/BUILD",
- "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,",
- " manifest = 'AndroidManifest.xml',",
- " resource_files = ['res/drawable/dummyResource2.png'],",
- " srcs = ['libraryTwo.java'])");
- final String libraryOne = "dummyLibraryOne";
- final String libraryTwo = "dummyLibraryTwo";
-
- checkForCorrectLibraries(
- "no-runtime", Arrays.asList(libraryOne), Collections.<String>emptyList());
- checkForCorrectLibraries(
- "no-runtime-2", Arrays.asList(libraryOne, libraryTwo), Collections.<String>emptyList());
- checkForCorrectLibraries(
- "only-runtime", Collections.<String>emptyList(), Arrays.asList(libraryOne));
- checkForCorrectLibraries(
- "only-runtime-2", Collections.<String>emptyList(), Arrays.asList(libraryOne, libraryTwo));
- checkForCorrectLibraries(
- "runtime-and-dep", Arrays.asList(libraryOne), Arrays.asList(libraryTwo));
- checkForCorrectLibraries(
- "runtime-and-dep-2", Arrays.asList(libraryTwo), Arrays.asList(libraryOne));
- }
-
- private String createDepArrayString(Collection<String> deps) {
- if (deps.isEmpty()) {
- return "";
- }
- ArrayList<String> list = new ArrayList<>();
- for (String dep : deps) {
- list.add(String.format("//java/android:%s", dep));
- }
- return "'" + Joiner.on("', '").join(list) + "'";
- }
-
- private void checkForCorrectLibraries(
- String name, Collection<String> deps, Collection<String> runtimeDeps) throws Exception {
- final String libraryFormat =
- "java/android/%s_processed_manifest/AndroidManifest.xml:" + "java/android/%s.aar";
- writeFile(
- String.format("javatests/android/%s/BUILD", name),
- "android_local_test(name = 'dummyTest',",
- " srcs = ['test.java'],",
- " runtime_deps = [" + createDepArrayString(runtimeDeps) + "],",
- " deps = [" + createDepArrayString(deps) + "])");
- ConfiguredTarget target =
- getConfiguredTarget(String.format("//javatests/android/%s:dummyTest", name));
- assertThat(target).isNotNull();
- RunfilesSupport support = target.getProvider(FilesToRunProvider.class).getRunfilesSupport();
- assertThat(support).isNotNull();
- Artifact deployJar =
- getFileConfiguredTarget(String.format("//javatests/android/%s:dummyTest_deploy.jar", name))
- .getArtifact();
- List<String> deployJarInputs =
- ActionsTestUtil.prettyArtifactNames(getGeneratingAction(deployJar).getInputs());
-
- LinkedHashSet<String> uniqueDeps = new LinkedHashSet<>();
- for (String dep : Iterables.concat(runtimeDeps, deps)) {
- uniqueDeps.add(String.format(libraryFormat, dep, dep));
- assertThat(deployJarInputs).contains("java/android/" + dep + "_resources.jar");
- }
- checkRuntimeSupportInputs(uniqueDeps, support);
- }
-
- protected abstract void checkRuntimeSupportInputs(
- LinkedHashSet<String> uniqueDeps, RunfilesSupport support) throws Exception;
-
- @Test
public void testFeatureFlagsAttributeSetsSelectInDependency() throws Exception {
useConfiguration("--experimental_dynamic_configs=on");
writeFile(
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestTest.java
new file mode 100644
index 0000000000..d100b23808
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLocalTestTest.java
@@ -0,0 +1,116 @@
+// 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;
+package com.google.devtools.build.lib.rules.android;
+
+import static com.google.common.truth.Truth.assertThat;
+
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** A test for android_local_test. */
+@RunWith(JUnit4.class)
+public class AndroidLocalTestTest extends AbstractAndroidLocalTestTest {
+
+ @Test
+ public void testSimpleTestNotNull() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'])");
+ ConfiguredTarget target = getConfiguredTarget("//java/test:dummyTest");
+ assertThat(target).isNotNull();
+ }
+
+ @Test
+ public void testResourceFilesZipCalledResourceFilesZip() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'])");
+ ConfiguredTarget target = getConfiguredTarget("//java/test:dummyTest");
+
+ Artifact resourcesZip =
+ getImplicitOutputArtifact(target, AndroidRuleClasses.ANDROID_RESOURCES_ZIP);
+ assertThat(resourcesZip.getFilename()).isEqualTo("resource_files.zip");
+ }
+
+ @Test
+ public void testManifestInRunfiles() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'])");
+ ConfiguredTarget target = getConfiguredTarget("//java/test:dummyTest");
+ Iterable<Artifact> runfilesArtifacts = collectRunfiles(target);
+ Artifact manifest =
+ ActionsTestUtil.getFirstArtifactEndingWith(
+ runfilesArtifacts, "dummyTest_generated/dummyTest/AndroidManifest.xml");
+ assertThat(manifest).isNotNull();
+ }
+
+ @Test
+ public void testResourcesClassJarInRunfiles() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'])");
+ ConfiguredTarget target = getConfiguredTarget("//java/test:dummyTest");
+ Iterable<Artifact> runfilesArtifacts = collectRunfiles(target);
+ Artifact resourceClassJar =
+ getImplicitOutputArtifact(target, AndroidRuleClasses.ANDROID_RESOURCES_CLASS_JAR);
+ assertThat(runfilesArtifacts).contains(resourceClassJar);
+ }
+
+ @Test
+ public void testResourcesZipFileInRunfiles() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'])");
+ ConfiguredTarget target = getConfiguredTarget("//java/test:dummyTest");
+ Iterable<Artifact> runfilesArtifacts = collectRunfiles(target);
+ Artifact resourcesZip =
+ getImplicitOutputArtifact(target, AndroidRuleClasses.ANDROID_RESOURCES_ZIP);
+ assertThat(runfilesArtifacts).contains(resourcesZip);
+ }
+
+ @Test
+ public void testCanHaveManifestNotNamedAndroidManifestXml() throws Exception {
+ scratch.file(
+ "java/test/BUILD",
+ "android_local_test(name = 'dummyTest',",
+ " srcs = ['test.java'],",
+ " manifest = 'NotAndroidManifest.xml')");
+ assertNoEvents();
+ }
+
+ @Override
+ protected String getRuleName() {
+ return "android_local_test";
+ }
+
+ @Override
+ protected void writeFile(String path, String... lines) throws Exception {
+ scratch.file(path, lines);
+ }
+
+ @Override
+ protected void overwriteFile(String path, String... lines) throws Exception {
+ scratch.overwriteFile(path, lines);
+ }
+}