/* * Copyright (C) 2018 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 "Link.h" #include #include "AppInfo.h" #include "LoadedApk.h" #include "test/Test.h" using testing::Eq; using testing::HasSubstr; using testing::IsNull; using testing::Ne; using testing::NotNull; namespace aapt { using LinkTest = CommandTestFixture; TEST_F(LinkTest, RemoveRawXmlStrings) { StdErrDiagnostics diag; const std::string compiled_files_dir = GetTestPath("compiled"); ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"()", compiled_files_dir, &diag)); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(), "-o", out_apk, }; ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); // Load the binary xml tree android::ResXMLTree tree; std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); std::unique_ptr data = OpenFileAsData(apk.get(), "res/xml/test.xml"); ASSERT_THAT(data, Ne(nullptr)); AssertLoadXml(apk.get(), data.get(), &tree); // Check that the raw string index has not been assigned EXPECT_THAT(tree.getAttributeValueStringID(0), Eq(-1)); } TEST_F(LinkTest, KeepRawXmlStrings) { StdErrDiagnostics diag; const std::string compiled_files_dir = GetTestPath("compiled"); ASSERT_TRUE(CompileFile(GetTestPath("res/xml/test.xml"), R"()", compiled_files_dir, &diag)); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(), "-o", out_apk, "--keep-raw-values" }; ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); // Load the binary xml tree android::ResXMLTree tree; std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); std::unique_ptr data = OpenFileAsData(apk.get(), "res/xml/test.xml"); ASSERT_THAT(data, Ne(nullptr)); AssertLoadXml(apk.get(), data.get(), &tree); // Check that the raw string index has been set to the correct string pool entry int32_t raw_index = tree.getAttributeValueStringID(0); ASSERT_THAT(raw_index, Ne(-1)); EXPECT_THAT(util::GetString(tree.getStrings(), static_cast(raw_index)), Eq("007")); } TEST_F(LinkTest, NoCompressAssets) { StdErrDiagnostics diag; std::string content(500, 'a'); WriteFile(GetTestPath("assets/testtxt"), content); WriteFile(GetTestPath("assets/testtxt2"), content); WriteFile(GetTestPath("assets/test.txt"), content); WriteFile(GetTestPath("assets/test.hello.txt"), content); WriteFile(GetTestPath("assets/test.hello.xml"), content); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(), "-o", out_apk, "-0", ".txt", "-0", "txt2", "-0", ".hello.txt", "-0", "hello.xml", "-A", GetTestPath("assets") }; ASSERT_TRUE(Link(link_args, &diag)); std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); io::IFileCollection* zip = apk->GetFileCollection(); ASSERT_THAT(zip, Ne(nullptr)); auto file = zip->FindFile("assets/testtxt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_TRUE(file->WasCompressed()); file = zip->FindFile("assets/testtxt2"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); file = zip->FindFile("assets/test.txt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); file = zip->FindFile("assets/test.hello.txt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); file = zip->FindFile("assets/test.hello.xml"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); } TEST_F(LinkTest, NoCompressResources) { StdErrDiagnostics diag; std::string content(500, 'a'); const std::string compiled_files_dir = GetTestPath("compiled"); ASSERT_TRUE(CompileFile(GetTestPath("res/raw/testtxt"), content, compiled_files_dir, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test.txt"), content, compiled_files_dir, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test1.hello.txt"), content, compiled_files_dir, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/raw/test2.goodbye.xml"), content, compiled_files_dir, &diag)); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(), "-o", out_apk, "-0", ".txt", "-0", ".hello.txt", "-0", "goodbye.xml", }; ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); io::IFileCollection* zip = apk->GetFileCollection(); ASSERT_THAT(zip, Ne(nullptr)); auto file = zip->FindFile("res/raw/testtxt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_TRUE(file->WasCompressed()); file = zip->FindFile("res/raw/test.txt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); file = zip->FindFile("res/raw/test1.hello.hello.txt"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); file = zip->FindFile("res/raw/test2.goodbye.goodbye.xml"); ASSERT_THAT(file, Ne(nullptr)); EXPECT_FALSE(file->WasCompressed()); } TEST_F(LinkTest, OverlayStyles) { StdErrDiagnostics diag; const std::string compiled_files_dir = GetTestPath("compiled"); const std::string override_files_dir = GetTestPath("compiled-override"); ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), R"( )", compiled_files_dir, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/values/values-override.xml"), R"( )", override_files_dir, &diag)); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(kDefaultPackageName), "-o", out_apk, }; const auto override_files = file::FindFiles(override_files_dir, &diag); for (const auto &override_file : override_files.value()) { link_args.push_back("-R"); link_args.push_back(file::BuildPath({override_files_dir, override_file})); } ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); const Style* actual_style = test::GetValue )", compiled_files_dir, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/values/values-override.xml"), R"( )", override_files_dir, &diag)); const std::string out_apk = GetTestPath("out.apk"); std::vector link_args = { "--manifest", GetDefaultManifest(kDefaultPackageName), "--override-styles-instead-of-overlaying", "-o", out_apk, }; const auto override_files = file::FindFiles(override_files_dir, &diag); for (const auto &override_file : override_files.value()) { link_args.push_back("-R"); link_args.push_back(file::BuildPath({override_files_dir, override_file})); } ASSERT_TRUE(Link(link_args, compiled_files_dir, &diag)); std::unique_ptr apk = LoadedApk::LoadApkFromPath(out_apk, &diag); ASSERT_THAT(apk, Ne(nullptr)); const Style* actual_style = test::GetValue )"; const std::string xml_values = R"( )"; // Build a library with a public attribute const std::string lib_res = GetTestPath("test-res"); ASSERT_TRUE(CompileFile(GetTestPath("res/values/values.xml"), values, lib_res, &diag)); ASSERT_TRUE(CompileFile(GetTestPath("res/layout/layout.xml"), xml_values, lib_res, &diag)); const std::string lib_apk = GetTestPath("test.apk"); // clang-format off auto lib_link_args = LinkCommandBuilder(this) .SetManifestFile(ManifestBuilder(this).SetPackageName("com.test").Build()) .AddCompiledResDir(lib_res, &diag) .AddFlag("--no-auto-version") .Build(lib_apk); // clang-format on ASSERT_TRUE(Link(lib_link_args, &diag)); auto apk = LoadedApk::LoadApkFromPath(lib_apk, &diag); ASSERT_THAT(apk, NotNull()); // Test that the type flags determines the value type auto actual_bool = test::GetValue(apk->GetResourceTable(), "com.test:bool/is_enabled_bool"); ASSERT_THAT(actual_bool, NotNull()); EXPECT_EQ(android::Res_value::TYPE_INT_BOOLEAN, actual_bool->value.dataType); EXPECT_EQ(0xffffffffu, actual_bool->value.data); auto actual_str = test::GetValue(apk->GetResourceTable(), "com.test:string/is_enabled_str"); ASSERT_THAT(actual_str, NotNull()); EXPECT_EQ(*actual_str->value, "true"); // Test nested data structures auto actual_array = test::GetValue(apk->GetResourceTable(), "com.test:array/my_array"); ASSERT_THAT(actual_array, NotNull()); EXPECT_THAT(actual_array->elements.size(), Eq(1)); auto array_el_ref = ValueCast(actual_array->elements[0].get()); ASSERT_THAT(array_el_ref, NotNull()); EXPECT_THAT(array_el_ref->value.dataType, Eq(android::Res_value::TYPE_INT_BOOLEAN)); EXPECT_THAT(array_el_ref->value.data, Eq(0xffffffffu)); auto actual_style = test::GetValue