Generalize stat() tests in FsppFileTest for all node types

This commit is contained in:
Sebastian Messmer 2016-03-31 23:48:43 +08:00
parent e7c4f8150e
commit 4627666788
7 changed files with 217 additions and 98 deletions

View File

@ -8,6 +8,7 @@
#include "FsppFileTest.h"
#include "FsppSymlinkTest.h"
#include "FsppNodeTest_Rename.h"
#include "FsppNodeTest_Stat.h"
#include "FsppOpenFileTest.h"
#define FSPP_ADD_FILESYTEM_TESTS(FS_NAME, FIXTURE) \
@ -16,6 +17,10 @@
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppFileTest, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppSymlinkTest, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Rename, FIXTURE); \
INSTANTIATE_NODE_TEST_CASE( FS_NAME, FsppNodeTest_Stat, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_FileOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_DirOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppNodeTest_Stat_SymlinkOnly, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, FsppOpenFileTest, FIXTURE); \
#endif

View File

@ -55,22 +55,6 @@ public:
this->EXPECT_SIZE(0, *file);
}
void Test_Stat_CreatedFileIsEmpty(fspp::File *file) {
this->EXPECT_SIZE(0, *file);
}
void Test_Stat_Nlink(fspp::File *file) {
this->IN_STAT(*file, [] (struct stat st) {
EXPECT_EQ(1u, st.st_nlink);
});
}
void Test_Stat_IsFile(fspp::File *file) {
this->IN_STAT(*file, [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
});
}
void Test_Chown_Uid(fspp::File *file) {
file->chown(100, 200);
this->IN_STAT(*file, [] (struct stat st){
@ -177,30 +161,6 @@ TYPED_TEST_P(FsppFileTest, Truncate_ShrinkTo0_Nested) {
this->Test_Truncate_ShrinkTo0(this->file_nested.get());
}
TYPED_TEST_P(FsppFileTest, Stat_IsFile) {
this->Test_Stat_IsFile(this->file_root.get());
}
TYPED_TEST_P(FsppFileTest, Stat_IsFile_Nested) {
this->Test_Stat_IsFile(this->file_nested.get());
}
TYPED_TEST_P(FsppFileTest, Stat_CreatedFileIsEmpty) {
this->Test_Stat_CreatedFileIsEmpty(this->file_root.get());
}
TYPED_TEST_P(FsppFileTest, Stat_CreatedFileIsEmpty_Nested) {
this->Test_Stat_CreatedFileIsEmpty(this->file_nested.get());
}
TYPED_TEST_P(FsppFileTest, Stat_Nlink) {
this->Test_Stat_Nlink(this->file_root.get());
}
TYPED_TEST_P(FsppFileTest, Stat_Nlink_Nested) {
this->Test_Stat_Nlink(this->file_nested.get());
}
TYPED_TEST_P(FsppFileTest, Chown_Uid) {
this->Test_Chown_Uid(this->file_root.get());
}
@ -252,12 +212,6 @@ REGISTER_TYPED_TEST_CASE_P(FsppFileTest,
Truncate_Shrink_Nested,
Truncate_ShrinkTo0,
Truncate_ShrinkTo0_Nested,
Stat_CreatedFileIsEmpty,
Stat_CreatedFileIsEmpty_Nested,
Stat_Nlink,
Stat_Nlink_Nested,
Stat_IsFile,
Stat_IsFile_Nested,
Chown_Uid,
Chown_Uid_Nested,
Chown_Gid,
@ -272,4 +226,10 @@ REGISTER_TYPED_TEST_CASE_P(FsppFileTest,
//TODO unlink
//TODO Test all operations do (or don't) affect file timestamps correctly (including rename, which shouldn't modify access/modify time, but inode change time)
//TODO Move applicable test cases to new instances of FsppNodeTest (like FsppNodeTest_Rename) (e.g. utimens, chmod, ...)
//TODO access
//TODO utimens
//TODO chmod
//TODO chown
#endif

View File

@ -158,9 +158,6 @@ public:
}
};
/*
* Register each of the given test cases for all three classes: FsppNodeTest_File, FsppNodeTest_Dir and FsppNodeTest_Symlink
*/
REGISTER_NODE_TEST_CASE(FsppNodeTest_Rename,
TargetParentDirDoesntExist,
TargetParentDirIsFile,
@ -186,11 +183,4 @@ REGISTER_NODE_TEST_CASE(FsppNodeTest_Rename,
//TODO Test for rename (success AND error cases) that contents stay unchanged (i.e. file contents, directory children, symlink target)
//TODO (here and in other fstest operations): Test error paths
//TODO Move other applicable test cases from FsppFileTest to here (e.g. utimens, chmod, ...)
//TODO stat
//TODO access
//TODO utimens
//TODO chmod
//TODO chown
//TODO Test all operations do (or don't) affect timestamps correctly

View File

@ -0,0 +1,84 @@
#pragma once
#ifndef MESSMER_FSPP_FSTEST_FSPPNODETEST_STAT_H_
#define MESSMER_FSPP_FSTEST_FSPPNODETEST_STAT_H_
#include "testutils/FsppNodeTest.h"
#include "../fuse/FuseErrnoException.h"
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Stat: public FsppNodeTest<ConcreteFileSystemTestFixture> {
public:
void Test_Nlink() {
auto node = this->CreateNode("/mynode");
this->IN_STAT(*node, [] (struct stat st) {
EXPECT_EQ(1u, st.st_nlink);
});
}
};
// Test cases only run for file nodes
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Stat_FileOnly: public FileSystemTest<ConcreteFileSystemTestFixture>, public FsppNodeTest_File_Helper {};
TYPED_TEST_CASE_P(FsppNodeTest_Stat_FileOnly);
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, CreatedFileIsEmpty) {
auto file = this->CreateFile("/myfile");
this->EXPECT_SIZE(0, *file);
}
TYPED_TEST_P(FsppNodeTest_Stat_FileOnly, FileIsFile) {
auto file = this->CreateFile("/myfile");
this->IN_STAT(*file, [] (struct stat st) {
EXPECT_TRUE(S_ISREG(st.st_mode));
});
}
// Test cases only run for dir nodes
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Stat_DirOnly: public FileSystemTest<ConcreteFileSystemTestFixture>, public FsppNodeTest_Dir_Helper {};
TYPED_TEST_CASE_P(FsppNodeTest_Stat_DirOnly);
TYPED_TEST_P(FsppNodeTest_Stat_DirOnly, DirIsDir) {
auto file = this->CreateDir("/mydir");
this->IN_STAT(*file, [] (struct stat st) {
EXPECT_TRUE(S_ISDIR(st.st_mode));
});
}
// Test cases only run for symlink nodes
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest_Stat_SymlinkOnly: public FileSystemTest<ConcreteFileSystemTestFixture>, public FsppNodeTest_Symlink_Helper {};
TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly);
TYPED_TEST_P(FsppNodeTest_Stat_SymlinkOnly, SymlinkIsSymlink) {
auto file = this->CreateSymlink("/mysymlink");
this->IN_STAT(*file, [] (struct stat st) {
EXPECT_TRUE(S_ISLNK(st.st_mode));
});
}
REGISTER_NODE_TEST_CASE(FsppNodeTest_Stat,
Nlink
);
REGISTER_TYPED_TEST_CASE_P(FsppNodeTest_Stat_FileOnly,
CreatedFileIsEmpty,
FileIsFile
);
REGISTER_TYPED_TEST_CASE_P(FsppNodeTest_Stat_DirOnly,
DirIsDir
);
REGISTER_TYPED_TEST_CASE_P(FsppNodeTest_Stat_SymlinkOnly,
SymlinkIsSymlink
);
#endif
//TODO More test cases
//TODO Test all operations do (or don't) affect timestamps correctly

View File

@ -58,6 +58,21 @@ public:
EXPECT_NE(boost::none, symlink);
return std::move(*symlink);
}
cpputils::unique_ref<fspp::Dir> CreateDir(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createDir(path.filename().native(), this->MODE_PUBLIC, 0, 0);
return this->LoadDir(path);
}
cpputils::unique_ref<fspp::File> CreateFile(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createAndOpenFile(path.filename().native(), this->MODE_PUBLIC, 0, 0);
return this->LoadFile(path);
}
cpputils::unique_ref<fspp::Symlink> CreateSymlink(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createSymlink(path.filename().native(), "/my/symlink/target", 0, 0);
return this->LoadSymlink(path);
}
};

View File

@ -22,6 +22,7 @@ public:
std::unique_ptr<fspp::File> file_root;
std::unique_ptr<fspp::File> file_nested;
//TODO IN_STAT still needed after moving it to FsppNodeTest?
void IN_STAT(const fspp::File &file, std::function<void (struct stat)> callback) {
struct stat st1, st2;
file.stat(&st1);

View File

@ -7,70 +7,134 @@
#include <boost/preprocessor/variadic/to_seq.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
class FsppNodeTestBase {
public:
virtual void IN_STAT(const fspp::Node &node, std::function<void (struct stat)> callback) = 0;
virtual void EXPECT_SIZE(uint64_t expectedSize, const fspp::Node &node) = 0;
};
/**
* Inherit your fixture from this class to write a test case that is run on nodes, i.e. files, directories and symlinks.
* You can use this->CreateNode() to create a node and then call fspp::Node functions on it.
* Add your test cases as void Test_xxx() functions to your fixture and register/instantiate them using
* REGISTER_NODE_TEST_CASE and INSTANTIATE_NODE_TEST_CASE.
* It will then automatically create a test case for each node type (file, directory, symlink).
* See FsppNodeTest_Rename for an example.
*/
template<class ConcreteFileSystemTestFixture>
class FsppNodeTest: public FileSystemTest<ConcreteFileSystemTestFixture> {
class FsppNodeTest: public virtual FsppNodeTestBase, public FileSystemTest<ConcreteFileSystemTestFixture> {
public:
virtual cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) = 0;
protected:
cpputils::unique_ref<fspp::Dir> CreateDir(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createDir(path.filename().native(), this->MODE_PUBLIC, 0, 0);
return this->LoadDir(path);
}
cpputils::unique_ref<fspp::File> CreateFile(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createAndOpenFile(path.filename().native(), this->MODE_PUBLIC, 0, 0);
return this->LoadFile(path);
}
cpputils::unique_ref<fspp::Symlink> CreateSymlink(const boost::filesystem::path &path) {
this->LoadDir(path.parent_path())->createSymlink(path.filename().native(), "/my/symlink/target", 0, 0);
return this->LoadSymlink(path);
};
};
#define REGISTER_SINGLE_NODE_TEST_CASE(r, Class, Name) \
class FsppNodeTest_File_Helper: public virtual FsppNodeTestBase {
public:
void IN_STAT(const fspp::Node &file, std::function<void (struct stat)> callback) override {
struct stat st1, st2;
file.stat(&st1);
callback(st1);
dynamic_cast<const fspp::File &>(file).open(O_RDONLY)->stat(&st2);
callback(st2);
}
void EXPECT_SIZE(uint64_t expectedSize, const fspp::Node &node) override {
IN_STAT(node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});
EXPECT_NUMBYTES_READABLE(expectedSize, dynamic_cast<const fspp::File&>(node));
}
void EXPECT_NUMBYTES_READABLE(uint64_t expectedSize, const fspp::File &file) {
auto openFile = file.open(O_RDONLY);
cpputils::Data data(expectedSize);
//Try to read one byte more than the expected size
ssize_t readBytes = openFile->read(data.data(), expectedSize+1, 0);
//and check that it only read the expected size (but also not less)
EXPECT_EQ(expectedSize, (uint64_t)readBytes);
}
};
class FsppNodeTest_Dir_Helper: public virtual FsppNodeTestBase {
public:
void IN_STAT(const fspp::Node &file, std::function<void (struct stat)> callback) override {
struct stat st;
file.stat(&st);
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, const fspp::Node &node) override {
IN_STAT(node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});
}
};
class FsppNodeTest_Symlink_Helper: public virtual FsppNodeTestBase {
public:
void IN_STAT(const fspp::Node &file, std::function<void (struct stat)> callback) override {
struct stat st;
file.stat(&st);
callback(st);
}
void EXPECT_SIZE(uint64_t expectedSize, const fspp::Node &node) override {
IN_STAT(node, [expectedSize] (struct stat st) {
EXPECT_EQ(expectedSize, (uint64_t)st.st_size);
});
}
};
#define _REGISTER_SINGLE_NODE_TEST_CASE(r, Class, Name) \
TYPED_TEST_P(Class, Name) { \
this->BOOST_PP_CAT(Test_,Name)(); \
} \
#define REGISTER_NODE_TEST_CASES_FOR_CLASS(Class, ...) \
TYPED_TEST_CASE_P(Class); \
BOOST_PP_SEQ_FOR_EACH(REGISTER_SINGLE_NODE_TEST_CASE, Class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
#define _REGISTER_NODE_TEST_CASES_FOR_CLASS(Class, ...) \
BOOST_PP_SEQ_FOR_EACH(_REGISTER_SINGLE_NODE_TEST_CASE, Class, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__)); \
REGISTER_TYPED_TEST_CASE_P(Class, __VA_ARGS__); \
#define REGISTER_NODE_TEST_CASE(Class, ...) \
#define _REGISTER_FILE_TEST_CASE(Class, ...) \
template<class ConcreteFileSystemTestFixture> \
class Class##_File: public Class<ConcreteFileSystemTestFixture> { \
class Class##_FileNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_File_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateFile(path); \
} \
}; \
\
TYPED_TEST_CASE_P(Class##_FileNode); \
_REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_FileNode, __VA_ARGS__); \
#define _REGISTER_DIR_TEST_CASE(Class, ...) \
template<class ConcreteFileSystemTestFixture> \
class Class##_Dir: public Class<ConcreteFileSystemTestFixture> { \
class Class##_DirNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Dir_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateDir(path); \
} \
}; \
\
TYPED_TEST_CASE_P(Class##_DirNode); \
_REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_DirNode, __VA_ARGS__); \
#define _REGISTER_SYMLINK_TEST_CASE(Class, ...) \
template<class ConcreteFileSystemTestFixture> \
class Class##_Symlink: public Class<ConcreteFileSystemTestFixture> { \
class Class##_SymlinkNode: public Class<ConcreteFileSystemTestFixture>, public FsppNodeTest_Symlink_Helper { \
public: \
cpputils::unique_ref<fspp::Node> CreateNode(const boost::filesystem::path &path) override { \
return this->CreateSymlink(path); \
} \
}; \
\
REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_File, __VA_ARGS__); \
REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_Dir, __VA_ARGS__); \
REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_Symlink, __VA_ARGS__); \
TYPED_TEST_CASE_P(Class##_SymlinkNode); \
_REGISTER_NODE_TEST_CASES_FOR_CLASS(Class##_SymlinkNode, __VA_ARGS__); \
#define REGISTER_NODE_TEST_CASE(Class, ...) \
_REGISTER_FILE_TEST_CASE(Class, __VA_ARGS__); \
_REGISTER_DIR_TEST_CASE(Class, __VA_ARGS__); \
_REGISTER_SYMLINK_TEST_CASE(Class, __VA_ARGS__); \
#define INSTANTIATE_NODE_TEST_CASE(FS_NAME, Class, FIXTURE) \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_File, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_Dir, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_Symlink, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_FileNode, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_DirNode, FIXTURE); \
INSTANTIATE_TYPED_TEST_CASE_P(FS_NAME, Class##_SymlinkNode, FIXTURE); \
#endif