diff options
Diffstat (limited to 'src/test/java/com/google/devtools/build/lib/rules/android')
6 files changed, 394 insertions, 71 deletions
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java index 888047d871..35f940f6b5 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java @@ -2410,7 +2410,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase { checkError("java/android/resources", "r", "'java/android/resources/res/somefile.xml' is not in the expected resource directory " + "structure of <resource directory>/{" - + Joiner.on(',').join(LocalResourceContainer.Builder.RESOURCE_DIRECTORY_TYPES) + "}", + + Joiner.on(',').join(LocalResourceContainer.RESOURCE_DIRECTORY_TYPES) + "}", "android_binary(name = 'r',", " manifest = 'AndroidManifest.xml',", " resource_files = ['res/somefile.xml', 'r/t/f/m/raw/fold']", @@ -2424,7 +2424,7 @@ public class AndroidBinaryTest extends AndroidBuildViewTestCase { "r", "'java/android/resources/res/other/somefile.xml' is not in the expected resource directory " + "structure of <resource directory>/{" - + Joiner.on(',').join(LocalResourceContainer.Builder.RESOURCE_DIRECTORY_TYPES) + "}", + + Joiner.on(',').join(LocalResourceContainer.RESOURCE_DIRECTORY_TYPES) + "}", "android_binary(name = 'r',", " manifest = 'AndroidManifest.xml',", " resource_files = ['res/other/somefile.xml', 'r/t/f/m/raw/fold']", diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java index ab4a1c1eac..b8298e2ea9 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidLibraryTest.java @@ -822,7 +822,7 @@ public class AndroidLibraryTest extends AndroidBuildViewTestCase { 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) + "}", + + Joiner.on(',').join(LocalResourceContainer.RESOURCE_DIRECTORY_TYPES) + "}", "android_library(name = 'r',", " manifest = 'AndroidManifest.xml',", " resource_files = ['res/somefile.xml', 'r/t/f/m/raw/fold']", @@ -834,7 +834,7 @@ public class AndroidLibraryTest extends AndroidBuildViewTestCase { 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) + "}", + + Joiner.on(',').join(LocalResourceContainer.RESOURCE_DIRECTORY_TYPES) + "}", "android_library(name = 'r',", " manifest = 'AndroidManifest.xml',", " resource_files = ['res/other/somefile.xml', 'r/t/f/m/raw/fold']", diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/BUILD b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD index 96e6b301fe..c011cde25e 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/BUILD +++ b/src/test/java/com/google/devtools/build/lib/rules/android/BUILD @@ -77,6 +77,48 @@ java_test( ) java_test( + name = "ResourceFilterTest", + srcs = ["ResourceFilterTest.java"], + deps = [ + ":ResourceTestBase", + "//src/main/java/com/google/devtools/build/lib:android-rules", + "//src/main/java/com/google/devtools/build/lib/actions", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + ], +) + +java_test( + name = "LocalResourceContainerTest", + srcs = ["LocalResourceContainerTest.java"], + deps = [ + ":ResourceTestBase", + "//src/main/java/com/google/devtools/build/lib:android-rules", + "//src/main/java/com/google/devtools/build/lib:packages-internal", + "//src/main/java/com/google/devtools/build/lib:vfs", + "//src/main/java/com/google/devtools/build/lib/actions", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + ], +) + +java_library( + name = "ResourceTestBase", + srcs = ["ResourceTestBase.java"], + deps = [ + "//src/main/java/com/google/devtools/build/lib:inmemoryfs", + "//src/main/java/com/google/devtools/build/lib:packages-internal", + "//src/main/java/com/google/devtools/build/lib:vfs", + "//src/main/java/com/google/devtools/build/lib/actions", + "//third_party:guava", + "//third_party:junit4", + "//third_party:truth", + ], +) + +java_test( name = "AndroidDeviceScriptFixtureTest", srcs = ["AndroidDeviceScriptFixtureTest.java"], deps = [ diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/LocalResourceContainerTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/LocalResourceContainerTest.java new file mode 100644 index 0000000000..6f397bf5fb --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/android/LocalResourceContainerTest.java @@ -0,0 +1,172 @@ +// 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.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException; +import com.google.devtools.build.lib.packages.RuleErrorConsumer; +import com.google.devtools.build.lib.vfs.PathFragment; +import java.util.Map; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Tests {@link LocalResourceContainer} */ +@RunWith(JUnit4.class) +public class LocalResourceContainerTest extends ResourceTestBase { + private static final PathFragment DEFAULT_RESOURCE_ROOT = PathFragment.create(RESOURCE_ROOT); + private static final ImmutableList<PathFragment> RESOURCES_ROOTS = + ImmutableList.of(DEFAULT_RESOURCE_ROOT); + + @Before + @Test + public void testGetResourceRootsNoResources() throws Exception { + assertThat(getResourceRoots()).isEmpty(); + } + + @Test + public void testGetResourceRootsInvalidResourceDirectory() throws Exception { + try { + getResourceRoots("is-this-drawable-or-values/foo.xml"); + assertWithMessage("Expected exception not thrown!").fail(); + } catch (RuleErrorException e) { + // expected + } + + errorConsumer.assertAttributeError( + "resources", "is not in the expected resource directory structure"); + } + + @Test + public void testGetResourceRootsMultipleRoots() throws Exception { + try { + getResourceRoots("subdir/values/foo.xml", "otherdir/values/bar.xml"); + assertWithMessage("Expected exception not thrown!").fail(); + } catch (RuleErrorException e) { + // expected + } + + errorConsumer.assertAttributeError( + "resources", "All resources must share a common directory"); + } + + @Test + public void testGetResourceRoots() throws Exception { + assertThat(getResourceRoots("values-hdpi/foo.xml", "values-mdpi/bar.xml")) + .isEqualTo(RESOURCES_ROOTS); + } + + @Test + public void testGetResourceRootsCommonSubdirectory() throws Exception { + assertThat(getResourceRoots("subdir/values-hdpi/foo.xml", "subdir/values-mdpi/bar.xml")) + .containsExactly(DEFAULT_RESOURCE_ROOT.getRelative("subdir")); + } + + private ImmutableList<PathFragment> getResourceRoots(String... pathResourceStrings) + throws Exception { + return getResourceRoots(getResources(pathResourceStrings)); + } + + private ImmutableList<PathFragment> getResourceRoots(ImmutableList<Artifact> artifacts) + throws Exception { + return LocalResourceContainer.getResourceRoots(errorConsumer, artifacts); + } + + @Test + public void testFilterEmpty() throws Exception { + assertFilter(ImmutableList.<Artifact>of(), ImmutableList.<Artifact>of()); + } + + @Test + public void testFilterNoop() throws Exception { + ImmutableList<Artifact> resources = getResources("values-en/foo.xml", "values-es/bar.xml"); + assertFilter(resources, resources); + } + + @Test + public void testFilterToEmpty() throws Exception { + assertFilter( + getResources("values-en/foo.xml", "values-es/bar.xml"), ImmutableList.<Artifact>of()); + } + + @Test + public void testPartiallyFilter() throws Exception { + Artifact keptResource = getResource("values-en/foo.xml"); + assertFilter( + ImmutableList.of(keptResource, getResource("values-es/bar.xml")), + ImmutableList.of(keptResource)); + } + + private void assertFilter( + ImmutableList<Artifact> unfilteredResources, ImmutableList<Artifact> filteredResources) + throws Exception { + ResourceFilter filter = + new FakeResourceFilter(ImmutableMap.of(unfilteredResources, filteredResources)); + ImmutableList<PathFragment> unfilteredResourcesRoots = getResourceRoots(unfilteredResources); + LocalResourceContainer unfiltered = + new LocalResourceContainer( + unfilteredResources, + unfilteredResourcesRoots, + unfilteredResources, + unfilteredResourcesRoots); + + LocalResourceContainer filtered = unfiltered.filter(errorConsumer, filter); + + if (unfilteredResources.equals(filteredResources)) { + // The filtering was a no-op; the original object, not a copy, should be returned + assertThat(filtered).isSameAs(unfiltered); + } else { + // The resources and their roots should be filtered + assertThat(filtered.getResources()).containsExactlyElementsIn(filteredResources).inOrder(); + assertThat(filtered.getResourceRoots()) + .containsExactlyElementsIn(getResourceRoots(filteredResources)) + .inOrder(); + + // The assets and their roots should not be filtered; the original objects, not a copy, should + // be returned. + assertThat(filtered.getAssets()).isSameAs(unfiltered.getAssets()); + assertThat(filtered.getAssetRoots()).isSameAs(unfiltered.getAssetRoots()); + } + } + + private static class FakeResourceFilter extends ResourceFilter { + private final Map<ImmutableList<Artifact>, ImmutableList<Artifact>> filterInputToOutputMap; + + FakeResourceFilter( + Map<ImmutableList<Artifact>, ImmutableList<Artifact>> filterInputToOutputMap) { + super( + ImmutableList.<String>of(), + ImmutableList.<String>of(), + FilterBehavior.FILTER_IN_ANALYSIS); + this.filterInputToOutputMap = filterInputToOutputMap; + } + + @Override + public ImmutableList<Artifact> filter( + RuleErrorConsumer errorConsumer, ImmutableList<Artifact> artifacts) { + if (filterInputToOutputMap.containsKey(artifacts)) { + return filterInputToOutputMap.get(artifacts); + } + + assertWithMessage("Called with unexpected input: " + artifacts).fail(); + return artifacts; + } + } +} diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterTest.java index 8dbb18df72..b7aaf7d1d0 100644 --- a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterTest.java +++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceFilterTest.java @@ -14,22 +14,13 @@ package com.google.devtools.build.lib.rules.android; import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.Truth.assertWithMessage; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import com.google.common.collect.Multimap; import com.google.devtools.build.lib.actions.Artifact; -import com.google.devtools.build.lib.actions.Root; -import com.google.devtools.build.lib.packages.RuleErrorConsumer; import com.google.devtools.build.lib.rules.android.ResourceFilter.FilterBehavior; -import com.google.devtools.build.lib.vfs.FileSystem; -import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @@ -38,53 +29,7 @@ import org.junit.runners.JUnit4; // TODO(asteinb): Test behavior not already covered in this test, and, when practical, move unit // tests currently located in {@link AndroidBinaryTest} to this class instead. @RunWith(JUnit4.class) -public class ResourceFilterTest { - private FakeRuleErrorConsumer errorConsumer; - - @Before - public void setup() { - errorConsumer = new FakeRuleErrorConsumer(); - } - - private static final class FakeRuleErrorConsumer implements RuleErrorConsumer { - // Use an ArrayListMultimap since it allows duplicates - we'll want to know if a warning is - // reported twice. - private final Multimap<String, String> attributeWarnings = ArrayListMultimap.create(); - - @Override - public void ruleWarning(String message) {} - - @Override - public void ruleError(String message) { - assertWithMessage(message).fail(); - } - - @Override - public void attributeWarning(String attrName, String message) { - attributeWarnings.put(attrName, message); - } - - @Override - public void attributeError(String attrName, String message) { - assertWithMessage(message + " (attribute: " + attrName + ")").fail(); - } - - public Collection<String> getAndClearAttributeWarnings(String attrName) { - if (!attributeWarnings.containsKey(attrName)) { - return ImmutableList.of(); - } - - return attributeWarnings.removeAll(attrName); - } - - public void assertNoAttributeWarnings(String attrName) { - assertThat(attributeWarnings).doesNotContainKey(attrName); - } - }; - - private static final FileSystem FILE_SYSTEM = new InMemoryFileSystem(); - private static final Root ROOT = Root.asSourceRoot(FILE_SYSTEM.getRootDirectory()); - +public class ResourceFilterTest extends ResourceTestBase { @Test public void testFilterInExecution() { testNoopFilter( @@ -98,10 +43,10 @@ public class ResourceFilterTest { @Test public void testFilterEmpty() { testNoopFilter( - ImmutableList.of(), - ImmutableList.of(), + ImmutableList.<String>of(), + ImmutableList.<String>of(), FilterBehavior.FILTER_IN_ANALYSIS, - ImmutableList.of()); + ImmutableList.<String>of()); } @Test @@ -128,7 +73,7 @@ public class ResourceFilterTest { @Test public void testFilterByDensityPersistsOrdering() { testFilter( - ImmutableList.of(), + ImmutableList.<String>of(), ImmutableList.of("hdpi", "ldpi"), FilterBehavior.FILTER_IN_ANALYSIS, // If we add resources to the output list in density order, these resources will be @@ -306,7 +251,11 @@ public class ResourceFilterTest { FilterBehavior filterBehavior, List<String> resources) { testFilter( - resourceConfigurationFilters, densities, filterBehavior, resources, ImmutableList.of()); + resourceConfigurationFilters, + densities, + filterBehavior, + resources, + ImmutableList.<String>of()); } private void testFilter( @@ -317,12 +266,12 @@ public class ResourceFilterTest { List<String> resourcesToDiscard) { List<Artifact> unexpectedResources = new ArrayList<>(); for (String resource : resourcesToDiscard) { - unexpectedResources.add(getArtifact(resource)); + unexpectedResources.add(getResource(resource)); } List<Artifact> expectedResources = new ArrayList<>(); for (String resource : resourcesToKeep) { - expectedResources.add(getArtifact(resource)); + expectedResources.add(getResource(resource)); } ImmutableList<Artifact> allArtifacts = @@ -333,8 +282,4 @@ public class ResourceFilterTest { assertThat(filtered).containsExactlyElementsIn(expectedResources).inOrder(); } - - private static Artifact getArtifact(String pathString) { - return new Artifact(FILE_SYSTEM.getPath("/java/android/res/" + pathString), ROOT); - } } diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java new file mode 100644 index 0000000000..cada5518d9 --- /dev/null +++ b/src/test/java/com/google/devtools/build/lib/rules/android/ResourceTestBase.java @@ -0,0 +1,164 @@ +// 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.truth.Truth.assertThat; +import static com.google.common.truth.Truth.assertWithMessage; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Multimap; +import com.google.devtools.build.lib.actions.Artifact; +import com.google.devtools.build.lib.actions.ArtifactOwner; +import com.google.devtools.build.lib.actions.Root; +import com.google.devtools.build.lib.cmdline.Label; +import com.google.devtools.build.lib.cmdline.LabelSyntaxException; +import com.google.devtools.build.lib.packages.RuleErrorConsumer; +import com.google.devtools.build.lib.vfs.FileSystem; +import com.google.devtools.build.lib.vfs.Path; +import com.google.devtools.build.lib.vfs.inmemoryfs.InMemoryFileSystem; +import java.util.Collection; +import org.junit.After; +import org.junit.Before; + +/** Base class for tests that work with resource artifacts. */ +public abstract class ResourceTestBase { + public static final String RESOURCE_ROOT = "java/android/res"; + + private static final ArtifactOwner OWNER = () -> { + try { + return Label.create("java", "all"); + } catch (LabelSyntaxException e) { + assertWithMessage(e.getMessage()).fail(); + return null; + } + }; + + /** A faked {@link RuleErrorConsumer} that validates that only expected errors were reported. */ + public static final class FakeRuleErrorConsumer implements RuleErrorConsumer { + private String ruleErrorMessage = null; + private String attributeErrorAttribute = null; + private String attributeErrorMessage = null; + + // Use an ArrayListMultimap since it allows duplicates - we'll want to know if a warning is + // reported twice. + private final Multimap<String, String> attributeWarnings = ArrayListMultimap.create(); + + @Override + public void ruleWarning(String message) {} + + @Override + public void ruleError(String message) { + ruleErrorMessage = message; + } + + @Override + public void attributeWarning(String attrName, String message) { + attributeWarnings.put(attrName, message); + } + + @Override + public void attributeError(String attrName, String message) { + attributeErrorAttribute = attrName; + attributeErrorMessage = message; + } + + public Collection<String> getAndClearAttributeWarnings(String attrName) { + if (!attributeWarnings.containsKey(attrName)) { + return ImmutableList.of(); + } + + return attributeWarnings.removeAll(attrName); + } + + public void assertNoAttributeWarnings(String attrName) { + assertThat(attributeWarnings).doesNotContainKey(attrName); + } + + /** + * Called at the end of a test to assert that that test produced a rule error + * + * @param expectedMessage a substring of the expected message + */ + public void assertRuleError(String expectedMessage) { + // Clear the message before asserting so that if we fail here the error is not masked by the + // @After call to assertNoUnexpectedErrors. + + String message = ruleErrorMessage; + ruleErrorMessage = null; + + assertThat(message).contains(expectedMessage); + } + + /** + * Called at the end of a test to assert that that test produced an attribute error + * + * @param expectedAttribute the attribute that caused the error + * @param expectedMessage a substring of the expected message + */ + public void assertAttributeError(String expectedAttribute, String expectedMessage) { + // Clear the message before asserting so that if we fail here the error is not masked by the + // @After call to assertNoUnexpectedErrors. + String attr = attributeErrorAttribute; + String message = attributeErrorMessage; + attributeErrorAttribute = null; + attributeErrorMessage = null; + + assertThat(message).contains(expectedMessage); + assertThat(attr).isEqualTo(expectedAttribute); + } + + /** + * Asserts this {@link RuleErrorConsumer} encountered no unexpected errors. To consume an + * expected error, call {@link #assertRuleError(String)} or {@link #assertAttributeError(String, + * String)} in your test after the error is produced. + */ + private void assertNoUnexpectedErrors() { + assertThat(ruleErrorMessage).isNull(); + assertThat(attributeErrorMessage).isNull(); + assertThat(attributeErrorAttribute).isNull(); + } + }; + + public FakeRuleErrorConsumer errorConsumer; + public FileSystem fileSystem; + public Root root; + + @Before + public void setup() { + errorConsumer = new FakeRuleErrorConsumer(); + fileSystem = new InMemoryFileSystem(); + root = Root.asDerivedRoot(fileSystem.getRootDirectory()); + } + + @After + public void assertNoErrors() { + errorConsumer.assertNoUnexpectedErrors(); + } + + public ImmutableList<Artifact> getResources(String... pathStrings) { + ImmutableList.Builder<Artifact> builder = ImmutableList.builder(); + for (String pathString : pathStrings) { + builder.add(getResource(pathString)); + } + + return builder.build(); + } + + public Artifact getResource(String pathString) { + Path path = fileSystem.getPath("/" + RESOURCE_ROOT + "/" + pathString); + return new Artifact( + path, root, root.getExecPath().getRelative(path.relativeTo(root.getPath())), OWNER); + } +} |