• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <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/FileStream.h>
24  #include <androidfw/StringPiece.h>
25  #include <dirent.h>
26  #include <gmock/gmock.h>
27  #include <gtest/gtest.h>
28  
29  #include "Diagnostics.h"
30  #include "cmd/Compile.h"
31  #include "cmd/Link.h"
32  #include "util/Files.h"
33  
34  using testing::Eq;
35  using testing::Ne;
36  
37  namespace aapt {
38  
39  const char* CommandTestFixture::kDefaultPackageName = "com.aapt.command.test";
40  
ClearDirectory(android::StringPiece path)41  void ClearDirectory(android::StringPiece path) {
42    const std::string root_dir(path);
43    std::unique_ptr<DIR, decltype(closedir)*> dir(opendir(root_dir.data()), closedir);
44    if (!dir) {
45      StdErrDiagnostics().Error(android::DiagMessage()
46                                << 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({testing::TempDir(), "_temp",
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  
TearDown()78  void TestDirectoryFixture::TearDown() {
79    ClearDirectory(temp_dir_);
80  }
81  
WriteFile(const std::string & path,const std::string & contents)82  void TestDirectoryFixture::WriteFile(const std::string& path, const std::string& contents) {
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  
90    CHECK(android::base::WriteStringToFile(contents, path));
91  }
92  
CompileFile(const std::string & path,const std::string & contents,android::StringPiece out_dir,android::IDiagnostics * diag)93  bool CommandTestFixture::CompileFile(const std::string& path, const std::string& contents,
94                                       android::StringPiece out_dir, android::IDiagnostics* diag) {
95    WriteFile(path, contents);
96    CHECK(file::mkdirs(out_dir.data()));
97    return CompileCommand(diag).Execute({path, "-o", out_dir, "-v"}, &std::cerr) == 0;
98  }
99  
Link(const std::vector<std::string> & args,android::IDiagnostics * diag)100  bool CommandTestFixture::Link(const std::vector<std::string>& args, android::IDiagnostics* diag) {
101    std::vector<android::StringPiece> link_args;
102    for(const std::string& arg : args) {
103      link_args.emplace_back(arg);
104    }
105  
106    // Link against the android SDK
107    std::string android_sdk =
108        file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
109                         "android-33.jar"});
110    link_args.insert(link_args.end(), {"-I", android_sdk});
111  
112    return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
113  }
114  
Link(const std::vector<std::string> & args,android::StringPiece flat_dir,android::IDiagnostics * diag)115  bool CommandTestFixture::Link(const std::vector<std::string>& args, android::StringPiece flat_dir,
116                                android::IDiagnostics* diag) {
117    std::vector<android::StringPiece> link_args;
118    for(const std::string& arg : args) {
119      link_args.emplace_back(arg);
120    }
121  
122    // Link against the android SDK
123    std::string android_sdk =
124        file::BuildPath({android::base::GetExecutableDirectory(), "integration-tests", "CommandTests",
125                         "android-33.jar"});
126    link_args.insert(link_args.end(), {"-I", android_sdk});
127  
128    // Add the files from the compiled resources directory to the link file arguments
129    std::optional<std::vector<std::string>> compiled_files = file::FindFiles(flat_dir, diag);
130    if (compiled_files) {
131      for (std::string& compile_file : compiled_files.value()) {
132        compile_file = file::BuildPath({flat_dir, compile_file});
133        link_args.emplace_back(std::move(compile_file));
134      }
135    }
136  
137    return LinkCommand(diag).Execute(link_args, &std::cerr) == 0;
138  }
139  
GetDefaultManifest(const char * package_name)140  std::string CommandTestFixture::GetDefaultManifest(const char* package_name) {
141    const std::string manifest_file = GetTestPath("AndroidManifest.xml");
142    WriteFile(manifest_file, android::base::StringPrintf(R"(
143        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
144            package="%s">
145        </manifest>)", package_name));
146    return manifest_file;
147  }
148  
149  std::unique_ptr<io::IData> CommandTestFixture::OpenFileAsData(LoadedApk* apk,
150                                                                android::StringPiece path) {
151    return apk
152        ->GetFileCollection()
153        ->FindFile(path)
154        ->OpenAsData();
155  }
156  
157  void CommandTestFixture::AssertLoadXml(LoadedApk* apk, const io::IData* data,
158                                         android::ResXMLTree *out_tree) {
159    ASSERT_THAT(apk, Ne(nullptr));
160  
161    out_tree->setTo(data->data(), data->size());
162    ASSERT_THAT(out_tree->getError(), Eq(android::OK));
163    while (out_tree->next() != android::ResXMLTree::START_TAG) {
164      ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::BAD_DOCUMENT));
165      ASSERT_THAT(out_tree->getEventType(), Ne(android::ResXMLTree::END_DOCUMENT));
166    }
167  }
168  
169  ManifestBuilder::ManifestBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
170  }
171  
172  ManifestBuilder& ManifestBuilder::SetPackageName(const std::string& package_name) {
173    package_name_ = package_name;
174    return *this;
175  }
176  
177  ManifestBuilder& ManifestBuilder::AddContents(const std::string& contents) {
178    contents_ += contents + "\n";
179    return *this;
180  }
181  
182  std::string ManifestBuilder::Build(const std::string& file_path) {
183    const char* manifest_template = R"(
184        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
185            package="%s">
186            %s
187        </manifest>)";
188  
189    fixture_->WriteFile(file_path, android::base::StringPrintf(
190                                       manifest_template, package_name_.c_str(), contents_.c_str()));
191    return file_path;
192  }
193  
194  std::string ManifestBuilder::Build() {
195    return Build(fixture_->GetTestPath("AndroidManifest.xml"));
196  }
197  
198  LinkCommandBuilder::LinkCommandBuilder(CommandTestFixture* fixture) : fixture_(fixture) {
199  }
200  
201  LinkCommandBuilder& LinkCommandBuilder::SetManifestFile(const std::string& file) {
202    manifest_supplied_ = true;
203    args_.emplace_back("--manifest");
204    args_.emplace_back(file);
205    return *this;
206  }
207  
208  LinkCommandBuilder& LinkCommandBuilder::AddFlag(const std::string& flag) {
209    args_.emplace_back(flag);
210    return *this;
211  }
212  
213  LinkCommandBuilder& LinkCommandBuilder::AddCompiledResDir(const std::string& dir,
214                                                            android::IDiagnostics* diag) {
215    if (auto files = file::FindFiles(dir, diag)) {
216      for (std::string& compile_file : files.value()) {
217        args_.emplace_back(file::BuildPath({dir, compile_file}));
218      }
219    }
220    return *this;
221  }
222  
223  LinkCommandBuilder& LinkCommandBuilder::AddParameter(const std::string& param,
224                                                       const std::string& value) {
225    args_.emplace_back(param);
226    args_.emplace_back(value);
227    return *this;
228  }
229  
230  std::vector<std::string> LinkCommandBuilder::Build(const std::string& out_apk) {
231    if (!manifest_supplied_) {
232      SetManifestFile(ManifestBuilder(fixture_).Build());
233    }
234    args_.emplace_back("-o");
235    args_.emplace_back(out_apk);
236    return args_;
237  }
238  
239  }  // namespace aapt
240