| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "runtests-utils-test-utils.h" |
| |
| #include <dirent.h> |
| #include <errno.h> |
| #include <fcntl.h> |
| #include <limits.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| #include <string_view> |
| |
| #include <fbl/string.h> |
| #include <fbl/string_buffer.h> |
| #include <fbl/unique_fd.h> |
| #include <fbl/vector.h> |
| #include <runtests-utils/runtests-utils.h> |
| #include <zxtest/zxtest.h> |
| |
| namespace runtests { |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // HELPER CLASSES |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| fbl::String packaged_script_dir() { |
| fbl::String test_root_dir(getenv("TEST_ROOT_DIR")); |
| fbl::String runtests_utils_test_data_dir( |
| JoinPath(test_root_dir, "test/sys/runtests-utils-testdata")); |
| return runtests_utils_test_data_dir; |
| } |
| |
| PackagedScriptFile::PackagedScriptFile(const std::string_view path) { |
| fbl::String script_dir = packaged_script_dir(); |
| path_ = JoinPath(script_dir, path); |
| |
| // Open the file to be sure that it exists. |
| const int fd = open(path_.data(), O_RDONLY); |
| ZX_ASSERT_MSG(-1 != fd, "%s", strerror(errno)); |
| ZX_ASSERT_MSG(-1 != close(fd), "%s", strerror(errno)); |
| } |
| |
| PackagedScriptFile::~PackagedScriptFile() = default; |
| |
| std::string_view PackagedScriptFile::path() const { return path_; } |
| |
| ScopedStubFile::ScopedStubFile(const std::string_view path) : path_(path) { |
| const int fd = open(path_.data(), O_CREAT | O_WRONLY, S_IRWXU); |
| ZX_ASSERT_MSG(-1 != fd, "%s", strerror(errno)); |
| ZX_ASSERT_MSG(-1 != close(fd), "%s", strerror(errno)); |
| } |
| |
| ScopedStubFile::~ScopedStubFile() { remove(path_.data()); } |
| |
| ScopedTestFile::ScopedTestFile(const std::string_view path, const std::string_view file) |
| : path_(path) { |
| fbl::unique_fd input_fd{open(file.data(), O_RDONLY)}; |
| ZX_ASSERT_MSG(input_fd, "%s", strerror(errno)); |
| |
| fbl::unique_fd output_fd{open(path_.data(), O_CREAT | O_WRONLY, S_IRWXU)}; |
| ZX_ASSERT_MSG(output_fd, "%s", strerror(errno)); |
| |
| constexpr size_t kBufSize = 1024; |
| |
| char buf[kBufSize]; |
| ssize_t n; |
| while ((n = read(input_fd.get(), buf, kBufSize)) > 0) { |
| ZX_ASSERT_MSG(write(output_fd.get(), buf, n) == n, "write failed: %s", strerror(errno)); |
| } |
| ZX_ASSERT_MSG(n != -1, "read failed: %s", strerror(errno)); |
| } |
| |
| ScopedTestFile::~ScopedTestFile() { remove(path_.data()); } |
| |
| std::string_view ScopedTestFile::path() const { return path_; } |
| |
| int ScopedTestDir::num_test_dirs_created_ = 0; |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // FILE I/O HELPERS |
| /////////////////////////////////////////////////////////////////////////////// |
| |
| // Returns the number of files or subdirectories in a given directory. |
| int NumEntriesInDir(const char* dir_path) { |
| struct dirent* entry; |
| int num_entries = 0; |
| DIR* dp; |
| |
| if (!(dp = opendir(dir_path))) { |
| // dir_path actually points to a file. Return -1 by convention. |
| return -1; |
| } |
| while ((entry = readdir(dp))) { |
| // Skip "." and "..". |
| if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { |
| continue; |
| } |
| ++num_entries; |
| } |
| closedir(dp); |
| return num_entries; |
| } |
| |
| // Computes the relative path within |output_dir| of the output file of the |
| // test at |test_path|, setting |output_file_rel_path| as its value if |
| // successful. |
| // Returns true iff successful. |
| bool GetOutputFileRelPath(std::string_view output_dir, std::string_view test_path, |
| fbl::String* output_file_rel_path) { |
| if (output_file_rel_path == nullptr) { |
| printf("FAILURE: |output_file_rel_path| was null."); |
| return false; |
| } |
| fbl::String dir_of_test_output = JoinPath(output_dir, test_path); |
| DIR* dp = opendir(dir_of_test_output.c_str()); |
| if (dp == nullptr) { |
| printf("FAILURE: could not open directory %s: %s\n", dir_of_test_output.c_str(), |
| strerror(errno)); |
| return false; |
| } |
| struct dirent* entry; |
| int num_entries = 0; |
| fbl::String output_file_name; |
| while ((entry = readdir(dp))) { |
| // Skip "." and "..". |
| if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) { |
| continue; |
| } |
| if (entry->d_type != DT_REG) { |
| continue; |
| } |
| output_file_name = fbl::String(entry->d_name); |
| ++num_entries; |
| } |
| closedir(dp); |
| *output_file_rel_path = JoinPath(test_path, output_file_name); |
| if (num_entries != 1) { |
| printf( |
| "FAILURE: there are %d entries in %s. There should only be a " |
| "single output file\n", |
| num_entries, dir_of_test_output.c_str()); |
| } |
| return num_entries == 1; |
| } |
| |
| namespace { |
| |
| constexpr char kTmp[] = "/tmp"; |
| |
| // This ensures that ScopedTestDir, ScopedTestFile, and ScopedStubFile, which we |
| // make heavy use of in these tests, are indeed scoped and tear down without |
| // error. |
| TEST(TestHelpers, ScopedDirsAndFilesAreIndeedScoped) { |
| const int baseEntries = NumEntriesInDir(kTmp); |
| |
| { |
| ScopedTestDir dir(kTmp); |
| EXPECT_EQ(1 + baseEntries, NumEntriesInDir(kTmp)); |
| |
| EXPECT_EQ(0, NumEntriesInDir(dir.path())); |
| { |
| fbl::String file_name1 = JoinPath(dir.path(), "a.sh"); |
| PackagedScriptFile source_file_1("succeed.sh"); |
| ScopedTestFile file1(file_name1, source_file_1.path()); |
| |
| EXPECT_EQ(1, NumEntriesInDir(dir.path())); |
| { |
| fbl::String file_name2 = JoinPath(dir.path(), "b.sh"); |
| ScopedStubFile file2(file_name2); |
| EXPECT_EQ(2, NumEntriesInDir(dir.path())); |
| } |
| EXPECT_EQ(1, NumEntriesInDir(dir.path())); |
| } |
| EXPECT_EQ(0, NumEntriesInDir(dir.path())); |
| } |
| |
| EXPECT_EQ(baseEntries, NumEntriesInDir(kTmp)); |
| |
| { |
| ScopedTestDir dir1(kTmp); |
| ScopedTestDir dir2(kTmp); |
| ScopedTestDir dir3(kTmp); |
| EXPECT_EQ(3 + baseEntries, NumEntriesInDir(kTmp)); |
| } |
| |
| EXPECT_EQ(baseEntries, NumEntriesInDir(kTmp)); |
| } |
| |
| } // namespace |
| } // namespace runtests |