| /* |
| * 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 "test/Fixture.h" |
| |
| #include <android-base/errors.h> |
| #include <android-base/file.h> |
| #include <android-base/stringprintf.h> |
| #include <android-base/utf8.h> |
| #include <androidfw/FileStream.h> |
| #include <androidfw/StringPiece.h> |
| #include <dirent.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "Diagnostics.h" |
| #include "cmd/Compile.h" |
| #include "cmd/Link.h" |
| #include "util/Files.h" |
| |
| using testing::Eq; |
| using testing::Ne; |
| |
| namespace aapt { |
| |
| const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test"; |
| |
| void ClearDirectory(android::StringPiece path) { |
| const std::string root_dir(path); |
| std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir); |
| if (!dir) { |
| StdErrDiagnostics().Error(android::DiagMessage() |
| << android::base::SystemErrorCodeToString(errno)); |
| return; |
| } |
| |
| while (struct dirent* entry = readdir(dir.get())) { |
| // Do not delete hidden files and do not recurse to the parent of this directory |
| if (util::StartsWith(entry->d_name, ".")) { |
| continue; |
| } |
| |
| std::string full_path = file::BuildPath({root_dir, entry->d_name}); |
| if (file::GetFileType(full_path) == file::FileType::kDirectory) { |
| ClearDirectory(full_path); |
| #ifdef _WIN32 |
| _rmdir(full_path.c_str()); |
| #else |
| rmdir(full_path.c_str()); |
| #endif |
| } else { |
| android::base::utf8::unlink(full_path.c_str()); |
| } |
| } |
| } |
| |
| void TestDirectoryFixture::SetUp() { |
| temp_dir_ = file::BuildPath({testing::TempDir(), "_temp", |
| testing::UnitTest::GetInstance()->current_test_case()->name(), |
| testing::UnitTest::GetInstance()->current_test_info()->name()}); |
| ASSERT_TRUE(file::mkdirs(temp_dir_)); |
| ClearDirectory(temp_dir_); |
| } |
| |
| void TestDirectoryFixture::TearDown() { |
| ClearDirectory(temp_dir_); |
| } |
| |
| void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) { |
| // Create any intermediate directories specified in the path |
| auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep); |
| if (pos != path.rend()) { |
| std::string dirs = path.substr(0, (&*pos - path.data())); |
| file::mkdirs(dirs); |
| } |
| |
| CHECK(android::base::WriteStringToFile(contents, path)); |
| } |
| |
| bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents, |
| android::StringPiece out_dir, android::IDiagnostics* diag) { |
| WriteFile(path, contents); |
| CHECK(file::mkdirs(out_dir.data())); |
| return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0; |
| } |
| |
| bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) { |
| std::vector<android::StringPiece> link_args; |
| for(const std::string& arg : args) { |
| link_args.emplace_back(arg); |
| } |
| |
| // Link against the android SDK |
| std::string android_sdk = |
| file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests", |
| "android-33.jar"}); |
| link_args.insert(link_args.end(), {"-I", android_sdk}); |
| |
| return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; |
| } |
| |
| bool CommandTestFixture::Link(const std::vector<std::string>& args, android::StringPiece flat_dir, |
| android::IDiagnostics* diag) { |
| std::vector<android::StringPiece> link_args; |
| for(const std::string& arg : args) { |
| link_args.emplace_back(arg); |
| } |
| |
| // Link against the android SDK |
| std::string android_sdk = |
| file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests", |
| "android-33.jar"}); |
| link_args.insert(link_args.end(), {"-I", android_sdk}); |
| |
| // Add the files from the compiled resources directory to the link file arguments |
| std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag); |
| if (compiled_files) { |
| for (std::string& compile_file : compiled_files.value()) { |
| compile_file = file::BuildPath({flat_dir, compile_file}); |
| link_args.emplace_back(std::move(compile_file)); |
| } |
| } |
| |
| return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; |
| } |
| |
| std::string CommandTestFixture::GetDefaultManifest(const char* package_name) { |
| const std::string manifest_file = GetTestPath("AndroidManifest.xml"); |
| WriteFile(manifest_file, android::base::StringPrintf(R"( |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| package="%s"> |
| </manifest>)", package_name)); |
| return manifest_file; |
| } |
| |
| std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk, |
| android::StringPiece path) { |
| return apk |
| ->GetFileCollection() |
| ->FindFile(path) |
| ->OpenAsData(); |
| } |
| |
| void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data, |
| android::ResXMLTree *out_tree) { |
| ASSERT_THAT(apk, Ne(nullptr)); |
| |
| out_tree->setTo(data->data(), data->size()); |
| ASSERT_THAT(out_tree->getError(), Eq(android::OK)); |
| while (out_tree->next() != android::ResXMLTree::START_TAG) { |
| ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); |
| ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); |
| } |
| } |
| |
| ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) { |
| } |
| |
| ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) { |
| package_name_ = package_name; |
| return *this; |
| } |
| |
| ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) { |
| contents_ += contents + "\n"; |
| return *this; |
| } |
| |
| std::string ManifestBuilder::Build(const std::string& file_path) { |
| const char* manifest_template = R"( |
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| package="%s"> |
| %s |
| </manifest>)"; |
| |
| fixture_->WriteFile(file_path, android::base::StringPrintf( |
| manifest_template, package_name_.c_str(), contents_.c_str())); |
| return file_path; |
| } |
| |
| std::string ManifestBuilder::Build() { |
| return Build(fixture_->GetTestPath("AndroidManifest.xml")); |
| } |
| |
| LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) { |
| } |
| |
| LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) { |
| manifest_supplied_ = true; |
| args_.emplace_back("--manifest"); |
| args_.emplace_back(file); |
| return *this; |
| } |
| |
| LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) { |
| args_.emplace_back(flag); |
| return *this; |
| } |
| |
| LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir, |
| android::IDiagnostics* diag) { |
| if (auto files = file::FindFiles(dir, diag)) { |
| for (std::string& compile_file : files.value()) { |
| args_.emplace_back(file::BuildPath({dir, compile_file})); |
| } |
| } |
| return *this; |
| } |
| |
| LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param, |
| const std::string& value) { |
| args_.emplace_back(param); |
| args_.emplace_back(value); |
| return *this; |
| } |
| |
| std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) { |
| if (!manifest_supplied_) { |
| SetManifestFile(ManifestBuilder(fixture_).Build()); |
| } |
| args_.emplace_back("-o"); |
| args_.emplace_back(out_apk); |
| return args_; |
| } |
| |
| } // namespace aapt |