Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "test/Fixture.h" |
| 18 | |
Ryan Mitchell | 5855de7 | 2021-02-24 14:39:13 -0800 | [diff] [blame] | 19 | #include <android-base/errors.h> |
| 20 | #include <android-base/file.h> |
| 21 | #include <android-base/stringprintf.h> |
| 22 | #include <android-base/utf8.h> |
| 23 | #include <androidfw/StringPiece.h> |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 24 | #include <dirent.h> |
Ryan Mitchell | 5855de7 | 2021-02-24 14:39:13 -0800 | [diff] [blame] | 25 | #include <gmock/gmock.h> |
| 26 | #include <gtest/gtest.h> |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 27 | |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 28 | #include "Diagnostics.h" |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 29 | #include "cmd/Compile.h" |
| 30 | #include "cmd/Link.h" |
| 31 | #include "io/FileStream.h" |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 32 | #include "util/Files.h" |
| 33 | |
| 34 | using testing::Eq; |
| 35 | using testing::Ne; |
| 36 | |
| 37 | namespace aapt { |
| 38 | |
Ryan Mitchell | a55dc2e | 2019-01-24 10:58:23 -0800 | [diff] [blame] | 39 | const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test"; |
| 40 | |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 41 | void ClearDirectory(const android::StringPiece& path) { |
| 42 | const std::string root_dir = path.to_string(); |
| 43 | std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir); |
| 44 | if (!dir) { |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 45 | StdErrDiagnostics().Error(android::DiagMessage() |
| 46 | << android::base::SystemErrorCodeToString(errno)); |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 47 | return; |
| 48 | } |
| 49 | |
| 50 | while (struct dirent* entry = readdir(dir.get())) { |
| 51 | // Do not delete hidden files and do not recurse to the parent of this directory |
| 52 | if (util::StartsWith(entry->d_name, ".")) { |
| 53 | continue; |
| 54 | } |
| 55 | |
| 56 | std::string full_path = file::BuildPath({root_dir, entry->d_name}); |
| 57 | if (file::GetFileType(full_path) == file::FileType::kDirectory) { |
| 58 | ClearDirectory(full_path); |
| 59 | #ifdef _WIN32 |
| 60 | _rmdir(full_path.c_str()); |
| 61 | #else |
| 62 | rmdir(full_path.c_str()); |
| 63 | #endif |
| 64 | } else { |
| 65 | android::base::utf8::unlink(full_path.c_str()); |
| 66 | } |
| 67 | } |
| 68 | } |
| 69 | |
| 70 | void TestDirectoryFixture::SetUp() { |
weisu | 90d3fb6 | 2021-12-12 22:24:52 +0000 | [diff] [blame] | 71 | temp_dir_ = file::BuildPath({testing::TempDir(), "_temp", |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 72 | testing::UnitTest::GetInstance()->current_test_case()->name(), |
| 73 | testing::UnitTest::GetInstance()->current_test_info()->name()}); |
| 74 | ASSERT_TRUE(file::mkdirs(temp_dir_)); |
| 75 | ClearDirectory(temp_dir_); |
| 76 | } |
| 77 | |
| 78 | void TestDirectoryFixture::TearDown() { |
| 79 | ClearDirectory(temp_dir_); |
| 80 | } |
| 81 | |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 82 | void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) { |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 83 | // Create any intermediate directories specified in the path |
| 84 | auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep); |
| 85 | if (pos != path.rend()) { |
| 86 | std::string dirs = path.substr(0, (&*pos - path.data())); |
| 87 | file::mkdirs(dirs); |
| 88 | } |
| 89 | |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 90 | CHECK(android::base::WriteStringToFile(contents, path)); |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 91 | } |
| 92 | |
| 93 | bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents, |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 94 | const android::StringPiece& out_dir, |
| 95 | android::IDiagnostics* diag) { |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 96 | WriteFile(path, contents); |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 97 | CHECK(file::mkdirs(out_dir.data())); |
| 98 | return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0; |
| 99 | } |
| 100 | |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 101 | bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) { |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 102 | std::vector<android::StringPiece> link_args; |
| 103 | for(const std::string& arg : args) { |
| 104 | link_args.emplace_back(arg); |
| 105 | } |
| 106 | |
| 107 | // Link against the android SDK |
| 108 | std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(), |
| 109 | "integration-tests", "CommandTests", |
| 110 | "android-28.jar"}); |
| 111 | link_args.insert(link_args.end(), {"-I", android_sdk}); |
| 112 | |
| 113 | return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; |
| 114 | } |
| 115 | |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 116 | bool CommandTestFixture::Link(const std::vector<std::string>& args, |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 117 | const android::StringPiece& flat_dir, android::IDiagnostics* diag) { |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 118 | std::vector<android::StringPiece> link_args; |
| 119 | for(const std::string& arg : args) { |
| 120 | link_args.emplace_back(arg); |
| 121 | } |
| 122 | |
| 123 | // Link against the android SDK |
| 124 | std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(), |
| 125 | "integration-tests", "CommandTests", |
| 126 | "android-28.jar"}); |
| 127 | link_args.insert(link_args.end(), {"-I", android_sdk}); |
| 128 | |
| 129 | // Add the files from the compiled resources directory to the link file arguments |
Ryan Mitchell | 4382e44 | 2021-07-14 12:53:01 -0700 | [diff] [blame] | 130 | std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag); |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 131 | if (compiled_files) { |
| 132 | for (std::string& compile_file : compiled_files.value()) { |
| 133 | compile_file = file::BuildPath({flat_dir, compile_file}); |
| 134 | link_args.emplace_back(std::move(compile_file)); |
| 135 | } |
| 136 | } |
| 137 | |
| 138 | return LinkCommand(diag).Execute(link_args, &std::cerr) == 0; |
| 139 | } |
| 140 | |
Ryan Mitchell | a55dc2e | 2019-01-24 10:58:23 -0800 | [diff] [blame] | 141 | std::string CommandTestFixture::GetDefaultManifest(const char* package_name) { |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 142 | const std::string manifest_file = GetTestPath("AndroidManifest.xml"); |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 143 | WriteFile(manifest_file, android::base::StringPrintf(R"( |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 144 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
Ryan Mitchell | a55dc2e | 2019-01-24 10:58:23 -0800 | [diff] [blame] | 145 | package="%s"> |
Ryan Mitchell | 81dfca0 | 2019-06-07 10:20:27 -0700 | [diff] [blame] | 146 | </manifest>)", package_name)); |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 147 | return manifest_file; |
| 148 | } |
| 149 | |
Winson | b7be793 | 2019-01-23 11:10:52 -0800 | [diff] [blame] | 150 | std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk, |
| 151 | const android::StringPiece& path) { |
| 152 | return apk |
| 153 | ->GetFileCollection() |
| 154 | ->FindFile(path) |
| 155 | ->OpenAsData(); |
| 156 | } |
| 157 | |
| 158 | void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data, |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 159 | android::ResXMLTree *out_tree) { |
| 160 | ASSERT_THAT(apk, Ne(nullptr)); |
| 161 | |
Ryan Mitchell | 479fa39 | 2019-01-02 17:15:39 -0800 | [diff] [blame] | 162 | out_tree->setTo(data->data(), data->size()); |
| 163 | ASSERT_THAT(out_tree->getError(), Eq(android::OK)); |
| 164 | while (out_tree->next() != android::ResXMLTree::START_TAG) { |
| 165 | ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT)); |
| 166 | ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT)); |
| 167 | } |
| 168 | } |
| 169 | |
Ryan Mitchell | 5855de7 | 2021-02-24 14:39:13 -0800 | [diff] [blame] | 170 | ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) { |
| 171 | } |
| 172 | |
| 173 | ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) { |
| 174 | package_name_ = package_name; |
| 175 | return *this; |
| 176 | } |
| 177 | |
| 178 | ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) { |
| 179 | contents_ += contents + "\n"; |
| 180 | return *this; |
| 181 | } |
| 182 | |
| 183 | std::string ManifestBuilder::Build(const std::string& file_path) { |
| 184 | const char* manifest_template = R"( |
| 185 | <manifest xmlns:android="http://schemas.android.com/apk/res/android" |
| 186 | package="%s"> |
| 187 | %s |
| 188 | </manifest>)"; |
| 189 | |
| 190 | fixture_->WriteFile(file_path, android::base::StringPrintf( |
| 191 | manifest_template, package_name_.c_str(), contents_.c_str())); |
| 192 | return file_path; |
| 193 | } |
| 194 | |
| 195 | std::string ManifestBuilder::Build() { |
| 196 | return Build(fixture_->GetTestPath("AndroidManifest.xml")); |
| 197 | } |
| 198 | |
| 199 | LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) { |
| 200 | } |
| 201 | |
| 202 | LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) { |
| 203 | manifest_supplied_ = true; |
| 204 | args_.emplace_back("--manifest"); |
| 205 | args_.emplace_back(file); |
| 206 | return *this; |
| 207 | } |
| 208 | |
| 209 | LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) { |
| 210 | args_.emplace_back(flag); |
| 211 | return *this; |
| 212 | } |
| 213 | |
| 214 | LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir, |
Jeremy Meyer | 56f36e8 | 2022-05-20 20:35:42 +0000 | [diff] [blame^] | 215 | android::IDiagnostics* diag) { |
Ryan Mitchell | 5855de7 | 2021-02-24 14:39:13 -0800 | [diff] [blame] | 216 | if (auto files = file::FindFiles(dir, diag)) { |
| 217 | for (std::string& compile_file : files.value()) { |
| 218 | args_.emplace_back(file::BuildPath({dir, compile_file})); |
| 219 | } |
| 220 | } |
| 221 | return *this; |
| 222 | } |
| 223 | |
| 224 | LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param, |
| 225 | const std::string& value) { |
| 226 | args_.emplace_back(param); |
| 227 | args_.emplace_back(value); |
| 228 | return *this; |
| 229 | } |
| 230 | |
| 231 | std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) { |
| 232 | if (!manifest_supplied_) { |
| 233 | SetManifestFile(ManifestBuilder(fixture_).Build()); |
| 234 | } |
| 235 | args_.emplace_back("-o"); |
| 236 | args_.emplace_back(out_apk); |
| 237 | return args_; |
| 238 | } |
| 239 | |
weisu | 90d3fb6 | 2021-12-12 22:24:52 +0000 | [diff] [blame] | 240 | } // namespace aapt |