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
19 #include <dirent.h>
20
21 #include "android-base/errors.h"
22 #include "android-base/file.h"
23 #include "android-base/stringprintf.h"
24 #include "android-base/utf8.h"
25 #include "androidfw/StringPiece.h"
26 #include "gmock/gmock.h"
27 #include "gtest/gtest.h"
28
29 #include "cmd/Compile.h"
30 #include "cmd/Link.h"
31 #include "io/FileStream.h"
32 #include "io/Util.h"
33 #include "util/Files.h"
34
35 using testing::Eq;
36 using testing::Ne;
37
38 namespace aapt {
39
40 const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
41
ClearDirectory(const android::StringPiece & path)42 void ClearDirectory(const android::StringPiece& path) {
43 const std::string root_dir = path.to_string();
44 std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
45 if (!dir) {
46 StdErrDiagnostics().Error(DiagMessage() << android::base::SystemErrorCodeToString(errno));
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
SetUp()70 void TestDirectoryFixture::SetUp() {
71 temp_dir_ = file::BuildPath({android::base::GetExecutableDirectory(),
72 "_temp",
73 testing::UnitTest::GetInstance()->current_test_case()->name(),
74 testing::UnitTest::GetInstance()->current_test_info()->name()});
75 ASSERT_TRUE(file::mkdirs(temp_dir_));
76 ClearDirectory(temp_dir_);
77 }
78
TearDown()79 void TestDirectoryFixture::TearDown() {
80 ClearDirectory(temp_dir_);
81 }
82
WriteFile(const std::string & path,const std::string & contents)83 bool TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
84 CHECK(util::StartsWith(path, temp_dir_))
85 << "Attempting to create a file outside of test temporary directory.";
86
87 // Create any intermediate directories specified in the path
88 auto pos = std::find(path.rbegin(), path.rend(), file::sDirSep);
89 if (pos != path.rend()) {
90 std::string dirs = path.substr(0, (&*pos - path.data()));
91 file::mkdirs(dirs);
92 }
93
94 return android::base::WriteStringToFile(contents, path);
95 }
96
CompileFile(const std::string & path,const std::string & contents,const android::StringPiece & out_dir,IDiagnostics * diag)97 bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
98 const android::StringPiece& out_dir, IDiagnostics* diag) {
99 CHECK(WriteFile(path, contents));
100 CHECK(file::mkdirs(out_dir.data()));
101 return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
102 }
103
Link(const std::vector<std::string> & args,const android::StringPiece & flat_dir,IDiagnostics * diag)104 bool CommandTestFixture::Link(const std::vector<std::string>& args,
105 const android::StringPiece& flat_dir, IDiagnostics* diag) {
106 std::vector<android::StringPiece> link_args;
107 for(const std::string& arg : args) {
108 link_args.emplace_back(arg);
109 }
110
111 // Link against the android SDK
112 std::string android_sdk = file::BuildPath({android::base::GetExecutableDirectory(),
113 "integration-tests", "CommandTests",
114 "android-28.jar"});
115 link_args.insert(link_args.end(), {"-I", android_sdk});
116
117 // Add the files from the compiled resources directory to the link file arguments
118 Maybe<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
119 if (compiled_files) {
120 for (std::string& compile_file : compiled_files.value()) {
121 compile_file = file::BuildPath({flat_dir, compile_file});
122 link_args.emplace_back(std::move(compile_file));
123 }
124 }
125
126 return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
127 }
128
GetDefaultManifest(const char * package_name)129 std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
130 const std::string manifest_file = GetTestPath("AndroidManifest.xml");
131 CHECK(WriteFile(manifest_file, android::base::StringPrintf(R"(
132 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
133 package="%s">
134 </manifest>)", package_name)));
135 return manifest_file;
136 }
137
138 std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
139 const android::StringPiece& path) {
140 return apk
141 ->GetFileCollection()
142 ->FindFile(path)
143 ->OpenAsData();
144 }
145
146 void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data,
147 android::ResXMLTree *out_tree) {
148 ASSERT_THAT(apk, Ne(nullptr));
149
150 out_tree->setTo(data->data(), data->size());
151 ASSERT_THAT(out_tree->getError(), Eq(android::OK));
152 while (out_tree->next() != android::ResXMLTree::START_TAG) {
153 ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
154 ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
155 }
156 }
157
158 } // namespace aapt