blob: 7564c5d376b11fd83503c3503e11ebb3eb815a92 [file] [log] [blame]
// 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 com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.truth.BooleanSubject;
import com.google.devtools.build.lib.actions.Artifact;
import com.google.devtools.build.lib.analysis.config.BuildOptions;
import com.google.devtools.build.lib.analysis.config.transitions.PatchTransition;
import com.google.devtools.build.lib.cmdline.Label;
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.packages.AttributeMap;
import com.google.devtools.build.lib.packages.RuleClass.ConfiguredTargetFactory.RuleErrorException;
import com.google.devtools.build.lib.rules.android.ResourceFilterFactory.AddDynamicallyConfiguredResourceFilteringTransition;
import com.google.devtools.build.lib.rules.android.ResourceFilterFactory.FilterBehavior;
import com.google.devtools.build.lib.testutil.FakeAttributeMapper;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests {@link ResourceFilterFactory}. */
// 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 ResourceFilterFactoryTest extends ResourceTestBase {
private NestedSet<ResourceContainer> getResourceContainers(ImmutableList<Artifact>... resources)
throws Exception {
NestedSetBuilder<ResourceContainer> builder = NestedSetBuilder.naiveLinkOrder();
for (ImmutableList<Artifact> resourceList : resources) {
builder.add(getResourceContainer(resourceList));
}
return builder.build();
}
private ResourceContainer getResourceContainer(ImmutableList<Artifact> resources)
throws Exception {
// Get dummy objects for irrelevant values required by the builder.
Artifact manifest = getResource("manifest");
// Include a hashCode of the resources in the label. A hack in ResourceContainer currently means
// that class has a limited hashCode method that doesn't take resources into account.
// TODO(bazel-team): Remove this hack once that one no longer exists.
Label label =
Label.create(
manifest.getOwnerLabel().getPackageName(), "resourceContainer_" + resources.hashCode());
return ResourceContainer.builder()
.setResources(resources)
.setResourcesRoots(
LocalResourceContainer.getResourceRoots(errorConsumer, resources, "resource_files"))
.setLabel(label)
.setManifestExported(false)
.setManifest(manifest)
.build();
}
@Test
public void testFilterInExecution() throws Exception {
testNoopFilter(
"en",
"hdpi",
FilterBehavior.FILTER_IN_EXECUTION,
ImmutableList.of(
"values-en/foo.xml", "values/foo.xml", "values-hdpi/foo.png", "values-ldpi/foo.png"));
}
@Test
public void testFilterEmpty() throws Exception {
testNoopFilter("", "", FilterBehavior.FILTER_IN_ANALYSIS, ImmutableList.<String>of());
}
@Test
public void testFilterDefaultAndNonDefault() throws Exception {
testNoopFilter(
"en",
"xhdpi,xxhdpi",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("drawable/ic_clear.xml", "drawable-v21/ic_clear.xml"));
}
/**
* Tests that version qualifiers are ignored for both resource qualifier and density filtering.
*/
@Test
public void testFilterVersionIgnored() throws Exception {
testNoopFilter(
"v4",
"hdpi",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("drawable-hdpi-v4/foo.png", "drawable-hdpi-v11/foo.png"));
}
@Test
public void testFilterByDensityPersistsOrdering() throws Exception {
testFilter(
"",
"hdpi,ldpi",
FilterBehavior.FILTER_IN_ANALYSIS,
// If we add resources to the output list in density order, these resources will be
// rearranged.
ImmutableList.of(
"drawable-hdpi/foo.png",
"drawable-ldpi/foo.png",
"drawable-ldpi/bar.png",
"drawable-hdpi/bar.png"),
// Filter out some resources to make sure the original list isn't just returned because the
// filtering was a no-op.
ImmutableList.of("drawable-mdpi/foo.png", "drawable-mdpi/bar.png"));
}
/** Tests handling of Aapt's old region format */
@Test
public void testFilterOldLanguageFormat() throws Exception {
testFilter(
"en_US",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("values-en/foo.xml", "values-en-rUS/foo.xml"),
ImmutableList.of("values-fr/foo.xml", "values-en-rCA/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterOldLanguageFormatWithAdditionalQualifiers() throws Exception {
testFilter(
"en_US-ldrtl",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("values-en/foo.xml", "values-en-rUS/foo.xml"),
ImmutableList.of("values-fr/foo.xml", "values-en-rCA/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterOldLanguageFormatWithMcc() throws Exception {
testFilter(
"mcc111-en_US",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("values-en/foo.xml", "values-en-rUS/foo.xml"),
ImmutableList.of("values-fr/foo.xml", "values-en-rCA/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterOldLanguageFormatWithMccAndMnc() throws Exception {
testFilter(
"mcc111-mnc111-en_US",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("values-en/foo.xml", "values-en-rUS/foo.xml"),
ImmutableList.of("values-fr/foo.xml", "values-en-rCA/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterSerbianLatinCharacters() throws Exception {
testFilter(
"sr-Latn,sr-rLatn,sr_Latn,b+sr+Latn",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of(
"values-sr/foo.xml",
"values-b+sr+Latn/foo.xml",
"values-sr-Latn/foo.xml",
"values-sr-rLatn/foo.xml"),
// Serbian in explicitly Cyrillic characters should be filtered out.
ImmutableList.of("values-b+sr+Cyrl/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterSerbianCharactersNotSpecified() throws Exception {
testNoopFilter(
"sr",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of(
"values-sr/foo.xml",
"values-b+sr+Latn/foo.xml",
"values-b+sr+Cyrl/foo.xml",
"values-sr-Latn/foo.xml",
"values-sr-rLatn/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterSpanishLatinAmericaAndCaribbean() throws Exception {
testFilter(
"es-419,es_419,b+es+419",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of("values-es/foo.xml", "values-b+es+419/foo.xml", "values-es-419/foo.xml"),
// Spanish with another region specified should be filtered out.
ImmutableList.of("values-es-rUS/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterSpanishRegionNotSpecified() throws Exception {
testNoopFilter(
"es",
"",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of(
"values-es/foo.xml",
"values-b+es+419/foo.xml",
"values-es-rUS/foo.xml",
"values-es-419/foo.xml"));
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterDeprecatedQualifierFormatsRuleWarnings() throws RuleErrorException {
ImmutableList<Artifact> badResources =
getResources(
"values-es_US/foo.xml",
"drawable-sr-Latn/foo.xml",
"layout-es-419/foo.xml",
"values-mcc310-es_US/foo.xml",
"values-sr_rLatn/foo.xml",
"drawable-es_419/foo.xml");
ImmutableList<String> expectedWarnings =
ImmutableList.of(
"For resource folder drawable-sr-Latn, when referring to Serbian in Latin characters, "
+ "use of qualifier 'sr-Latn' is deprecated. Use 'b+sr+Latn' instead.",
"For resource folder layout-es-419, when referring to Spanish for Latin America and "
+ "the Caribbean, use of qualifier 'es-419' is deprecated. Use 'b+es+419' instead.",
"For resource folder values-es_US, when referring to locale qualifiers with regions, "
+ "use of qualifier 'es_US' is deprecated. Use 'es-rUS' instead.");
ResourceFilterFactory filter =
new ResourceFilterFactory(
ImmutableList.of("en"), ImmutableList.of(), FilterBehavior.FILTER_IN_ANALYSIS);
doFilter(filter, badResources);
assertThat(errorConsumer.getAndClearRuleWarnings()).containsExactlyElementsIn(expectedWarnings);
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
// Filtering again with this filter should not produce additional warnings
doFilter(filter, badResources);
errorConsumer.assertNoRuleWarnings();
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
// Filtering with a new filter should produce warnings again, since it is working on a different
// target
filter =
new ResourceFilterFactory(
ImmutableList.of("en"), ImmutableList.of(), FilterBehavior.FILTER_IN_ANALYSIS);
doFilter(filter, badResources);
assertThat(errorConsumer.getAndClearRuleWarnings()).containsExactlyElementsIn(expectedWarnings);
errorConsumer.assertNoAttributeWarnings(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME);
}
@Test
public void testFilterResourceConflict() throws Exception {
testNoopFilter(
"en",
"hdpi",
FilterBehavior.FILTER_IN_ANALYSIS,
ImmutableList.of(
"first-subdir/res/drawable-en-hdpi/foo.png",
"second-subdir/res/drawable-en-hdpi/foo.png"));
}
@Test
public void testFilterWithDynamicConfiguration() throws Exception {
testFilter(
"en",
"hdpi",
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION,
ImmutableList.of("drawable-en-hdpi/foo.png"),
ImmutableList.of("drawable-en-ldpi/foo.png", "drawable-fr-hdpi/foo.png"));
}
private void testNoopFilter(
String resourceConfigurationFilters,
String densities,
FilterBehavior filterBehavior,
List<String> resources)
throws Exception {
testFilter(
resourceConfigurationFilters,
densities,
filterBehavior,
resources,
ImmutableList.<String>of());
}
private void testFilter(
String resourceConfigurationFilters,
String densities,
FilterBehavior filterBehavior,
List<String> resourcesToKeep,
List<String> resourcesToDiscard)
throws Exception {
List<Artifact> unexpectedResources = new ArrayList<>();
for (String resource : resourcesToDiscard) {
unexpectedResources.add(getResource(resource));
}
List<Artifact> expectedResources = new ArrayList<>();
for (String resource : resourcesToKeep) {
expectedResources.add(getResource(resource));
}
ImmutableList<Artifact> allArtifacts =
ImmutableList.copyOf(Iterables.concat(expectedResources, unexpectedResources));
ResourceFilterFactory resourceFilterFactory =
makeResourceFilter(resourceConfigurationFilters, densities, filterBehavior);
ImmutableList<Artifact> filtered = doFilter(resourceFilterFactory, allArtifacts);
assertThat(filtered).containsExactlyElementsIn(expectedResources).inOrder();
// Only dependencies need to be tracked for ignoring in execution
assertThat(resourceFilterFactory.getResourcesToIgnoreInExecution()).isEmpty();
}
@Test
public void testFilterLocalAndTransitive() throws Exception {
Artifact localResourceToKeep = getResource("drawable-en-hdpi/local.png");
Artifact localResourceToDiscard = getResource("drawable-en-ldpi/local.png");
// These resources go in different ResourceContainers to ensure we are filter across all
// resources.
Artifact directResourceToKeep = getResource("direct/drawable-en-hdpi/direct.png");
Artifact directResourceToDiscard = getResource("direct/drawable-en-ldpi/direct.png");
Artifact transitiveResourceToKeep = getResource("transitive/drawable-en-hdpi/transitive.png");
Artifact transitiveResourceToDiscard =
getResource("transitive/drawable-en-ldpi/transitive.png");
LocalResourceContainer localResources =
LocalResourceContainer.forResources(
errorConsumer, ImmutableList.of(localResourceToKeep, localResourceToDiscard));
ResourceDependencies resourceDependencies =
ResourceDependencies.empty()
.withResources(
getResourceContainers(
ImmutableList.of(transitiveResourceToDiscard),
ImmutableList.of(transitiveResourceToKeep)),
getResourceContainers(
ImmutableList.of(directResourceToDiscard),
ImmutableList.of(directResourceToKeep)),
new NestedSetBuilder<Artifact>(Order.NAIVE_LINK_ORDER)
.add(directResourceToDiscard)
.add(directResourceToKeep)
.addTransitive(
NestedSetBuilder.create(
Order.NAIVE_LINK_ORDER,
transitiveResourceToDiscard,
transitiveResourceToKeep))
.build());
ResourceFilterFactory resourceFilterFactory =
makeResourceFilter("en", "hdpi", FilterBehavior.FILTER_IN_ANALYSIS);
ResourceFilter filter =
resourceFilterFactory.getResourceFilter(
errorConsumer, resourceDependencies, localResources);
assertThat(localResources.filter(errorConsumer, filter).getResources())
.containsExactly(localResourceToKeep);
ResourceDependencies filteredResourceDeps = resourceDependencies.filter(filter);
// TODO: Remove - assert was same order before
assertThat(resourceDependencies.getTransitiveResources())
.containsAllOf(directResourceToKeep, transitiveResourceToKeep)
.inOrder();
assertThat(filteredResourceDeps.getTransitiveResources())
.containsExactly(directResourceToKeep, transitiveResourceToKeep)
.inOrder();
List<ResourceContainer> directContainers =
filteredResourceDeps.getDirectResourceContainers().toList();
assertThat(directContainers).hasSize(2);
ResourceContainer directToDiscard = directContainers.get(0);
assertThat(directToDiscard.getResources()).isEmpty();
assertThat(directToDiscard.getResourcesRoots()).isEmpty();
ResourceContainer directToKeep = directContainers.get(1);
assertThat(directToKeep.getResources()).containsExactly(directResourceToKeep);
assertThat(directToKeep.getResourcesRoots())
.containsExactly(
directResourceToKeep.getExecPath().getParentDirectory().getParentDirectory());
List<ResourceContainer> transitiveContainers =
filteredResourceDeps.getTransitiveResourceContainers().toList();
assertThat(transitiveContainers).hasSize(2);
ResourceContainer transitiveToDiscard = transitiveContainers.get(0);
assertThat(transitiveToDiscard.getResources()).isEmpty();
assertThat(transitiveToDiscard.getResourcesRoots()).isEmpty();
ResourceContainer transitiveToKeep = transitiveContainers.get(1);
assertThat(transitiveToKeep.getResources()).containsExactly(transitiveResourceToKeep);
assertThat(transitiveToKeep.getResourcesRoots())
.containsExactly(
transitiveResourceToKeep.getExecPath().getParentDirectory().getParentDirectory());
// We tell the resource processing actions to ignore references to filtered resources from
// dependencies.
assertThat(resourceFilterFactory.getResourcesToIgnoreInExecution())
.containsExactly("drawable-en-ldpi/direct.png", "drawable-en-ldpi/transitive.png");
}
@Test
public void testIsPrefilteringFilterInExecution() throws Exception {
assertIsPrefiltering(FilterBehavior.FILTER_IN_EXECUTION, false);
}
@Test
public void testIsPrefilteringFilterInAnalysis() throws Exception {
assertIsPrefiltering(FilterBehavior.FILTER_IN_ANALYSIS, true);
}
@Test
public void testIsPrefilteringFilterInAnalysisWithDynamicConfiguration() throws Exception {
assertIsPrefiltering(FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION, true);
}
private void assertIsPrefiltering(FilterBehavior behavior, boolean expectWhenNonEmpty)
throws Exception {
// Empty filters should never prefilter
assertIsPrefiltering(false, false, behavior).isFalse();
// Prefiltering behavior should be the same regardless of which setting is set
assertIsPrefiltering(true, false, behavior).isEqualTo(expectWhenNonEmpty);
assertIsPrefiltering(false, true, behavior).isEqualTo(expectWhenNonEmpty);
assertIsPrefiltering(true, true, behavior).isEqualTo(expectWhenNonEmpty);
}
private BooleanSubject assertIsPrefiltering(
boolean hasConfigurationFilters, boolean hasDensities, FilterBehavior behavior)
throws Exception {
return assertThat(
makeResourceFilter(
hasConfigurationFilters ? "en" : "", hasDensities ? "hdpi" : "", behavior)
.isPrefiltering());
}
@Test
public void testGetOutputDirectorySuffixEmpty() throws Exception {
assertThat(
makeResourceFilter("", "", FilterBehavior.FILTER_IN_ANALYSIS)
.getOutputDirectorySuffix())
.isNull();
}
@Test
public void testGetOutputDirectoryOnlyFilterConfigurations() throws Exception {
String configurationFilters = "en,es-rUS,fr";
assertThat(
makeResourceFilter(configurationFilters, "", FilterBehavior.FILTER_IN_ANALYSIS)
.getOutputDirectorySuffix())
.isEqualTo(configurationFilters + "_");
}
@Test
public void testGetOutputDirectoryOnlyDensities() throws Exception {
String densities = "hdpi,ldpi,xhdpi";
assertThat(
makeResourceFilter("", densities, FilterBehavior.FILTER_IN_ANALYSIS)
.getOutputDirectorySuffix())
.isEqualTo("_" + densities);
}
/**
* Only densities is a legal (if unhelpful) resource_configuration_filters settings. Ensure it
* produces a different output directory than a similar densities value.
*/
@Test
public void testGetOutputDirectoryDensitiesAreDifferentFromDensityConfigurationFilters()
throws Exception {
ResourceFilterFactory configurationFilter =
makeResourceFilter("hdpi", "", FilterBehavior.FILTER_IN_ANALYSIS);
ResourceFilterFactory densityFilter =
makeResourceFilter("", "hdpi", FilterBehavior.FILTER_IN_ANALYSIS);
assertThat(configurationFilter.getOutputDirectorySuffix())
.isNotEqualTo(densityFilter.getOutputDirectorySuffix());
}
@Test
public void testGetOutputDirectory() throws Exception {
assertThat(
makeResourceFilter("en,fr-rCA", "hdpi,ldpi", FilterBehavior.FILTER_IN_ANALYSIS)
.getOutputDirectorySuffix())
.isEqualTo("en,fr-rCA_hdpi,ldpi");
}
/**
* Asserts that identical but differently ordered arguments still produce the same output
* directory. If filters are identical, there's no reason to rebuild.
*/
@Test
public void testGetOutputDirectoryDifferentlyOrdered() throws Exception {
ResourceFilterFactory first =
makeResourceFilter("en,fr", "hdpi,ldpi", FilterBehavior.FILTER_IN_ANALYSIS);
ResourceFilterFactory second =
makeResourceFilter("fr,en", "ldpi,hdpi", FilterBehavior.FILTER_IN_ANALYSIS);
assertThat(first.getOutputDirectorySuffix()).isEqualTo(second.getOutputDirectorySuffix());
}
@Test
public void testGetOutputDirectoryDuplicated() throws Exception {
ResourceFilterFactory duplicated =
makeResourceFilter("en,en", "hdpi,hdpi", FilterBehavior.FILTER_IN_ANALYSIS);
ResourceFilterFactory normal =
makeResourceFilter("en", "hdpi", FilterBehavior.FILTER_IN_ANALYSIS);
assertThat(duplicated.getOutputDirectorySuffix()).isEqualTo(normal.getOutputDirectorySuffix());
}
private ResourceFilterFactory makeResourceFilter(
String resourceConfigurationFilters, String densities, FilterBehavior behavior)
throws Exception {
return makeResourceFilter(
ImmutableList.of(resourceConfigurationFilters), ImmutableList.of(densities), behavior);
}
private ResourceFilterFactory makeResourceFilter(
ImmutableList<String> resourceConfigurationFilters,
ImmutableList<String> densities,
FilterBehavior behavior)
throws Exception {
return ResourceFilterFactory.forBaseAndAttrs(
ResourceFilterFactory.empty(behavior),
getAttributeMap(resourceConfigurationFilters, densities));
}
private AttributeMap getAttributeMap(
ImmutableList<String> resourceConfigurationFilters, ImmutableList<String> densities) {
return FakeAttributeMapper.builder()
.withStringList(
ResourceFilterFactory.RESOURCE_CONFIGURATION_FILTERS_NAME, resourceConfigurationFilters)
.withStringList(ResourceFilterFactory.DENSITIES_NAME, densities)
.build();
}
private ImmutableList<Artifact> doFilter(
ResourceFilterFactory resourceFilterFactory, ImmutableList<Artifact> artifacts)
throws RuleErrorException {
LocalResourceContainer localResourceContainer =
LocalResourceContainer.forResources(errorConsumer, artifacts);
ResourceDependencies resourceDeps = ResourceDependencies.empty();
ResourceFilter filter =
resourceFilterFactory.getResourceFilter(
errorConsumer, resourceDeps, localResourceContainer);
assertThat(resourceDeps.filter(filter)).isSameAs(resourceDeps);
return localResourceContainer.filter(errorConsumer, filter).getResources();
}
@Test
public void testWithAttrsFromAttrsNotSpecified() throws Exception {
assertThat(
ResourceFilterFactory.forBaseAndAttrs(
ResourceFilterFactory.empty(FilterBehavior.FILTER_IN_ANALYSIS),
FakeAttributeMapper.empty())
.hasFilters())
.isFalse();
}
@Test
public void testGetTopLevelTransitionFilterInExecution() throws Exception {
assertThat(
getTopLevelTransition(
ImmutableList.of("en"),
ImmutableList.of("hdpi"),
FilterBehavior.FILTER_IN_EXECUTION,
true))
.isNull();
}
@Test
public void testGetTopLevelTransitionFilterInAnalysis() throws Exception {
assertThat(
getTopLevelTransition(
ImmutableList.of("en"),
ImmutableList.of("hdpi"),
FilterBehavior.FILTER_IN_ANALYSIS,
true))
.isNull();
}
@Test
public void testGetTopLevelTransitionNotBinary() throws Exception {
assertThat(
getTopLevelTransition(
ImmutableList.of("en"),
ImmutableList.of("hdpi"),
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION,
false))
.isSameAs(
ResourceFilterFactory.REMOVE_DYNAMICALLY_CONFIGURED_RESOURCE_FILTERING_TRANSITION);
}
@Test
public void testGetTopLevelTransitionNoFilters() throws Exception {
assertThat(
getTopLevelTransition(
ImmutableList.<String>of(),
ImmutableList.<String>of(),
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION,
true))
.isSameAs(
ResourceFilterFactory.REMOVE_DYNAMICALLY_CONFIGURED_RESOURCE_FILTERING_TRANSITION);
}
@Test
public void testGetTopLevelTransition() throws Exception {
ImmutableList<String> resourceConfigurationFilters = ImmutableList.of("en");
ImmutableList<String> densities = ImmutableList.of("hdpi");
PatchTransition transition =
getTopLevelTransition(
resourceConfigurationFilters,
densities,
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION,
true);
assertThat(transition).isInstanceOf(AddDynamicallyConfiguredResourceFilteringTransition.class);
AddDynamicallyConfiguredResourceFilteringTransition addTransition =
(AddDynamicallyConfiguredResourceFilteringTransition) transition;
ResourceFilterFactory foundFilter =
ResourceFilterFactory.forBaseAndAttrs(
ResourceFilterFactory.empty(
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION),
addTransition.getAttrs());
ResourceFilterFactory expectedFilter =
makeResourceFilter(
resourceConfigurationFilters,
densities,
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION);
assertThat(foundFilter).isEqualTo(expectedFilter);
}
private PatchTransition getTopLevelTransition(
ImmutableList<String> resourceConfigurationFilters,
ImmutableList<String> densities,
FilterBehavior behavior,
boolean isBinary)
throws Exception {
AttributeMap attrs = getAttributeMap(resourceConfigurationFilters, densities);
return makeResourceFilter("", "", behavior)
.getTopLevelPatchTransition(isBinary ? "android_binary" : "android_library", attrs);
}
@Test
public void testRemoveDynamicConfigurationTransition() throws Exception {
assertPatchTransition(
makeResourceFilter(
"en", "ldpi", FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION),
ResourceFilterFactory.REMOVE_DYNAMICALLY_CONFIGURED_RESOURCE_FILTERING_TRANSITION,
ResourceFilterFactory.empty(FilterBehavior.FILTER_IN_ANALYSIS));
}
@Test
public void testAddDynamicConfigurationTransitionDynamicConfiguration() throws Exception {
ImmutableList<String> resourceConfigurationFilters = ImmutableList.of("en", "es-rUS", "fr");
ImmutableList<String> densities = ImmutableList.of("ldpi", "hdpi");
AttributeMap attrs = getAttributeMap(resourceConfigurationFilters, densities);
assertPatchTransition(
ResourceFilterFactory.empty(FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION),
new ResourceFilterFactory.AddDynamicallyConfiguredResourceFilteringTransition(attrs),
makeResourceFilter(
resourceConfigurationFilters,
densities,
FilterBehavior.FILTER_IN_ANALYSIS_WITH_DYNAMIC_CONFIGURATION));
}
private void assertPatchTransition(
ResourceFilterFactory oldResourceFilterFactory,
PatchTransition transition,
ResourceFilterFactory expectedNewResourceFilterFactory) {
AndroidConfiguration.Options oldAndroidOptions = getAndroidOptions(oldResourceFilterFactory);
BuildOptions oldOptions = BuildOptions.builder().add(oldAndroidOptions).build();
BuildOptions newOptions = transition.apply(oldOptions);
// The old options should not have been changed
assertThat(oldAndroidOptions.resourceFilterFactory).isSameAs(oldResourceFilterFactory);
assertThat(oldAndroidOptions).isEqualTo(getAndroidOptions(oldResourceFilterFactory));
// Besides the ResourceFilterFactory, the new options should be the same as the old ones
assertThat(newOptions.getOptions()).hasSize(1);
AndroidConfiguration.Options newAndroidOptions =
newOptions.get(AndroidConfiguration.Options.class);
assertThat(newAndroidOptions).isEqualTo(getAndroidOptions(expectedNewResourceFilterFactory));
}
private AndroidConfiguration.Options getAndroidOptions(
ResourceFilterFactory resourceFilterFactory) {
AndroidConfiguration.Options androidOptions =
(AndroidConfiguration.Options) new AndroidConfiguration.Options().getDefault();
androidOptions.resourceFilterFactory = resourceFilterFactory;
return androidOptions;
}
}