xref: /aosp_15_r20/frameworks/base/tools/aapt2/test/Fixture.cpp (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
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