I have some code iterating over files using std::filesystem
. I am using dependency injection to mock out the directory_iterator
logic, but I have trouble constructing a mocked directory_entry
, which does not allow setting all the values and always sets them based on a real file under given path.
#include <gmock/gmock.h>
#include <filesystem>
namespace fs = std::filesystem;
class directory_provider {
public:
virtual std::vector<fs::directory_entry> list_dir(const fs::path& path) = 0;
};
class filesystem_provider : public directory_provider {
public:
std::vector<fs::directory_entry> list_dir(const fs::path& path) override {
return { fs::directory_iterator{ path }, fs::directory_iterator{} };
}
};
class mock_provider : public directory_provider {
public:
MOCK_METHOD(std::vector<fs::directory_entry>, list_dir, (const fs::path& path), (override));
};
Is there a way to solve this, allowing me to return a directory_entry
with arbitrary values such as file_size
and is_regular_file
. As it stands, I cannot even set arbitrary path without throwing a filesystem_error
with "No such file or directory".
I tried changing the return type to std::vector<directory_entry_pod>
or std::vector<std::unique_ptr<directory_entry_provider>>
, where the first simply copies all data into a struct I can easily fill in UT, while the other wraps directory_entry
into a polymorphic class I can mock. Unfortunately, I measured the conversions and/or polymorphism to decrease throughput of production code by as much as 50% (all optimized, testing recursively on large repos like Linux kernel).
Short answer: No, you cannot populate a directory_entry
with arbitrary data.
(Slightly) longer answer:
According to cppreference the directory_entry
class represents a directory entry. It also present few ways to actually modify the content of that class. After inspecting the few functions we can use to actually populate the class with data, we see that all of them only takes a path and all of them can fail on OS API error. This means that the only way to actually populate this class with the desired data, is to ensure that it actually is a valid directory_entry
(i.e. create that entry in the filesystem with the desired data and give the directory_entry
the path to that newly created filesystem entry).