| // Copyright 2018 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.devtools.build.lib.actions.Artifact; |
| import com.google.devtools.build.lib.analysis.RuleContext; |
| 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.vfs.PathFragment; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.JUnit4; |
| |
| /** Tests {@link AndroidAssets} */ |
| @RunWith(JUnit4.class) |
| public class AndroidAssetsTest extends ResourceTestBase { |
| @Test |
| public void testParse() throws Exception { |
| RuleContext ruleContext = getRuleContext(); |
| AndroidAssets assets = getLocalAssets(); |
| ParsedAndroidAssets parsed = |
| assets.parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT); |
| |
| // Assets should be unchanged |
| assertThat(parsed.getAssets()).isEqualTo(assets.getAssets()); |
| assertThat(parsed.getAssetRoots()).isEqualTo(assets.getAssetRoots()); |
| |
| // Label should be correct |
| assertThat(parsed.getLabel()).isEqualTo(ruleContext.getLabel()); |
| |
| // Symbols file should be created from raw assets |
| assertActionArtifacts( |
| ruleContext, |
| /* inputs = */ assets.getAssets(), |
| /* outputs = */ ImmutableList.of(parsed.getSymbols())); |
| |
| // There should be no compiled symbols |
| assertThat(parsed.getCompiledSymbols()).isNull(); |
| } |
| |
| @Test |
| public void testParseAapt2() throws Exception { |
| mockAndroidSdkWithAapt2(); |
| useConfiguration("--android_sdk=//sdk:sdk"); |
| |
| RuleContext ruleContext = getRuleContext(); |
| AndroidAssets assets = getLocalAssets(); |
| |
| ParsedAndroidAssets parsed = |
| assets.parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT2); |
| |
| // Assets should be unchanged |
| assertThat(parsed.getAssets()).isEqualTo(assets.getAssets()); |
| assertThat(parsed.getAssetRoots()).isEqualTo(assets.getAssetRoots()); |
| |
| // Label should be correct |
| assertThat(parsed.getLabel()).isEqualTo(ruleContext.getLabel()); |
| |
| // There should be compiled symbols |
| assertThat(parsed.getCompiledSymbols()).isNotNull(); |
| |
| // Symbols and compiled symbols files should be created from raw assets |
| assertActionArtifacts( |
| ruleContext, |
| /* inputs = */ assets.getAssets(), |
| /* outputs = */ ImmutableList.of(parsed.getSymbols())); |
| assertActionArtifacts( |
| ruleContext, |
| /* inputs = */ assets.getAssets(), |
| /* outputs = */ ImmutableList.of(parsed.getCompiledSymbols())); |
| } |
| |
| @Test |
| public void testMergeNoDeps() throws Exception { |
| RuleContext ruleContext = getRuleContext(); |
| ParsedAndroidAssets parsed = |
| getLocalAssets().parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT); |
| MergedAndroidAssets merged = assertMerge(ruleContext, parsed, AssetDependencies.empty()); |
| |
| // The assets can be correctly built into a provider |
| AndroidAssetsInfo info = merged.toProvider(); |
| assertThat(info.getLabel()).isEqualTo(merged.getLabel()); |
| |
| // The provider just has the local values |
| assertThat(info.getAssets()).containsExactlyElementsIn(merged.getAssets()).inOrder(); |
| assertThat(info.getSymbols()).containsExactly(merged.getSymbols()); |
| assertThat(info.getDirectParsedAssets()).containsExactly(parsed); |
| assertThat(info.getTransitiveParsedAssets()).isEmpty(); |
| } |
| |
| @Test |
| public void testMergeNeverlink() throws Exception { |
| RuleContext ruleContext = getRuleContext(); |
| ParsedAndroidAssets parsed = |
| getLocalAssets().parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT); |
| AssetDependencies deps = makeDeps(ruleContext, /* neverlink = */ true, AndroidAaptVersion.AAPT); |
| |
| MergedAndroidAssets merged = assertMerge(ruleContext, parsed, deps); |
| |
| AndroidAssetsInfo info = merged.toProvider(); |
| assertThat(info.getLabel()).isEqualTo(merged.getLabel()); |
| |
| // The provider should be empty because of neverlinking |
| assertThat(info.getAssets()).isEmpty(); |
| assertThat(info.getSymbols()).isEmpty(); |
| assertThat(info.getDirectParsedAssets()).isEmpty(); |
| assertThat(info.getTransitiveParsedAssets()).isEmpty(); |
| assertThat(info.getCompiledSymbols()).isEmpty(); |
| } |
| |
| @Test |
| public void testMerge() throws Exception { |
| RuleContext ruleContext = getRuleContext(); |
| ParsedAndroidAssets parsed = |
| getLocalAssets().parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT); |
| AssetDependencies deps = |
| makeDeps(ruleContext, /* neverlink = */ false, AndroidAaptVersion.AAPT); |
| |
| MergedAndroidAssets merged = assertMerge(ruleContext, parsed, deps); |
| |
| AndroidAssetsInfo info = merged.toProvider(); |
| assertThat(info.getLabel()).isEqualTo(merged.getLabel()); |
| |
| // The provider should have transitive and direct deps |
| assertThat(info.getAssets()) |
| .containsExactlyElementsIn(Iterables.concat(parsed.getAssets(), deps.getTransitiveAssets())) |
| .inOrder(); |
| assertThat(info.getSymbols()) |
| .containsExactlyElementsIn( |
| Iterables.concat(ImmutableList.of(parsed.getSymbols()), deps.getTransitiveSymbols())) |
| .inOrder(); |
| assertThat(info.getDirectParsedAssets()).containsExactly(parsed).inOrder(); |
| assertThat(info.getTransitiveParsedAssets()) |
| .containsExactlyElementsIn( |
| Iterables.concat(deps.getTransitiveParsedAssets(), deps.getDirectParsedAssets())) |
| .inOrder(); |
| |
| // There should be no compiled symbols |
| assertThat(info.getCompiledSymbols()).isEmpty(); |
| } |
| |
| @Test |
| public void testMergeAapt2() throws Exception { |
| mockAndroidSdkWithAapt2(); |
| useConfiguration("--android_sdk=//sdk:sdk"); |
| |
| RuleContext ruleContext = getRuleContext(); |
| ParsedAndroidAssets parsed = |
| getLocalAssets().parse(AndroidDataContext.forNative(ruleContext), AndroidAaptVersion.AAPT2); |
| AssetDependencies deps = |
| makeDeps(ruleContext, /* neverlink = */ false, AndroidAaptVersion.AAPT2); |
| |
| MergedAndroidAssets merged = assertMerge(ruleContext, parsed, deps); |
| |
| AndroidAssetsInfo info = merged.toProvider(); |
| assertThat(info.getLabel()).isEqualTo(merged.getLabel()); |
| |
| // The provider should have transitive and direct deps |
| assertThat(info.getAssets()) |
| .containsExactlyElementsIn(Iterables.concat(parsed.getAssets(), deps.getTransitiveAssets())) |
| .inOrder(); |
| assertThat(info.getSymbols()) |
| .containsExactlyElementsIn( |
| Iterables.concat(ImmutableList.of(parsed.getSymbols()), deps.getTransitiveSymbols())) |
| .inOrder(); |
| assertThat(info.getCompiledSymbols()) |
| .containsExactlyElementsIn( |
| Iterables.concat( |
| ImmutableList.of(parsed.getCompiledSymbols()), |
| deps.getTransitiveCompiledSymbols())); |
| assertThat(info.getDirectParsedAssets()).containsExactly(parsed).inOrder(); |
| assertThat(info.getTransitiveParsedAssets()) |
| .containsExactlyElementsIn( |
| Iterables.concat(deps.getTransitiveParsedAssets(), deps.getDirectParsedAssets())) |
| .inOrder(); |
| } |
| |
| private AssetDependencies makeDeps( |
| RuleContext ruleContext, boolean neverlink, AndroidAaptVersion aaptVersion) { |
| ParsedAndroidAssets firstDirect = getDependencyAssets(ruleContext, "first_direct", aaptVersion); |
| ParsedAndroidAssets secondDirect = |
| getDependencyAssets(ruleContext, "second_direct", aaptVersion); |
| ParsedAndroidAssets firstTransitive = |
| getDependencyAssets(ruleContext, "first_transitive", aaptVersion); |
| ParsedAndroidAssets secondTransitive = |
| getDependencyAssets(ruleContext, "second_transitive", aaptVersion); |
| |
| return AssetDependencies.of( |
| neverlink, |
| NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, firstDirect, secondDirect), |
| NestedSetBuilder.create(Order.NAIVE_LINK_ORDER, firstTransitive, secondTransitive), |
| NestedSetBuilder.wrap( |
| Order.NAIVE_LINK_ORDER, |
| Iterables.concat( |
| firstDirect.getAssets(), |
| secondDirect.getAssets(), |
| firstTransitive.getAssets(), |
| secondTransitive.getAssets())), |
| NestedSetBuilder.wrap( |
| Order.NAIVE_LINK_ORDER, |
| ImmutableList.of( |
| firstDirect.getSymbols(), |
| secondDirect.getSymbols(), |
| firstTransitive.getSymbols(), |
| secondTransitive.getSymbols())), |
| aaptVersion == AndroidAaptVersion.AAPT2 |
| ? NestedSetBuilder.wrap( |
| Order.NAIVE_LINK_ORDER, |
| ImmutableList.of( |
| firstDirect.getCompiledSymbols(), |
| secondDirect.getCompiledSymbols(), |
| firstTransitive.getCompiledSymbols(), |
| secondTransitive.getCompiledSymbols())) |
| : NestedSetBuilder.emptySet(Order.NAIVE_LINK_ORDER)); |
| } |
| |
| private MergedAndroidAssets assertMerge( |
| RuleContext ruleContext, ParsedAndroidAssets parsed, AssetDependencies deps) |
| throws InterruptedException { |
| MergedAndroidAssets merged = |
| MergedAndroidAssets.mergeFrom(AndroidDataContext.forNative(ruleContext), parsed, deps); |
| |
| // Inherited values should be unchanged |
| assertThat(new ParsedAndroidAssets(merged)).isEqualTo(parsed); |
| |
| // The raw assets should be used to merge |
| assertActionArtifacts( |
| ruleContext, |
| /* inputs = */ ImmutableList.<Artifact>builder() |
| .addAll(merged.getAssets()) |
| .add(merged.getSymbols()) |
| .addAll(deps.getTransitiveAssets()) |
| .addAll(deps.getTransitiveSymbols()) |
| .build(), |
| /* outputs = */ ImmutableList.of(merged.getMergedAssets())); |
| |
| return merged; |
| } |
| |
| private AndroidAssets getLocalAssets() { |
| return new AndroidAssets( |
| ImmutableList.of(getResource("asset_1"), getResource("asset_2")), |
| ImmutableList.of(PathFragment.create("asset_dir")), |
| "asset_dir"); |
| } |
| |
| private ParsedAndroidAssets getDependencyAssets( |
| RuleContext ruleContext, String depName, AndroidAaptVersion aaptVersion) { |
| return ParsedAndroidAssets.of( |
| new AndroidAssets( |
| ImmutableList.of(getResource(depName + "_asset_1"), getResource(depName + "_asset_2")), |
| ImmutableList.of(PathFragment.create(depName)), |
| depName), |
| getResource("symbols_for_" + depName), |
| aaptVersion == AndroidAaptVersion.AAPT2 |
| ? getResource("compiled_symbols_for_" + depName) |
| : null, |
| ruleContext.getLabel()); |
| } |
| |
| private RuleContext getRuleContext() throws Exception { |
| return getRuleContextForActionTesting( |
| scratchConfiguredTarget("pkg", "r", "android_library(name='r')")); |
| } |
| } |