blob: dbc0e36431049c85dd15b78f35e57791a0e5d415 [file] [log] [blame]
Ryan Mitchell479fa392019-01-02 17:15:39 -08001/*
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 Mitchell5855de72021-02-24 14:39:13 -080019#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 Meyer56f36e82022-05-20 20:35:42 +000024#include <dirent.h>
Ryan Mitchell5855de72021-02-24 14:39:13 -080025#include <gmock/gmock.h>
26#include <gtest/gtest.h>
Ryan Mitchell479fa392019-01-02 17:15:39 -080027
Jeremy Meyer56f36e82022-05-20 20:35:42 +000028#include "Diagnostics.h"
Ryan Mitchell479fa392019-01-02 17:15:39 -080029#include "cmd/Compile.h"
30#include "cmd/Link.h"
31#include "io/FileStream.h"
Ryan Mitchell479fa392019-01-02 17:15:39 -080032#include "util/Files.h"
33
34using testing::Eq;
35using testing::Ne;
36
37namespace aapt {
38
Ryan Mitchella55dc2e2019-01-24 10:58:23 -080039const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
40
Ryan Mitchell479fa392019-01-02 17:15:39 -080041void 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 Meyer56f36e82022-05-20 20:35:42 +000045 StdErrDiagnostics().Error(android::DiagMessage()
46 << android::base::SystemErrorCodeToString(errno));
Ryan Mitchell479fa392019-01-02 17:15:39 -080047 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
70void TestDirectoryFixture::SetUp() {
weisu90d3fb62021-12-12 22:24:52 +000071 temp_dir_ = file::BuildPath({testing::TempDir(), "_temp",
Ryan Mitchell479fa392019-01-02 17:15:39 -080072 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
78void TestDirectoryFixture::TearDown() {
79 ClearDirectory(temp_dir_);
80}
81
Ryan Mitchell81dfca02019-06-07 10:20:27 -070082void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
Ryan Mitchell479fa392019-01-02 17:15:39 -080083 // 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 Mitchell81dfca02019-06-07 10:20:27 -070090 CHECK(android::base::WriteStringToFile(contents, path));
Ryan Mitchell479fa392019-01-02 17:15:39 -080091}
92
93bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
Jeremy Meyer56f36e82022-05-20 20:35:42 +000094 const android::StringPiece& out_dir,
95 android::IDiagnostics* diag) {
Ryan Mitchell81dfca02019-06-07 10:20:27 -070096 WriteFile(path, contents);
Ryan Mitchell479fa392019-01-02 17:15:39 -080097 CHECK(file::mkdirs(out_dir.data()));
98 return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
99}
100
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000101bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) {
Ryan Mitchell81dfca02019-06-07 10:20:27 -0700102 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
Josh Houec67cb42022-06-09 19:19:21 +0800108 std::string android_sdk =
109 file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
110 "android-33.jar"});
Ryan Mitchell81dfca02019-06-07 10:20:27 -0700111 link_args.insert(link_args.end(), {"-I", android_sdk});
112
113 return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
114}
115
Ryan Mitchell479fa392019-01-02 17:15:39 -0800116bool CommandTestFixture::Link(const std::vector<std::string>& args,
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000117 const android::StringPiece& flat_dir, android::IDiagnostics* diag) {
Ryan Mitchell479fa392019-01-02 17:15:39 -0800118 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
Josh Houec67cb42022-06-09 19:19:21 +0800124 std::string android_sdk =
125 file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
126 "android-33.jar"});
Ryan Mitchell479fa392019-01-02 17:15:39 -0800127 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 Mitchell4382e442021-07-14 12:53:01 -0700130 std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
Ryan Mitchell479fa392019-01-02 17:15:39 -0800131 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 Mitchella55dc2e2019-01-24 10:58:23 -0800141std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
Ryan Mitchell479fa392019-01-02 17:15:39 -0800142 const std::string manifest_file = GetTestPath("AndroidManifest.xml");
Ryan Mitchell81dfca02019-06-07 10:20:27 -0700143 WriteFile(manifest_file, android::base::StringPrintf(R"(
Ryan Mitchell479fa392019-01-02 17:15:39 -0800144 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
Ryan Mitchella55dc2e2019-01-24 10:58:23 -0800145 package="%s">
Ryan Mitchell81dfca02019-06-07 10:20:27 -0700146 </manifest>)", package_name));
Ryan Mitchell479fa392019-01-02 17:15:39 -0800147 return manifest_file;
148}
149
Winsonb7be7932019-01-23 11:10:52 -0800150std::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
158void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data,
Ryan Mitchell479fa392019-01-02 17:15:39 -0800159 android::ResXMLTree *out_tree) {
160 ASSERT_THAT(apk, Ne(nullptr));
161
Ryan Mitchell479fa392019-01-02 17:15:39 -0800162 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 Mitchell5855de72021-02-24 14:39:13 -0800170ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
171}
172
173ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) {
174 package_name_ = package_name;
175 return *this;
176}
177
178ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) {
179 contents_ += contents + "\n";
180 return *this;
181}
182
183std::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
195std::string ManifestBuilder::Build() {
196 return Build(fixture_->GetTestPath("AndroidManifest.xml"));
197}
198
199LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
200}
201
202LinkCommandBuilder& 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
209LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
210 args_.emplace_back(flag);
211 return *this;
212}
213
214LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
Jeremy Meyer56f36e82022-05-20 20:35:42 +0000215 android::IDiagnostics* diag) {
Ryan Mitchell5855de72021-02-24 14:39:13 -0800216 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
224LinkCommandBuilder& 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
231std::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
weisu90d3fb62021-12-12 22:24:52 +0000240} // namespace aapt