Require explicit ordering of groups in the configuration file to ensure that the correct version code is set. Ordering based on a single ABI is straight forward to ensure Play Store delivers the correct APK, but when an APK needs more than one ABI things get messy quickly. This also goes for screen density etc. The only thing that is easily sorted without this attribute is android-sdk since an artifact can only reference a single SDK. Test: unit tests Test: manually split an APK with update config.xml Change-Id: I37a2b8b8a8409d6d6ff27c7142d4c8c8065a7a51
976 lines
32 KiB
C++
976 lines
32 KiB
C++
/*
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
*
|
|
* 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.
|
|
*/
|
|
|
|
#include "configuration/ConfigurationParser.h"
|
|
|
|
#include <string>
|
|
|
|
#include "android-base/stringprintf.h"
|
|
#include "androidfw/ResourceTypes.h"
|
|
|
|
#include "SdkConstants.h"
|
|
#include "configuration/ConfigurationParser.internal.h"
|
|
#include "test/Test.h"
|
|
#include "xml/XmlDom.h"
|
|
|
|
namespace aapt {
|
|
|
|
namespace configuration {
|
|
void PrintTo(const AndroidSdk& sdk, std::ostream* os) {
|
|
*os << "SDK: min=" << sdk.min_sdk_version
|
|
<< ", target=" << sdk.target_sdk_version.value_or_default(-1)
|
|
<< ", max=" << sdk.max_sdk_version.value_or_default(-1);
|
|
}
|
|
|
|
bool operator==(const ConfiguredArtifact& lhs, const ConfiguredArtifact& rhs) {
|
|
return lhs.name == rhs.name && lhs.abi_group == rhs.abi_group &&
|
|
lhs.screen_density_group == rhs.screen_density_group &&
|
|
lhs.locale_group == rhs.locale_group && lhs.android_sdk == rhs.android_sdk &&
|
|
lhs.device_feature_group == rhs.device_feature_group &&
|
|
lhs.gl_texture_group == rhs.gl_texture_group;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& out, const Maybe<std::string>& value) {
|
|
PrintTo(value, &out);
|
|
return out;
|
|
}
|
|
|
|
void PrintTo(const ConfiguredArtifact& artifact, std::ostream* os) {
|
|
*os << "\n{"
|
|
<< "\n name: " << artifact.name << "\n sdk: " << artifact.android_sdk
|
|
<< "\n abi: " << artifact.abi_group << "\n density: " << artifact.screen_density_group
|
|
<< "\n locale: " << artifact.locale_group
|
|
<< "\n features: " << artifact.device_feature_group
|
|
<< "\n textures: " << artifact.gl_texture_group << "\n}\n";
|
|
}
|
|
|
|
namespace handler {
|
|
|
|
namespace {
|
|
|
|
using ::aapt::configuration::Abi;
|
|
using ::aapt::configuration::AndroidManifest;
|
|
using ::aapt::configuration::AndroidSdk;
|
|
using ::aapt::configuration::ConfiguredArtifact;
|
|
using ::aapt::configuration::DeviceFeature;
|
|
using ::aapt::configuration::ExtractConfiguration;
|
|
using ::aapt::configuration::GlTexture;
|
|
using ::aapt::configuration::Locale;
|
|
using ::aapt::configuration::PostProcessingConfiguration;
|
|
using ::aapt::xml::Element;
|
|
using ::aapt::xml::NodeCast;
|
|
using ::android::ResTable_config;
|
|
using ::android::base::StringPrintf;
|
|
using ::testing::ElementsAre;
|
|
using ::testing::Eq;
|
|
using ::testing::SizeIs;
|
|
using ::testing::StrEq;
|
|
|
|
constexpr const char* kValidConfig = R"(<?xml version="1.0" encoding="utf-8" ?>
|
|
<post-process xmlns="http://schemas.android.com/tools/aapt">
|
|
<abi-groups>
|
|
<abi-group label="other" version-code-order="2">
|
|
<abi>x86</abi>
|
|
<abi>mips</abi>
|
|
</abi-group>
|
|
<abi-group label="arm" version-code-order="1">
|
|
<abi>armeabi-v7a</abi>
|
|
<abi>arm64-v8a</abi>
|
|
</abi-group>
|
|
</abi-groups>
|
|
<screen-density-groups>
|
|
<screen-density-group label="large" version-code-order="2">
|
|
<screen-density>xhdpi</screen-density>
|
|
<screen-density>xxhdpi</screen-density>
|
|
<screen-density>xxxhdpi</screen-density>
|
|
</screen-density-group>
|
|
<screen-density-group label="alldpi" version-code-order="1">
|
|
<screen-density>ldpi</screen-density>
|
|
<screen-density>mdpi</screen-density>
|
|
<screen-density>hdpi</screen-density>
|
|
<screen-density>xhdpi</screen-density>
|
|
<screen-density>xxhdpi</screen-density>
|
|
<screen-density>xxxhdpi</screen-density>
|
|
</screen-density-group>
|
|
</screen-density-groups>
|
|
<locale-groups>
|
|
<locale-group label="europe" version-code-order="1">
|
|
<locale>en</locale>
|
|
<locale>es</locale>
|
|
<locale>fr</locale>
|
|
<locale>de</locale>
|
|
</locale-group>
|
|
<locale-group label="north-america" version-code-order="2">
|
|
<locale>en</locale>
|
|
<locale>es-rMX</locale>
|
|
<locale>fr-rCA</locale>
|
|
</locale-group>
|
|
<locale-group label="all" version-code-order="-1">
|
|
<locale />
|
|
</locale-group>
|
|
</locale-groups>
|
|
<android-sdks>
|
|
<android-sdk
|
|
label="v19"
|
|
minSdkVersion="19"
|
|
targetSdkVersion="24"
|
|
maxSdkVersion="25">
|
|
<manifest>
|
|
<!--- manifest additions here XSLT? TODO -->
|
|
</manifest>
|
|
</android-sdk>
|
|
</android-sdks>
|
|
<gl-texture-groups>
|
|
<gl-texture-group label="dxt1" version-code-order="2">
|
|
<gl-texture name="GL_EXT_texture_compression_dxt1">
|
|
<texture-path>assets/dxt1/*</texture-path>
|
|
</gl-texture>
|
|
</gl-texture-group>
|
|
</gl-texture-groups>
|
|
<device-feature-groups>
|
|
<device-feature-group label="low-latency" version-code-order="2">
|
|
<supports-feature>android.hardware.audio.low_latency</supports-feature>
|
|
</device-feature-group>
|
|
</device-feature-groups>
|
|
<artifacts>
|
|
<artifact-format>
|
|
${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
|
|
</artifact-format>
|
|
<artifact
|
|
name="art1"
|
|
abi-group="arm"
|
|
screen-density-group="large"
|
|
locale-group="europe"
|
|
android-sdk="v19"
|
|
gl-texture-group="dxt1"
|
|
device-feature-group="low-latency"/>
|
|
<artifact
|
|
name="art2"
|
|
abi-group="other"
|
|
screen-density-group="alldpi"
|
|
locale-group="north-america"
|
|
android-sdk="v19"
|
|
gl-texture-group="dxt1"
|
|
device-feature-group="low-latency"/>
|
|
</artifacts>
|
|
</post-process>
|
|
)";
|
|
|
|
class ConfigurationParserTest : public ConfigurationParser, public ::testing::Test {
|
|
public:
|
|
ConfigurationParserTest() : ConfigurationParser("", "config.xml") {
|
|
}
|
|
|
|
protected:
|
|
StdErrDiagnostics diag_;
|
|
};
|
|
|
|
TEST_F(ConfigurationParserTest, ForPath_NoFile) {
|
|
auto result = ConfigurationParser::ForPath("./does_not_exist.xml");
|
|
EXPECT_FALSE(result);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ExtractConfiguration) {
|
|
Maybe<PostProcessingConfiguration> maybe_config =
|
|
ExtractConfiguration(kValidConfig, "dummy.xml", &diag_);
|
|
|
|
PostProcessingConfiguration config = maybe_config.value();
|
|
|
|
auto& arm = config.abi_groups["arm"];
|
|
auto& other = config.abi_groups["other"];
|
|
EXPECT_EQ(arm.order, 1);
|
|
EXPECT_EQ(other.order, 2);
|
|
|
|
auto& large = config.screen_density_groups["large"];
|
|
auto& alldpi = config.screen_density_groups["alldpi"];
|
|
EXPECT_EQ(large.order, 2);
|
|
EXPECT_EQ(alldpi.order, 1);
|
|
|
|
auto& north_america = config.locale_groups["north-america"];
|
|
auto& europe = config.locale_groups["europe"];
|
|
auto& all = config.locale_groups["all"];
|
|
// Checked in reverse to make sure access order does not matter.
|
|
EXPECT_EQ(north_america.order, 2);
|
|
EXPECT_EQ(europe.order, 1);
|
|
EXPECT_EQ(all.order, -1);
|
|
EXPECT_EQ(3ul, config.locale_groups.size());
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ValidateFile) {
|
|
auto parser = ConfigurationParser::ForContents(kValidConfig, "conf.xml").WithDiagnostics(&diag_);
|
|
auto result = parser.Parse("test.apk");
|
|
ASSERT_TRUE(result);
|
|
const std::vector<OutputArtifact>& value = result.value();
|
|
EXPECT_THAT(value, SizeIs(2ul));
|
|
|
|
const OutputArtifact& a1 = value[0];
|
|
EXPECT_EQ(a1.name, "art1.apk");
|
|
EXPECT_EQ(a1.version, 1);
|
|
EXPECT_THAT(a1.abis, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a));
|
|
EXPECT_THAT(a1.screen_densities,
|
|
ElementsAre(test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
|
|
EXPECT_THAT(a1.locales, ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es"),
|
|
test::ParseConfigOrDie("fr"), test::ParseConfigOrDie("de")));
|
|
ASSERT_TRUE(a1.android_sdk);
|
|
ASSERT_TRUE(a1.android_sdk.value().min_sdk_version);
|
|
EXPECT_EQ(a1.android_sdk.value().min_sdk_version, 19l);
|
|
EXPECT_THAT(a1.textures, SizeIs(1ul));
|
|
EXPECT_THAT(a1.features, SizeIs(1ul));
|
|
|
|
const OutputArtifact& a2 = value[1];
|
|
EXPECT_EQ(a2.name, "art2.apk");
|
|
EXPECT_EQ(a2.version, 2);
|
|
EXPECT_THAT(a2.abis, ElementsAre(Abi::kX86, Abi::kMips));
|
|
EXPECT_THAT(a2.screen_densities,
|
|
ElementsAre(test::ParseConfigOrDie("ldpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("mdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("hdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("xhdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("xxhdpi").CopyWithoutSdkVersion(),
|
|
test::ParseConfigOrDie("xxxhdpi").CopyWithoutSdkVersion()));
|
|
EXPECT_THAT(a2.locales,
|
|
ElementsAre(test::ParseConfigOrDie("en"), test::ParseConfigOrDie("es-rMX"),
|
|
test::ParseConfigOrDie("fr-rCA")));
|
|
ASSERT_TRUE(a2.android_sdk);
|
|
ASSERT_TRUE(a2.android_sdk.value().min_sdk_version);
|
|
EXPECT_EQ(a2.android_sdk.value().min_sdk_version, 19l);
|
|
EXPECT_THAT(a2.textures, SizeIs(1ul));
|
|
EXPECT_THAT(a2.features, SizeIs(1ul));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ConfiguredArtifactOrdering) {
|
|
// Create a base builder with the configuration groups but no artifacts to allow it to be copied.
|
|
test::PostProcessingConfigurationBuilder base_builder = test::PostProcessingConfigurationBuilder()
|
|
.AddAbiGroup("arm")
|
|
.AddAbiGroup("arm64")
|
|
.AddAndroidSdk("v23", 23)
|
|
.AddAndroidSdk("v19", 19);
|
|
|
|
{
|
|
// Test version ordering.
|
|
ConfiguredArtifact v23;
|
|
v23.android_sdk = {"v23"};
|
|
ConfiguredArtifact v19;
|
|
v19.android_sdk = {"v19"};
|
|
|
|
test::PostProcessingConfigurationBuilder builder = base_builder;
|
|
PostProcessingConfiguration config = builder.AddArtifact(v23).AddArtifact(v19).Build();
|
|
|
|
config.SortArtifacts();
|
|
ASSERT_THAT(config.artifacts, SizeIs(2));
|
|
EXPECT_THAT(config.artifacts[0], Eq(v19));
|
|
EXPECT_THAT(config.artifacts[1], Eq(v23));
|
|
}
|
|
|
|
{
|
|
// Test ABI ordering.
|
|
ConfiguredArtifact arm;
|
|
arm.android_sdk = {"v19"};
|
|
arm.abi_group = {"arm"};
|
|
ConfiguredArtifact arm64;
|
|
arm64.android_sdk = {"v19"};
|
|
arm64.abi_group = {"arm64"};
|
|
|
|
test::PostProcessingConfigurationBuilder builder = base_builder;
|
|
PostProcessingConfiguration config = builder.AddArtifact(arm64).AddArtifact(arm).Build();
|
|
|
|
config.SortArtifacts();
|
|
ASSERT_THAT(config.artifacts, SizeIs(2));
|
|
EXPECT_THAT(config.artifacts[0], Eq(arm));
|
|
EXPECT_THAT(config.artifacts[1], Eq(arm64));
|
|
}
|
|
|
|
{
|
|
// Test Android SDK has precedence over ABI.
|
|
ConfiguredArtifact arm;
|
|
arm.android_sdk = {"v23"};
|
|
arm.abi_group = {"arm"};
|
|
ConfiguredArtifact arm64;
|
|
arm64.android_sdk = {"v19"};
|
|
arm64.abi_group = {"arm64"};
|
|
|
|
test::PostProcessingConfigurationBuilder builder = base_builder;
|
|
PostProcessingConfiguration config = builder.AddArtifact(arm64).AddArtifact(arm).Build();
|
|
|
|
config.SortArtifacts();
|
|
ASSERT_THAT(config.artifacts, SizeIs(2));
|
|
EXPECT_THAT(config.artifacts[0], Eq(arm64));
|
|
EXPECT_THAT(config.artifacts[1], Eq(arm));
|
|
}
|
|
|
|
{
|
|
// Test version is better than ABI.
|
|
ConfiguredArtifact arm;
|
|
arm.abi_group = {"arm"};
|
|
ConfiguredArtifact v19;
|
|
v19.android_sdk = {"v19"};
|
|
|
|
test::PostProcessingConfigurationBuilder builder = base_builder;
|
|
PostProcessingConfiguration config = builder.AddArtifact(v19).AddArtifact(arm).Build();
|
|
|
|
config.SortArtifacts();
|
|
ASSERT_THAT(config.artifacts, SizeIs(2));
|
|
EXPECT_THAT(config.artifacts[0], Eq(arm));
|
|
EXPECT_THAT(config.artifacts[1], Eq(v19));
|
|
}
|
|
|
|
{
|
|
// Test version is sorted higher than no version.
|
|
ConfiguredArtifact arm;
|
|
arm.abi_group = {"arm"};
|
|
ConfiguredArtifact v19;
|
|
v19.abi_group = {"arm"};
|
|
v19.android_sdk = {"v19"};
|
|
|
|
test::PostProcessingConfigurationBuilder builder = base_builder;
|
|
PostProcessingConfiguration config = builder.AddArtifact(v19).AddArtifact(arm).Build();
|
|
|
|
config.SortArtifacts();
|
|
ASSERT_THAT(config.artifacts, SizeIs(2));
|
|
EXPECT_THAT(config.artifacts[0], Eq(arm));
|
|
EXPECT_THAT(config.artifacts[1], Eq(v19));
|
|
}
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, InvalidNamespace) {
|
|
constexpr const char* invalid_ns = R"(<?xml version="1.0" encoding="utf-8" ?>
|
|
<post-process xmlns="http://schemas.android.com/tools/another-unknown-tool" />)";
|
|
|
|
auto result = ConfigurationParser::ForContents(invalid_ns, "config.xml").Parse("test.apk");
|
|
ASSERT_FALSE(result);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ArtifactAction) {
|
|
PostProcessingConfiguration config;
|
|
const auto doc = test::BuildXmlDom(R"xml(
|
|
<artifact
|
|
abi-group="arm"
|
|
screen-density-group="large"
|
|
locale-group="europe"
|
|
android-sdk="v19"
|
|
gl-texture-group="dxt1"
|
|
device-feature-group="low-latency"/>)xml");
|
|
|
|
ASSERT_TRUE(ArtifactTagHandler(&config, NodeCast<Element>(doc->root.get()), &diag_));
|
|
|
|
EXPECT_THAT(config.artifacts, SizeIs(1ul));
|
|
|
|
auto& artifact = config.artifacts.back();
|
|
EXPECT_FALSE(artifact.name); // TODO: make this fail.
|
|
EXPECT_EQ("arm", artifact.abi_group.value());
|
|
EXPECT_EQ("large", artifact.screen_density_group.value());
|
|
EXPECT_EQ("europe", artifact.locale_group.value());
|
|
EXPECT_EQ("v19", artifact.android_sdk.value());
|
|
EXPECT_EQ("dxt1", artifact.gl_texture_group.value());
|
|
EXPECT_EQ("low-latency", artifact.device_feature_group.value());
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ArtifactFormatAction) {
|
|
const auto doc = test::BuildXmlDom(R"xml(
|
|
<artifact-format>
|
|
${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release
|
|
</artifact-format>)xml");
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = ArtifactFormatTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
ASSERT_TRUE(config.artifact_format);
|
|
EXPECT_EQ(
|
|
"${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release",
|
|
static_cast<std::string>(config.artifact_format.value())
|
|
);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AbiGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<abi-group label="arm" version-code-order="2">
|
|
<!-- First comment. -->
|
|
<abi>
|
|
armeabi-v7a
|
|
</abi>
|
|
<!-- Another comment. -->
|
|
<abi>arm64-v8a</abi>
|
|
</abi-group>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.abi_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.abi_groups.count("arm"));
|
|
|
|
auto& out = config.abi_groups["arm"].entry;
|
|
ASSERT_THAT(out, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup) {
|
|
static constexpr const char* xml =
|
|
R"xml(<abi-group label="arm64-v8a" version-code-order="3"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.abi_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.abi_groups.count("arm64-v8a"));
|
|
|
|
auto& out = config.abi_groups["arm64-v8a"];
|
|
ASSERT_THAT(out.entry, ElementsAre(Abi::kArm64V8a));
|
|
EXPECT_EQ(3, out.order);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AbiGroupAction_EmptyGroup_NoOrder) {
|
|
static constexpr const char* xml = R"xml(<abi-group label="arm64-v8a"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AbiGroupAction_InvalidEmptyGroup) {
|
|
static constexpr const char* xml = R"xml(<abi-group label="arm" order="2"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AbiGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<screen-density-group label="large" version-code-order="2">
|
|
<screen-density>xhdpi</screen-density>
|
|
<screen-density>
|
|
xxhdpi
|
|
</screen-density>
|
|
<screen-density>xxxhdpi</screen-density>
|
|
</screen-density-group>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.screen_density_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.screen_density_groups.count("large"));
|
|
|
|
ConfigDescription xhdpi;
|
|
xhdpi.density = ResTable_config::DENSITY_XHIGH;
|
|
ConfigDescription xxhdpi;
|
|
xxhdpi.density = ResTable_config::DENSITY_XXHIGH;
|
|
ConfigDescription xxxhdpi;
|
|
xxxhdpi.density = ResTable_config::DENSITY_XXXHIGH;
|
|
|
|
auto& out = config.screen_density_groups["large"].entry;
|
|
ASSERT_THAT(out, ElementsAre(xhdpi, xxhdpi, xxxhdpi));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup) {
|
|
static constexpr const char* xml =
|
|
R"xml(<screen-density-group label="xhdpi" version-code-order="4"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.screen_density_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.screen_density_groups.count("xhdpi"));
|
|
|
|
ConfigDescription xhdpi;
|
|
xhdpi.density = ResTable_config::DENSITY_XHIGH;
|
|
|
|
auto& out = config.screen_density_groups["xhdpi"];
|
|
EXPECT_THAT(out.entry, ElementsAre(xhdpi));
|
|
EXPECT_EQ(4, out.order);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_EmtpyGroup_NoVersion) {
|
|
static constexpr const char* xml = R"xml(<screen-density-group label="xhdpi"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, ScreenDensityGroupAction_InvalidEmtpyGroup) {
|
|
static constexpr const char* xml = R"xml(<screen-density-group label="really-big-screen"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = ScreenDensityGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, LocaleGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<locale-group label="europe" version-code-order="2">
|
|
<locale>en</locale>
|
|
<locale>es</locale>
|
|
<locale>fr</locale>
|
|
<locale>de</locale>
|
|
</locale-group>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.locale_groups.size());
|
|
ASSERT_EQ(1u, config.locale_groups.count("europe"));
|
|
|
|
const auto& out = config.locale_groups["europe"].entry;
|
|
|
|
ConfigDescription en = test::ParseConfigOrDie("en");
|
|
ConfigDescription es = test::ParseConfigOrDie("es");
|
|
ConfigDescription fr = test::ParseConfigOrDie("fr");
|
|
ConfigDescription de = test::ParseConfigOrDie("de");
|
|
|
|
ASSERT_THAT(out, ElementsAre(en, es, fr, de));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup) {
|
|
static constexpr const char* xml = R"xml(<locale-group label="en" version-code-order="6"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.locale_groups.size());
|
|
ASSERT_EQ(1u, config.locale_groups.count("en"));
|
|
|
|
const auto& out = config.locale_groups["en"];
|
|
|
|
ConfigDescription en = test::ParseConfigOrDie("en");
|
|
|
|
EXPECT_THAT(out.entry, ElementsAre(en));
|
|
EXPECT_EQ(6, out.order);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, LocaleGroupAction_EmtpyGroup_NoOrder) {
|
|
static constexpr const char* xml = R"xml(<locale-group label="en"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, LocaleGroupAction_InvalidEmtpyGroup) {
|
|
static constexpr const char* xml = R"xml(<locale-group label="arm64"/>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = LocaleGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<android-sdk label="v19"
|
|
minSdkVersion="19"
|
|
targetSdkVersion="24"
|
|
maxSdkVersion="25">
|
|
<manifest>
|
|
<!--- manifest additions here XSLT? TODO -->
|
|
</manifest>
|
|
</android-sdk>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.android_sdks.size());
|
|
ASSERT_EQ(1u, config.android_sdks.count("v19"));
|
|
|
|
auto& out = config.android_sdks["v19"];
|
|
|
|
AndroidSdk sdk;
|
|
sdk.min_sdk_version = 19;
|
|
sdk.target_sdk_version = 24;
|
|
sdk.max_sdk_version = 25;
|
|
sdk.manifest = AndroidManifest();
|
|
|
|
ASSERT_EQ(sdk, out);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_SingleVersion) {
|
|
{
|
|
const char* xml = "<android-sdk label='v19' minSdkVersion='19'></android-sdk>";
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.android_sdks.size());
|
|
ASSERT_EQ(1u, config.android_sdks.count("v19"));
|
|
|
|
auto& out = config.android_sdks["v19"];
|
|
EXPECT_EQ(19, out.min_sdk_version);
|
|
EXPECT_FALSE(out.max_sdk_version);
|
|
EXPECT_FALSE(out.target_sdk_version);
|
|
}
|
|
|
|
{
|
|
const char* xml =
|
|
"<android-sdk label='v19' minSdkVersion='19' maxSdkVersion='19'></android-sdk>";
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.android_sdks.size());
|
|
ASSERT_EQ(1u, config.android_sdks.count("v19"));
|
|
|
|
auto& out = config.android_sdks["v19"];
|
|
EXPECT_EQ(19, out.max_sdk_version.value());
|
|
EXPECT_EQ(19, out.min_sdk_version);
|
|
EXPECT_FALSE(out.target_sdk_version);
|
|
}
|
|
|
|
{
|
|
const char* xml =
|
|
"<android-sdk label='v19' minSdkVersion='19' targetSdkVersion='19'></android-sdk>";
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.android_sdks.size());
|
|
ASSERT_EQ(1u, config.android_sdks.count("v19"));
|
|
|
|
auto& out = config.android_sdks["v19"];
|
|
EXPECT_EQ(19, out.target_sdk_version.value());
|
|
EXPECT_EQ(19, out.min_sdk_version);
|
|
EXPECT_FALSE(out.max_sdk_version);
|
|
}
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_InvalidVersion) {
|
|
static constexpr const char* xml = R"xml(
|
|
<android-sdk
|
|
label="v19"
|
|
minSdkVersion="v19"
|
|
targetSdkVersion="v24"
|
|
maxSdkVersion="v25">
|
|
<manifest>
|
|
<!--- manifest additions here XSLT? TODO -->
|
|
</manifest>
|
|
</android-sdk>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_FALSE(ok);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, AndroidSdkGroupAction_NonNumeric) {
|
|
static constexpr const char* xml = R"xml(
|
|
<android-sdk
|
|
label="P"
|
|
minSdkVersion="25"
|
|
targetSdkVersion="%s"
|
|
maxSdkVersion="%s">
|
|
</android-sdk>)xml";
|
|
|
|
const auto& dev_sdk = GetDevelopmentSdkCodeNameAndVersion();
|
|
const char* codename = dev_sdk.first.data();
|
|
const ApiVersion& version = dev_sdk.second;
|
|
|
|
auto doc = test::BuildXmlDom(StringPrintf(xml, codename, codename));
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = AndroidSdkTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
ASSERT_EQ(1ul, config.android_sdks.size());
|
|
ASSERT_EQ(1u, config.android_sdks.count("P"));
|
|
|
|
auto& out = config.android_sdks["P"];
|
|
|
|
AndroidSdk sdk;
|
|
sdk.min_sdk_version = 25;
|
|
sdk.target_sdk_version = version;
|
|
sdk.max_sdk_version = version;
|
|
|
|
ASSERT_EQ(sdk, out);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, GlTextureGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<gl-texture-group label="dxt1" version-code-order="2">
|
|
<gl-texture name="GL_EXT_texture_compression_dxt1">
|
|
<texture-path>assets/dxt1/main/*</texture-path>
|
|
<texture-path>
|
|
assets/dxt1/test/*
|
|
</texture-path>
|
|
</gl-texture>
|
|
</gl-texture-group>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = GlTextureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.gl_texture_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.gl_texture_groups.count("dxt1"));
|
|
|
|
auto& out = config.gl_texture_groups["dxt1"].entry;
|
|
|
|
GlTexture texture{
|
|
std::string("GL_EXT_texture_compression_dxt1"),
|
|
{"assets/dxt1/main/*", "assets/dxt1/test/*"}
|
|
};
|
|
|
|
ASSERT_EQ(1ul, out.size());
|
|
ASSERT_EQ(texture, out[0]);
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, DeviceFeatureGroupAction) {
|
|
static constexpr const char* xml = R"xml(
|
|
<device-feature-group label="low-latency" version-code-order="2">
|
|
<supports-feature>android.hardware.audio.low_latency</supports-feature>
|
|
<supports-feature>
|
|
android.hardware.audio.pro
|
|
</supports-feature>
|
|
</device-feature-group>)xml";
|
|
|
|
auto doc = test::BuildXmlDom(xml);
|
|
|
|
PostProcessingConfiguration config;
|
|
bool ok = DeviceFeatureGroupTagHandler(&config, NodeCast<Element>(doc.get()->root.get()), &diag_);
|
|
ASSERT_TRUE(ok);
|
|
|
|
EXPECT_THAT(config.device_feature_groups, SizeIs(1ul));
|
|
ASSERT_EQ(1u, config.device_feature_groups.count("low-latency"));
|
|
|
|
auto& out = config.device_feature_groups["low-latency"].entry;
|
|
|
|
DeviceFeature low_latency = "android.hardware.audio.low_latency";
|
|
DeviceFeature pro = "android.hardware.audio.pro";
|
|
ASSERT_THAT(out, ElementsAre(low_latency, pro));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, Group_Valid) {
|
|
Group<int32_t> group;
|
|
group["item1"].order = 1;
|
|
group["item2"].order = 2;
|
|
group["item3"].order = 3;
|
|
group["item4"].order = 4;
|
|
group["item5"].order = 5;
|
|
group["item6"].order = 6;
|
|
|
|
EXPECT_TRUE(IsGroupValid(group, "test", &diag_));
|
|
}
|
|
|
|
TEST_F(ConfigurationParserTest, Group_OverlappingOrder) {
|
|
Group<int32_t> group;
|
|
group["item1"].order = 1;
|
|
group["item2"].order = 2;
|
|
group["item3"].order = 3;
|
|
group["item4"].order = 2;
|
|
group["item5"].order = 5;
|
|
group["item6"].order = 1;
|
|
|
|
EXPECT_FALSE(IsGroupValid(group, "test", &diag_));
|
|
}
|
|
|
|
// Artifact name parser test cases.
|
|
|
|
TEST(ArtifactTest, Simple) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact x86;
|
|
x86.abi_group = {"x86"};
|
|
|
|
auto x86_result = x86.ToArtifactName("something.${abi}.apk", "", &diag);
|
|
ASSERT_TRUE(x86_result);
|
|
EXPECT_EQ(x86_result.value(), "something.x86.apk");
|
|
|
|
ConfiguredArtifact arm;
|
|
arm.abi_group = {"armeabi-v7a"};
|
|
|
|
{
|
|
auto arm_result = arm.ToArtifactName("app.${abi}.apk", "", &diag);
|
|
ASSERT_TRUE(arm_result);
|
|
EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
|
|
}
|
|
|
|
{
|
|
auto arm_result = arm.ToArtifactName("app.${abi}.apk", "different_name.apk", &diag);
|
|
ASSERT_TRUE(arm_result);
|
|
EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
|
|
}
|
|
|
|
{
|
|
auto arm_result = arm.ToArtifactName("${basename}.${abi}.apk", "app.apk", &diag);
|
|
ASSERT_TRUE(arm_result);
|
|
EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
|
|
}
|
|
|
|
{
|
|
auto arm_result = arm.ToArtifactName("app.${abi}.${ext}", "app.apk", &diag);
|
|
ASSERT_TRUE(arm_result);
|
|
EXPECT_EQ(arm_result.value(), "app.armeabi-v7a.apk");
|
|
}
|
|
}
|
|
|
|
TEST(ArtifactTest, Complex) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact artifact;
|
|
artifact.abi_group = {"mips64"};
|
|
artifact.screen_density_group = {"ldpi"};
|
|
artifact.device_feature_group = {"df1"};
|
|
artifact.gl_texture_group = {"glx1"};
|
|
artifact.locale_group = {"en-AU"};
|
|
artifact.android_sdk = {"v26"};
|
|
|
|
{
|
|
auto result = artifact.ToArtifactName(
|
|
"app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
|
|
}
|
|
|
|
{
|
|
auto result = artifact.ToArtifactName(
|
|
"app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
|
|
}
|
|
|
|
{
|
|
auto result = artifact.ToArtifactName(
|
|
"${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.apk", "app.apk", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
|
|
}
|
|
|
|
{
|
|
auto result = artifact.ToArtifactName(
|
|
"app.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}.${ext}", "app.apk", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
|
|
}
|
|
|
|
{
|
|
auto result = artifact.ToArtifactName(
|
|
"${basename}.${density}_${locale}_${feature}_${gl}.${sdk}.${abi}", "app.apk", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.v26.mips64.apk");
|
|
}
|
|
}
|
|
|
|
TEST(ArtifactTest, Missing) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact x86;
|
|
x86.abi_group = {"x86"};
|
|
|
|
EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "", &diag));
|
|
EXPECT_FALSE(x86.ToArtifactName("something.apk", "", &diag));
|
|
EXPECT_FALSE(x86.ToArtifactName("something.${density}.apk", "something.apk", &diag));
|
|
EXPECT_FALSE(x86.ToArtifactName("something.apk", "something.apk", &diag));
|
|
}
|
|
|
|
TEST(ArtifactTest, Empty) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact artifact;
|
|
|
|
EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
|
|
EXPECT_TRUE(artifact.ToArtifactName("something.apk", "", &diag));
|
|
EXPECT_FALSE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
|
|
EXPECT_TRUE(artifact.ToArtifactName("something.apk", "something.apk", &diag));
|
|
}
|
|
|
|
TEST(ArtifactTest, Repeated) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact artifact;
|
|
artifact.screen_density_group = {"mdpi"};
|
|
|
|
ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "", &diag));
|
|
EXPECT_FALSE(artifact.ToArtifactName("something.${density}.${density}.apk", "", &diag));
|
|
ASSERT_TRUE(artifact.ToArtifactName("something.${density}.apk", "something.apk", &diag));
|
|
}
|
|
|
|
TEST(ArtifactTest, Nesting) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact x86;
|
|
x86.abi_group = {"x86"};
|
|
|
|
EXPECT_FALSE(x86.ToArtifactName("something.${abi${density}}.apk", "", &diag));
|
|
|
|
const Maybe<std::string>& name = x86.ToArtifactName("something.${abi${abi}}.apk", "", &diag);
|
|
ASSERT_TRUE(name);
|
|
EXPECT_EQ(name.value(), "something.${abix86}.apk");
|
|
}
|
|
|
|
TEST(ArtifactTest, Recursive) {
|
|
StdErrDiagnostics diag;
|
|
ConfiguredArtifact artifact;
|
|
artifact.device_feature_group = {"${gl}"};
|
|
artifact.gl_texture_group = {"glx1"};
|
|
|
|
EXPECT_FALSE(artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag));
|
|
|
|
artifact.device_feature_group = {"df1"};
|
|
artifact.gl_texture_group = {"${feature}"};
|
|
{
|
|
const auto& result = artifact.ToArtifactName("app.${feature}.${gl}.apk", "", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.df1.${feature}.apk");
|
|
}
|
|
|
|
// This is an invalid case, but should be the only possible case due to the ordering of
|
|
// replacement.
|
|
artifact.device_feature_group = {"${gl}"};
|
|
artifact.gl_texture_group = {"glx1"};
|
|
{
|
|
const auto& result = artifact.ToArtifactName("app.${feature}.apk", "", &diag);
|
|
ASSERT_TRUE(result);
|
|
EXPECT_EQ(result.value(), "app.glx1.apk");
|
|
}
|
|
}
|
|
|
|
} // namespace
|
|
} // namespace handler
|
|
} // namespace configuration
|
|
} // namespace aapt
|