-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
250 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,248 @@ | ||
#include "pch.h" | ||
|
||
#include "HealthGPS.Console/configuration_parsing.h" | ||
#include "HealthGPS.Console/configuration_parsing_helpers.h" | ||
|
||
#include <fstream> | ||
#include <random> | ||
#include <type_traits> | ||
|
||
using json = nlohmann::json; | ||
using namespace host; | ||
|
||
#define TYPE_OF(x) std::remove_cvref_t<decltype(x)> | ||
|
||
namespace { | ||
const std::string TEST_KEY = "my_key"; | ||
const std::string TEST_KEY2 = "other_key"; | ||
|
||
#ifdef _WIN32 | ||
const std::filesystem::path TEST_PATH_ABSOLUTE = R"(C:\Users\hgps)"; | ||
#else | ||
const std::filesystem::path TEST_PATH_ABSOLUTE = "/home/hgps"; | ||
#endif | ||
|
||
class TempDir { | ||
public: | ||
TempDir() : rnd_{std::random_device()()} { | ||
path_ = std::filesystem::path{::testing::TempDir()} / "hgps" / random_string(); | ||
if (!std::filesystem::create_directories(path_)) { | ||
throw std::runtime_error{"Could not create temp dir"}; | ||
} | ||
|
||
path_ = std::filesystem::absolute(path_); | ||
} | ||
|
||
~TempDir() { | ||
if (std::filesystem::exists(path_)) { | ||
std::filesystem::remove_all(path_); | ||
} | ||
} | ||
|
||
std::string random_string() const { return std::to_string(rnd_()); } | ||
|
||
const auto &path() const { return path_; } | ||
|
||
private: | ||
mutable std::mt19937 rnd_; | ||
std::filesystem::path path_; | ||
|
||
std::filesystem::path createTempDir() { | ||
const auto rnd = std::random_device()(); | ||
const auto path = | ||
std::filesystem::path{::testing::TempDir()} / "hgps" / std::to_string(rnd); | ||
if (!std::filesystem::create_directories(path)) { | ||
throw std::runtime_error{"Could not create temp dir"}; | ||
} | ||
|
||
return std::filesystem::absolute(path); | ||
} | ||
}; | ||
|
||
class PathHelper : public ::testing::Test { | ||
public: | ||
const auto &tmp_path() const { return dir_.path(); } | ||
|
||
std::filesystem::path random_filename() const { return dir_.random_string(); } | ||
|
||
std::filesystem::path create_file_relative() const { | ||
auto file_path = random_filename(); | ||
std::ofstream ofs{dir_.path() / file_path}; | ||
return file_path; | ||
} | ||
|
||
std::filesystem::path create_file_absolute() const { | ||
auto file_path = tmp_path() / random_filename(); | ||
std::ofstream ofs{file_path}; | ||
return file_path; | ||
} | ||
|
||
private: | ||
TempDir dir_; | ||
}; | ||
|
||
} // anonymous namespace | ||
|
||
TEST(ConfigParsing, Get) { | ||
json j; | ||
|
||
// Null object | ||
EXPECT_THROW(get(j, TEST_KEY), ConfigurationError); | ||
|
||
// Key missing | ||
j[TEST_KEY2] = 1; | ||
EXPECT_THROW(get(j, TEST_KEY), ConfigurationError); | ||
|
||
// Key present | ||
j[TEST_KEY] = 2; | ||
EXPECT_NO_THROW(get(j, TEST_KEY)); | ||
} | ||
|
||
template <class Func> void testGetTo(const Func &f) { | ||
f(1); | ||
f(std::string{"hello"}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToGood) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
TYPE_OF(exp) out; | ||
EXPECT_TRUE(get_to(j, TEST_KEY, out)); | ||
EXPECT_EQ(out, exp); | ||
}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToGoodSetFlag) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
const auto check = [&exp, &j](bool initial) { | ||
bool success = initial; | ||
TYPE_OF(exp) out; | ||
EXPECT_TRUE(get_to(j, TEST_KEY, out, success)); | ||
EXPECT_EQ(success, initial); // flag shouldn't have been modified | ||
EXPECT_EQ(out, exp); | ||
}; | ||
|
||
check(true); | ||
check(false); | ||
}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToBadKey) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
// Try reading a different, non-existent key | ||
TYPE_OF(exp) out; | ||
EXPECT_FALSE(get_to(j, TEST_KEY2, out)); | ||
}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToBadKeySetFlag) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
// Try reading a different, non-existent key | ||
bool success = true; | ||
TYPE_OF(exp) out; | ||
EXPECT_FALSE(get_to(j, TEST_KEY2, out, success)); | ||
EXPECT_FALSE(success); | ||
}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToWrongType) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
// Deliberately choose a different type from the inputs so we get a mismatch | ||
std::vector<int> out; | ||
EXPECT_FALSE(get_to(j, TEST_KEY, out)); | ||
}); | ||
} | ||
|
||
TEST(ConfigParsing, GetToWrongTypeSetFlag) { | ||
testGetTo([](const auto &exp) { | ||
json j; | ||
j[TEST_KEY] = exp; | ||
|
||
// Deliberately choose a different type from the inputs so we get a mismatch | ||
std::vector<int> out; | ||
bool success = true; | ||
EXPECT_FALSE(get_to(j, TEST_KEY, out, success)); | ||
EXPECT_FALSE(success); | ||
}); | ||
} | ||
|
||
TEST_F(PathHelper, RebaseValidPathGood) { | ||
{ | ||
const auto absPath = create_file_absolute(); | ||
auto path = absPath; | ||
ASSERT_TRUE(path.is_absolute()); | ||
EXPECT_NO_THROW(rebase_valid_path(path, tmp_path())); | ||
|
||
// As path is absolute, it shouldn't be modified | ||
EXPECT_EQ(path, absPath); | ||
} | ||
|
||
{ | ||
const auto relPath = create_file_relative(); | ||
auto path = relPath; | ||
ASSERT_TRUE(path.is_relative()); | ||
EXPECT_NO_THROW(rebase_valid_path(path, tmp_path())); | ||
|
||
// Path should have been rebased | ||
EXPECT_EQ(path, tmp_path() / relPath); | ||
} | ||
} | ||
|
||
TEST_F(PathHelper, RebaseValidPathBad) { | ||
{ | ||
auto path = TEST_PATH_ABSOLUTE; | ||
ASSERT_TRUE(path.is_absolute()); | ||
EXPECT_THROW(rebase_valid_path(path, tmp_path()), ConfigurationError); | ||
} | ||
|
||
{ | ||
auto path = random_filename(); | ||
ASSERT_TRUE(path.is_relative()); | ||
EXPECT_THROW(rebase_valid_path(path, tmp_path()), ConfigurationError); | ||
} | ||
} | ||
|
||
TEST_F(PathHelper, RebaseValidPathTo) { | ||
|
||
{ | ||
// Should fail because key doesn't exist | ||
std::filesystem::path out; | ||
EXPECT_FALSE(rebase_valid_path_to(json{}, TEST_KEY, out, tmp_path())); | ||
} | ||
|
||
{ | ||
const auto relPath = create_file_relative(); | ||
ASSERT_TRUE(relPath.is_relative()); | ||
|
||
json j; | ||
j[TEST_KEY] = relPath; | ||
std::filesystem::path out; | ||
EXPECT_TRUE(rebase_valid_path_to(j, TEST_KEY, out, tmp_path())); | ||
|
||
// Path should have been rebased | ||
EXPECT_EQ(out, tmp_path() / relPath); | ||
} | ||
|
||
{ | ||
json j; | ||
j[TEST_KEY] = TEST_PATH_ABSOLUTE; | ||
std::filesystem::path out; | ||
EXPECT_FALSE(rebase_valid_path_to(j, TEST_KEY, out, tmp_path())); | ||
} | ||
} | ||
|
||
TEST_F(PathHelper, RebaseValidPathToSetFlag) {} |