/* * 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 #include "androidfw/ResourceTypes.h" #include "test/Test.h" #include "xml/XmlDom.h" namespace aapt { namespace { using ::android::ResTable_config; using configuration::Abi; using configuration::AndroidSdk; using configuration::Artifact; using configuration::PostProcessingConfiguration; using configuration::DeviceFeature; using configuration::GlTexture; using configuration::Locale; using configuration::AndroidManifest; using ::testing::ElementsAre; using xml::Element; using xml::NodeCast; constexpr const char* kValidConfig = R"( armeabi-v7a arm64-v8a x86 mips xhdpi xxhdpi xxxhdpi ldpi mdpi hdpi xhdpi xxhdpi xxxhdpi assets/dxt1/* android.hardware.audio.low_latency ${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release )"; class ConfigurationParserTest : public ConfigurationParser, public ::testing::Test { public: ConfigurationParserTest() : ConfigurationParser("") {} protected: StdErrDiagnostics diag_; }; TEST_F(ConfigurationParserTest, ForPath_NoFile) { auto result = ConfigurationParser::ForPath("./does_not_exist.xml"); EXPECT_FALSE(result); } TEST_F(ConfigurationParserTest, ValidateFile) { auto parser = ConfigurationParser::ForContents(kValidConfig).WithDiagnostics(&diag_); auto result = parser.Parse(); ASSERT_TRUE(result); PostProcessingConfiguration& value = result.value(); EXPECT_EQ(2ul, value.artifacts.size()); ASSERT_TRUE(value.artifact_format); EXPECT_EQ( "${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release", value.artifact_format.value() ); EXPECT_EQ(2ul, value.abi_groups.size()); EXPECT_EQ(2ul, value.abi_groups["arm"].size()); EXPECT_EQ(2ul, value.abi_groups["other"].size()); EXPECT_EQ(2ul, value.screen_density_groups.size()); EXPECT_EQ(3ul, value.screen_density_groups["large"].size()); EXPECT_EQ(6ul, value.screen_density_groups["alldpi"].size()); EXPECT_EQ(3ul, value.locale_groups.size()); EXPECT_EQ(4ul, value.locale_groups["europe"].size()); EXPECT_EQ(3ul, value.locale_groups["north-america"].size()); EXPECT_EQ(1ul, value.locale_groups["all"].size()); EXPECT_EQ(1ul, value.android_sdk_groups.size()); EXPECT_EQ(1ul, value.android_sdk_groups["19"].size()); EXPECT_EQ(1ul, value.gl_texture_groups.size()); EXPECT_EQ(1ul, value.gl_texture_groups["dxt1"].size()); EXPECT_EQ(1ul, value.device_feature_groups.size()); EXPECT_EQ(1ul, value.device_feature_groups["low-latency"].size()); } TEST_F(ConfigurationParserTest, InvalidNamespace) { constexpr const char* invalid_ns = R"( )"; auto result = ConfigurationParser::ForContents(invalid_ns).Parse(); ASSERT_FALSE(result); } TEST_F(ConfigurationParserTest, ArtifactAction) { static constexpr const char* xml = R"xml( )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = artifact_handler_(&config, NodeCast(doc->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(1ul, config.artifacts.size()); auto& artifact = config.artifacts.front(); EXPECT_EQ("", 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("19", artifact.android_sdk_group.value()); EXPECT_EQ("dxt1", artifact.gl_texture_group.value()); EXPECT_EQ("low-latency", artifact.device_feature_group.value()); // Perform a second action to ensure we get 2 artifacts. static constexpr const char* second = R"xml( )xml"; doc = test::BuildXmlDom(second); ok = artifact_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(2ul, config.artifacts.size()); } TEST_F(ConfigurationParserTest, ArtifactFormatAction) { static constexpr const char* xml = R"xml( ${base}.${abi}.${screen-density}.${locale}.${sdk}.${gl}.${feature}.release )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = artifact_format_handler_(&config, NodeCast(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(config.artifact_format.value()) ); } TEST_F(ConfigurationParserTest, AbiGroupAction) { static constexpr const char* xml = R"xml( armeabi-v7a arm64-v8a )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = abi_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(1ul, config.abi_groups.size()); ASSERT_EQ(1u, config.abi_groups.count("arm")); auto& out = config.abi_groups["arm"]; ASSERT_THAT(out, ElementsAre(Abi::kArmV7a, Abi::kArm64V8a)); } TEST_F(ConfigurationParserTest, ScreenDensityGroupAction) { static constexpr const char* xml = R"xml( xhdpi xxhdpi xxxhdpi )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = screen_density_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(1ul, config.screen_density_groups.size()); 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"]; ASSERT_THAT(out, ElementsAre(xhdpi, xxhdpi, xxxhdpi)); } TEST_F(ConfigurationParserTest, LocaleGroupAction) { static constexpr const char* xml = R"xml( )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = locale_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); ASSERT_EQ(1ul, config.locale_groups.size()); ASSERT_EQ(1u, config.locale_groups.count("europe")); auto& out = config.locale_groups["europe"]; Locale en; en.lang = std::string("en"); Locale es; es.lang = std::string("es"); Locale fr; fr.lang = std::string("fr"); Locale de; de.lang = std::string("de"); ASSERT_THAT(out, ElementsAre(en, es, fr, de)); } TEST_F(ConfigurationParserTest, AndroidSdkGroupAction) { static constexpr const char* xml = R"xml( )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = android_sdk_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); ASSERT_EQ(1ul, config.android_sdk_groups.size()); ASSERT_EQ(1u, config.android_sdk_groups.count("19")); auto& out = config.android_sdk_groups["19"]; AndroidSdk sdk; sdk.min_sdk_version = std::string("19"); sdk.target_sdk_version = std::string("24"); sdk.max_sdk_version = std::string("25"); sdk.manifest = AndroidManifest(); ASSERT_EQ(1ul, out.size()); ASSERT_EQ(sdk, out[0]); } TEST_F(ConfigurationParserTest, GlTextureGroupAction) { static constexpr const char* xml = R"xml( assets/dxt1/main/* assets/dxt1/test/* )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = gl_texture_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(1ul, config.gl_texture_groups.size()); ASSERT_EQ(1u, config.gl_texture_groups.count("dxt1")); auto& out = config.gl_texture_groups["dxt1"]; 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( android.hardware.audio.low_latency android.hardware.audio.pro )xml"; auto doc = test::BuildXmlDom(xml); PostProcessingConfiguration config; bool ok = device_feature_group_handler_(&config, NodeCast(doc.get()->root.get()), &diag_); ASSERT_TRUE(ok); EXPECT_EQ(1ul, config.device_feature_groups.size()); ASSERT_EQ(1u, config.device_feature_groups.count("low-latency")); auto& out = config.device_feature_groups["low-latency"]; DeviceFeature low_latency = "android.hardware.audio.low_latency"; DeviceFeature pro = "android.hardware.audio.pro"; ASSERT_THAT(out, ElementsAre(low_latency, pro)); } TEST(ArtifactTest, Simple) { StdErrDiagnostics diag; Artifact 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"); Artifact 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"); } TEST(ArtifactTest, Complex) { StdErrDiagnostics diag; Artifact 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_group = {"26"}; auto result = artifact.ToArtifactName("app.{density}_{locale}_{feature}_{gl}.sdk{sdk}.{abi}.apk", &diag); ASSERT_TRUE(result); EXPECT_EQ(result.value(), "app.ldpi_en-AU_df1_glx1.sdk26.mips64.apk"); } TEST(ArtifactTest, Missing) { StdErrDiagnostics diag; Artifact x86; x86.abi_group = {"x86"}; EXPECT_FALSE(x86.ToArtifactName("something.{density}.apk", &diag)); EXPECT_FALSE(x86.ToArtifactName("something.apk", &diag)); } TEST(ArtifactTest, Empty) { StdErrDiagnostics diag; Artifact artifact; EXPECT_FALSE(artifact.ToArtifactName("something.{density}.apk", &diag)); EXPECT_TRUE(artifact.ToArtifactName("something.apk", &diag)); } } // namespace } // namespace aapt