From bcf2d7bffc7f7049660446d674e591d018f9ceaa Mon Sep 17 00:00:00 2001 From: Dan Paulat Date: Wed, 8 Jun 2022 23:31:39 -0500 Subject: [PATCH] Adding map settings --- scwx-qt/scwx-qt.cmake | 2 + .../scwx/qt/manager/settings_manager.cpp | 22 +- .../scwx/qt/manager/settings_manager.hpp | 2 + .../source/scwx/qt/settings/map_settings.cpp | 222 ++++++++++++++++++ .../source/scwx/qt/settings/map_settings.hpp | 48 ++++ test/data | 2 +- .../scwx/qt/manager/settings_manager.test.cpp | 62 +++-- 7 files changed, 330 insertions(+), 30 deletions(-) create mode 100644 scwx-qt/source/scwx/qt/settings/map_settings.cpp create mode 100644 scwx-qt/source/scwx/qt/settings/map_settings.hpp diff --git a/scwx-qt/scwx-qt.cmake b/scwx-qt/scwx-qt.cmake index fbe9577d..9ef664bd 100644 --- a/scwx-qt/scwx-qt.cmake +++ b/scwx-qt/scwx-qt.cmake @@ -76,8 +76,10 @@ set(SRC_MAP source/scwx/qt/map/color_table_layer.cpp set(HDR_REQUEST source/scwx/qt/request/nexrad_file_request.hpp) set(SRC_REQUEST source/scwx/qt/request/nexrad_file_request.cpp) set(HDR_SETTINGS source/scwx/qt/settings/general_settings.hpp + source/scwx/qt/settings/map_settings.hpp source/scwx/qt/settings/palette_settings.hpp) set(SRC_SETTINGS source/scwx/qt/settings/general_settings.cpp + source/scwx/qt/settings/map_settings.cpp source/scwx/qt/settings/palette_settings.cpp) set(HDR_TYPES source/scwx/qt/types/radar_product_record.hpp) set(SRC_TYPES source/scwx/qt/types/radar_product_record.cpp) diff --git a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp index 04b258ee..c30a6a82 100644 --- a/scwx-qt/source/scwx/qt/manager/settings_manager.cpp +++ b/scwx-qt/source/scwx/qt/manager/settings_manager.cpp @@ -20,7 +20,12 @@ namespace SettingsManager static const std::string logPrefix_ = "scwx::qt::manager::settings_manager"; static const auto logger_ = scwx::util::Logger::Create(logPrefix_); +static const std::string kGeneralKey = "general"; +static const std::string kMapKey = "maps"; +static const std::string kPaletteKey = "palette"; + static std::shared_ptr generalSettings_ = nullptr; +static std::shared_ptr mapSettings_ = nullptr; static std::shared_ptr paletteSettings_ = nullptr; static boost::json::value ConvertSettingsToJson(); @@ -79,6 +84,11 @@ std::shared_ptr general_settings() return generalSettings_; } +std::shared_ptr map_settings() +{ + return mapSettings_; +} + std::shared_ptr palette_settings() { return paletteSettings_; @@ -88,8 +98,9 @@ static boost::json::value ConvertSettingsToJson() { boost::json::object settingsJson; - settingsJson["general"] = generalSettings_->ToJson(); - settingsJson["palette"] = paletteSettings_->ToJson(); + settingsJson[kGeneralKey] = generalSettings_->ToJson(); + settingsJson[kMapKey] = mapSettings_->ToJson(); + settingsJson[kPaletteKey] = paletteSettings_->ToJson(); return settingsJson; } @@ -99,6 +110,7 @@ static void GenerateDefaultSettings() logger_->info("Generating default settings"); generalSettings_ = settings::GeneralSettings::Create(); + mapSettings_ = settings::MapSettings::Create(); paletteSettings_ = settings::PaletteSettings::Create(); } @@ -109,9 +121,11 @@ static bool LoadSettings(const boost::json::object& settingsJson) bool jsonDirty = false; generalSettings_ = settings::GeneralSettings::Load( - settingsJson.if_contains("general"), jsonDirty); + settingsJson.if_contains(kGeneralKey), jsonDirty); + mapSettings_ = + settings::MapSettings::Load(settingsJson.if_contains(kMapKey), jsonDirty); paletteSettings_ = settings::PaletteSettings::Load( - settingsJson.if_contains("palette"), jsonDirty); + settingsJson.if_contains(kPaletteKey), jsonDirty); return jsonDirty; } diff --git a/scwx-qt/source/scwx/qt/manager/settings_manager.hpp b/scwx-qt/source/scwx/qt/manager/settings_manager.hpp index 9fb555b9..64dcc692 100644 --- a/scwx-qt/source/scwx/qt/manager/settings_manager.hpp +++ b/scwx-qt/source/scwx/qt/manager/settings_manager.hpp @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace scwx @@ -16,6 +17,7 @@ void Initialize(); void ReadSettings(const std::string& settingsPath); std::shared_ptr general_settings(); +std::shared_ptr map_settings(); std::shared_ptr palette_settings(); } // namespace SettingsManager diff --git a/scwx-qt/source/scwx/qt/settings/map_settings.cpp b/scwx-qt/source/scwx/qt/settings/map_settings.cpp new file mode 100644 index 00000000..1153211c --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/map_settings.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include + +#include +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +static const std::string logPrefix_ = "scwx::qt::settings::map_settings"; +static const auto logger_ = scwx::util::Logger::Create(logPrefix_); + +static constexpr size_t kCount_ = 4u; +static const std::string kDefaultRadarSite_ = "KLSX"; +static const std::string kDefaultRadarProductGroup_ = "L3"; + +static const std::array kDefaultRadarProduct_ { + "N0B", "N0G", "N0C", "N0X"}; + +class MapSettingsImpl +{ +public: + struct MapData + { + std::string radarSite_; + std::string radarProductGroup_; + std::string radarProduct_; + }; + + explicit MapSettingsImpl() { SetDefaults(); } + + ~MapSettingsImpl() {} + + void SetDefaults(size_t i) + { + map_[i].radarSite_ = kDefaultRadarSite_; + map_[i].radarProductGroup_ = kDefaultRadarProductGroup_; + map_[i].radarProduct_ = kDefaultRadarProduct_[i]; + } + + void SetDefaults() + { + for (size_t i = 0; i < kCount_; i++) + { + SetDefaults(i); + } + } + + std::array map_; +}; + +MapSettings::MapSettings() : p(std::make_unique()) {} +MapSettings::~MapSettings() = default; + +MapSettings::MapSettings(MapSettings&&) noexcept = default; +MapSettings& MapSettings::operator=(MapSettings&&) noexcept = default; + +size_t MapSettings::count() const +{ + return kCount_; +} + +std::string MapSettings::radar_site(size_t i) const +{ + return p->map_[i].radarSite_; +} + +std::string MapSettings::radar_product_group(size_t i) const +{ + return p->map_[i].radarProductGroup_; +} + +std::string MapSettings::radar_product(size_t i) const +{ + return p->map_[i].radarProduct_; +} + +boost::json::value MapSettings::ToJson() const +{ + boost::json::value json; + + json = boost::json::value_from(p->map_); + + return json; +} + +std::shared_ptr MapSettings::Create() +{ + std::shared_ptr generalSettings = + std::make_shared(); + + generalSettings->p->SetDefaults(); + + return generalSettings; +} + +std::shared_ptr MapSettings::Load(const boost::json::value* json, + bool& jsonDirty) +{ + std::shared_ptr mapSettings = std::make_shared(); + + if (json != nullptr && json->is_array()) + { + const boost::json::array& mapArray = json->as_array(); + + for (size_t i = 0; i < kCount_; ++i) + { + if (i < mapArray.size() && mapArray.at(i).is_object()) + { + const boost::json::object& mapRecord = mapArray.at(i).as_object(); + MapSettingsImpl::MapData& mapRecordSettings = + mapSettings->p->map_[i]; + + // Load JSON Elements + jsonDirty |= + !util::json::FromJsonString(mapRecord, + "radar_site", + mapRecordSettings.radarSite_, + kDefaultRadarSite_); + jsonDirty |= + !util::json::FromJsonString(mapRecord, + "radar_product_group", + mapRecordSettings.radarProductGroup_, + kDefaultRadarSite_); + jsonDirty |= + !util::json::FromJsonString(mapRecord, + "radar_product", + mapRecordSettings.radarProduct_, + kDefaultRadarSite_); + + // Validate Radar Site + if (config::RadarSite::Get(mapRecordSettings.radarSite_) == nullptr) + { + mapRecordSettings.radarSite_ = kDefaultRadarSite_; + jsonDirty = true; + } + + // Validate Radar Product Group + common::RadarProductGroup radarProductGroup = + common::GetRadarProductGroup( + mapRecordSettings.radarProductGroup_); + if (radarProductGroup == common::RadarProductGroup::Unknown) + { + mapRecordSettings.radarProductGroup_ = + kDefaultRadarProductGroup_; + radarProductGroup = + common::GetRadarProductGroup(kDefaultRadarProductGroup_); + jsonDirty = true; + } + + // Validate Radar Product + if (radarProductGroup == common::RadarProductGroup::Level2 && + common::GetLevel2Product(mapRecordSettings.radarProduct_) == + common::Level2Product::Unknown) + { + mapRecordSettings.radarProductGroup_ = + kDefaultRadarProductGroup_; + mapRecordSettings.radarProduct_ = kDefaultRadarProduct_[i]; + jsonDirty = true; + } + + // TODO: Validate level 3 product + } + else + { + logger_->warn( + "Too few array entries, resetting record {} to defaults", i + 1); + jsonDirty = true; + mapSettings->p->SetDefaults(i); + } + } + } + else + { + if (json == nullptr) + { + logger_->warn("Key is not present, resetting to defaults"); + } + else if (!json->is_array()) + { + logger_->warn("Invalid json, resetting to defaults"); + } + + mapSettings->p->SetDefaults(); + jsonDirty = true; + } + + return mapSettings; +} + +void tag_invoke(boost::json::value_from_tag, + boost::json::value& jv, + const MapSettingsImpl::MapData& data) +{ + jv = {{"radar_site", data.radarSite_}, + {"radar_product_group", data.radarProductGroup_}, + {"radar_product", data.radarProduct_}}; +} + +bool operator==(const MapSettings& lhs, const MapSettings& rhs) +{ + return (lhs.p->map_ == rhs.p->map_); +} + +bool operator==(const MapSettingsImpl::MapData& lhs, + const MapSettingsImpl::MapData& rhs) +{ + return (lhs.radarSite_ == rhs.radarSite_ && + lhs.radarProductGroup_ == rhs.radarProductGroup_ && + lhs.radarProduct_ == rhs.radarProduct_); +} + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/scwx-qt/source/scwx/qt/settings/map_settings.hpp b/scwx-qt/source/scwx/qt/settings/map_settings.hpp new file mode 100644 index 00000000..95be2e18 --- /dev/null +++ b/scwx-qt/source/scwx/qt/settings/map_settings.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include +#include + +#include + +namespace scwx +{ +namespace qt +{ +namespace settings +{ + +class MapSettingsImpl; + +class MapSettings +{ +public: + explicit MapSettings(); + ~MapSettings(); + + MapSettings(const MapSettings&) = delete; + MapSettings& operator=(const MapSettings&) = delete; + + MapSettings(MapSettings&&) noexcept; + MapSettings& operator=(MapSettings&&) noexcept; + + size_t count() const; + std::string radar_site(size_t i) const; + std::string radar_product_group(size_t i) const; + std::string radar_product(size_t i) const; + + boost::json::value ToJson() const; + + static std::shared_ptr Create(); + static std::shared_ptr Load(const boost::json::value* json, + bool& jsonDirty); + + friend bool operator==(const MapSettings& lhs, const MapSettings& rhs); + +private: + std::unique_ptr p; +}; + +} // namespace settings +} // namespace qt +} // namespace scwx diff --git a/test/data b/test/data index 288b2cb9..e1aea58d 160000 --- a/test/data +++ b/test/data @@ -1 +1 @@ -Subproject commit 288b2cb9b2dd540d44f684229973a97e61c79911 +Subproject commit e1aea58dcbb7ad961b974a6a00a83971031f4e0b diff --git a/test/source/scwx/qt/manager/settings_manager.test.cpp b/test/source/scwx/qt/manager/settings_manager.test.cpp index 5082441d..cedb0a41 100644 --- a/test/source/scwx/qt/manager/settings_manager.test.cpp +++ b/test/source/scwx/qt/manager/settings_manager.test.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -17,8 +18,20 @@ static const std::string DEFAULT_SETTINGS_FILE = static const std::string TEMP_SETTINGS_FILE = std::string(SCWX_TEST_DATA_DIR) + "/json/settings/settings-temp.json"; +class SettingsManagerTest : public testing::Test +{ + virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); } +}; + class DefaultSettingsTest : public testing::TestWithParam { + virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); } +}; + +class BadSettingsTest : + public testing::TestWithParam> +{ + virtual void SetUp() { scwx::qt::config::RadarSite::Initialize(); } }; void VerifyDefaults() @@ -45,8 +58,10 @@ void CompareFiles(const std::string& file1, const std::string& file2) EXPECT_EQ(buffer1.str(), buffer2.str()); } -TEST(SettingsManager, CreateJson) +TEST_F(SettingsManagerTest, CreateJson) { + scwx::qt::config::RadarSite::Initialize(); + std::string filename {TEMP_SETTINGS_FILE}; // Verify file doesn't exist prior to test start @@ -63,7 +78,7 @@ TEST(SettingsManager, CreateJson) EXPECT_EQ(std::filesystem::exists(filename), false); } -TEST(SettingsManager, SettingsKeax) +TEST_F(SettingsManagerTest, SettingsKeax) { std::string filename(std::string(SCWX_TEST_DATA_DIR) + "/json/settings/settings-keax.json"); @@ -71,6 +86,10 @@ TEST(SettingsManager, SettingsKeax) SettingsManager::ReadSettings(filename); EXPECT_EQ(SettingsManager::general_settings()->default_radar_site(), "KEAX"); + for (size_t i = 0; i < SettingsManager::map_settings()->count(); ++i) + { + EXPECT_EQ(SettingsManager::map_settings()->radar_site(i), "KEAX"); + } } TEST_P(DefaultSettingsTest, DefaultSettings) @@ -95,39 +114,32 @@ INSTANTIATE_TEST_SUITE_P(SettingsManager, "settings-empty-groups.json", "settings-empty-object.json")); -TEST(SettingsManager, SettingsBadMinimum) +TEST_P(BadSettingsTest, BadSettings) { - std::string minimumFile(std::string(SCWX_TEST_DATA_DIR) + - "/json/settings/settings-minimum.json"); - std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) + - "/json/settings/settings-bad-minimum.json"); - std::string filename {TEMP_SETTINGS_FILE}; + auto& [goodFilename, badFilename] = GetParam(); + + const std::string goodFile(std::string(SCWX_TEST_DATA_DIR) + + "/json/settings/" + goodFilename); + const std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) + + "/json/settings/" + badFilename); + const std::string filename {TEMP_SETTINGS_FILE}; std::filesystem::copy_file(sourceFile, filename); SettingsManager::ReadSettings(filename); - CompareFiles(filename, minimumFile); + CompareFiles(filename, goodFile); std::filesystem::remove(filename); } -TEST(SettingsManager, SettingsBadMaximum) -{ - std::string maximumFile(std::string(SCWX_TEST_DATA_DIR) + - "/json/settings/settings-maximum.json"); - std::string sourceFile(std::string(SCWX_TEST_DATA_DIR) + - "/json/settings/settings-bad-maximum.json"); - std::string filename {TEMP_SETTINGS_FILE}; - - std::filesystem::copy_file(sourceFile, filename); - - SettingsManager::ReadSettings(filename); - - CompareFiles(filename, maximumFile); - - std::filesystem::remove(filename); -} +INSTANTIATE_TEST_SUITE_P( + SettingsManager, + BadSettingsTest, + testing::Values( + std::make_pair("settings-minimum.json", "settings-bad-minimum.json"), + std::make_pair("settings-maximum.json", "settings-bad-maximum.json"), + std::make_pair("settings-maps.json", "settings-bad-maps.json"))); } // namespace manager } // namespace qt