blob: 05b882fbac2f1f86d174bf981909089fa08dc80f [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 "fixture.h"
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <inttypes.h>
#include <limits.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <fbl/string.h>
#include <fbl/string_buffer.h>
#include <fbl/string_printf.h>
#include <fbl/unique_fd.h>
#include <unittest/unittest.h>
#include <zircon/syscalls.h>
namespace fuzzing {
namespace testing {
// Public methods
Fixture::~Fixture() {
Reset();
}
fbl::String Fixture::path(const char* fmt, ...) const {
va_list ap;
va_start(ap, fmt);
fbl::String result = path(fmt, ap);
va_end(ap);
return result;
}
fbl::String Fixture::path(const char* fmt, va_list ap) const {
if (!fmt) {
return root_;
}
fbl::StringBuffer<PATH_MAX> buffer;
buffer.AppendVPrintf(fmt, ap);
fbl::String relpath = buffer.ToString();
if (relpath[0] == '/') {
return relpath;
}
buffer.Clear();
buffer.Append(root_);
buffer.Append(relpath);
return buffer.ToString();
}
// Protected methods
Fixture::Fixture() {}
bool Fixture::Create() {
BEGIN_HELPER;
Reset();
uint64_t randnum;
zx_cprng_draw(&randnum, sizeof(randnum));
root_ = fbl::StringPrintf("/tmp/path-unit-test-%" PRIu64 "/", randnum);
ASSERT_TRUE(CreateDirectory(nullptr));
END_HELPER;
}
bool Fixture::CreateFile(const char* pathname, const char* contents) {
BEGIN_HELPER;
ASSERT_NONNULL(pathname);
fbl::String local = path(pathname);
pathname = local.c_str();
const char* sep = strrchr(pathname, '/');
fbl::String basename(pathname, sep - pathname);
ASSERT_TRUE(CreateDirectory(basename.c_str()));
fbl::unique_fd fd(open(pathname, O_RDWR | O_CREAT, 0777));
ASSERT_TRUE(!!fd);
if (contents) {
ASSERT_GE(write(fd.get(), contents, strlen(contents) + 1), 0);
}
END_HELPER;
}
bool Fixture::CreateDirectory(const char* pathname) {
BEGIN_HELPER;
fbl::String local = path(pathname);
pathname = local.c_str();
struct stat buf;
if (stat(pathname, &buf) == 0) {
ASSERT_TRUE(S_ISDIR(buf.st_mode));
} else {
ASSERT_EQ(errno, ENOENT);
// Trim trailing slashes
size_t len = strlen(pathname);
while (len > 0 && pathname[len - 1] == '/') {
--len;
}
local.Set(pathname, len);
pathname = local.c_str();
// Find last segment
const char* sep = strrchr(pathname, '/');
ASSERT_NONNULL(sep);
fbl::String basename(pathname, sep - pathname);
ASSERT_TRUE(CreateDirectory(basename.c_str()));
ASSERT_GE(mkdir(pathname, 0777), 0);
}
END_HELPER;
}
bool Fixture::RemoveDirectory(const char* pathname) {
BEGIN_HELPER;
ASSERT_NONNULL(pathname);
char buffer[PATH_MAX];
DIR* dir = opendir(pathname);
if (dir) {
struct dirent* ent;
while ((ent = readdir(dir))) {
if (strcmp(".", ent->d_name) == 0) {
continue;
}
snprintf(buffer, sizeof(buffer), "%s/%s", pathname, ent->d_name);
if (ent->d_type == DT_DIR) {
EXPECT_TRUE(RemoveDirectory(buffer));
} else {
EXPECT_GE(unlink(buffer), 0);
}
}
closedir(dir);
EXPECT_GE(rmdir(pathname), 0);
}
END_HELPER;
}
void Fixture::Reset() {
if (!root_.empty()) {
RemoveDirectory(root_.c_str());
}
root_.clear();
unsafe_.clear();
}
} // namespace testing
} // namespace fuzzing