diff --git a/src/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp b/src/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp new file mode 100644 index 00000000..397a4b2f --- /dev/null +++ b/src/test/fspp/fuse/readDir/FuseReadDirDirnameTest.cpp @@ -0,0 +1,51 @@ +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "testutils/FuseReadDirTest.h" + +using ::testing::_; +using ::testing::StrEq; +using ::testing::Return; + +using std::make_unique; +using std::unique_ptr; +using std::vector; +using std::string; + +class FuseReadDirDirnameTest: public FuseReadDirTest { +public: +}; + +TEST_F(FuseReadDirDirnameTest, ReadRootDir) { + EXPECT_CALL(fsimpl, readDir(StrEq("/"))) + .Times(1).WillOnce(ReturnDirEntries({})); + + ReadDir("/"); +} + +TEST_F(FuseReadDirDirnameTest, ReadDir) { + ReturnIsDirOnLstat("/mydir"); + EXPECT_CALL(fsimpl, readDir(StrEq("/mydir"))) + .Times(1).WillOnce(ReturnDirEntries({})); + + ReadDir("/mydir"); +} + +TEST_F(FuseReadDirDirnameTest, ReadDirNested) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsDirOnLstat("/mydir/mydir2"); + EXPECT_CALL(fsimpl, readDir(StrEq("/mydir/mydir2"))) + .Times(1).WillOnce(ReturnDirEntries({})); + + ReadDir("/mydir/mydir2"); +} + +TEST_F(FuseReadDirDirnameTest, ReadDirNested2) { + ReturnIsDirOnLstat("/mydir"); + ReturnIsDirOnLstat("/mydir/mydir2"); + ReturnIsDirOnLstat("/mydir/mydir2/mydir3"); + EXPECT_CALL(fsimpl, readDir(StrEq("/mydir/mydir2/mydir3"))) + .Times(1).WillOnce(ReturnDirEntries({})); + + ReadDir("/mydir/mydir2/mydir3"); +} diff --git a/src/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp b/src/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp new file mode 100644 index 00000000..50ad7648 --- /dev/null +++ b/src/test/fspp/fuse/readDir/FuseReadDirErrorTest.cpp @@ -0,0 +1,43 @@ +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "testutils/FuseReadDirTest.h" + +#include "fspp/fuse/FuseErrnoException.h" + +using ::testing::_; +using ::testing::StrEq; +using ::testing::Throw; +using ::testing::WithParamInterface; +using ::testing::Values; + +using std::make_unique; +using std::unique_ptr; +using std::vector; +using std::string; + +using namespace fspp::fuse; + +class FuseReadDirErrorTest: public FuseReadDirTest, public WithParamInterface { +}; +INSTANTIATE_TEST_CASE_P(FuseReadDirErrorTest, FuseReadDirErrorTest, Values(EACCES, EBADF, EMFILE, ENFILE, ENOMEM, ENOTDIR, EFAULT, EINVAL)); + +//TODO On ENOENT, libfuse doesn't return the ENOENT error, but returns a success response with an empty directory. Why? + +TEST_F(FuseReadDirErrorTest, NoError) { + ReturnIsDirOnLstat(DIRNAME); + EXPECT_CALL(fsimpl, readDir(StrEq(DIRNAME))) + .Times(1).WillOnce(ReturnDirEntries({})); + + int error = ReadDirReturnError(DIRNAME); + EXPECT_EQ(0, error); +} + +TEST_P(FuseReadDirErrorTest, ReturnedErrorCodeIsCorrect) { + ReturnIsDirOnLstat(DIRNAME); + EXPECT_CALL(fsimpl, readDir(StrEq(DIRNAME))) + .Times(1).WillOnce(Throw(FuseErrnoException(GetParam()))); + + int error = ReadDirReturnError(DIRNAME); + EXPECT_EQ(GetParam(), error); +} diff --git a/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp b/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp new file mode 100644 index 00000000..c60caf37 --- /dev/null +++ b/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.cpp @@ -0,0 +1,85 @@ +#include "FuseReadDirTest.h" + +using std::unique_ptr; +using std::make_unique; +using std::vector; +using std::string; +using std::initializer_list; + +using ::testing::Action; +using ::testing::Return; + +unique_ptr> FuseReadDirTest::ReadDir(const char *dirname) { + auto fs = TestFS(); + + DIR *dir = openDir(fs.get(), dirname); + + auto result = make_unique>(); + readDirEntries(dir, result.get()); + closeDir(dir); + return result; +} + +int FuseReadDirTest::ReadDirReturnError(const char *dirname) { + auto fs = TestFS(); + + errno = 0; + DIR *dir = openDirAllowError(fs.get(), dirname); + EXPECT_EQ(errno!=0, dir==nullptr) << "errno should exactly be != 0 if opendir returned nullptr"; + if (errno != 0) { + return errno; + } + + auto result = make_unique>(); + int error = readDirEntriesAllowError(dir, result.get()); + closeDir(dir); + return error; +} + +DIR *FuseReadDirTest::openDir(TempTestFS *fs, const char *dirname) { + DIR *dir = openDirAllowError(fs, dirname); + EXPECT_NE(nullptr, dir) << "Opening directory failed"; + return dir; +} + +DIR *FuseReadDirTest::openDirAllowError(TempTestFS *fs, const char *dirname) { + auto realpath = fs->mountDir() / dirname; + return ::opendir(realpath.c_str()); +} + +void FuseReadDirTest::readDirEntries(DIR *dir, vector *result) { + int error = readDirEntriesAllowError(dir, result); + EXPECT_EQ(0, error); +} + +int FuseReadDirTest::readDirEntriesAllowError(DIR *dir, vector *result) { + struct dirent *entry = nullptr; + int error = readNextDirEntryAllowError(dir, &entry); + if (error != 0) { + return error; + } + while(entry != nullptr) { + result->push_back(entry->d_name); + int error = readNextDirEntryAllowError(dir, &entry); + if (error != 0) { + return error; + } + } + return 0; +} + +int FuseReadDirTest::readNextDirEntryAllowError(DIR *dir, struct dirent **result) { + errno = 0; + *result = ::readdir(dir); + return errno; +} + +void FuseReadDirTest::closeDir(DIR *dir) { + int retval = ::closedir(dir); + EXPECT_EQ(0, retval) << "Closing dir failed"; +} + +Action*(const char*)> FuseReadDirTest::ReturnDirEntries(vector entries) { + vector *direntries = new vector(entries); + return Return(direntries); +} diff --git a/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h b/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h new file mode 100644 index 00000000..ebbdda1a --- /dev/null +++ b/src/test/fspp/fuse/readDir/testutils/FuseReadDirTest.h @@ -0,0 +1,26 @@ +#pragma once +#ifndef TEST_FSPP_FUSE_READDIR_TESTUTILS_FUSEREADDIRTEST_H_ +#define TEST_FSPP_FUSE_READDIR_TESTUTILS_FUSEREADDIRTEST_H_ + +#include "test/testutils/FuseTest.h" +#include + +class FuseReadDirTest: public FuseTest { +public: + const char *DIRNAME = "/mydir"; + + std::unique_ptr> ReadDir(const char *dirname); + int ReadDirReturnError(const char *dirname); + + static ::testing::Action*(const char*)> ReturnDirEntries(std::vector entries); + +private: + DIR *openDir(TempTestFS *fs, const char *dirname); + DIR *openDirAllowError(TempTestFS *fs, const char *dirname); + void readDirEntries(DIR *dir, std::vector *result); + int readDirEntriesAllowError(DIR *dir, std::vector *result); + int readNextDirEntryAllowError(DIR *dir, struct dirent **result); + void closeDir(DIR *dir); +}; + +#endif