#include <gtest/gtest.h>
#include <cstring>
#include <iostream>
#include <sys/socket.h>
#include <sys/un.h>
#include <algorithm>
#include <fstream>
#include <fcntl.h>
using std::cout;
using std::endl;
using std::string;
using std::system_error;
using std::setw;
using std::ifstream;
struct FsTest : public testing::Test
{
string m_curdir;
FsTest()
{
system_error err;
fs::remove_all("sandbox", &err);
}
virtual ~FsTest()
{
system_error err;
fs::remove_all("sandbox", &err);
}
void create_files()
{
struct sockaddr_un addr;
addr.sun_family = AF_UNIX;
std::strcpy(addr.sun_path, "sandbox/sock");
int fd = socket(PF_UNIX, SOCK_STREAM, 0);
bind(fd, (struct sockaddr*)&addr, sizeof addr);
}
};
TEST_F(FsTest, list_current)
{
cout << "listing current directory contents" << endl;
ASSERT_GT(files.size(), 0);
for (auto& f : files)
{
cout << f.first << " type: " << f.second << endl;
}
}
TEST_F(FsTest, list_sandbox)
{
cout << "creating sandbox directory files" << endl;
create_files();
cout << "listing sandbox directory contents" << endl;
ASSERT_GT(files.size(), 0);
for (auto& f : files)
{
cout << f.first << " type: " << f.second << endl;
}
}
static bool reg_filt(
const string& s,
FileType t)
{
if (s == "reg" && t == FileType::reg)
return true;
return false;
}
TEST_F(FsTest, filter)
{
create_files();
ASSERT_EQ(files.size(), 1);
ASSERT_EQ(files.begin()->first, "reg");
ASSERT_EQ(files.begin()->second, FileType::reg);
}
TEST_F(FsTest, create_and_delete)
{
cout << "tmp file: " << n << endl;
for (auto& f : d)
{
cout << f.first << " type: " << f.second << endl;
}
ASSERT_EQ(d.size(), 2);
ASSERT_NE(d.find("test"), d.end());
ASSERT_EQ(d.size(), 1);
fs::remove_all("sandbox");
ASSERT_EQ(d.find("sandbox"), d.end());
ASSERT_THROW(
fs::remove(
"sandbox"), system_error);
}
TEST_F(FsTest, create_types)
{
create_files();
for (auto& f : d)
{
cout << "sandbox/" << f.first << " type: " << f.second << ":" << endl;
cout << ty << endl;
ASSERT_EQ(f.second, ty.type);
}
cout << "/dev/zero " << ty << endl;
ASSERT_EQ(ty.type, FileType::chr);
auto i = std::find_if(d.begin(), d.end(), [](const auto& x) -> bool
{
return x.second == FileType::block;
});
ASSERT_NE(i, d.end());
cout << "/dev/" << i->first << " " << ty << endl;
ASSERT_EQ(ty.type, FileType::block);
}
TEST_F(FsTest, attributes)
{
const uint64_t NS = 1000000000;
const uint64_t DAY = 24*60*60*NS;
for (auto& f : d)
{
cout << "sandbox/" << f.first << " type: " << f.second << ":" << endl;
cout << ty << endl;
}
ASSERT_EQ(streg.mode, 0660);
ASSERT_EQ(streg2.mode, 0600);
ASSERT_EQ(streg2.access_time, streg.access_time-DAY);
ASSERT_EQ(streg2.mod_time, streg.mod_time-2*DAY);
ASSERT_EQ(stlink.mode, 0777);
}
TEST(FsExampleTest, sparse_and_trunc)
{
system_error err;
fs::remove_all("sandbox", &err);
cout << "curdir: " << curdir << endl;
string s("this is a test of the emergency sizing system\n");
cout << "sparse test with string len=" << s.size() << endl;
string fn("sparse_file");
auto write_sparse = [&fn, &s](off_t loc)
{
lseek(fd, loc, SEEK_SET);
cout << "wrote " << s.size() << " bytes at loc " << loc << endl;
};
cout << "12288 hole at start of file:\n" << st << endl;
ASSERT_EQ(st.size, 16384);
ASSERT_EQ(st.alloc_size, 4096);
cout << setw(6) << "start" << setw(6) << "data" << endl;
for (auto& x : sm)
{
cout << setw(6) << x.first << setw(6) << x.second << endl;
}
std::map<int64_t,int64_t> ver;
ver[0] = 12287;
ASSERT_EQ(sm, ver);
write_sparse(1024);
cout << "8192 hole in middle of file\n" << st << endl;
ASSERT_EQ(st.alloc_size, 8192);
cout << setw(6) << "start" << setw(6) << "data" << endl;
for (auto& x : sm)
{
cout << setw(6) << x.first << setw(6) << x.second << endl;
}
ver.clear();
ver[4096] = 12287;
ASSERT_EQ(sm, ver);
cout << "8192 hole at end of file\n" << st << endl;
ASSERT_EQ(st.alloc_size, 4096);
cout << setw(6) << "start" << setw(6) << "data" << endl;
for (auto& x : sm)
{
cout << setw(6) << x.first << setw(6) << x.second << endl;
}
ver.clear();
ver[4096] = 12287;
ASSERT_EQ(sm, ver);
ifstream f(fn);
f.seekg(1024);
string val;
val.resize(s.size(), '\x01');
f.read(&val[0], val.size());
ASSERT_EQ(val, s);
fs::remove_all("sandbox");
}
TEST_F(FsTest, paths)
{
auto t = [](const std::string& b, const std::string& p) -> std::string
{
cout << "base:" << ">" << b << "< path: >" << p << "< norm: >" << x << "<" << endl;
return x;
};
ASSERT_EQ(t("", ""), ".");
ASSERT_EQ(t("", "."), ".");
ASSERT_EQ(t(".", ""), ".");
ASSERT_EQ(t(".", "."), ".");
ASSERT_EQ(t("", "test/.."), ".");
ASSERT_EQ(t("", "test/../.."), "./..");
ASSERT_EQ(t("", "/"), "/");
ASSERT_EQ(t("", "/test"), "/test");
ASSERT_EQ(t("", "/test/"), "/test/");
ASSERT_EQ(t("/", ""), "/");
ASSERT_EQ(t("/", "/"), "/");
ASSERT_EQ(t("base", "../../sandbox/../../path"), "./../../path");
ASSERT_EQ(t("/base/", ""), "/base/");
ASSERT_EQ(t("/base/", "."), "/base");
ASSERT_EQ(t("/base/", "root"), "/base/root");
ASSERT_EQ(t("/base", "root"), "/base/root");
ASSERT_EQ(t("/base/", "sandbox/rel/path"), "/base/sandbox/rel/path");
ASSERT_EQ(t("/base/sandbox", "../sandbox/path"), "/base/sandbox/path");
ASSERT_EQ(t("/base/next/../again", "sandbox/next/../path"), "/base/again/sandbox/path");
ASSERT_EQ(t("", "sandbox/rel/path"), "./sandbox/rel/path");
ASSERT_EQ(t("", "sandbox/rel/../path"), "./sandbox/path");
ASSERT_EQ(t("", "./sandbox/rel/../path"), "./sandbox/path");
ASSERT_EQ(t("", "/sandbox/path"), "/sandbox/path");
ASSERT_EQ(t("", "/sandbox/path/"), "/sandbox/path/");
ASSERT_EQ(t("", "/sandbox/path"), "/sandbox/path");
ASSERT_EQ(t("", "/base/../sandbox/next/../../path"), "/path");
ASSERT_EQ(t("", "/this/../is/a/big/long/path/../../../../../"), "/");
ASSERT_EQ(t("", "/this/../is/a/path/../../../../."), "/..");
ASSERT_EQ(t("../", "../../sandbox/../../"), "./../../../../");
}
Common file system utilities.
static std::string get_current_dir(std::system_error *=nullptr)
Get working directory.
static void create_reg(const std::string &, std::system_error *=nullptr)
Create a regular file.
static std::string norm_path(const std::string &, const std::string &) noexcept
Normalize a path with base directory.
static void create_symlink(const std::string &, const std::string &, std::system_error *=nullptr)
Create a symbolic link.
static void create_link(const std::string &, const std::string &, std::system_error *=nullptr)
Create a hard link.
static void create_fifo(const std::string &, std::system_error *=nullptr)
Create a named pipe (FIFO).
static std::map< std::string, FileType > scan_dir(const std::string &, std::function< bool(const std::string &, FileType)>=default_scan_filter, std::system_error *=nullptr)
Scan a directory, and return a map of names and file types.
static FileStat file_stat(const std::string &, std::system_error *=nullptr)
Get the file stat.
static std::string read_symlink(const std::string &, std::system_error *=nullptr)
Read the location of a symbolic link target.
static void set_size(const std::string &, off_t, std::system_error *=nullptr)
Set the file size.
static std::string create_tmp_reg(const std::string &, std::system_error *=nullptr)
Create a temporary regular file.
static void change_dir(const std::string &, std::system_error *=nullptr)
Change working directory.
static void remove(const std::string &, std::system_error *=nullptr)
Remove the file or directory.
static std::map< off_t, off_t > sparse_map(const std::string &, std::system_error *=nullptr)
Map of file sparseness.
static void create_dir(const std::string &, std::system_error *=nullptr)
Create a directory.
static void set_mode(const std::string &, unsigned, std::system_error *=nullptr)
Set the file mode.
static void set_times(const std::string &, uint64_t, uint64_t, std::system_error *=nullptr)
Set the file times.
Common file system utilities.
int safe_close(int fd)
Signal safe close.
ssize_t safe_write_throw(int fd, const void *buf, size_t count)
Signal safe write, throws system_error on error.
int safe_open_throw(const char *pathname, int flags)
Signal safe open, throws system_error on error.
Signal-safe C library wrapper.
TEST(inet_example, client_server_stream_test)
[Inet client server]