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