/* * 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 #include #include #include #include #include #include #include #include "cmd/Compile.h" #include "cmd/Link.h" #include "io/FileStream.h" #include "util/Files.h" using testing::Eq; using testing::Ne; namespace aapt { const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test"; void ClearDirectory(const android::StringPiece& path) { const std::string root_dir = path.to_string(); std::unique_ptr dir(opendir(root_dir.data()), closedir); if (!dir) { StdErrDiagnostics().Error(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({android::base::GetExecutableDirectory(), "_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, const android::StringPiece& out_dir, 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& args, IDiagnostics* diag) { std::vector 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-28.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& args, const android::StringPiece& flat_dir, IDiagnostics* diag) { std::vector 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-28.jar"}); link_args.insert(link_args.end(), {"-I", android_sdk}); // Add the files from the compiled resources directory to the link file arguments Maybe> 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"( )", package_name)); return manifest_file; } std::unique_ptr CommandTestFixture::OpenFileAsData(LoadedApk* apk, const 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"( %s )"; 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, 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 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