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 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 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 79 void TestDirectoryFixture::TearDown() { 80 ClearDirectory(temp_dir_); 81 } 82 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 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 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 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