[unit test] Complete FUSE unit tests #22
This commit is contained in:
@@ -18,6 +18,7 @@ cflags
|
|||||||
chrono
|
chrono
|
||||||
clsid
|
clsid
|
||||||
cmake_current_source_dir
|
cmake_current_source_dir
|
||||||
|
cmdc
|
||||||
coinit_apartmentthreaded
|
coinit_apartmentthreaded
|
||||||
comdlg32
|
comdlg32
|
||||||
conin$
|
conin$
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
### Issues
|
### Issues
|
||||||
|
|
||||||
* \#12 [unit test] Complete all providers unit tests
|
* \#12 [unit test] Complete all providers unit tests
|
||||||
|
* \#22 [unit test] Complete FUSE unit tests
|
||||||
* \#33 Complete initial v2.0 documentation
|
* \#33 Complete initial v2.0 documentation
|
||||||
* \#34 Add macOS support
|
* \#34 Add macOS support
|
||||||
* \#38 Pinning a file should automatically initiate a download to cache
|
* \#38 Pinning a file should automatically initiate a download to cache
|
||||||
|
@@ -23,12 +23,294 @@
|
|||||||
|
|
||||||
#include "fixtures/drive_fixture.hpp"
|
#include "fixtures/drive_fixture.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
void overwrite_text(const std::string &path, const char *s) {
|
||||||
|
int fd = ::open(path.c_str(), O_WRONLY | O_TRUNC);
|
||||||
|
ASSERT_NE(fd, -1);
|
||||||
|
write_all(fd, s, std::strlen(s));
|
||||||
|
::close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void write_all(int fd, const char *s, size_t n) {
|
||||||
|
size_t off = 0;
|
||||||
|
while (off < n) {
|
||||||
|
ssize_t w = ::write(fd, s + off, n - off);
|
||||||
|
ASSERT_NE(w, -1);
|
||||||
|
off += static_cast<size_t>(w);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto slurp(const std::string &path) -> std::string {
|
||||||
|
int fd = ::open(path.c_str(), O_RDONLY);
|
||||||
|
if (fd == -1)
|
||||||
|
return {};
|
||||||
|
std::string out;
|
||||||
|
char buf[4096];
|
||||||
|
for (;;) {
|
||||||
|
ssize_t r = ::read(fd, buf, sizeof(buf));
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r == -1) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out.append(buf, buf + r);
|
||||||
|
}
|
||||||
|
|
||||||
|
::close(fd);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
namespace repertory {
|
namespace repertory {
|
||||||
TYPED_TEST_SUITE(fuse_test, platform_provider_types);
|
TYPED_TEST_SUITE(fuse_test, platform_provider_types);
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_rename_a_file) {}
|
TYPED_TEST(fuse_test, can_rename_a_file) {
|
||||||
|
std::string src_file_name{"rename_test"};
|
||||||
|
auto src = this->create_file_and_test(src_file_name);
|
||||||
|
|
||||||
TYPED_TEST(fuse_test, can_rename_a_directory) {}
|
std::string dest_file_name{"rename_test_2"};
|
||||||
|
auto dst = this->create_file_and_test(dest_file_name);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ASSERT_EQ(0, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::access(src.c_str(), F_OK));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
struct stat st_unix{};
|
||||||
|
ASSERT_EQ(0, ::stat(dst.c_str(), &st_unix));
|
||||||
|
EXPECT_TRUE(S_ISREG(st_unix.st_mode));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, can_rename_a_directory) {
|
||||||
|
std::string src_dir_name{"rename_test"};
|
||||||
|
auto src_dir = this->create_directory_and_test(src_dir_name);
|
||||||
|
|
||||||
|
std::string dest_dir_name{"rename_test_2"};
|
||||||
|
auto dst_dir = this->create_directory_and_test(dest_dir_name);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ASSERT_EQ(0, ::rename(src_dir.c_str(), dst_dir.c_str()));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::access(src_dir.c_str(), F_OK));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
struct stat st{};
|
||||||
|
ASSERT_EQ(0, ::stat(dst_dir.c_str(), &st));
|
||||||
|
EXPECT_TRUE(S_ISDIR(st.st_mode));
|
||||||
|
|
||||||
|
this->rmdir_and_test(dst_dir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TYPED_TEST(fuse_test, rename_file_overwrite_existing) {
|
||||||
|
std::string src_name{"rename_overwrite_src.txt"};
|
||||||
|
std::string dst_name{"rename_overwrite_dst.txt"};
|
||||||
|
auto src = this->create_file_and_test(src_name);
|
||||||
|
auto dst = this->create_file_and_test(dst_name);
|
||||||
|
|
||||||
|
overwrite_text(src, "SRC");
|
||||||
|
overwrite_text(dst, "DST");
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ASSERT_EQ(0, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::access(src.c_str(), F_OK));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
EXPECT_EQ("SRC", slurp(dst));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_cross_directory) {
|
||||||
|
auto dir1 = this->create_directory_and_test("dir_1");
|
||||||
|
auto dir2 = this->create_directory_and_test("dir_2");
|
||||||
|
|
||||||
|
auto src = this->create_file_and_test("dir_1/file.txt");
|
||||||
|
std::string dst = utils::path::combine(dir2, {"moved.txt"});
|
||||||
|
|
||||||
|
overwrite_text(src, "CMDC");
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ASSERT_EQ(0, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::access(src.c_str(), F_OK));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
EXPECT_EQ("CMDC", slurp(dst));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
this->rmdir_and_test(dir1);
|
||||||
|
this->rmdir_and_test(dir2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_same_path) {
|
||||||
|
auto src = this->create_file_and_test("rn_same.txt");
|
||||||
|
overwrite_text(src, "CMDC");
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(0, ::rename(src.c_str(), src.c_str()));
|
||||||
|
EXPECT_EQ("CMDC", slurp(src));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_source_missing_sets_errno) {
|
||||||
|
auto dst = this->create_file_and_test("rn_any_dest.txt");
|
||||||
|
auto missing = this->mount_location() + "/rn_missing_src.txt";
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(missing.c_str(), dst.c_str()));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_destination_parent_missing_sets_errno) {
|
||||||
|
auto src = this->create_file_and_test("rn_good_src.txt");
|
||||||
|
auto dst = this->mount_location() + "/rn_missing_parent/rn_dest.txt";
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_into_existing_directory_sets_eisdir) {
|
||||||
|
auto src = this->create_file_and_test("rn_file.txt");
|
||||||
|
auto dstdir = this->create_directory_and_test("rn_dest_dir");
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dstdir.c_str()));
|
||||||
|
EXPECT_EQ(EISDIR, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
this->rmdir_and_test(dstdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_no_write_on_source_parent_sets_eacces) {
|
||||||
|
auto srcdir = this->create_directory_and_test("rn_srcp");
|
||||||
|
auto dstdir = this->create_directory_and_test("rn_dstp");
|
||||||
|
auto src = this->create_file_and_test("rn_srcp/a.txt");
|
||||||
|
auto dst = dstdir + "/b.txt";
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(srcdir.c_str(), 0555));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
EXPECT_EQ(EACCES, errno);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(srcdir.c_str(), 0755));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
this->rmdir_and_test(srcdir);
|
||||||
|
this->rmdir_and_test(dstdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_no_write_on_destination_parent_sets_eacces) {
|
||||||
|
auto srcdir = this->create_directory_and_test("rn_srcp2");
|
||||||
|
auto dstdir = this->create_directory_and_test("rn_dstp2");
|
||||||
|
auto src = this->create_file_and_test("rn_srcp2/a.txt");
|
||||||
|
auto dst = dstdir + "/b.txt";
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(dstdir.c_str(), 0555));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
EXPECT_EQ(EACCES, errno);
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(dstdir.c_str(), 0755));
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
this->rmdir_and_test(srcdir);
|
||||||
|
this->rmdir_and_test(dstdir);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_overwrite_readonly_destination_succeeds) {
|
||||||
|
auto src = this->create_file_and_test("rn_src_ro.txt");
|
||||||
|
auto dst = this->create_file_and_test("rn_dst_ro.txt");
|
||||||
|
|
||||||
|
overwrite_text(src, "NEW");
|
||||||
|
overwrite_text(dst, "OLD");
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(dst.c_str(), 0444));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
int rn = ::rename(src.c_str(), dst.c_str());
|
||||||
|
if (rn == -1 && errno == EROFS) {
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
ASSERT_EQ(0, ::chmod(dst.c_str(), 0644));
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
GTEST_SKIP();
|
||||||
|
}
|
||||||
|
ASSERT_EQ(0, rn);
|
||||||
|
|
||||||
|
EXPECT_EQ("NEW", slurp(dst));
|
||||||
|
|
||||||
|
ASSERT_EQ(0, ::chmod(dst.c_str(), 0644));
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_on_readonly_mount_sets_erofs_or_skip) {
|
||||||
|
auto src = this->create_file_and_test("rn_ro_src.txt");
|
||||||
|
auto dst = this->mount_location() + "/rn_ro_dst.txt";
|
||||||
|
|
||||||
|
if (::rename(src.c_str(), src.c_str()) == 0) {
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
GTEST_SKIP();
|
||||||
|
}
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
EXPECT_EQ(EROFS, errno);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_open_fd_remains_valid) {
|
||||||
|
auto src = this->create_file_and_test("rn_fd_src.txt");
|
||||||
|
auto dst = this->mount_location() + "/rn_fd_dst.txt";
|
||||||
|
|
||||||
|
overwrite_text(src, "HELLO");
|
||||||
|
|
||||||
|
int fd = ::open(src.c_str(), O_RDWR);
|
||||||
|
ASSERT_NE(fd, -1);
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
ASSERT_EQ(0, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::access(src.c_str(), F_OK));
|
||||||
|
EXPECT_EQ(ENOENT, errno);
|
||||||
|
|
||||||
|
ASSERT_NE(-1, ::lseek(fd, 0, SEEK_END));
|
||||||
|
write_all(fd, " WORLD", 6);
|
||||||
|
::close(fd);
|
||||||
|
|
||||||
|
EXPECT_EQ("HELLO WORLD", slurp(dst));
|
||||||
|
this->unlink_file_and_test(dst);
|
||||||
|
}
|
||||||
|
|
||||||
|
TYPED_TEST(fuse_test, rename_file_destination_component_name_too_long) {
|
||||||
|
auto src = this->create_file_and_test("rn_ntl_src.txt");
|
||||||
|
|
||||||
|
std::string longname(300, 'a');
|
||||||
|
std::string dst = this->mount_location() + "/" + longname;
|
||||||
|
|
||||||
|
errno = 0;
|
||||||
|
EXPECT_EQ(-1, ::rename(src.c_str(), dst.c_str()));
|
||||||
|
EXPECT_TRUE(errno == ENAMETOOLONG || errno == EINVAL);
|
||||||
|
|
||||||
|
this->unlink_file_and_test(src);
|
||||||
|
} */
|
||||||
} // namespace repertory
|
} // namespace repertory
|
||||||
|
|
||||||
#endif // !defined(_WIN32)
|
#endif // !defined(_WIN32)
|
||||||
|
Reference in New Issue
Block a user