blob: 3a5ae25890bba333de3c376a4acca89be4245d6e [file] [log] [blame]
// 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 <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 <fbl/auto_call.h>
#include <fbl/string.h>
#include <fbl/string_buffer.h>
#include <fbl/unique_fd.h>
#include <fbl/unique_ptr.h>
#include <fbl/vector.h>
#include <runtests-utils/runtests-utils.h>
#include <unittest/unittest.h>
#include "runtests-utils-test-globals.h"
#include "runtests-utils-test-utils.h"
namespace runtests {
///////////////////////////////////////////////////////////////////////////////
// HELPER CLASSES
///////////////////////////////////////////////////////////////////////////////
ScopedScriptFile::ScopedScriptFile(const fbl::StringPiece path,
const fbl::StringPiece contents)
: path_(path) {
const int fd = open(path_.data(), O_CREAT | O_WRONLY, S_IRWXU);
ZX_ASSERT_MSG(-1 != fd, "%s", strerror(errno));
ZX_ASSERT(
sizeof(kScriptShebang) ==
static_cast<size_t>(write(fd, kScriptShebang, sizeof(kScriptShebang))));
ZX_ASSERT(contents.size() ==
static_cast<size_t>(write(fd, contents.data(), contents.size())));
ZX_ASSERT_MSG(-1 != close(fd), "%s", strerror(errno));
}
ScopedScriptFile::~ScopedScriptFile() {
remove(path_.data());
}
fbl::StringPiece ScopedScriptFile::path() const {
return path_;
}
ScopedTestFile::ScopedTestFile(
const fbl::StringPiece path, const fbl::StringPiece 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());
}
fbl::StringPiece 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(const fbl::StringPiece& output_dir,
const fbl::StringPiece& 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\n", dir_of_test_output.c_str());
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 {
// This ensures that ScopedTestDir and ScopedScriptFile, which we make heavy
// use of in these tests, are indeed scoped and tear down without error.
bool ScopedDirsAndFilesAreIndeedScoped() {
BEGIN_TEST;
// Entering a test case, test_dir.path() should be empty.
EXPECT_EQ(0, NumEntriesInDir(TestFsRoot()));
{
ScopedTestDir dir;
EXPECT_EQ(1, NumEntriesInDir(TestFsRoot()));
EXPECT_EQ(0, NumEntriesInDir(dir.path()));
{
fbl::String file_name1 = JoinPath(dir.path(), "a.sh");
ScopedScriptFile file1(file_name1, "A");
EXPECT_EQ(1, NumEntriesInDir(dir.path()));
{
fbl::String file_name2 = JoinPath(dir.path(), "b.sh");
ScopedScriptFile file2(file_name2, "B");
EXPECT_EQ(2, NumEntriesInDir(dir.path()));
}
EXPECT_EQ(1, NumEntriesInDir(dir.path()));
}
EXPECT_EQ(0, NumEntriesInDir(dir.path()));
}
EXPECT_EQ(0, NumEntriesInDir(TestFsRoot()));
{
ScopedTestDir dir1;
ScopedTestDir dir2;
ScopedTestDir dir3;
EXPECT_EQ(3, NumEntriesInDir(TestFsRoot()));
}
EXPECT_EQ(0, NumEntriesInDir(TestFsRoot()));
END_TEST;
}
BEGIN_TEST_CASE(TestHelpers)
RUN_TEST(ScopedDirsAndFilesAreIndeedScoped)
END_TEST_CASE(TestHelpers)
} // namespace
} // namespace runtests