diff --git a/handler.cpp b/handler.cpp index aa0c52a..e0d8bcf 100644 --- a/handler.cpp +++ b/handler.cpp @@ -3,14 +3,46 @@ #include #include -const std::filesystem::path kPATH{"/var/finger/users/"}; +bool RealFilesystemWrapper::exists(const std::filesystem::path &path) const { + return std::filesystem::exists(path); +} + +std::string +RealFilesystemWrapper::read_file(const std::filesystem::path &path) const { + std::ifstream file(path); + if (!file.is_open()) { + return ""; + } + + std::string content; + std::string line; + + while (std::getline(file, line)) { + content += line + "\n"; + } + + if (content.empty()) { + return ""; + } + + // Return the content with proper line endings + if (content.back() == '\n') { + content.pop_back(); // Remove the last newline + content += "\r\n"; + return content; + } + + content += "\r\n"; + return content; +} std::string process(const std::string &username) { RealFilesystemWrapper fs; - return process(username, fs); + return process(username, fs, kPATH); } -std::string process(const std::string &username, const IFilesystemWrapper &fs) { +std::string process(const std::string &username, const IFilesystemWrapper &fs, + const std::filesystem::path &basepath) { try { // Check for directory traversal patterns if (username.find("../") != std::string::npos || @@ -34,7 +66,7 @@ std::string process(const std::string &username, const IFilesystemWrapper &fs) { } // Attempt to open the plan file (if any) and return the contents as a string - std::filesystem::path planPath = kPATH / username; + std::filesystem::path planPath = basepath / username; // Check if the plan file exists using the filesystem wrapper if (!fs.exists(planPath)) { diff --git a/handler.hpp b/handler.hpp index 1f3f07a..e88d59b 100644 --- a/handler.hpp +++ b/handler.hpp @@ -15,34 +15,8 @@ public: class RealFilesystemWrapper : public IFilesystemWrapper { public: - bool exists(const std::filesystem::path &path) const override { - return std::filesystem::exists(path); - } - - std::string read_file(const std::filesystem::path &path) const override { - std::ifstream file(path); - if (!file.is_open()) { - return ""; - } - - std::string content; - std::string line; - while (std::getline(file, line)) { - content += line + "\n"; - } - - // Return the content with proper line endings - if (!content.empty() && content.back() == '\n') { - content.pop_back(); // Remove the last newline - content += "\r\n"; - return content; - } else if (!content.empty()) { - content += "\r\n"; - return content; - } - - return ""; - } + bool exists(const std::filesystem::path &path) const override; + std::string read_file(const std::filesystem::path &path) const override; }; class InvalidInput : public std::runtime_error { @@ -50,5 +24,8 @@ public: InvalidInput(const std::string &what = "") : std::runtime_error(what) {} }; +const std::filesystem::path kPATH{"/var/finger/users/"}; + std::string process(const std::string &username); -std::string process(const std::string &username, const IFilesystemWrapper &fs); +std::string process(const std::string &username, const IFilesystemWrapper &fs, + const std::filesystem::path &basepath = kPATH); diff --git a/main.cpp b/main.cpp index 2f208da..999b374 100644 --- a/main.cpp +++ b/main.cpp @@ -1,5 +1,3 @@ - - #include #include @@ -22,8 +20,6 @@ namespace this_coro = boost::asio::this_coro; awaitable dofinger(const std::string &username) { co_return process(username); - // co_return std::string("this is some finger information for ") + username + - // std::string("\r\n"); } awaitable echo(tcp::socket socket) { @@ -31,7 +27,6 @@ awaitable echo(tcp::socket socket) { char data[1024]; auto bytes_read = co_await socket.async_read_some(boost::asio::buffer(data), deferred); - // strip \r\n from data std::string username(data, bytes_read); // Remove trailing \r\n characters while (!username.empty() && diff --git a/test_handler_mock.cpp b/test_handler_mock.cpp index 75634a0..2f5c3f6 100644 --- a/test_handler_mock.cpp +++ b/test_handler_mock.cpp @@ -4,23 +4,6 @@ #include #include -// 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: @@ -100,30 +83,6 @@ TEST_F(ProcessMockTest, MultipleFileOperations) { 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();