From ac3b3595c7b32529c8704c93802f9f7d24112c92 Mon Sep 17 00:00:00 2001 From: Andy Ford Date: Sun, 15 Jan 2023 15:29:35 +0000 Subject: [PATCH] feat: display outbound leg information for holds --- src/plugin/CMakeLists.txt | 2 +- src/plugin/geometry/Measurement.cpp | 12 ++++ src/plugin/geometry/Measurement.h | 23 +++++++ src/plugin/geometry/MeasurementUnit.cpp | 8 +++ src/plugin/geometry/MeasurementUnit.h | 18 ++++++ .../geometry/MeasurementUnitFactory.cpp | 50 +++++++++++++++ src/plugin/geometry/MeasurementUnitFactory.h | 9 +++ src/plugin/geometry/MeasurementUnitType.h | 11 ++++ src/plugin/hold/HoldDisplay.cpp | 17 +++++- src/plugin/hold/HoldDisplayFunctions.cpp | 10 +++ src/plugin/hold/HoldDisplayFunctions.h | 1 + src/plugin/hold/HoldingData.cpp | 2 +- src/plugin/hold/HoldingData.h | 15 ++++- src/plugin/hold/HoldingDataSerializer.cpp | 14 ++++- test/plugin/CMakeLists.txt | 2 +- .../geometry/MeasurementUnitFactoryTest.cpp | 61 +++++++++++++++++++ test/plugin/hold/HoldDisplayFunctionsTest.cpp | 15 +++++ test/plugin/hold/HoldModuleTest.cpp | 20 +++++- .../plugin/hold/HoldingDataSerializerTest.cpp | 61 +++++++++++++++++++ .../PublishedHoldCollectionFactoryTest.cpp | 6 ++ 20 files changed, 349 insertions(+), 8 deletions(-) create mode 100644 src/plugin/geometry/Measurement.cpp create mode 100644 src/plugin/geometry/Measurement.h create mode 100644 src/plugin/geometry/MeasurementUnit.cpp create mode 100644 src/plugin/geometry/MeasurementUnit.h create mode 100644 src/plugin/geometry/MeasurementUnitFactory.cpp create mode 100644 src/plugin/geometry/MeasurementUnitFactory.h create mode 100644 src/plugin/geometry/MeasurementUnitType.h create mode 100644 test/plugin/geometry/MeasurementUnitFactoryTest.cpp diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt index e03e49588..206de1ee5 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/plugin/CMakeLists.txt @@ -269,7 +269,7 @@ set(src__flightrule source_group("src\\flightrule" FILES ${src__flightrule}) set(src__geometry - geometry/Line.cpp geometry/Line.h geometry/DistanceRadiusToScreenRadius.cpp geometry/DistanceRadiusToScreenRadius.h) + geometry/Line.cpp geometry/Line.h geometry/DistanceRadiusToScreenRadius.cpp geometry/DistanceRadiusToScreenRadius.h geometry/MeasurementUnitType.h geometry/MeasurementUnitFactory.cpp geometry/MeasurementUnitFactory.h geometry/Measurement.cpp geometry/Measurement.h geometry/MeasurementUnit.cpp geometry/MeasurementUnit.h) source_group("src\\geometry" FILES ${src__geometry}) set(src__graphics diff --git a/src/plugin/geometry/Measurement.cpp b/src/plugin/geometry/Measurement.cpp new file mode 100644 index 000000000..34dd0d33f --- /dev/null +++ b/src/plugin/geometry/Measurement.cpp @@ -0,0 +1,12 @@ +#include "Measurement.h" +#include "MeasurementUnit.h" + +namespace UKControllerPlugin::Geometry { + + Measurement::Measurement(std::unique_ptr unit, double value) : unit(std::move(unit)), value(value) + { + assert(this->unit && "Invalid unit in measurement"); + } + + Measurement::~Measurement() = default; +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/Measurement.h b/src/plugin/geometry/Measurement.h new file mode 100644 index 000000000..fa41fe1ea --- /dev/null +++ b/src/plugin/geometry/Measurement.h @@ -0,0 +1,23 @@ +#pragma once +#include "MeasurementUnit.h" + +namespace UKControllerPlugin::Geometry { + + struct MeasurementUnit; + + /** + * A measurement, comprising a unit and a value + */ + struct Measurement + { + public: + Measurement(std::unique_ptr unit, double value); + ~Measurement(); + + // The unit for the measurement + std::unique_ptr unit; + + // The value of the measurement + double value; + }; +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/MeasurementUnit.cpp b/src/plugin/geometry/MeasurementUnit.cpp new file mode 100644 index 000000000..60db18c51 --- /dev/null +++ b/src/plugin/geometry/MeasurementUnit.cpp @@ -0,0 +1,8 @@ +#include "MeasurementUnit.h" + +namespace UKControllerPlugin::Geometry { + auto MeasurementUnit::operator==(const MeasurementUnitType& type) const -> bool + { + return this->type == type; + } +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/MeasurementUnit.h b/src/plugin/geometry/MeasurementUnit.h new file mode 100644 index 000000000..955c84d3b --- /dev/null +++ b/src/plugin/geometry/MeasurementUnit.h @@ -0,0 +1,18 @@ +#pragma once +#include "MeasurementUnitType.h" + +namespace UKControllerPlugin::Geometry { + struct MeasurementUnit + { + MeasurementUnit(MeasurementUnitType type, std::string description) + : type(type), description(std::move(description)){}; + + // An enum representing the unit type + MeasurementUnitType type; + + // A description of the unit + std::string description; + + [[nodiscard]] auto operator==(const MeasurementUnitType& type) const -> bool; + }; +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/MeasurementUnitFactory.cpp b/src/plugin/geometry/MeasurementUnitFactory.cpp new file mode 100644 index 000000000..bca377a00 --- /dev/null +++ b/src/plugin/geometry/MeasurementUnitFactory.cpp @@ -0,0 +1,50 @@ +#include "MeasurementUnit.h" +#include "MeasurementUnitFactory.h" + +namespace UKControllerPlugin::Geometry { + + auto UnitTypeFromString(const std::string& unitString) -> MeasurementUnitType + { + if (unitString == "s") { + return MeasurementUnitType::Seconds; + } + + if (unitString == "min") { + return MeasurementUnitType::Minutes; + } + + if (unitString == "nm") { + return MeasurementUnitType::NauticalMiles; + } + + return MeasurementUnitType::None; + } + + auto UnitToString(MeasurementUnitType unit) -> std::string + { + if (unit == MeasurementUnitType::Seconds) { + return "Seconds"; + } + + if (unit == MeasurementUnitType::Minutes) { + return "Minutes"; + } + + if (unit == MeasurementUnitType::NauticalMiles) { + return "NM"; + } + + return "??"; + } + + auto UnitFromString(const std::string& unitString) -> std::unique_ptr + { + const auto unitType = UnitTypeFromString(unitString); + return std::make_unique(unitType, UnitToString(unitType)); + } + + auto UnitStringValid(const std::string& unitString) -> bool + { + return UnitTypeFromString(unitString) != MeasurementUnitType::None; + } +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/MeasurementUnitFactory.h b/src/plugin/geometry/MeasurementUnitFactory.h new file mode 100644 index 000000000..7b06e1c9f --- /dev/null +++ b/src/plugin/geometry/MeasurementUnitFactory.h @@ -0,0 +1,9 @@ +#pragma once +#include "MeasurementUnitType.h" + +namespace UKControllerPlugin::Geometry { + struct MeasurementUnit; + + [[nodiscard]] auto UnitFromString(const std::string& unitString) -> std::unique_ptr; + [[nodiscard]] auto UnitStringValid(const std::string& unitString) -> bool; +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/geometry/MeasurementUnitType.h b/src/plugin/geometry/MeasurementUnitType.h new file mode 100644 index 000000000..6dd3170e9 --- /dev/null +++ b/src/plugin/geometry/MeasurementUnitType.h @@ -0,0 +1,11 @@ +#pragma once + +namespace UKControllerPlugin::Geometry { + enum class MeasurementUnitType : unsigned int + { + None, + Seconds, + Minutes, + NauticalMiles, + }; +} // namespace UKControllerPlugin::Geometry diff --git a/src/plugin/hold/HoldDisplay.cpp b/src/plugin/hold/HoldDisplay.cpp index ceb111fda..8df650482 100644 --- a/src/plugin/hold/HoldDisplay.cpp +++ b/src/plugin/hold/HoldDisplay.cpp @@ -14,6 +14,8 @@ #include "euroscope/EuroscopePluginLoopbackInterface.h" #include "euroscope/EuroscopeRadarLoopbackInterface.h" #include "euroscope/UserSetting.h" +#include "geometry/Measurement.h" +#include "geometry/MeasurementUnit.h" #include "graphics/GdiGraphicsInterface.h" #include "list/PopupListInterface.h" #include "navaids/Navaid.h" @@ -686,7 +688,8 @@ namespace UKControllerPlugin { const HoldingData* hold = *this->publishedHolds.cbegin(); // Render the data - Gdiplus::Rect dataRect = {this->windowPos.x, this->dataStartHeight, this->windowWidth, this->lineHeight}; + Gdiplus::Rect dataRect = {this->windowPos.x, this->dataStartHeight - 10, this->windowWidth, + this->lineHeight}; graphics.DrawString( std::wstring(L"Fix: ") + ConvertToTchar(this->navaid.identifier), dataRect, this->dataBrush); @@ -703,6 +706,18 @@ namespace UKControllerPlugin { dataRect.Y = dataRect.Y + this->lineHeight + 5; graphics.DrawString(std::wstring(L"Minimum: ") + ConvertToTchar(hold->minimum), dataRect, this->dataBrush); + + dataRect.Y = dataRect.Y + this->lineHeight + 5; + + if (*hold->outboundLeg->unit == Geometry::MeasurementUnitType::None) { + graphics.DrawString(std::wstring(L"Outbound Leg: --"), dataRect, this->dataBrush); + } else { + graphics.DrawString( + std::wstring(L"Outbound Leg: ") + FormatOutboundLegValue(hold->outboundLeg->value) + L" " + + ConvertToTchar(hold->outboundLeg->unit->description), + dataRect, + this->dataBrush); + } } /* diff --git a/src/plugin/hold/HoldDisplayFunctions.cpp b/src/plugin/hold/HoldDisplayFunctions.cpp index 5366c8346..46969c243 100644 --- a/src/plugin/hold/HoldDisplayFunctions.cpp +++ b/src/plugin/hold/HoldDisplayFunctions.cpp @@ -111,5 +111,15 @@ namespace UKControllerPlugin { return verticalSpeed > 0 ? 1 : -1; } + + auto FormatOutboundLegValue(double value) -> std::wstring + { + std::wstringstream stream; + stream.setf(std::ios::fixed); + stream.precision(1); + stream << value; + + return stream.str(); + } } // namespace Hold } // namespace UKControllerPlugin diff --git a/src/plugin/hold/HoldDisplayFunctions.h b/src/plugin/hold/HoldDisplayFunctions.h index ca5189745..db1482003 100644 --- a/src/plugin/hold/HoldDisplayFunctions.h +++ b/src/plugin/hold/HoldDisplayFunctions.h @@ -14,5 +14,6 @@ namespace UKControllerPlugin { unsigned int GetDisplayRow(int holdMax, int occupiedLevel); std::wstring GetTimeInHoldDisplayString(const std::chrono::system_clock::time_point& entryTime); int GetVerticalSpeedDirection(int verticalSpeed); + [[nodiscard]] auto FormatOutboundLegValue(double value) -> std::wstring; } // namespace Hold } // namespace UKControllerPlugin diff --git a/src/plugin/hold/HoldingData.cpp b/src/plugin/hold/HoldingData.cpp index e9c324e7d..95379950d 100644 --- a/src/plugin/hold/HoldingData.cpp +++ b/src/plugin/hold/HoldingData.cpp @@ -11,7 +11,7 @@ namespace UKControllerPlugin::Hold { : identifier(original.identifier), fix(original.fix), description(original.description), minimum(original.minimum), maximum(original.maximum), inbound(original.inbound), turnDirection(original.turnDirection), restrictions(std::move(original.restrictions)), - deemedSeparatedHolds(std::move(original.deemedSeparatedHolds)) + deemedSeparatedHolds(std::move(original.deemedSeparatedHolds)), outboundLeg(std::move(original.outboundLeg)) { } diff --git a/src/plugin/hold/HoldingData.h b/src/plugin/hold/HoldingData.h index 50e1350b8..80641485b 100644 --- a/src/plugin/hold/HoldingData.h +++ b/src/plugin/hold/HoldingData.h @@ -1,4 +1,7 @@ #pragma once +#include "geometry/Measurement.h" +#include "geometry/MeasurementUnit.h" +#include "geometry/MeasurementUnitType.h" namespace UKControllerPlugin { namespace Hold { @@ -19,10 +22,15 @@ namespace UKControllerPlugin { unsigned int inbound = 361, std::string turnDirection = "up", std::set> restrictions = {}, - std::set> deemedSeparatedHolds = {}) + std::set> deemedSeparatedHolds = {}, + std::unique_ptr outboundLeg = std::make_unique( + std::make_unique(Geometry::MeasurementUnitType::None, "Unknown Units"), + -1.0)) : identifier(identifier), fix(fix), description(description), minimum(minimum), maximum(maximum), inbound(inbound), turnDirection(turnDirection), restrictions(std::move(restrictions)), - deemedSeparatedHolds(std::move(deemedSeparatedHolds)){}; + deemedSeparatedHolds(std::move(deemedSeparatedHolds)), outboundLeg(std::move(outboundLeg)) + { + } ~HoldingData(); HoldingData(HoldingData const&) = delete; HoldingData& operator=(HoldingData const&) = delete; @@ -57,6 +65,9 @@ namespace UKControllerPlugin { // Holds against which this hold is deemed separated std::set> deemedSeparatedHolds; + // The outbound leg + std::unique_ptr outboundLeg; + /* Compare two holds */ diff --git a/src/plugin/hold/HoldingDataSerializer.cpp b/src/plugin/hold/HoldingDataSerializer.cpp index 8d1b49adf..ba2248ec6 100644 --- a/src/plugin/hold/HoldingDataSerializer.cpp +++ b/src/plugin/hold/HoldingDataSerializer.cpp @@ -5,6 +5,8 @@ #include "HoldingDataSerializer.h" #include "HoldRestrictionSerializer.h" #include "bootstrap/PersistenceContainer.h" +#include "geometry/MeasurementUnitType.h" +#include "geometry/MeasurementUnitFactory.h" using UKControllerPlugin::Bootstrap::PersistenceContainer; @@ -29,6 +31,12 @@ namespace UKControllerPlugin::Hold { json.at("maximum_altitude").get_to(holdingData.maximum); json.at("inbound_heading").get_to(holdingData.inbound); json.at("turn_direction").get_to(holdingData.turnDirection); + + if (!json.at("outbound_leg_unit").is_null()) { + holdingData.outboundLeg = std::make_unique( + Geometry::UnitFromString(json.at("outbound_leg_unit").get()), + json.at("outbound_leg_value").get()); + } } void from_json_with_restrictions( @@ -60,6 +68,10 @@ namespace UKControllerPlugin::Hold { data.at("turn_direction").is_string() && (data.at("turn_direction") == "left" || data.at("turn_direction") == "right") && data.find("restrictions") != data.end() && data.at("restrictions").is_array() && - data.contains("deemed_separated_holds") && data.at("deemed_separated_holds").is_array(); + data.contains("deemed_separated_holds") && data.at("deemed_separated_holds").is_array() && + data.contains("outbound_leg_value") && data.contains("outbound_leg_unit") && + (data.at("outbound_leg_unit").is_null() || + (data.at("outbound_leg_value").is_number() && data.at("outbound_leg_unit").is_string() && + Geometry::UnitStringValid(data.at("outbound_leg_unit").get()))); } } // namespace UKControllerPlugin::Hold diff --git a/test/plugin/CMakeLists.txt b/test/plugin/CMakeLists.txt index e8ef0b78e..55c38389e 100644 --- a/test/plugin/CMakeLists.txt +++ b/test/plugin/CMakeLists.txt @@ -146,7 +146,7 @@ set(test__flightrule source_group("test\\flightrule" FILES ${test__flightrule}) set(test__geometry - geometry/LineTest.cpp geometry/DistanceRadiusToScreenRadiusTest.cpp) + geometry/LineTest.cpp geometry/DistanceRadiusToScreenRadiusTest.cpp geometry/MeasurementUnitFactoryTest.cpp) source_group("test\\geometry" FILES ${test__geometry}) set(test__handoff diff --git a/test/plugin/geometry/MeasurementUnitFactoryTest.cpp b/test/plugin/geometry/MeasurementUnitFactoryTest.cpp new file mode 100644 index 000000000..d2dcc18e7 --- /dev/null +++ b/test/plugin/geometry/MeasurementUnitFactoryTest.cpp @@ -0,0 +1,61 @@ +#include "geometry/MeasurementUnit.h" +#include "geometry/MeasurementUnitType.h" +#include "geometry/MeasurementUnitFactory.h" + +using UKControllerPlugin::Geometry::MeasurementUnitType; +using UKControllerPlugin::Geometry::UnitFromString; +using UKControllerPlugin::Geometry::UnitStringValid; + +namespace UKControllerPluginTest::Geometry { + class MeasurementUnitFactoryTest : public testing::Test + { + }; + + TEST_F(MeasurementUnitFactoryTest, ItReturnsSecondsFromString) + { + const auto unit = UnitFromString("s"); + EXPECT_EQ(*unit, MeasurementUnitType::Seconds); + EXPECT_EQ(unit->description, "Seconds"); + } + + TEST_F(MeasurementUnitFactoryTest, ItReturnsMinutesFromString) + { + const auto unit = UnitFromString("min"); + EXPECT_EQ(*unit, MeasurementUnitType::Minutes); + EXPECT_EQ(unit->description, "Minutes"); + } + + TEST_F(MeasurementUnitFactoryTest, ItReturnsNauticalMilesFromString) + { + const auto unit = UnitFromString("nm"); + EXPECT_EQ(*unit, MeasurementUnitType::NauticalMiles); + EXPECT_EQ(unit->description, "NM"); + } + + TEST_F(MeasurementUnitFactoryTest, ItReturnsUnknownUnitFromString) + { + const auto unit = UnitFromString("abc"); + EXPECT_EQ(*unit, MeasurementUnitType::None); + EXPECT_EQ(unit->description, "??"); + } + + TEST_F(MeasurementUnitFactoryTest, StringIsValidSeconds) + { + EXPECT_TRUE(UnitStringValid("s")); + } + + TEST_F(MeasurementUnitFactoryTest, StringIsValidMinutes) + { + EXPECT_TRUE(UnitStringValid("min")); + } + + TEST_F(MeasurementUnitFactoryTest, StringIsValidNauticalMiles) + { + EXPECT_TRUE(UnitStringValid("nm")); + } + + TEST_F(MeasurementUnitFactoryTest, StringIsNotValidUnknownString) + { + EXPECT_FALSE(UnitStringValid("abc")); + } +} // namespace UKControllerPluginTest::Geometry diff --git a/test/plugin/hold/HoldDisplayFunctionsTest.cpp b/test/plugin/hold/HoldDisplayFunctionsTest.cpp index e14bc8435..84938195b 100644 --- a/test/plugin/hold/HoldDisplayFunctionsTest.cpp +++ b/test/plugin/hold/HoldDisplayFunctionsTest.cpp @@ -169,4 +169,19 @@ namespace UKControllerPluginTest::Hold { { EXPECT_EQ(-1, UKControllerPlugin::Hold::GetVerticalSpeedDirection(-500)); } + + TEST(HoldDisplayFunctionsTest, ItReturnsOutboundLegValueIfWhole) + { + EXPECT_EQ(std::wstring(L"2.0"), UKControllerPlugin::Hold::FormatOutboundLegValue(2.0)); + } + + TEST(HoldDisplayFunctionsTest, ItReturnsOutboundLegValueIfMultipleDecimalPlaces) + { + EXPECT_EQ(std::wstring(L"3.1"), UKControllerPlugin::Hold::FormatOutboundLegValue(3.134)); + } + + TEST(HoldDisplayFunctionsTest, ItReturnsOutboundLegValueIfOneDecimalPlace) + { + EXPECT_EQ(std::wstring(L"4.5"), UKControllerPlugin::Hold::FormatOutboundLegValue(4.5)); + } } // namespace UKControllerPluginTest::Hold diff --git a/test/plugin/hold/HoldModuleTest.cpp b/test/plugin/hold/HoldModuleTest.cpp index 45d110152..beeeb868a 100644 --- a/test/plugin/hold/HoldModuleTest.cpp +++ b/test/plugin/hold/HoldModuleTest.cpp @@ -21,6 +21,9 @@ #include "hold/HoldManager.h" #include "hold/PublishedHoldCollection.h" #include "hold/HoldSelectionMenu.h" +#include "geometry/Measurement.h" +#include "geometry/MeasurementUnit.h" +#include "geometry/MeasurementUnitFactory.h" using ::testing::_; using ::testing::NiceMock; @@ -67,6 +70,8 @@ namespace UKControllerPluginTest::Hold { {"maximum_altitude", 15000}, {"inbound_heading", 309}, {"turn_direction", "right"}, + {"outbound_leg_unit", "nm"}, + {"outbound_leg_value", 1.5}, {"restrictions", nlohmann::json::array()}, {"deemed_separated_holds", nlohmann::json::array()}}; @@ -79,6 +84,8 @@ namespace UKControllerPluginTest::Hold { {"maximum_altitude", 15000}, {"inbound_heading", 309}, {"turn_direction", "right"}, + {"outbound_leg_unit", "nm"}, + {"outbound_leg_value", 1.5}, {"restrictions", nlohmann::json::array()}, {"deemed_separated_holds", nlohmann::json::array()}}; @@ -194,7 +201,18 @@ namespace UKControllerPluginTest::Hold { TEST_F(HoldModuleTest, ItLoadsHoldData) { BootstrapPlugin(this->mockDependencyProvider, this->container); - HoldingData expectedHold = {1, "TIMBA", "TIMBA", 7000, 15000, 309, HoldingData::TURN_DIRECTION_RIGHT, {}, {}}; + HoldingData expectedHold = { + 1, + "TIMBA", + "TIMBA", + 7000, + 15000, + 309, + HoldingData::TURN_DIRECTION_RIGHT, + {}, + {}, + std::make_unique( + UKControllerPlugin::Geometry::UnitFromString("nm"), 1.5)}; std::set expectedHoldSet; expectedHoldSet.emplace(&expectedHold); diff --git a/test/plugin/hold/HoldingDataSerializerTest.cpp b/test/plugin/hold/HoldingDataSerializerTest.cpp index 603575647..608811d71 100644 --- a/test/plugin/hold/HoldingDataSerializerTest.cpp +++ b/test/plugin/hold/HoldingDataSerializerTest.cpp @@ -3,9 +3,11 @@ #include "hold/HoldingDataSerializer.h" #include "hold/HoldingData.h" #include "bootstrap/PersistenceContainer.h" +#include "geometry/MeasurementUnitType.h" using ::testing::Test; using UKControllerPlugin::Bootstrap::PersistenceContainer; +using UKControllerPlugin::Geometry::MeasurementUnitType; using UKControllerPlugin::Hold::from_json_with_restrictions; using UKControllerPlugin::Hold::HoldingData; using UKControllerPlugin::Hold::holdSerializerInvalid; @@ -33,6 +35,8 @@ namespace UKControllerPluginTest { {"turn_direction", "right"}, {"restrictions", nlohmann::json::array({restriction})}, {"deemed_separated_holds", nlohmann::json::array({deemedSeparatedHold})}, + {"outbound_leg_unit", "nm"}, + {"outbound_leg_value", 1.5}, }; } @@ -46,6 +50,13 @@ namespace UKControllerPluginTest { EXPECT_TRUE(JsonValid(this->testData)); } + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsTrueAllValidWithUnitAndValueNull) + { + this->testData["outbound_leg_unit"] = nlohmann::json::value_t::null; + this->testData["outbound_leg_value"] = nlohmann::json::value_t::null; + EXPECT_TRUE(JsonValid(this->testData)); + } + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseNoId) { this->testData.erase("id"); @@ -154,6 +165,36 @@ namespace UKControllerPluginTest { EXPECT_EQ(holdSerializerInvalid, this->testData.get()); } + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseNoOutboundLegUnit) + { + this->testData.erase("outbound_leg_unit"); + EXPECT_FALSE(JsonValid(testData)); + } + + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseOutboundLegUnitNotString) + { + this->testData["outbound_leg_unit"] = 123; + EXPECT_FALSE(JsonValid(testData)); + } + + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseOutboundLegUnitNotValid) + { + this->testData["outbound_leg_unit"] = "abc"; + EXPECT_FALSE(JsonValid(testData)); + } + + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseNoOutboundLegValue) + { + this->testData.erase("outbound_leg_value"); + EXPECT_FALSE(JsonValid(testData)); + } + + TEST_F(HoldingDataSerializerTest, ValidJsonReturnsFalseOutboundLegValueNotNumber) + { + this->testData["outbound_leg_value"] = "abc"; + EXPECT_FALSE(JsonValid(testData)); + } + TEST_F(HoldingDataSerializerTest, ReturnsHoldingDataFromJson) { HoldingData actual = this->testData.get(); @@ -164,6 +205,8 @@ namespace UKControllerPluginTest { EXPECT_EQ(15000, actual.maximum); EXPECT_EQ(309, actual.inbound); EXPECT_EQ("right", actual.turnDirection); + EXPECT_EQ(MeasurementUnitType::NauticalMiles, *actual.outboundLeg->unit); + EXPECT_DOUBLE_EQ(1.5, actual.outboundLeg->value); } TEST_F(HoldingDataSerializerTest, ReturnsHoldingDataWithRestrictionsFromJson) @@ -177,10 +220,28 @@ namespace UKControllerPluginTest { EXPECT_EQ(15000, actual.maximum); EXPECT_EQ(309, actual.inbound); EXPECT_EQ("right", actual.turnDirection); + EXPECT_EQ(MeasurementUnitType::NauticalMiles, *actual.outboundLeg->unit); + EXPECT_DOUBLE_EQ(1.5, actual.outboundLeg->value); EXPECT_EQ(1, actual.restrictions.size()); EXPECT_TRUE((*actual.restrictions.cbegin())->LevelRestricted(7000)); EXPECT_TRUE((*actual.restrictions.cbegin())->LevelRestricted(9000)); EXPECT_EQ(2, (*actual.deemedSeparatedHolds.cbegin())->identifier); } + + TEST_F(HoldingDataSerializerTest, ReturnsHoldingDataFromJsonNoOutboundLegData) + { + this->testData["outbound_leg_unit"] = nlohmann::json::value_t::null; + this->testData["outbound_leg_value"] = nlohmann::json::value_t::null; + HoldingData actual = this->testData.get(); + EXPECT_EQ(1, actual.identifier); + EXPECT_EQ("TIMBA", actual.fix); + EXPECT_EQ("TIMBA LOW", actual.description); + EXPECT_EQ(7000, actual.minimum); + EXPECT_EQ(15000, actual.maximum); + EXPECT_EQ(309, actual.inbound); + EXPECT_EQ("right", actual.turnDirection); + EXPECT_EQ(MeasurementUnitType::None, *actual.outboundLeg->unit); + EXPECT_DOUBLE_EQ(-1.0, actual.outboundLeg->value); + } } // namespace Hold } // namespace UKControllerPluginTest diff --git a/test/plugin/hold/PublishedHoldCollectionFactoryTest.cpp b/test/plugin/hold/PublishedHoldCollectionFactoryTest.cpp index 9e82355b6..c18b09568 100644 --- a/test/plugin/hold/PublishedHoldCollectionFactoryTest.cpp +++ b/test/plugin/hold/PublishedHoldCollectionFactoryTest.cpp @@ -45,6 +45,8 @@ namespace UKControllerPluginTest { hold1["turn_direction"] = "right"; hold1["restrictions"] = nlohmann::json::array(); hold1["deemed_separated_holds"] = nlohmann::json::array(); + hold1["outbound_leg_unit"] = "nm"; + hold1["outbound_leg_value"] = 1.5; nlohmann::json hold2; hold2["id"] = 2; hold2["description"] = "WILLO"; @@ -53,6 +55,8 @@ namespace UKControllerPluginTest { hold2["maximum_altitude"] = 15000; hold2["inbound_heading"] = 285; hold2["turn_direction"] = "left"; + hold2["outbound_leg_unit"] = "nm"; + hold2["outbound_leg_value"] = 1.5; hold2["restrictions"] = nlohmann::json::array(); hold2["deemed_separated_holds"] = nlohmann::json::array(); @@ -78,6 +82,8 @@ namespace UKControllerPluginTest { hold["maximum_altitude"] = 15000; hold["inbound_heading"] = 309; hold["turn_direction"] = "left"; + hold["outbound_leg_unit"] = "nm"; + hold["outbound_leg_value"] = 1.5; data = {hold};