From 2888ea6efdaf4ccc2f9212d90d0acc8a9493f6c8 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Wed, 16 May 2018 21:34:01 -0700 Subject: [PATCH] - Make homedir work on windows - add test cases for homedir --- src/cpp-utils/system/homedir.cpp | 101 +++++++++++++----- src/cpp-utils/system/homedir.h | 19 +++- test/cpp-utils/CMakeLists.txt | 1 + test/cpp-utils/system/HomedirTest.cpp | 71 ++++++++++++ .../testutils/TestWithFakeHomeDirectory.h | 8 +- 5 files changed, 165 insertions(+), 35 deletions(-) create mode 100644 test/cpp-utils/system/HomedirTest.cpp diff --git a/src/cpp-utils/system/homedir.cpp b/src/cpp-utils/system/homedir.cpp index 9055548b..9b7d6691 100644 --- a/src/cpp-utils/system/homedir.cpp +++ b/src/cpp-utils/system/homedir.cpp @@ -1,6 +1,70 @@ #include "homedir.h" #include + +namespace bf = boost::filesystem; +using std::string; + +#if !defined(_MSC_VER) + #include +namespace { + bf::path _get_home_directory() { + struct passwd* pwd = getpwuid(getuid()); + string homedir; + if (pwd) { + homedir = pwd->pw_dir; + } else { + // try the $HOME environment variable + homedir = getenv("HOME"); + } + if (homedir == "") { + throw std::runtime_error("Couldn't determine home directory for user"); + } + return homedir; + } + + bf::path _get_appdata_directory() { + const char* xdg_data_dir = std::getenv("XDG_DATA_HOME"); + if (xdg_data_dir != nullptr) { + return xdg_data_dir; + } + + return _get_home_directory() / ".local" / "share"; + } +} + +#else + +#include +namespace { + struct PathBuffer final { + PWSTR path = nullptr; + + ~PathBuffer() { + CoTaskMemFree(path); + } + }; + + bf::path _get_known_path(KNOWNFOLDERID folderId) { + PathBuffer path; + HRESULT result_code = ::SHGetKnownFolderPath(folderId, 0, nullptr, &path.path); + if (S_OK != result_code) { + throw std::runtime_error("Failed getting user home directory. Hresult: " + std::to_string(result_code)); + } + bf::path result(path.path); + return result; + } + + bf::path _get_home_directory() { + return _get_known_path(FOLDERID_Profile); + } + + bf::path _get_appdata_directory() { + return _get_known_path(FOLDERID_LocalAppData); + } +} + +#endif namespace bf = boost::filesystem; using std::string; @@ -9,7 +73,8 @@ namespace cpputils { namespace system { HomeDirectory::HomeDirectory() - :_home_directory(_get_home_directory()) { + : _home_directory(::_get_home_directory()) + , _appdata_directory(::_get_appdata_directory()) { } HomeDirectory &HomeDirectory::singleton() { @@ -21,38 +86,24 @@ namespace cpputils { return singleton()._home_directory; } - bf::path HomeDirectory::_get_home_directory() { - struct passwd* pwd = getpwuid(getuid()); - string homedir; - if (pwd) { - homedir = pwd->pw_dir; - } else { - // try the $HOME environment variable - homedir = getenv("HOME"); - } - if (homedir == "") { - throw std::runtime_error("Couldn't determine home directory for user"); - } - return homedir; + const bf::path &HomeDirectory::getXDGDataDir() { + return singleton()._appdata_directory; } - bf::path HomeDirectory::getXDGDataDir() { - const char* xdg_data_dir = std::getenv("XDG_DATA_HOME"); - if (xdg_data_dir != nullptr) { - return xdg_data_dir; - } - - return cpputils::system::HomeDirectory::get() / ".local" / "share"; - } - - FakeHomeDirectoryRAII::FakeHomeDirectoryRAII(const boost::filesystem::path &fakeHomeDirectory) - :_oldHomeDirectory(HomeDirectory::singleton()._home_directory) { + FakeHomeDirectoryRAII::FakeHomeDirectoryRAII(const bf::path& fakeHomeDirectory, const bf::path& fakeAppdataDirectory) + : _oldHomeDirectory(HomeDirectory::singleton()._home_directory) + , _oldAppdataDirectory(HomeDirectory::singleton()._appdata_directory) { HomeDirectory::singleton()._home_directory = fakeHomeDirectory; + HomeDirectory::singleton()._appdata_directory = fakeAppdataDirectory; } FakeHomeDirectoryRAII::~FakeHomeDirectoryRAII() { // Reset to old (non-fake) value HomeDirectory::singleton()._home_directory = _oldHomeDirectory; + HomeDirectory::singleton()._appdata_directory = _oldAppdataDirectory; } + + FakeTempHomeDirectoryRAII::FakeTempHomeDirectoryRAII() + : _tempDir(), _fakeHome(_tempDir.path() / "home", _tempDir.path() / "appdata") {} } } diff --git a/src/cpp-utils/system/homedir.h b/src/cpp-utils/system/homedir.h index 79d97850..a2f3b54c 100644 --- a/src/cpp-utils/system/homedir.h +++ b/src/cpp-utils/system/homedir.h @@ -5,6 +5,7 @@ #include #include "../macros.h" #include +#include "../tempfile/TempDir.h" namespace cpputils { namespace system { @@ -15,14 +16,14 @@ namespace cpputils { public: static const boost::filesystem::path &get(); - static boost::filesystem::path getXDGDataDir(); + static const boost::filesystem::path &getXDGDataDir(); private: boost::filesystem::path _home_directory; + boost::filesystem::path _appdata_directory; HomeDirectory(); static HomeDirectory &singleton(); - boost::filesystem::path _get_home_directory(); friend class FakeHomeDirectoryRAII; @@ -32,15 +33,27 @@ namespace cpputils { class FakeHomeDirectoryRAII final { public: - FakeHomeDirectoryRAII(const boost::filesystem::path &fakeHomeDirectory); + FakeHomeDirectoryRAII(const boost::filesystem::path &fakeHomeDirectory, const boost::filesystem::path &fakeAppdataDirectory); ~FakeHomeDirectoryRAII(); private: boost::filesystem::path _oldHomeDirectory; + boost::filesystem::path _oldAppdataDirectory; DISALLOW_COPY_AND_ASSIGN(FakeHomeDirectoryRAII); }; + class FakeTempHomeDirectoryRAII final { + public: + FakeTempHomeDirectoryRAII(); + + private: + TempDir _tempDir; + FakeHomeDirectoryRAII _fakeHome; + + DISALLOW_COPY_AND_ASSIGN(FakeTempHomeDirectoryRAII); + }; + } } diff --git a/test/cpp-utils/CMakeLists.txt b/test/cpp-utils/CMakeLists.txt index 392a8f56..67786f96 100644 --- a/test/cpp-utils/CMakeLists.txt +++ b/test/cpp-utils/CMakeLists.txt @@ -46,6 +46,7 @@ set(SOURCES assert/assert_include_test.cpp assert/assert_debug_test.cpp system/MemoryTest.cpp + system/HomedirTest.cpp ) add_executable(${PROJECT_NAME} ${SOURCES}) diff --git a/test/cpp-utils/system/HomedirTest.cpp b/test/cpp-utils/system/HomedirTest.cpp new file mode 100644 index 00000000..e3cff3c8 --- /dev/null +++ b/test/cpp-utils/system/HomedirTest.cpp @@ -0,0 +1,71 @@ +#include +#include +#include + +using cpputils::system::HomeDirectory; +using cpputils::system::FakeHomeDirectoryRAII; +using cpputils::system::FakeTempHomeDirectoryRAII; +using cpputils::TempDir; + +namespace bf = boost::filesystem; + +TEST(HomedirTest, HomedirExists) { + EXPECT_TRUE(bf::exists(HomeDirectory::get())); +} + +TEST(HomedirTest, AppDataDirExists) { + EXPECT_TRUE(bf::exists(HomeDirectory::getXDGDataDir())); +} + +TEST(HomedirTest, FakeHomeDirectorySetsHomedirCorrectly) { + TempDir fakeHomeDir, fakeAppDataDir; + FakeHomeDirectoryRAII a(fakeHomeDir.path(), fakeAppDataDir.path()); + + EXPECT_EQ(fakeHomeDir.path(), HomeDirectory::get()); + EXPECT_EQ(fakeAppDataDir.path(), HomeDirectory::getXDGDataDir()); +} + +TEST(HomedirTest, FakeHomeDirectoryResetsHomedirCorrectly) { + bf::path actualHomeDir = HomeDirectory::get(); + bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); + + { + TempDir fakeHomeDir, fakeAppDataDir; + FakeHomeDirectoryRAII a(fakeHomeDir.path(), fakeAppDataDir.path()); + + EXPECT_NE(actualHomeDir, HomeDirectory::get()); + EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); + } + EXPECT_EQ(actualHomeDir, HomeDirectory::get()); + EXPECT_EQ(actualAppDataDir, HomeDirectory::getXDGDataDir()); +} + +TEST(HomedirTest, FakeTempHomeDirectorySetsHomedirCorrectly) { + bf::path actualHomeDir = HomeDirectory::get(); + bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); + + FakeTempHomeDirectoryRAII a; + + EXPECT_NE(actualHomeDir, HomeDirectory::get()); + EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); +} + +TEST(HomedirTest, FakeTempHomeDirectoryResetsHomedirCorrectly) { + bf::path actualHomeDir = HomeDirectory::get(); + bf::path actualAppDataDir = HomeDirectory::getXDGDataDir(); + + { + FakeTempHomeDirectoryRAII a; + + EXPECT_NE(actualHomeDir, HomeDirectory::get()); + EXPECT_NE(actualAppDataDir, HomeDirectory::getXDGDataDir()); + } + EXPECT_EQ(actualHomeDir, HomeDirectory::get()); + EXPECT_EQ(actualAppDataDir, HomeDirectory::getXDGDataDir()); +} + +TEST(HomedirTest, FakeTempHomeDirectoryUsesDifferentDirsForHomedirAndAppdataDir) { + FakeTempHomeDirectoryRAII a; + + EXPECT_NE(HomeDirectory::get(), HomeDirectory::getXDGDataDir()); +} diff --git a/test/cryfs/testutils/TestWithFakeHomeDirectory.h b/test/cryfs/testutils/TestWithFakeHomeDirectory.h index a0fef63e..b2e979ab 100644 --- a/test/cryfs/testutils/TestWithFakeHomeDirectory.h +++ b/test/cryfs/testutils/TestWithFakeHomeDirectory.h @@ -6,14 +6,8 @@ #include class TestWithFakeHomeDirectory { -public: - TestWithFakeHomeDirectory() - :homedir(), fakeHomeDirRAII(homedir.path()) { - } - private: - cpputils::TempDir homedir; - cpputils::system::FakeHomeDirectoryRAII fakeHomeDirRAII; + cpputils::system::FakeTempHomeDirectoryRAII fakeHomeDirRAII; }; #endif