Switch to using a filesystem class for better testing

This commit is contained in:
pmb
2025-06-25 11:59:07 -07:00
parent 3d35345eb9
commit e880f6ba1d
5 changed files with 200 additions and 39 deletions
+130
View File
@@ -0,0 +1,130 @@
#include "handler.hpp"
#include <filesystem>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <memory>
// Note: This is a demonstration of how to set up Google Mock for filesystem
// operations. To properly mock std::filesystem::exists, you would need to
// refactor handler.cpp to use dependency injection or create a filesystem
// wrapper interface.
// Mock interface for filesystem operations
/*
class IFilesystemWrapper {
public:
virtual ~IFilesystemWrapper() = default;
virtual bool exists(const std::filesystem::path& path) const = 0;
virtual std::string read_file(const std::filesystem::path& path) const = 0;
};
*/
#include "handler.hpp"
// Mock implementation
class MockFilesystemWrapper : public IFilesystemWrapper {
public:
MOCK_METHOD(bool, exists, (const std::filesystem::path &path),
(const, override));
MOCK_METHOD(std::string, read_file, (const std::filesystem::path &path),
(const, override));
};
// Test fixture for demonstrating Google Mock setup
class ProcessMockTest : public ::testing::Test {
protected:
void SetUp() override {
mock_filesystem = std::make_unique<MockFilesystemWrapper>();
}
void TearDown() override { mock_filesystem.reset(); }
std::unique_ptr<MockFilesystemWrapper> mock_filesystem;
};
// Test using the actual process function with mocked filesystem
TEST_F(ProcessMockTest, ProcessWithFileExists) {
// Setup mock expectations
EXPECT_CALL(*mock_filesystem, exists(::testing::_))
.WillOnce(::testing::Return(true));
EXPECT_CALL(*mock_filesystem, read_file(::testing::_))
.WillOnce(::testing::Return("Mock file content\r\n"));
// Test the actual process function with mocked filesystem
std::string result = process("testuser", *mock_filesystem);
EXPECT_EQ(result, "Mock file content\r\n");
}
// Test process function when file doesn't exist
TEST_F(ProcessMockTest, ProcessWithFileNotFound) {
EXPECT_CALL(*mock_filesystem, exists(::testing::_))
.WillOnce(::testing::Return(false));
// Test the actual process function - should return username when file doesn't
// exist
std::string result = process("nonexistentuser", *mock_filesystem);
EXPECT_EQ(result, "nonexistentuser");
}
// Test process function when file exists but is empty
TEST_F(ProcessMockTest, ProcessWithEmptyFile) {
EXPECT_CALL(*mock_filesystem, exists(::testing::_))
.WillOnce(::testing::Return(true));
EXPECT_CALL(*mock_filesystem, read_file(::testing::_))
.WillOnce(::testing::Return(""));
// Test the actual process function - should return username when file is
// empty
std::string result = process("emptyfileuser", *mock_filesystem);
EXPECT_EQ(result, "emptyfileuser");
}
// Test showing multiple expectations
TEST_F(ProcessMockTest, MultipleFileOperations) {
using ::testing::_;
using ::testing::Return;
EXPECT_CALL(*mock_filesystem, exists(_))
.Times(2)
.WillOnce(Return(true))
.WillOnce(Return(false));
EXPECT_CALL(*mock_filesystem, read_file(_))
.WillOnce(Return("First file content\r\n"));
// Test multiple calls
EXPECT_TRUE(mock_filesystem->exists("/path1"));
EXPECT_EQ(mock_filesystem->read_file("/path1"), "First file content\r\n");
EXPECT_FALSE(mock_filesystem->exists("/path2"));
}
/*
* REFACTORING SUGGESTION:
*
* To properly mock std::filesystem::exists in your handler.cpp, consider:
*
* 1. Create a filesystem wrapper interface:
* class IFilesystemWrapper {
* public:
* virtual bool exists(const std::filesystem::path& path) const = 0;
* virtual std::string read_file(const std::filesystem::path& path) const
* = 0;
* };
*
* 2. Modify process() function to accept the wrapper:
* std::string process(const std::string& username,
* const IFilesystemWrapper& fs =
* RealFilesystemWrapper{});
*
* 3. Use dependency injection in tests:
* MockFilesystemWrapper mock_fs;
* EXPECT_CALL(mock_fs, exists(_)).WillOnce(Return(true));
* std::string result = process("testuser", mock_fs);
*/
int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}