From 41871aac3786e1c907aa07d4b24310649f9ab1ea Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 19:49:56 +0000 Subject: [PATCH 01/59] feat: Add stand assignment source tracking with runtime-configurable colours --- src/plugin/stands/StandAssignmentSource.h | 22 +++ .../stands/StandColourConfiguration.cpp | 137 ++++++++++++++++++ src/plugin/stands/StandColourConfiguration.h | 67 +++++++++ src/plugin/stands/StandEventHandler.cpp | 97 ++++++++++--- src/plugin/stands/StandEventHandler.h | 15 +- src/plugin/stands/StandModule.cpp | 10 +- 6 files changed, 323 insertions(+), 25 deletions(-) create mode 100644 src/plugin/stands/StandAssignmentSource.h create mode 100644 src/plugin/stands/StandColourConfiguration.cpp create mode 100644 src/plugin/stands/StandColourConfiguration.h diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h new file mode 100644 index 000000000..5af4ab98b --- /dev/null +++ b/src/plugin/stands/StandAssignmentSource.h @@ -0,0 +1,22 @@ +#pragma once +#include + +namespace UKControllerPlugin::Stands { + /* + Represents a stand assignment with its source (how it was assigned). + */ + struct StandAssignmentSource + { + // The ID of the assigned stand + int standId; + + // The source of the assignment (user, reservation_allocator, vaa_allocator, system_auto) + std::string source; + + // The four possible sources for stand assignments + static constexpr std::string_view SOURCE_USER = "user"; + static constexpr std::string_view SOURCE_RESERVATION_ALLOCATOR = "reservation_allocator"; + static constexpr std::string_view SOURCE_VAA_ALLOCATOR = "vaa_allocator"; + static constexpr std::string_view SOURCE_SYSTEM = "system_auto"; + }; +} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp new file mode 100644 index 000000000..666b6d55d --- /dev/null +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -0,0 +1,137 @@ +#include "StandColourConfiguration.h" +#include "StandAssignmentSource.h" +#include "euroscope/UserSetting.h" +#include "helper/HelperFunctions.h" +#include +#include + +namespace UKControllerPlugin::Stands { + + StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& userSetting) + : userSetting(userSetting) + { + // Initialize with default colours + sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = DEFAULT_SYSTEM_COLOUR; + + // Try to load from UserSettings + LoadFromUserSettings(); + } + + auto StandColourConfiguration::GetColourForSource(const std::string& source) const -> COLORREF + { + auto it = sourceColours.find(source); + if (it != sourceColours.cend()) { + return it->second; + } + + return DEFAULT_COLOUR; + } + + void StandColourConfiguration::LoadFromUserSettings() + { + try { + std::string key(SETTING_PREFIX); + + // Load user colour + key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_USER); + if (this->userSetting.HasEntry(key)) { + sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = + this->userSetting.GetColourEntry(key, DEFAULT_USER_COLOUR); + } + + // Load reservation allocator colour + key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); + if (this->userSetting.HasEntry(key)) { + sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = + this->userSetting.GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); + } + + // Load VAA allocator colour + key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); + if (this->userSetting.HasEntry(key)) { + sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = + this->userSetting.GetColourEntry(key, DEFAULT_VAA_COLOUR); + } + + // Load system colour + key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_SYSTEM); + if (this->userSetting.HasEntry(key)) { + sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = + this->userSetting.GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); + } + + LogInfo("Loaded stand assignment source colours from UserSettings"); + } catch (const std::exception& e) { + LogWarning("Failed to load stand colours from UserSettings: " + std::string(e.what())); + } + } + + void StandColourConfiguration::SaveToUserSettings() + { + try { + for (const auto& [source, colour] : sourceColours) { + const std::string key = std::string(SETTING_PREFIX) + source; + this->userSetting.Save(key, "Stand assignment source colour for " + source, colour); + } + LogInfo("Saved stand assignment source colours to UserSettings"); + } catch (const std::exception& e) { + LogWarning("Failed to save stand colours to UserSettings: " + std::string(e.what())); + } + } + + void StandColourConfiguration::SetColourForSource(const std::string& source, COLORREF colour) + { + sourceColours[source] = colour; + // Immediately save to UserSettings + try { + const std::string key = std::string(SETTING_PREFIX) + source; + this->userSetting.Save(key, "Stand assignment source colour for " + source, colour); + } catch (const std::exception& e) { + LogWarning("Failed to save stand colour for '" + source + "': " + std::string(e.what())); + } + } + + auto StandColourConfiguration::HexToColorref(const std::string& hex) -> COLORREF + { + std::string colourStr = hex; + + // Remove '#' if present + if (!colourStr.empty() && colourStr[0] == '#') { + colourStr = colourStr.substr(1); + } + + // Validate hex string length + if (colourStr.length() != 6) { + throw std::invalid_argument("Hex colour must be 6 characters (without #)"); + } + + // Parse hex values + try { + // Windows COLORREF is BGR, not RGB, so we parse as RGB and convert + const uint32_t rgbValue = std::stoul(colourStr, nullptr, 16); + const auto r = static_cast((rgbValue >> 16) & 0xFF); + const auto g = static_cast((rgbValue >> 8) & 0xFF); + const auto b = static_cast(rgbValue & 0xFF); + + return RGB(r, g, b); + } catch (const std::exception& e) { + throw std::invalid_argument(std::string("Invalid hex colour format: ") + e.what()); + } + } + + auto StandColourConfiguration::ColourrefToHex(COLORREF colour) -> std::string + { + // COLORREF is BGR format, convert to RGB for hex + const auto b = static_cast((colour >> 0) & 0xFF); + const auto g = static_cast((colour >> 8) & 0xFF); + const auto r = static_cast((colour >> 16) & 0xFF); + + std::stringstream ss; + ss << "#" << std::hex << std::setfill('0') << std::setw(2) << static_cast(r) << std::setw(2) + << static_cast(g) << std::setw(2) << static_cast(b); + return ss.str(); + } +} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h new file mode 100644 index 000000000..235aabb8f --- /dev/null +++ b/src/plugin/stands/StandColourConfiguration.h @@ -0,0 +1,67 @@ +#pragma once +#include "nlohmann/json.hpp" +#include +#include +#include + +namespace UKControllerPlugin::Euroscope { + class UserSetting; +} + +namespace UKControllerPlugin::Stands { + /* + Manages colour configuration for stand assignments based on their source. + Colours are persisted to EuroScope UserSettings and can be customized without recompilation. + */ + class StandColourConfiguration + { + public: + explicit StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& userSetting); + + /* + Get the colour for a given assignment source. + Returns a default grey if source is not found or not set. + */ + [[nodiscard]] auto GetColourForSource(const std::string& source) const -> COLORREF; + + /* + Load colours from UserSettings, with fallback to defaults. + */ + void LoadFromUserSettings(); + + /* + Save colours to UserSettings. + */ + void SaveToUserSettings(); + + /* + Set a colour for a specific source (runtime change). + */ + void SetColourForSource(const std::string& source, COLORREF colour); + + private: + // Converts a hex colour string (e.g. "#FF00FF") to a COLORREF + [[nodiscard]] static auto HexToColorref(const std::string& hex) -> COLORREF; + + // Converts COLORREF to hex string + [[nodiscard]] static auto ColourrefToHex(COLORREF colour) -> std::string; + + // Reference to user settings for persistence + UKControllerPlugin::Euroscope::UserSetting& userSetting; + + // Map of source to RGB colour + std::map sourceColours; + + // Default colour (grey) for unknown sources + static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); + + // Default colours if not configured + static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 255, 255); // white + static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 255, 0); // yellow + static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(0, 255, 255); // cyan + static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(180, 180, 180); // grey + + // UserSetting key prefix for colours + static constexpr std::string_view SETTING_PREFIX = "stand_colour_"; + }; +} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index b74df94c1..5013dd91a 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -32,10 +32,11 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId) + int standSelectedCallbackId, + const StandColourConfiguration& colourConfiguration) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), integrationEventHandler(integrationEventHandler), ownership(ownership), - standSelectedCallbackId(standSelectedCallbackId) + standSelectedCallbackId(standSelectedCallbackId), colourConfiguration(colourConfiguration) { assert(this->ownership != nullptr && "Ownership must not be null"); } @@ -115,7 +116,7 @@ namespace UKControllerPlugin::Stands { } // Assign that stand - this->AssignStandToAircraft(callsign, *stand); + this->AssignStandToAircraft(callsign, *stand, std::string(StandAssignmentSource::SOURCE_USER)); int standId = stand->id; auto callsignForRequest = callsign; @@ -192,7 +193,7 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignedStandForCallsign(const std::string& callsign) const -> int { auto assignment = this->standAssignments.find(callsign); - return assignment == this->standAssignments.cend() ? noStandAssigned : assignment->second; + return assignment == this->standAssignments.cend() ? noStandAssigned : assignment->second.standId; } auto StandEventHandler::GetLastAirfield() const -> std::string @@ -217,7 +218,7 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId) { - this->standAssignments[callsign] = standId; + this->standAssignments[callsign] = {standId, std::string(StandAssignmentSource::SOURCE_SYSTEM)}; } void StandEventHandler::StandSelected(int functionId, std::string context, RECT mousePosition) @@ -254,8 +255,8 @@ namespace UKControllerPlugin::Stands { auto mapLock = this->LockStandMap(); auto assignedStand = this->standAssignments.find(flightplan.GetCallsign()); if (assignedStand != this->standAssignments.cend() && - this->stands.find(assignedStand->second) != this->stands.cend()) { - startingText = this->stands.find(assignedStand->second)->identifier; + this->stands.find(assignedStand->second.standId) != this->stands.cend()) { + startingText = this->stands.find(assignedStand->second.standId)->identifier; } // Display the popup @@ -277,7 +278,13 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetTagItemDescription(int tagItemId) const -> std::string { - return "Assigned Stand"; + if (tagItemId == 110) { + return "Assigned Stand"; + } + if (tagItemId == 200) { + return "Stand Assignment Source"; + } + return ""; } /* @@ -286,13 +293,26 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::SetTagItemData(UKControllerPlugin::Tag::TagData& tagData) { auto mapLock = this->LockStandMap(); - if (this->standAssignments.count(tagData.GetFlightplan().GetCallsign()) != 0) { - auto stand = this->stands.find(this->standAssignments.at(tagData.GetFlightplan().GetCallsign())); - if (stand == this->stands.cend()) { - return; - } + const auto& callsign = tagData.GetFlightplan().GetCallsign(); + if (this->standAssignments.count(callsign) == 0) { + return; + } + const auto& assignment = this->standAssignments.at(callsign); + auto stand = this->stands.find(assignment.standId); + if (stand == this->stands.cend()) { + return; + } + + // Tag item 110: Show stand identifier with colour based on source + if (tagData.GetItemCode() == 110) { tagData.SetItemString(stand->identifier); + tagData.SetTagColour(this->colourConfiguration.GetColourForSource(assignment.source)); + } + // Tag item 200: Show assignment source shorthand + else if (tagData.GetItemCode() == 200) { + tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); + tagData.SetTagColour(this->colourConfiguration.GetColourForSource(assignment.source)); } } @@ -303,6 +323,33 @@ namespace UKControllerPlugin::Stands { this->stands.find(message.at("stand_id").get()) != this->stands.cend(); } + auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> std::string + { + if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { + return message.at("assignment_source").get(); + } + + return std::string(StandAssignmentSource::SOURCE_SYSTEM); + } + + auto StandEventHandler::GetAssignmentSourceShorthand(const std::string& source) -> std::string + { + if (source == StandAssignmentSource::SOURCE_USER) { + return "USER"; + } + if (source == StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR) { + return "RES"; + } + if (source == StandAssignmentSource::SOURCE_VAA_ALLOCATOR) { + return "VAA"; + } + if (source == StandAssignmentSource::SOURCE_SYSTEM) { + return "AUTO"; + } + + return "UNK"; + } + auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool { return message.is_object() && message.contains("callsign") && message.at("callsign").is_string(); @@ -358,13 +405,13 @@ namespace UKControllerPlugin::Stands { return; } - if (this->stands.find(this->standAssignments.at(flightPlan.GetCallsign()))->identifier == - flightPlan.GetAnnotation(this->annotationIndex)) { + const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); + const auto& stand = this->stands.find(assignment.standId); + if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { return; } - flightPlan.AnnotateFlightStrip( - this->annotationIndex, this->stands.find(this->standAssignments.at(flightPlan.GetCallsign()))->identifier); + flightPlan.AnnotateFlightStrip(this->annotationIndex, stand->identifier); } void StandEventHandler::FlightPlanDisconnectEvent(EuroScopeCFlightPlanInterface& flightPlan) @@ -400,7 +447,8 @@ namespace UKControllerPlugin::Stands { this->AssignStandToAircraft( assignment->at("callsign").get(), - *this->stands.find(assignment->at("stand_id").get())); + *this->stands.find(assignment->at("stand_id").get()), + GetAssignmentSourceFromMessage(*assignment)); } LogInfo("Loaded " + std::to_string(this->standAssignments.size()) + " stand assignments"); } catch (ApiException&) { @@ -424,7 +472,8 @@ namespace UKControllerPlugin::Stands { this->AssignStandToAircraft( message.data.at("callsign").get(), - *this->stands.find(message.data.at("stand_id").get())); + *this->stands.find(message.data.at("stand_id").get()), + GetAssignmentSourceFromMessage(message.data)); } else if (message.event == "App\\Events\\StandUnassignedEvent") { // If a stand has been unassigned, unassign it here if (!UnassignmentMessageValid(message.data)) { @@ -455,16 +504,22 @@ namespace UKControllerPlugin::Stands { } void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) + { + this->AssignStandToAircraft(callsign, stand, std::string(StandAssignmentSource::SOURCE_SYSTEM)); + } + + void + StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source) { this->AnnotateFlightStrip(callsign, stand.id); - this->standAssignments[callsign] = stand.id; + this->standAssignments[callsign] = {stand.id, source}; this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); LogInfo( "Stand id " + std::to_string(stand.id) + "(" + stand.airfieldCode + "/" + stand.identifier + ") " "assigned to " + - callsign); + callsign + " (source: " + source + ")"); } auto StandEventHandler::ActionsToProcess() const -> std::vector { diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 0c4981986..21e3b5f0a 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -1,6 +1,8 @@ #pragma once #include "CompareStands.h" #include "Stand.h" +#include "StandAssignmentSource.h" +#include "StandColourConfiguration.h" #include "flightplan/FlightPlanEventHandlerInterface.h" #include "integration/ExternalMessageHandlerInterface.h" #include "integration/IntegrationActionProcessor.h" @@ -41,7 +43,8 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId); + int standSelectedCallbackId, + const StandColourConfiguration& colourConfiguration); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, @@ -95,6 +98,7 @@ namespace UKControllerPlugin::Stands { private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); + void AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source); [[nodiscard]] auto AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; @@ -104,6 +108,8 @@ namespace UKControllerPlugin::Stands { void DoApiStandRequest(const std::string& callsign, const nlohmann::json data); void UnassignStandForAircraft(const std::string& callsign); [[nodiscard]] auto AssignmentMessageValid(const nlohmann::json& message) const -> bool; + [[nodiscard]] static auto GetAssignmentSourceFromMessage(const nlohmann::json& message) -> std::string; + [[nodiscard]] static auto GetAssignmentSourceShorthand(const std::string& source) -> std::string; auto CanAssignStand(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool; static auto UnassignmentMessageValid(const nlohmann::json& message) -> bool; auto @@ -126,8 +132,11 @@ namespace UKControllerPlugin::Stands { // All the stands we have std::set stands; - // The currently assigned stands and who they are assigned to - std::map standAssignments; + // The currently assigned stands and who they are assigned to, with source information + std::map standAssignments; + + // Colour configuration for stand assignment sources + const StandColourConfiguration& colourConfiguration; // Locks the stand assignments map to prevent concurrent edits std::recursive_mutex mapMutex; diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index d42f41c7f..211f6294f 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -2,6 +2,7 @@ #include "StandEventHandler.h" #include "StandModule.h" #include "StandSerializer.h" +#include "StandColourConfiguration.h" #include "bootstrap/PersistenceContainer.h" #include "dependency/DependencyLoaderInterface.h" #include "euroscope/CallbackFunction.h" @@ -24,6 +25,7 @@ namespace UKControllerPlugin::Stands { // The tag item id for assigned stand const int assignedStandTagItemId = 110; + const int standAssignmentSourceTagItemId = 200; const int openStandAssignmentPopupTagFunctionId = 9007; const int openStandAssignmentEditBoxTagFunctionId = 9008; @@ -33,6 +35,10 @@ namespace UKControllerPlugin::Stands { std::set stands; from_json(dependencies.LoadDependency(GetDependencyKey(), nlohmann::json::object()), stands); + // Load stand colour configuration from EuroScope user settings + auto colourConfiguration = std::make_shared(*container.pluginUserSettingHandler); + colourConfiguration->LoadFromUserSettings(); + // Create the event handler auto standSelectedCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); std::shared_ptr eventHandler = std::make_shared( @@ -42,7 +48,8 @@ namespace UKControllerPlugin::Stands { *container.integrationModuleContainer->outboundMessageHandler, container.airfieldOwnership, stands, - standSelectedCallbackId); + standSelectedCallbackId, + *colourConfiguration); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( @@ -84,6 +91,7 @@ namespace UKControllerPlugin::Stands { // Assign to handlers container.flightplanHandler->RegisterHandler(eventHandler); container.tagHandler->RegisterTagItem(assignedStandTagItemId, eventHandler); + container.tagHandler->RegisterTagItem(standAssignmentSourceTagItemId, eventHandler); container.pushEventProcessors->AddProcessor(eventHandler); container.externalEventHandler->AddHandler(eventHandler); container.integrationModuleContainer->inboundMessageHandler->AddProcessor(eventHandler); From 355d4797b4db2497f593e9c74a39a6e7dd823cc0 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 20:09:01 +0000 Subject: [PATCH 02/59] refactor: Corrections from Personal Review --- .../stands/StandColourConfiguration.cpp | 47 +- src/plugin/stands/StandColourConfiguration.h | 6 +- src/plugin/stands/StandEventHandler.cpp | 18 +- src/plugin/stands/StandEventHandler.h | 8 +- src/plugin/stands/StandModule.cpp | 15 +- test/plugin/stands/StandEventHandlerTest.cpp | 514 ++++++++++++------ 6 files changed, 421 insertions(+), 187 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 666b6d55d..a6cf411cc 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -8,7 +8,7 @@ namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& userSetting) - : userSetting(userSetting) + : userSetting(&userSetting) { // Initialize with default colours sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; @@ -20,6 +20,15 @@ namespace UKControllerPlugin::Stands { LoadFromUserSettings(); } + StandColourConfiguration::StandColourConfiguration() : userSetting(nullptr) + { + // Initialize with default colours (no persistence without UserSetting) + sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; + sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = DEFAULT_SYSTEM_COLOUR; + } + auto StandColourConfiguration::GetColourForSource(const std::string& source) const -> COLORREF { auto it = sourceColours.find(source); @@ -32,35 +41,37 @@ namespace UKControllerPlugin::Stands { void StandColourConfiguration::LoadFromUserSettings() { - try { - std::string key(SETTING_PREFIX); + if (!this->userSetting) { + return; + } + try { // Load user colour - key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_USER); - if (this->userSetting.HasEntry(key)) { + std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_USER); + if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = - this->userSetting.GetColourEntry(key, DEFAULT_USER_COLOUR); + this->userSetting->GetColourEntry(key, DEFAULT_USER_COLOUR); } // Load reservation allocator colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); - if (this->userSetting.HasEntry(key)) { + if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = - this->userSetting.GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); + this->userSetting->GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); } // Load VAA allocator colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); - if (this->userSetting.HasEntry(key)) { + if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = - this->userSetting.GetColourEntry(key, DEFAULT_VAA_COLOUR); + this->userSetting->GetColourEntry(key, DEFAULT_VAA_COLOUR); } // Load system colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_SYSTEM); - if (this->userSetting.HasEntry(key)) { + if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = - this->userSetting.GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); + this->userSetting->GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); } LogInfo("Loaded stand assignment source colours from UserSettings"); @@ -71,10 +82,14 @@ namespace UKControllerPlugin::Stands { void StandColourConfiguration::SaveToUserSettings() { + if (!this->userSetting) { + return; + } + try { for (const auto& [source, colour] : sourceColours) { const std::string key = std::string(SETTING_PREFIX) + source; - this->userSetting.Save(key, "Stand assignment source colour for " + source, colour); + this->userSetting->Save(key, "Stand assignment source colour for " + source, colour); } LogInfo("Saved stand assignment source colours to UserSettings"); } catch (const std::exception& e) { @@ -86,9 +101,13 @@ namespace UKControllerPlugin::Stands { { sourceColours[source] = colour; // Immediately save to UserSettings + if (!this->userSetting) { + return; + } + try { const std::string key = std::string(SETTING_PREFIX) + source; - this->userSetting.Save(key, "Stand assignment source colour for " + source, colour); + this->userSetting->Save(key, "Stand assignment source colour for " + source, colour); } catch (const std::exception& e) { LogWarning("Failed to save stand colour for '" + source + "': " + std::string(e.what())); } diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 235aabb8f..abdec2669 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -1,5 +1,4 @@ #pragma once -#include "nlohmann/json.hpp" #include #include #include @@ -17,6 +16,7 @@ namespace UKControllerPlugin::Stands { { public: explicit StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& userSetting); + explicit StandColourConfiguration(); /* Get the colour for a given assignment source. @@ -46,8 +46,8 @@ namespace UKControllerPlugin::Stands { // Converts COLORREF to hex string [[nodiscard]] static auto ColourrefToHex(COLORREF colour) -> std::string; - // Reference to user settings for persistence - UKControllerPlugin::Euroscope::UserSetting& userSetting; + // Reference to user settings for persistence (null if not available) + UKControllerPlugin::Euroscope::UserSetting* userSetting; // Map of source to RGB colour std::map sourceColours; diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 5013dd91a..579f8d6eb 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -33,7 +33,7 @@ namespace UKControllerPlugin::Stands { std::shared_ptr ownership, std::set stands, int standSelectedCallbackId, - const StandColourConfiguration& colourConfiguration) + std::shared_ptr colourConfiguration) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), integrationEventHandler(integrationEventHandler), ownership(ownership), standSelectedCallbackId(standSelectedCallbackId), colourConfiguration(colourConfiguration) @@ -278,10 +278,10 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetTagItemDescription(int tagItemId) const -> std::string { - if (tagItemId == 110) { + if (tagItemId == assignedStandTagItemId) { return "Assigned Stand"; } - if (tagItemId == 200) { + if (tagItemId == standAssignmentSourceTagItemId) { return "Stand Assignment Source"; } return ""; @@ -304,15 +304,15 @@ namespace UKControllerPlugin::Stands { return; } - // Tag item 110: Show stand identifier with colour based on source - if (tagData.GetItemCode() == 110) { + // Tag item: Show stand identifier with colour based on source + if (tagData.GetItemCode() == assignedStandTagItemId) { tagData.SetItemString(stand->identifier); - tagData.SetTagColour(this->colourConfiguration.GetColourForSource(assignment.source)); + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } - // Tag item 200: Show assignment source shorthand - else if (tagData.GetItemCode() == 200) { + // Tag item: Show assignment source shorthand + else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); - tagData.SetTagColour(this->colourConfiguration.GetColourForSource(assignment.source)); + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } } diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 21e3b5f0a..2a4a4eac4 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -44,7 +44,7 @@ namespace UKControllerPlugin::Stands { std::shared_ptr ownership, std::set stands, int standSelectedCallbackId, - const StandColourConfiguration& colourConfiguration); + std::shared_ptr colourConfiguration); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, @@ -96,6 +96,10 @@ namespace UKControllerPlugin::Stands { // No stand has been assigned to the aircraft inline static const int noStandAssigned = -1; + // Tag item IDs for stand display and source indication + inline static const int assignedStandTagItemId = 110; + inline static const int standAssignmentSourceTagItemId = 200; + private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); void AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source); @@ -136,7 +140,7 @@ namespace UKControllerPlugin::Stands { std::map standAssignments; // Colour configuration for stand assignment sources - const StandColourConfiguration& colourConfiguration; + std::shared_ptr colourConfiguration; // Locks the stand assignments map to prevent concurrent edits std::recursive_mutex mapMutex; diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 211f6294f..374507c46 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -24,8 +24,7 @@ using UKControllerPlugin::Tag::TagFunction; namespace UKControllerPlugin::Stands { // The tag item id for assigned stand - const int assignedStandTagItemId = 110; - const int standAssignmentSourceTagItemId = 200; + // Tag item IDs are defined in StandEventHandler const int openStandAssignmentPopupTagFunctionId = 9007; const int openStandAssignmentEditBoxTagFunctionId = 9008; @@ -36,8 +35,10 @@ namespace UKControllerPlugin::Stands { from_json(dependencies.LoadDependency(GetDependencyKey(), nlohmann::json::object()), stands); // Load stand colour configuration from EuroScope user settings - auto colourConfiguration = std::make_shared(*container.pluginUserSettingHandler); - colourConfiguration->LoadFromUserSettings(); + // If pluginUserSettingHandler is not available (e.g., in tests), creates default-only config + auto colourConfiguration = container.pluginUserSettingHandler + ? std::make_shared(*container.pluginUserSettingHandler) + : std::make_shared(); // Create the event handler auto standSelectedCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); @@ -49,7 +50,7 @@ namespace UKControllerPlugin::Stands { container.airfieldOwnership, stands, standSelectedCallbackId, - *colourConfiguration); + colourConfiguration); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( @@ -90,8 +91,8 @@ namespace UKControllerPlugin::Stands { // Assign to handlers container.flightplanHandler->RegisterHandler(eventHandler); - container.tagHandler->RegisterTagItem(assignedStandTagItemId, eventHandler); - container.tagHandler->RegisterTagItem(standAssignmentSourceTagItemId, eventHandler); + container.tagHandler->RegisterTagItem(StandEventHandler::assignedStandTagItemId, eventHandler); + container.tagHandler->RegisterTagItem(StandEventHandler::standAssignmentSourceTagItemId, eventHandler); container.pushEventProcessors->AddProcessor(eventHandler); container.externalEventHandler->AddHandler(eventHandler); container.integrationModuleContainer->inboundMessageHandler->AddProcessor(eventHandler); diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 2bdf46e72..68d258116 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -1,8 +1,11 @@ #include "stands/StandEventHandler.h" +#include "stands/StandColourConfiguration.h" +#include "stands/StandAssignmentSource.h" #include "tag/TagData.h" #include "api/ApiException.h" #include "controller/ActiveCallsign.h" #include "controller/ControllerPosition.h" +#include "euroscope/UserSetting.h" #include "ownership/AirfieldServiceProviderCollection.h" #include "ownership/ServiceProvision.h" #include "stands/StandUnassignedMessage.h" @@ -15,6 +18,7 @@ using ::testing::Return; using ::testing::Test; using ::testing::Throw; using UKControllerPlugin::Api::ApiException; +using UKControllerPlugin::Euroscope::UserSetting; using UKControllerPlugin::Integration::InboundMessage; using UKControllerPlugin::Integration::MessageType; using UKControllerPlugin::Plugin::PopupMenuItem; @@ -23,6 +27,8 @@ using UKControllerPlugin::Push::PushEventSubscription; using UKControllerPlugin::Stands::CompareStands; using UKControllerPlugin::Stands::Stand; using UKControllerPlugin::Stands::StandAssignedMessage; +using UKControllerPlugin::Stands::StandAssignmentSource; +using UKControllerPlugin::Stands::StandColourConfiguration; using UKControllerPlugin::Stands::StandEventHandler; using UKControllerPlugin::Stands::StandUnassignedMessage; using UKControllerPlugin::Tag::TagData; @@ -31,6 +37,7 @@ using UKControllerPluginTest::Euroscope::MockEuroScopeCControllerInterface; using UKControllerPluginTest::Euroscope::MockEuroScopeCFlightPlanInterface; using UKControllerPluginTest::Euroscope::MockEuroScopeCRadarTargetInterface; using UKControllerPluginTest::Euroscope::MockEuroscopePluginLoopbackInterface; +using UKControllerPluginTest::Euroscope::MockUserSettingProviderInterface; using UKControllerPluginTest::Integration::MockOutboundIntegrationEventHandler; using UKControllerPluginTest::TaskManager::MockTaskRunnerInterface; @@ -42,16 +49,22 @@ namespace UKControllerPluginTest { public: StandEventHandlerTest() : controller(2, "LON_S_CTR", 129.420, std::vector{"EGKK"}, true, false, true), - userCallsign(std::make_shared( - "LON_S_CTR", "Test", controller, true)), - notUserCallsign(std::make_shared( - "LON_S_CTR", "Test", controller, false)), + userCallsign( + std::make_shared( + "LON_S_CTR", "Test", controller, true)), + notUserCallsign( + std::make_shared( + "LON_S_CTR", "Test", controller, false)), airfieldOwnership( std::make_shared()), + userSetting(mockUserSettingProvider), + colourConfiguration(std::make_shared(userSetting)), tagData(flightplan, radarTarget, 110, 1, itemString, &euroscopeColourCode, &tagColour, &fontSize), - handler(api, taskRunner, plugin, mockIntegration, airfieldOwnership, GetStands(), 1) + handler( + api, taskRunner, plugin, mockIntegration, airfieldOwnership, GetStands(), 1, colourConfiguration) { ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); + ON_CALL(this->mockUserSettingProvider, KeyExists(_)).WillByDefault(Return(false)); this->mockController = std::make_shared>(); } @@ -76,10 +89,13 @@ namespace UKControllerPluginTest { NiceMock flightplan; NiceMock radarTarget; std::shared_ptr> mockController; + NiceMock mockUserSettingProvider; UKControllerPlugin::Controller::ControllerPosition controller; std::shared_ptr userCallsign; std::shared_ptr notUserCallsign; std::shared_ptr airfieldOwnership; + UserSetting userSetting; + std::shared_ptr colourConfiguration; TagData tagData; StandEventHandler handler; }; @@ -107,6 +123,163 @@ namespace UKControllerPluginTest { EXPECT_EQ("Foooooo", this->tagData.GetItemString()); } + TEST_F(StandEventHandlerTest, ItReturnsDescriptionForTagItem200) + { + EXPECT_EQ("Stand Assignment Source", this->handler.GetTagItemDescription(200)); + } + + TEST_F(StandEventHandlerTest, ItReturnsAssignedStandSourceShorthandForTagItem200) + { + this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_USER)); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ("USER", sourceTagData.GetItemString()); + } + + TEST_F(StandEventHandlerTest, ItReturnsReservationAllocatorShorthandForTagItem200) + { + this->handler.AssignStandToAircraft( + "BAW123", 1, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ("RES ", sourceTagData.GetItemString()); + } + + TEST_F(StandEventHandlerTest, ItReturnsVaaAllocatorShorthandForTagItem200) + { + this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ("VAA ", sourceTagData.GetItemString()); + } + + TEST_F(StandEventHandlerTest, ItReturnsSystemAutoShorthandForTagItem200) + { + this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_SYSTEM)); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ("AUTO", sourceTagData.GetItemString()); + } + + TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem200IfStandNotAssigned) + { + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ("Foooooo", sourceTagData.GetItemString()); + } + + TEST_F(StandEventHandlerTest, TagItem110UsesUserSourceColourWhenUserAssigns) + { + this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_USER)); + COLORREF expectedColour = this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_USER); + this->handler.SetTagItemData(this->tagData); + EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + } + + TEST_F(StandEventHandlerTest, TagItem110UsesReservationSourceColour) + { + this->handler.AssignStandToAircraft( + "BAW123", 3, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + COLORREF expectedColour = + this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); + this->handler.SetTagItemData(this->tagData); + EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + } + + TEST_F(StandEventHandlerTest, TagItem110UsesVaaSourceColour) + { + this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); + COLORREF expectedColour = + this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); + this->handler.SetTagItemData(this->tagData); + EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + } + + TEST_F(StandEventHandlerTest, TagItem110UsesSystemSourceColour) + { + this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_SYSTEM)); + COLORREF expectedColour = + this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_SYSTEM); + this->handler.SetTagItemData(this->tagData); + EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + } + + TEST_F(StandEventHandlerTest, TagItem200UsesUserSourceColour) + { + this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_USER)); + COLORREF expectedColour = this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_USER); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); + } + + TEST_F(StandEventHandlerTest, TagItem200UsesReservationSourceColour) + { + this->handler.AssignStandToAircraft( + "BAW123", 3, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + COLORREF expectedColour = + this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); + TagData sourceTagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); + } + TEST_F(StandEventHandlerTest, ItSubscribesToChannels) { std::set expectedSubscriptions; @@ -1506,8 +1679,9 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItUnassignsStandFromIntegrationMessage) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(1); @@ -1525,8 +1699,9 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftFromMessageIfNothingToDo) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(0); @@ -1545,8 +1720,9 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfBadCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", 123}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", 123}}}}); bool successCalled = false; std::vector failureMessages; @@ -1563,8 +1739,9 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfNoCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", nlohmann::json::object()}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", nlohmann::json::object()}}); bool successCalled = false; std::vector failureMessages; @@ -1604,11 +1781,12 @@ namespace UKControllerPluginTest { EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", 2)).Times(1); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1626,11 +1804,12 @@ namespace UKControllerPluginTest { { ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(nullptr)); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1646,11 +1825,12 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1666,11 +1846,12 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1686,11 +1867,12 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1706,11 +1888,12 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1726,15 +1909,16 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", - { - {"callsign", "BAW123"}, - {"airfield", "EGKK"}, - }}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", + { + {"callsign", "BAW123"}, + {"airfield", "EGKK"}, + }}}); bool successCalled = false; std::vector failureMessages; @@ -1750,11 +1934,12 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}}}); + auto message = InboundMessage::FromJson( + nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}}}); bool successCalled = false; std::vector failureMessages; @@ -1772,8 +1957,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1825,13 +2011,14 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -1845,8 +2032,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1898,13 +2086,14 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnForbidden(); this->handler.StandSelected(1, "AUTO", {}); @@ -1917,8 +2106,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1970,13 +2160,14 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -1990,8 +2181,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -2043,13 +2235,14 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -2063,8 +2256,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -2116,13 +2310,14 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -2136,8 +2331,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -2190,8 +2386,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -2252,8 +2449,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -2314,8 +2512,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2359,12 +2558,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -2378,8 +2578,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2423,12 +2624,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnServerError(); this->handler.StandSelected(1, "AUTO", {}); @@ -2441,8 +2643,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2486,12 +2689,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -2505,8 +2709,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2550,12 +2755,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -2569,8 +2775,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2614,12 +2821,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody( + nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -2633,8 +2841,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2687,8 +2896,9 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); + provisions.push_back( + std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport From c547eeeb3267d0386d344a99812f9c637d9ef7f6 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 20:24:13 +0000 Subject: [PATCH 03/59] feat: Enhance StandEventHandler with source tracking and update related tests --- src/plugin/stands/StandAssignmentSource.h | 1 + src/plugin/stands/StandColourConfiguration.h | 1 + src/plugin/stands/StandEventHandler.cpp | 15 +- src/plugin/stands/StandEventHandler.h | 1 + test/plugin/stands/StandEventHandlerTest.cpp | 170 +++++++------------ 5 files changed, 77 insertions(+), 111 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index 5af4ab98b..ee7edf330 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -1,5 +1,6 @@ #pragma once #include +#include namespace UKControllerPlugin::Stands { /* diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index abdec2669..411875a1a 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include namespace UKControllerPlugin::Euroscope { diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 579f8d6eb..0b0b2e0a4 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -35,8 +35,8 @@ namespace UKControllerPlugin::Stands { int standSelectedCallbackId, std::shared_ptr colourConfiguration) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - integrationEventHandler(integrationEventHandler), ownership(ownership), - standSelectedCallbackId(standSelectedCallbackId), colourConfiguration(colourConfiguration) + colourConfiguration(colourConfiguration), integrationEventHandler(integrationEventHandler), + ownership(ownership), standSelectedCallbackId(standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } @@ -221,6 +221,11 @@ namespace UKControllerPlugin::Stands { this->standAssignments[callsign] = {standId, std::string(StandAssignmentSource::SOURCE_SYSTEM)}; } + void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, const std::string& source) + { + this->standAssignments[callsign] = {standId, source}; + } + void StandEventHandler::StandSelected(int functionId, std::string context, RECT mousePosition) { /* @@ -338,16 +343,16 @@ namespace UKControllerPlugin::Stands { return "USER"; } if (source == StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR) { - return "RES"; + return "RES "; } if (source == StandAssignmentSource::SOURCE_VAA_ALLOCATOR) { - return "VAA"; + return "VAA "; } if (source == StandAssignmentSource::SOURCE_SYSTEM) { return "AUTO"; } - return "UNK"; + return "UNK "; } auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 2a4a4eac4..64e2717b1 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -67,6 +67,7 @@ namespace UKControllerPlugin::Stands { [[nodiscard]] auto GetLastAirfield() const -> std::string; void RemoveFlightStripAnnotation(const std::string& callsign) const; void SetAssignedStand(const std::string& callsign, int standId); + void SetAssignedStand(const std::string& callsign, int standId, const std::string& source); void StandSelected(int functionId, std::string context, RECT); void DisplayStandAssignmentEditBox( UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan, diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 68d258116..861b1b2a0 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -78,6 +78,49 @@ namespace UKControllerPluginTest { return stands; } + void SetAssignedStandWithSource(int standId, const std::string& source) + { + this->handler.SetAssignedStand("BAW123", standId, source); + } + + auto CreateSourceTagData() -> TagData + { + return TagData( + this->flightplan, + this->radarTarget, + 200, + 1, + this->itemString, + &this->euroscopeColourCode, + &this->tagColour, + &this->fontSize); + } + + void ExpectTagItem200Shorthand(const std::string& source, const std::string& expectedShorthand) + { + this->SetAssignedStandWithSource(1, source); + auto sourceTagData = this->CreateSourceTagData(); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ(expectedShorthand, sourceTagData.GetItemString()); + } + + void ExpectTagItem110ColourForSource(const std::string& source) + { + this->SetAssignedStandWithSource(3, source); + COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); + this->handler.SetTagItemData(this->tagData); + EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + } + + void ExpectTagItem200ColourForSource(const std::string& source) + { + this->SetAssignedStandWithSource(3, source); + COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); + auto sourceTagData = this->CreateSourceTagData(); + this->handler.SetTagItemData(sourceTagData); + EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); + } + double fontSize = 24.1; COLORREF tagColour = RGB(255, 255, 255); int euroscopeColourCode = EuroScopePlugIn::TAG_COLOR_ASSUMED; @@ -130,154 +173,69 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItReturnsAssignedStandSourceShorthandForTagItem200) { - this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_USER)); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ("USER", sourceTagData.GetItemString()); + this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_USER), "USER"); } TEST_F(StandEventHandlerTest, ItReturnsReservationAllocatorShorthandForTagItem200) { - this->handler.AssignStandToAircraft( - "BAW123", 1, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ("RES ", sourceTagData.GetItemString()); + this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), "RES "); } TEST_F(StandEventHandlerTest, ItReturnsVaaAllocatorShorthandForTagItem200) { - this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ("VAA ", sourceTagData.GetItemString()); + this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), "VAA "); } TEST_F(StandEventHandlerTest, ItReturnsSystemAutoShorthandForTagItem200) { - this->handler.AssignStandToAircraft("BAW123", 1, std::string(StandAssignmentSource::SOURCE_SYSTEM)); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ("AUTO", sourceTagData.GetItemString()); + this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_SYSTEM), "AUTO"); } TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem200IfStandNotAssigned) { - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); + auto sourceTagData = this->CreateSourceTagData(); this->handler.SetTagItemData(sourceTagData); EXPECT_EQ("Foooooo", sourceTagData.GetItemString()); } TEST_F(StandEventHandlerTest, TagItem110UsesUserSourceColourWhenUserAssigns) { - this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_USER)); - COLORREF expectedColour = this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_USER); - this->handler.SetTagItemData(this->tagData); - EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_USER)); } TEST_F(StandEventHandlerTest, TagItem110UsesReservationSourceColour) { - this->handler.AssignStandToAircraft( - "BAW123", 3, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); - COLORREF expectedColour = - this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); - this->handler.SetTagItemData(this->tagData); - EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); } TEST_F(StandEventHandlerTest, TagItem110UsesVaaSourceColour) { - this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); - COLORREF expectedColour = - this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); - this->handler.SetTagItemData(this->tagData); - EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); } TEST_F(StandEventHandlerTest, TagItem110UsesSystemSourceColour) { - this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_SYSTEM)); - COLORREF expectedColour = - this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_SYSTEM); - this->handler.SetTagItemData(this->tagData); - EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); + this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_SYSTEM)); } TEST_F(StandEventHandlerTest, TagItem200UsesUserSourceColour) { - this->handler.AssignStandToAircraft("BAW123", 3, std::string(StandAssignmentSource::SOURCE_USER)); - COLORREF expectedColour = this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_USER); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); + this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_USER)); } TEST_F(StandEventHandlerTest, TagItem200UsesReservationSourceColour) { - this->handler.AssignStandToAircraft( - "BAW123", 3, std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); - COLORREF expectedColour = - this->colourConfiguration->GetColourForSource(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); - TagData sourceTagData( - this->flightplan, - this->radarTarget, - 200, - 1, - this->itemString, - &this->euroscopeColourCode, - &this->tagColour, - &this->fontSize); - this->handler.SetTagItemData(sourceTagData); - EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); + this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + } + + TEST_F(StandEventHandlerTest, TagItem200UsesVaaSourceColour) + { + this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); + } + + TEST_F(StandEventHandlerTest, TagItem200UsesSystemSourceColour) + { + this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_SYSTEM)); } TEST_F(StandEventHandlerTest, ItSubscribesToChannels) From 4e80ae93f43a26ecc3c7a331e52b9338ee52f1d8 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 20:34:41 +0000 Subject: [PATCH 04/59] refactor: Update StandColourConfiguration and StandEventHandler for improved source handling --- .../stands/StandColourConfiguration.cpp | 4 +- src/plugin/stands/StandEventHandler.cpp | 8 ++ src/plugin/stands/StandEventHandler.h | 3 +- test/plugin/stands/StandEventHandlerTest.cpp | 77 +++++++------------ 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index a6cf411cc..0c40a416b 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,8 +2,10 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" -#include +#include #include +#include +#include namespace UKControllerPlugin::Stands { diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 0b0b2e0a4..399ad943e 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -1,4 +1,5 @@ #include "StandAssignedMessage.h" +#include "StandColourConfiguration.h" #include "StandEventHandler.h" #include "StandUnassignedMessage.h" #include "api/ApiException.h" @@ -412,6 +413,13 @@ namespace UKControllerPlugin::Stands { const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); const auto& stand = this->stands.find(assignment.standId); + if (stand == this->stands.cend()) { + LogWarning( + "Assigned stand id " + std::to_string(assignment.standId) + " not found for " + + flightPlan.GetCallsign()); + return; + } + if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { return; } diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 64e2717b1..fd3bf93c1 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -2,7 +2,6 @@ #include "CompareStands.h" #include "Stand.h" #include "StandAssignmentSource.h" -#include "StandColourConfiguration.h" #include "flightplan/FlightPlanEventHandlerInterface.h" #include "integration/ExternalMessageHandlerInterface.h" #include "integration/IntegrationActionProcessor.h" @@ -26,6 +25,8 @@ namespace UKControllerPlugin { } // namespace UKControllerPlugin namespace UKControllerPlugin::Stands { + class StandColourConfiguration; + /* Handles events related to stands. */ diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 861b1b2a0..7813b94dc 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -1,6 +1,7 @@ #include "stands/StandEventHandler.h" #include "stands/StandColourConfiguration.h" #include "stands/StandAssignmentSource.h" +#include #include "tag/TagData.h" #include "api/ApiException.h" #include "controller/ActiveCallsign.h" @@ -171,24 +172,18 @@ namespace UKControllerPluginTest { EXPECT_EQ("Stand Assignment Source", this->handler.GetTagItemDescription(200)); } - TEST_F(StandEventHandlerTest, ItReturnsAssignedStandSourceShorthandForTagItem200) + TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForTagItem200) { - this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_USER), "USER"); - } - - TEST_F(StandEventHandlerTest, ItReturnsReservationAllocatorShorthandForTagItem200) - { - this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), "RES "); - } - - TEST_F(StandEventHandlerTest, ItReturnsVaaAllocatorShorthandForTagItem200) - { - this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), "VAA "); - } + const std::string sources[] = { + std::string(StandAssignmentSource::SOURCE_USER), + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + const std::string expectedShorthand[] = {"USER", "RES ", "VAA ", "AUTO"}; - TEST_F(StandEventHandlerTest, ItReturnsSystemAutoShorthandForTagItem200) - { - this->ExpectTagItem200Shorthand(std::string(StandAssignmentSource::SOURCE_SYSTEM), "AUTO"); + for (size_t i = 0; i < std::size(sources); ++i) { + this->ExpectTagItem200Shorthand(sources[i], expectedShorthand[i]); + } } TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem200IfStandNotAssigned) @@ -198,44 +193,30 @@ namespace UKControllerPluginTest { EXPECT_EQ("Foooooo", sourceTagData.GetItemString()); } - TEST_F(StandEventHandlerTest, TagItem110UsesUserSourceColourWhenUserAssigns) + TEST_F(StandEventHandlerTest, TagItem110UsesSourceColours) { - this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_USER)); - } + const std::string sources[] = { + std::string(StandAssignmentSource::SOURCE_USER), + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - TEST_F(StandEventHandlerTest, TagItem110UsesReservationSourceColour) - { - this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); - } - - TEST_F(StandEventHandlerTest, TagItem110UsesVaaSourceColour) - { - this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); - } - - TEST_F(StandEventHandlerTest, TagItem110UsesSystemSourceColour) - { - this->ExpectTagItem110ColourForSource(std::string(StandAssignmentSource::SOURCE_SYSTEM)); - } - - TEST_F(StandEventHandlerTest, TagItem200UsesUserSourceColour) - { - this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_USER)); - } - - TEST_F(StandEventHandlerTest, TagItem200UsesReservationSourceColour) - { - this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + for (const auto& source : sources) { + this->ExpectTagItem110ColourForSource(source); + } } - TEST_F(StandEventHandlerTest, TagItem200UsesVaaSourceColour) + TEST_F(StandEventHandlerTest, TagItem200UsesSourceColours) { - this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); - } + const std::string sources[] = { + std::string(StandAssignmentSource::SOURCE_USER), + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - TEST_F(StandEventHandlerTest, TagItem200UsesSystemSourceColour) - { - this->ExpectTagItem200ColourForSource(std::string(StandAssignmentSource::SOURCE_SYSTEM)); + for (const auto& source : sources) { + this->ExpectTagItem200ColourForSource(source); + } } TEST_F(StandEventHandlerTest, ItSubscribesToChannels) From c1f98b78b963b69662bf2ca75b2f21b41f796602 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 20:36:28 +0000 Subject: [PATCH 05/59] feat: Add StandAssignmentSource and StandColourConfiguration files to stands source group --- src/plugin/CMakeLists.txt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt index e33f908c0..dd818321f 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/plugin/CMakeLists.txt @@ -906,6 +906,9 @@ set(src__stands "stands/CompareStands.cpp" "stands/CompareStands.h" "stands/Stand.h" + "stands/StandAssignmentSource.h" + "stands/StandColourConfiguration.cpp" + "stands/StandColourConfiguration.h" "stands/StandEventHandler.cpp" "stands/StandEventHandler.h" "stands/StandModule.cpp" From bc151cad74d1fd4f95172ccf9c9b160a541244a7 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 22:13:44 +0000 Subject: [PATCH 06/59] chore: consolidate code changes for improved maintainability --- .../stands/StandColourConfiguration.cpp | 23 +- src/plugin/stands/StandColourConfiguration.h | 4 +- src/plugin/stands/StandEventHandler.cpp | 15 +- src/plugin/stands/StandEventHandler.h | 11 +- src/plugin/stands/StandModule.cpp | 3 +- test/plugin/stands/StandEventHandlerTest.cpp | 957 +++--------------- 6 files changed, 183 insertions(+), 830 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 0c40a416b..bbe258a66 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -3,14 +3,13 @@ #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" #include -#include -#include +#include #include namespace UKControllerPlugin::Stands { - StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& userSetting) - : userSetting(&userSetting) + StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& setting) + : userSetting(&setting) { // Initialize with default colours sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; @@ -33,8 +32,7 @@ namespace UKControllerPlugin::Stands { auto StandColourConfiguration::GetColourForSource(const std::string& source) const -> COLORREF { - auto it = sourceColours.find(source); - if (it != sourceColours.cend()) { + if (auto it = sourceColours.find(source); it != sourceColours.cend()) { return it->second; } @@ -138,8 +136,10 @@ namespace UKControllerPlugin::Stands { const auto b = static_cast(rgbValue & 0xFF); return RGB(r, g, b); - } catch (const std::exception& e) { + } catch (const std::invalid_argument& e) { throw std::invalid_argument(std::string("Invalid hex colour format: ") + e.what()); + } catch (const std::out_of_range& e) { + throw std::invalid_argument(std::string("Hex colour value out of range: ") + e.what()); } } @@ -150,9 +150,10 @@ namespace UKControllerPlugin::Stands { const auto g = static_cast((colour >> 8) & 0xFF); const auto r = static_cast((colour >> 16) & 0xFF); - std::stringstream ss; - ss << "#" << std::hex << std::setfill('0') << std::setw(2) << static_cast(r) << std::setw(2) - << static_cast(g) << std::setw(2) << static_cast(b); - return ss.str(); + return std::format( + "#{:02x}{:02x}{:02x}", + static_cast(r), + static_cast(g), + static_cast(b)); } } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 411875a1a..e757037af 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -2,7 +2,7 @@ #include #include #include -#include +#include namespace UKControllerPlugin::Euroscope { class UserSetting; @@ -51,7 +51,7 @@ namespace UKControllerPlugin::Stands { UKControllerPlugin::Euroscope::UserSetting* userSetting; // Map of source to RGB colour - std::map sourceColours; + std::map> sourceColours; // Default colour (grey) for unknown sources static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 399ad943e..690da0efb 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -2,6 +2,7 @@ #include "StandColourConfiguration.h" #include "StandEventHandler.h" #include "StandUnassignedMessage.h" +#include #include "api/ApiException.h" #include "api/ApiInterface.h" #include "api/ApiRequestFactory.h" @@ -33,11 +34,10 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId, - std::shared_ptr colourConfiguration) + StandEventHandlerConfig config) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - colourConfiguration(colourConfiguration), integrationEventHandler(integrationEventHandler), - ownership(ownership), standSelectedCallbackId(standSelectedCallbackId) + colourConfiguration(std::move(config.colourConfiguration)), integrationEventHandler(integrationEventHandler), + ownership(ownership), standSelectedCallbackId(config.standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } @@ -300,7 +300,7 @@ namespace UKControllerPlugin::Stands { { auto mapLock = this->LockStandMap(); const auto& callsign = tagData.GetFlightplan().GetCallsign(); - if (this->standAssignments.count(callsign) == 0) { + if (!this->standAssignments.contains(callsign)) { return; } @@ -407,7 +407,7 @@ namespace UKControllerPlugin::Stands { EuroScopeCFlightPlanInterface& flightPlan, EuroScopeCRadarTargetInterface& radarTarget) { auto mapLock = this->LockStandMap(); - if (this->standAssignments.count(flightPlan.GetCallsign()) == 0) { + if (!this->standAssignments.contains(flightPlan.GetCallsign())) { return; } @@ -415,8 +415,7 @@ namespace UKControllerPlugin::Stands { const auto& stand = this->stands.find(assignment.standId); if (stand == this->stands.cend()) { LogWarning( - "Assigned stand id " + std::to_string(assignment.standId) + " not found for " + - flightPlan.GetCallsign()); + std::format("Assigned stand id {} not found for {}", assignment.standId, flightPlan.GetCallsign())); return; } diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index fd3bf93c1..b38f8bc7a 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -27,6 +27,12 @@ namespace UKControllerPlugin { namespace UKControllerPlugin::Stands { class StandColourConfiguration; + struct StandEventHandlerConfig + { + int standSelectedCallbackId; + std::shared_ptr colourConfiguration; + }; + /* Handles events related to stands. */ @@ -44,8 +50,7 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId, - std::shared_ptr colourConfiguration); + StandEventHandlerConfig config); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, @@ -139,7 +144,7 @@ namespace UKControllerPlugin::Stands { std::set stands; // The currently assigned stands and who they are assigned to, with source information - std::map standAssignments; + std::map> standAssignments; // Colour configuration for stand assignment sources std::shared_ptr colourConfiguration; diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 374507c46..774069f35 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -49,8 +49,7 @@ namespace UKControllerPlugin::Stands { *container.integrationModuleContainer->outboundMessageHandler, container.airfieldOwnership, stands, - standSelectedCallbackId, - colourConfiguration); + StandEventHandlerConfig{standSelectedCallbackId, colourConfiguration}); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 7813b94dc..6d261c38f 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -1,6 +1,7 @@ #include "stands/StandEventHandler.h" #include "stands/StandColourConfiguration.h" #include "stands/StandAssignmentSource.h" +#include #include #include "tag/TagData.h" #include "api/ApiException.h" @@ -62,7 +63,13 @@ namespace UKControllerPluginTest { colourConfiguration(std::make_shared(userSetting)), tagData(flightplan, radarTarget, 110, 1, itemString, &euroscopeColourCode, &tagColour, &fontSize), handler( - api, taskRunner, plugin, mockIntegration, airfieldOwnership, GetStands(), 1, colourConfiguration) + api, + taskRunner, + plugin, + mockIntegration, + airfieldOwnership, + GetStands(), + StandEventHandlerConfig{1, colourConfiguration}) { ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); ON_CALL(this->mockUserSettingProvider, KeyExists(_)).WillByDefault(Return(false)); @@ -122,6 +129,64 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedColour, sourceTagData.GetTagColour()); } + // Sets IsTracked, IsTrackedByUser, IsVatsimRecognisedController, + // GetOrigin("EGKK") and GetDistanceFromOrigin on the fixture flightplan. + void SetupFlightplan(bool tracked, bool trackedByUser, bool vatsim = true, double distance = 4) + { + ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(tracked)); + ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(trackedByUser)); + ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); + ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(vatsim)); + ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); + ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(distance)); + } + + // Creates a NiceMock flightplan wired up as plugin.GetSelectedFlightplan(). + [[nodiscard]] auto MakeSelectedFlightplan(bool tracked = false, bool trackedByUser = false) + -> std::shared_ptr> + { + auto fp = std::make_shared>(); + ON_CALL(*fp, IsTracked()).WillByDefault(Return(tracked)); + ON_CALL(*fp, IsTrackedByUser()).WillByDefault(Return(trackedByUser)); + ON_CALL(*fp, GetCallsign()).WillByDefault(Return("BAW123")); + ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(fp)); + return fp; + } + + // Calls handler.ProcessAction capturing success/failure into the provided refs. + void CallProcessAction( + std::shared_ptr message, + bool& successCalled, + std::vector& failureMessages) + { + this->handler.ProcessAction( + message, + [&successCalled]() { successCalled = true; }, + [&failureMessages](std::vector msgs) { failureMessages = std::move(msgs); }); + } + + // Creates a mock flightplan registered for "BAW123", sets up the + // AnnotateFlightStrip(3,"1L") expectation, and expects the integration event. + [[nodiscard]] auto MakeSyncFlightplanForBaw123Stand1() + -> std::shared_ptr> + { + auto fp = std::make_shared>(); + ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(fp)); + EXPECT_CALL(*fp, AnnotateFlightStrip(3, "1L")).Times(1); + auto expectedMsg = std::make_shared("BAW123", "EGKK", "1L"); + EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMsg))).Times(1); + return fp; + } + + [[nodiscard]] static auto AllSources() -> std::array + { + return { + std::string(StandAssignmentSource::SOURCE_USER), + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + } + double fontSize = 24.1; COLORREF tagColour = RGB(255, 255, 255); int euroscopeColourCode = EuroScopePlugIn::TAG_COLOR_ASSUMED; @@ -174,12 +239,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForTagItem200) { - const std::string sources[] = { - std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - const std::string expectedShorthand[] = {"USER", "RES ", "VAA ", "AUTO"}; + const auto sources = AllSources(); + const std::array expectedShorthand = {"USER", "RES ", "VAA ", "AUTO"}; for (size_t i = 0; i < std::size(sources); ++i) { this->ExpectTagItem200Shorthand(sources[i], expectedShorthand[i]); @@ -195,11 +256,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, TagItem110UsesSourceColours) { - const std::string sources[] = { - std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + const auto sources = AllSources(); for (const auto& source : sources) { this->ExpectTagItem110ColourForSource(source); @@ -208,11 +265,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, TagItem200UsesSourceColours) { - const std::string sources[] = { - std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + const auto sources = AllSources(); for (const auto& source : sources) { this->ExpectTagItem200ColourForSource(source); @@ -236,15 +289,7 @@ namespace UKControllerPluginTest { {"stand_id", 1}, }}; - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); this->handler.ProcessPushEvent(message); ASSERT_EQ(1, this->handler.GetAssignedStandForCallsign("BAW123")); @@ -477,15 +522,7 @@ namespace UKControllerPluginTest { }); assignments.push_back(nlohmann::json::object()); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -505,15 +542,7 @@ namespace UKControllerPluginTest { {"stand_id", 2}, }); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -534,15 +563,7 @@ namespace UKControllerPluginTest { {"stand_id", 2}, }); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -562,15 +583,7 @@ namespace UKControllerPluginTest { {"callsign", "VIR245"}, }); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -591,15 +604,7 @@ namespace UKControllerPluginTest { {"stand_id", "2"}, }); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -620,15 +625,7 @@ namespace UKControllerPluginTest { {"stand_id", -55}, }); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); - - EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "1L")).Times(1); - - auto expectedMessage = std::make_shared("BAW123", "EGKK", "1L"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); + auto pluginReturnedFp = MakeSyncFlightplanForBaw123Stand1(); EXPECT_CALL(this->api, GetAssignedStands()).Times(1).WillOnce(Return(assignments)); @@ -681,19 +678,7 @@ namespace UKControllerPluginTest { menuItemStandNone.fixedPosition = true; // Tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, true); RECT expectedArea = {0, 0, 400, 600}; EXPECT_CALL(this->plugin, TriggerPopupList(RectEq(expectedArea), "Assign Stand", 2)).Times(1); @@ -736,22 +721,9 @@ namespace UKControllerPluginTest { menuItemStandNone.fixedPosition = true; // Not tracked by anyone - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 8); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGLL")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(8)); - RECT expectedArea = {0, 0, 400, 600}; EXPECT_CALL(this->plugin, TriggerPopupList(RectEq(expectedArea), "Assign Stand", 2)).Times(1); @@ -767,19 +739,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntTriggerTheSelectionMenuIfFlightplanTrackedBySomeoneElse) { // Not tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, false); RECT expectedArea = {0, 0, 400, 600}; EXPECT_CALL(this->plugin, TriggerPopupList(RectEq(expectedArea), "Assign Stand", 2)).Times(0); @@ -792,19 +752,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntTriggerTheSelectionMenuIfNotVatsimRecognisedController) { // Not tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false, false); RECT expectedArea = {0, 0, 400, 600}; EXPECT_CALL(this->plugin, TriggerPopupList(RectEq(expectedArea), "Assign Stand", 2)).Times(0); @@ -817,19 +765,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItTriggersTheStandEditBoxWithDepartureAirportIfWithinLimit) { // Tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, true); RECT expectedArea = {0, 0, 80, 25}; EXPECT_CALL(this->plugin, ShowTextEditPopup(RectEq(expectedArea), 1, "")).Times(1); @@ -841,22 +777,9 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItTriggersTheStandEditBoxWithArrivalAirportIfNotCloseToDeparture) { // Not tracked by anyone - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 8); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGLL")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(8)); - RECT expectedArea = {0, 0, 80, 25}; EXPECT_CALL(this->plugin, ShowTextEditPopup(RectEq(expectedArea), 1, "")).Times(1); @@ -867,19 +790,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntTriggerTheEditBoxIfFlightplanTrackedBySomeoneElse) { // Not tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, false); EXPECT_CALL(this->plugin, ShowTextEditPopup(_, _, _)).Times(0); @@ -890,19 +801,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntTriggerTheEditBoxIfNotVatsimRecognisedController) { // Not tracked by user - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, false, false); EXPECT_CALL(this->plugin, ShowTextEditPopup(_, _, _)).Times(0); @@ -915,22 +814,9 @@ namespace UKControllerPluginTest { this->handler.SetAssignedStand("BAW123", 1); // Not tracked by anyone - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 8); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGLL")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(8)); - RECT expectedArea = {0, 0, 80, 25}; EXPECT_CALL(this->plugin, ShowTextEditPopup(RectEq(expectedArea), 1, "1L")).Times(1); @@ -940,32 +826,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntMakeAStandAssignmentRequestIfFlightplanTrackedBySomeoneElse) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(true, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(true, false); EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", _)).Times(0); @@ -976,32 +841,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntMakeAStandAssignmentRequestIfNotVatsimRecognisedController) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(true, false); EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", _)).Times(0); @@ -1015,16 +859,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", 2)).Times(0); @@ -1035,32 +870,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItMakesAStandAssignmentRequestWhenStandSelected) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1078,32 +892,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, StandAssignmentsAreCaseInsensitive) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1121,32 +914,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItHandlesApiExceptionOnStandAssignment) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1164,32 +936,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntAssignStandFromTheWrongAirfield) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", _)).Times(0); @@ -1202,32 +953,11 @@ namespace UKControllerPluginTest { this->handler.SetAssignedStand("BAW123", 2); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1247,32 +977,11 @@ namespace UKControllerPluginTest { this->handler.SetAssignedStand("BAW123", 2); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1280,44 +989,23 @@ namespace UKControllerPluginTest { EXPECT_CALL(*pluginReturnedFp, AnnotateFlightStrip(3, "")).Times(1); - auto expectedMessage = std::make_shared("BAW123"); - EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); - - this->handler.StandSelected(1, "", {}); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); - } - - TEST_F(StandEventHandlerTest, ItHandlesApiExceptionsInAssignmentDeletion) - { - this->handler.SetAssignedStand("BAW123", 2); - - // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); + auto expectedMessage = std::make_shared("BAW123"); + EXPECT_CALL(this->mockIntegration, SendEvent(MatchMessageInterface(expectedMessage))).Times(1); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); + this->handler.StandSelected(1, "", {}); + EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + } - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); + TEST_F(StandEventHandlerTest, ItHandlesApiExceptionsInAssignmentDeletion) + { + this->handler.SetAssignedStand("BAW123", 2); - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); + // Trigger the menu first to set the last airport + SetupFlightplan(false, false); - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); + this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")) .Times(1) @@ -1335,16 +1023,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(0); @@ -1355,32 +1034,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntMakeDeletionRequestIfNoStandAssigned) { // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft(_)).Times(0); @@ -1393,32 +1051,11 @@ namespace UKControllerPluginTest { this->handler.SetAssignedStand("BAW123", 2); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(true, false); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft(_)).Times(0); @@ -1431,32 +1068,11 @@ namespace UKControllerPluginTest { this->handler.SetAssignedStand("BAW123", 2); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(4)); + SetupFlightplan(false, false, false); this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft(_)).Times(0); @@ -1522,16 +1138,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1551,16 +1158,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1589,16 +1187,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1626,10 +1215,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_TRUE(successCalled); EXPECT_TRUE(failureMessages.empty()); @@ -1646,10 +1232,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_TRUE(successCalled); EXPECT_TRUE(failureMessages.empty()); @@ -1665,10 +1248,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1684,10 +1264,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1700,16 +1277,7 @@ namespace UKControllerPluginTest { ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + auto pluginReturnedFp = MakeSelectedFlightplan(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(pluginReturnedFp)); @@ -1729,10 +1297,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_TRUE(successCalled); EXPECT_TRUE(failureMessages.empty()); @@ -1752,10 +1317,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1773,10 +1335,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1794,10 +1353,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1815,10 +1371,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1836,10 +1389,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1861,10 +1411,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1882,10 +1429,7 @@ namespace UKControllerPluginTest { bool successCalled = false; std::vector failureMessages; - this->handler.ProcessAction( - message, - [&successCalled]() { successCalled = true; }, - [&failureMessages](std::vector messages) { failureMessages = std::move(messages); }); + CallProcessAction(message, successCalled, failureMessages); EXPECT_FALSE(successCalled); EXPECT_FALSE(failureMessages.empty()); @@ -1902,22 +1446,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -1977,22 +1508,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2051,22 +1569,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2126,22 +1631,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2201,22 +1693,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2276,22 +1755,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2331,22 +1797,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 0.0); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(0.0)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2394,22 +1847,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2457,22 +1897,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2523,22 +1950,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2588,22 +2002,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2654,22 +2055,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2720,22 +2108,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2786,22 +2161,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = @@ -2841,22 +2203,9 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport - ON_CALL(this->flightplan, IsTracked()).WillByDefault(Return(false)); - - ON_CALL(this->flightplan, IsTrackedByUser()).WillByDefault(Return(false)); - - ON_CALL(this->plugin, GetUserControllerObject()).WillByDefault(Return(this->mockController)); - - ON_CALL(*this->mockController, IsVatsimRecognisedController()).WillByDefault(Return(true)); - - ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(this->flightplan, GetOrigin()).WillByDefault(Return("EGKK")); - + SetupFlightplan(false, false, true, 1); ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - ON_CALL(this->flightplan, GetDistanceFromOrigin()).WillByDefault(Return(1)); - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); std::shared_ptr> pluginReturnedFp = From 6ff5c1762fab79f5c2a6b612ec6de167d0011db0 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 22:26:22 +0000 Subject: [PATCH 07/59] feat: Add StandEventHandlerConfig to StandEventHandlerTest for enhanced configuration handling --- test/plugin/stands/StandEventHandlerTest.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 6d261c38f..22cbe2449 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -31,6 +31,7 @@ using UKControllerPlugin::Stands::Stand; using UKControllerPlugin::Stands::StandAssignedMessage; using UKControllerPlugin::Stands::StandAssignmentSource; using UKControllerPlugin::Stands::StandColourConfiguration; +using UKControllerPlugin::Stands::StandEventHandlerConfig; using UKControllerPlugin::Stands::StandEventHandler; using UKControllerPlugin::Stands::StandUnassignedMessage; using UKControllerPlugin::Tag::TagData; From 2ace07d320b1573c0297096a00ec6f7ecd9a928f Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 22:28:53 +0000 Subject: [PATCH 08/59] refactor: Simplify StandEventHandlerTest by consolidating JSON object creation --- test/plugin/stands/StandEventHandlerTest.cpp | 343 ++++++++----------- 1 file changed, 152 insertions(+), 191 deletions(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 22cbe2449..a8e04338c 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -31,8 +31,8 @@ using UKControllerPlugin::Stands::Stand; using UKControllerPlugin::Stands::StandAssignedMessage; using UKControllerPlugin::Stands::StandAssignmentSource; using UKControllerPlugin::Stands::StandColourConfiguration; -using UKControllerPlugin::Stands::StandEventHandlerConfig; using UKControllerPlugin::Stands::StandEventHandler; +using UKControllerPlugin::Stands::StandEventHandlerConfig; using UKControllerPlugin::Stands::StandUnassignedMessage; using UKControllerPlugin::Tag::TagData; using UKControllerPluginTest::Api::MockApiInterface; @@ -52,12 +52,10 @@ namespace UKControllerPluginTest { public: StandEventHandlerTest() : controller(2, "LON_S_CTR", 129.420, std::vector{"EGKK"}, true, false, true), - userCallsign( - std::make_shared( - "LON_S_CTR", "Test", controller, true)), - notUserCallsign( - std::make_shared( - "LON_S_CTR", "Test", controller, false)), + userCallsign(std::make_shared( + "LON_S_CTR", "Test", controller, true)), + notUserCallsign(std::make_shared( + "LON_S_CTR", "Test", controller, false)), airfieldOwnership( std::make_shared()), userSetting(mockUserSettingProvider), @@ -1208,9 +1206,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItUnassignsStandFromIntegrationMessage) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(1); @@ -1225,9 +1222,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftFromMessageIfNothingToDo) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(0); @@ -1243,9 +1239,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfBadCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", 123}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", 123}}}}); bool successCalled = false; std::vector failureMessages; @@ -1259,9 +1254,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfNoCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", nlohmann::json::object()}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", nlohmann::json::object()}}); bool successCalled = false; std::vector failureMessages; @@ -1289,12 +1283,11 @@ namespace UKControllerPluginTest { EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", 2)).Times(1); - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1309,12 +1302,11 @@ namespace UKControllerPluginTest { { ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(nullptr)); - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1327,12 +1319,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignMissing) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1345,12 +1336,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignNotString) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1363,12 +1353,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldMissing) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1381,12 +1370,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldNotString) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}}}); bool successCalled = false; std::vector failureMessages; @@ -1399,16 +1387,15 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandMissing) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", - { - {"callsign", "BAW123"}, - {"airfield", "EGKK"}, - }}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", + { + {"callsign", "BAW123"}, + {"airfield", "EGKK"}, + }}}); bool successCalled = false; std::vector failureMessages; @@ -1421,12 +1408,11 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandNotString) { - auto message = InboundMessage::FromJson( - nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}}}); + auto message = InboundMessage::FromJson(nlohmann::json{ + {"type", "assign_stand"}, + {"version", 1}, + {"id", "foo"}, + {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}}}); bool successCalled = false; std::vector failureMessages; @@ -1441,9 +1427,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1482,14 +1467,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -1503,9 +1487,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1544,14 +1527,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnForbidden(); this->handler.StandSelected(1, "AUTO", {}); @@ -1564,9 +1546,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1605,14 +1586,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -1626,9 +1606,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1667,14 +1646,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -1688,9 +1666,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1729,14 +1706,13 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -1750,9 +1726,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1792,9 +1767,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1842,9 +1816,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); // Trigger the menu first to set the last airport @@ -1892,9 +1865,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -1925,13 +1897,12 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -1945,9 +1916,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -1978,13 +1948,12 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnServerError(); this->handler.StandSelected(1, "AUTO", {}); @@ -1997,9 +1966,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2030,13 +1998,12 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -2050,9 +2017,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2083,13 +2049,12 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -2103,9 +2068,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2136,13 +2100,12 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody( - nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}}) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -2156,9 +2119,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport @@ -2198,9 +2160,8 @@ namespace UKControllerPluginTest { { // Make "us" the delivery controller std::vector> provisions; - provisions.push_back( - std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); + provisions.push_back(std::make_shared( + UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); // Trigger the menu first to set the last airport From 2d47b3480bbd5df5e25ace7f111164c4b9598906 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 22:36:39 +0000 Subject: [PATCH 09/59] Test fixes for clang-format --- test/plugin/stands/StandEventHandlerTest.cpp | 272 +++++++------------ 1 file changed, 91 insertions(+), 181 deletions(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index a8e04338c..a951b0c7d 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -50,12 +50,18 @@ namespace UKControllerPluginTest { class StandEventHandlerTest : public ApiTestCase { public: + [[nodiscard]] static auto + MakeActiveCallsign(const UKControllerPlugin::Controller::ControllerPosition& controller, bool isUser) + -> std::shared_ptr + { + return std::make_shared( + "LON_S_CTR", "Test", controller, isUser); + } + StandEventHandlerTest() : controller(2, "LON_S_CTR", 129.420, std::vector{"EGKK"}, true, false, true), - userCallsign(std::make_shared( - "LON_S_CTR", "Test", controller, true)), - notUserCallsign(std::make_shared( - "LON_S_CTR", "Test", controller, false)), + userCallsign(MakeActiveCallsign(controller, true)), + notUserCallsign(MakeActiveCallsign(controller, false)), airfieldOwnership( std::make_shared()), userSetting(mockUserSettingProvider), @@ -186,6 +192,45 @@ namespace UKControllerPluginTest { std::string(StandAssignmentSource::SOURCE_SYSTEM)}; } + [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) + { + return InboundMessage::FromJson( + nlohmann::json{{"type", type}, {"version", 1}, {"id", "foo"}, {"data", data}}); + } + + void SetProviderForAirfield( + const std::string& airfield, + UKControllerPlugin::Ownership::ServiceType serviceType = + UKControllerPlugin::Ownership::ServiceType::Delivery) + { + std::vector> provisions; + provisions.push_back( + std::make_shared(serviceType, userCallsign)); + airfieldOwnership->SetProvidersForAirfield(airfield, provisions); + } + + [[nodiscard]] static auto DepartureStandRequestBody() -> nlohmann::json + { + return nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"assignment_type", "departure"}, + {"latitude", 123}, + {"longitude", 456}, + }; + } + + [[nodiscard]] static auto ArrivalStandRequestBody() -> nlohmann::json + { + return nlohmann::json{ + {"callsign", "BAW123"}, + {"departure_airfield", "EGKK"}, + {"arrival_airfield", "EGGW"}, + {"assignment_type", "arrival"}, + {"aircraft_type", "B738"}, + }; + } + double fontSize = 24.1; COLORREF tagColour = RGB(255, 255, 255); int euroscopeColourCode = EuroScopePlugIn::TAG_COLOR_ASSUMED; @@ -1206,8 +1251,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItUnassignsStandFromIntegrationMessage) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = MakeInboundMessage("unassign_stand", {{"callsign", "BAW123"}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(1); @@ -1222,8 +1266,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftFromMessageIfNothingToDo) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", "BAW123"}}}}); + auto message = MakeInboundMessage("unassign_stand", {{"callsign", "BAW123"}}); EXPECT_CALL(this->api, DeleteStandAssignmentForAircraft("BAW123")).Times(0); @@ -1239,8 +1282,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfBadCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", {{"callsign", 123}}}}); + auto message = MakeInboundMessage("unassign_stand", {{"callsign", 123}}); bool successCalled = false; std::vector failureMessages; @@ -1254,8 +1296,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItDoesntUnassignStandFromAircraftIfNoCallsign) { this->handler.SetAssignedStand("BAW123", 3); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "unassign_stand"}, {"version", 1}, {"id", "foo"}, {"data", nlohmann::json::object()}}); + auto message = MakeInboundMessage("unassign_stand", nlohmann::json::object()); bool successCalled = false; std::vector failureMessages; @@ -1283,11 +1324,8 @@ namespace UKControllerPluginTest { EXPECT_CALL(this->api, AssignStandToAircraft("BAW123", 2)).Times(1); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = + MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1302,11 +1340,8 @@ namespace UKControllerPluginTest { { ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(nullptr)); - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = + MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1319,11 +1354,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = MakeInboundMessage("assign_stand", {{"airfield", "EGKK"}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1336,11 +1367,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}}}); + auto message = + MakeInboundMessage("assign_stand", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1353,11 +1381,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"stand", "55"}}}}); + auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1370,11 +1394,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}}}); + auto message = + MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}); bool successCalled = false; std::vector failureMessages; @@ -1387,15 +1408,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandMissing) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", - { - {"callsign", "BAW123"}, - {"airfield", "EGKK"}, - }}}); + auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}}); bool successCalled = false; std::vector failureMessages; @@ -1408,11 +1421,8 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandNotString) { - auto message = InboundMessage::FromJson(nlohmann::json{ - {"type", "assign_stand"}, - {"version", 1}, - {"id", "foo"}, - {"data", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}}}); + auto message = + MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}); bool successCalled = false; std::vector failureMessages; @@ -1426,10 +1436,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItRequestsADepartureStandFromApi) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1467,13 +1474,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(DepartureStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -1486,10 +1487,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesNonCreatedCode) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1527,13 +1525,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(DepartureStandRequestBody()) .WillReturnForbidden(); this->handler.StandSelected(1, "AUTO", {}); @@ -1545,10 +1537,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUnknownStandId) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1586,13 +1575,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(DepartureStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -1605,10 +1588,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesStandIdNotInteger) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1646,13 +1626,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(DepartureStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -1665,10 +1639,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesNoStandIdInJson) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1706,13 +1677,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"assignment_type", "departure"}, - {"latitude", 123}, - {"longitude", 456}, - }) + .WithBody(DepartureStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -1725,10 +1690,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesNotFoundRadarTarget) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1766,10 +1728,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUnknownDistanceFromOrigin) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 0.0); @@ -1815,10 +1774,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUserNotProvidingDelivery) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGKK", provisions); + SetProviderForAirfield("EGKK", UKControllerPlugin::Ownership::ServiceType::Ground); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1864,10 +1820,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItRequestsAnArrivalStandFromApi) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1897,12 +1850,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(ArrivalStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 3}}); @@ -1915,10 +1863,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesInvalidStatusCodeInResponse) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1948,12 +1893,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(ArrivalStandRequestBody()) .WillReturnServerError(); this->handler.StandSelected(1, "AUTO", {}); @@ -1965,10 +1905,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesInvalidStandIdInJson) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -1998,12 +1935,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(ArrivalStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); @@ -2016,10 +1948,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesNonIntegerStandIdInJson) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -2049,12 +1978,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(ArrivalStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); @@ -2067,10 +1991,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesNoStandIdInJson) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -2100,12 +2021,7 @@ namespace UKControllerPluginTest { this->ExpectApiRequest() ->Post() .To("stand/assignment/requestauto") - .WithBody(nlohmann::json{ - {"callsign", "BAW123"}, - {"departure_airfield", "EGKK"}, - {"arrival_airfield", "EGGW"}, - {"assignment_type", "arrival"}, - {"aircraft_type", "B738"}}) + .WithBody(ArrivalStandRequestBody()) .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); @@ -2118,10 +2034,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesZeroDistanceToOrigin) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Delivery, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW"); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); @@ -2159,10 +2072,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesUserNotProvidingDelivery) { // Make "us" the delivery controller - std::vector> provisions; - provisions.push_back(std::make_shared( - UKControllerPlugin::Ownership::ServiceType::Ground, userCallsign)); - airfieldOwnership->SetProvidersForAirfield("EGGW", provisions); + SetProviderForAirfield("EGGW", UKControllerPlugin::Ownership::ServiceType::Ground); // Trigger the menu first to set the last airport SetupFlightplan(false, false, true, 1); From 1c2df0b5602babe7c99a021cba2b8ae6041f035c Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Mon, 16 Mar 2026 22:59:33 +0000 Subject: [PATCH 10/59] dev: Testing a potential fix --- .../ecfmp/AircraftFlowMeasureMapTest.cpp | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp b/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp index cfab2c51c..e67a47bd9 100644 --- a/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp +++ b/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp @@ -78,21 +78,27 @@ namespace UKControllerPluginTest::ECFMP { map.OnEvent(::ECFMP::Plugin::FlowMeasureActivatedEvent{mockFlowMeasure1}); map.OnEvent(::ECFMP::Plugin::FlowMeasureActivatedEvent{mockFlowMeasure2}); + const auto& baw123FlowMeasures = map.GetFlowMeasuresForCallsign("BAW123"); + const auto& baw456FlowMeasures = map.GetFlowMeasuresForCallsign("BAW456"); + // Check that flightplan 1 has both measures, but flightplan 2 has only the second - EXPECT_EQ(2, map.GetFlowMeasuresForCallsign("BAW123").size()); - EXPECT_EQ(mockFlowMeasure1, *map.GetFlowMeasuresForCallsign("BAW123").begin()); - EXPECT_EQ(mockFlowMeasure2, *(++map.GetFlowMeasuresForCallsign("BAW123").begin())); - EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW456").size()); - EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW456").begin()); + EXPECT_EQ(2, baw123FlowMeasures.size()); + EXPECT_TRUE(baw123FlowMeasures.contains(mockFlowMeasure1)); + EXPECT_TRUE(baw123FlowMeasures.contains(mockFlowMeasure2)); + EXPECT_EQ(1, baw456FlowMeasures.size()); + EXPECT_TRUE(baw456FlowMeasures.contains(mockFlowMeasure2)); // Withdraw the first measure map.OnEvent(::ECFMP::Plugin::FlowMeasureWithdrawnEvent{mockFlowMeasure1}); + const auto& baw123FlowMeasuresAfterWithdrawal = map.GetFlowMeasuresForCallsign("BAW123"); + const auto& baw456FlowMeasuresAfterWithdrawal = map.GetFlowMeasuresForCallsign("BAW456"); + // Check that flightplan 1 now has just the second measure, but flightplan 2 has only the second - EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW123").size()); - EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW123").begin()); - EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW456").size()); - EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW456").begin()); + EXPECT_EQ(1, baw123FlowMeasuresAfterWithdrawal.size()); + EXPECT_TRUE(baw123FlowMeasuresAfterWithdrawal.contains(mockFlowMeasure2)); + EXPECT_EQ(1, baw456FlowMeasuresAfterWithdrawal.size()); + EXPECT_TRUE(baw456FlowMeasuresAfterWithdrawal.contains(mockFlowMeasure2)); } TEST_F(AircraftFlowMeasureMapTest, FlowMeasuresWithdrawingRemovesAllFromActiveAircraftFlowMeasures) From 9ae9b0d742e52e26a46801fe0b647bee4c71b805 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Tue, 17 Mar 2026 17:26:25 +0000 Subject: [PATCH 11/59] added the menu i forgot earlier needs rework a little Push for CI build due to issues with the DevContainer --- src/plugin/CMakeLists.txt | 2 + src/plugin/bootstrap/PersistenceContainer.h | 6 ++ src/plugin/radarscreen/RadarScreenFactory.cpp | 2 + src/plugin/stands/StandAssignmentSource.h | 1 - .../StandColourConfigurationMenuItem.cpp | 70 +++++++++++++++++++ .../stands/StandColourConfigurationMenuItem.h | 33 +++++++++ src/plugin/stands/StandModule.cpp | 36 +++++++++- src/plugin/stands/StandModule.h | 12 +++- 8 files changed, 157 insertions(+), 5 deletions(-) create mode 100644 src/plugin/stands/StandColourConfigurationMenuItem.cpp create mode 100644 src/plugin/stands/StandColourConfigurationMenuItem.h diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt index dd818321f..cfa931f2e 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/plugin/CMakeLists.txt @@ -909,6 +909,8 @@ set(src__stands "stands/StandAssignmentSource.h" "stands/StandColourConfiguration.cpp" "stands/StandColourConfiguration.h" + "stands/StandColourConfigurationMenuItem.cpp" + "stands/StandColourConfigurationMenuItem.h" "stands/StandEventHandler.cpp" "stands/StandEventHandler.h" "stands/StandModule.cpp" diff --git a/src/plugin/bootstrap/PersistenceContainer.h b/src/plugin/bootstrap/PersistenceContainer.h index 10e8e06f1..45195ca29 100644 --- a/src/plugin/bootstrap/PersistenceContainer.h +++ b/src/plugin/bootstrap/PersistenceContainer.h @@ -138,6 +138,10 @@ namespace UKControllerPlugin { class SquawkEventHandler; class SquawkGenerator; } // namespace Squawk + namespace Stands { + class StandColourConfiguration; + class StandColourConfigurationMenuItem; + } // namespace Stands namespace Tag { class TagItemCollection; } // namespace Tag @@ -236,6 +240,8 @@ namespace UKControllerPlugin::Bootstrap { std::unique_ptr holdDisplayFactory; std::shared_ptr notificationsMenuItem; std::shared_ptr departureReleaseHandler; + std::shared_ptr standColourConfiguration; + std::shared_ptr standColourConfigurationMenuItem; // Collections that are spawned multiple times. std::vector> allRadarRenders; diff --git a/src/plugin/radarscreen/RadarScreenFactory.cpp b/src/plugin/radarscreen/RadarScreenFactory.cpp index 743f675c4..c43593948 100644 --- a/src/plugin/radarscreen/RadarScreenFactory.cpp +++ b/src/plugin/radarscreen/RadarScreenFactory.cpp @@ -25,6 +25,7 @@ #include "releases/ReleaseModule.h" #include "sectorfile/SectorFileBootstrap.h" #include "srd/SrdModule.h" +#include "stands/StandModule.h" #include "wake/WakeModule.h" using UKControllerPlugin::Api::BootstrapConfigurationMenuItem; @@ -109,6 +110,7 @@ namespace UKControllerPlugin::RadarScreen { configurableDisplays, renderers, userSettingHandlers, commandHandlers, this->persistence); Srd::BootstrapRadarScreen(configurableDisplays); + Stands::BootstrapRadarScreen(this->persistence, configurableDisplays); Notifications::BootstrapRadarScreen(this->persistence, configurableDisplays); Releases::BootstrapRadarScreen(this->persistence, renderers); PrenoteModule::BootstrapRadarScreen(this->persistence, renderers); diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index ee7edf330..f48ad7aaa 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -8,7 +8,6 @@ namespace UKControllerPlugin::Stands { */ struct StandAssignmentSource { - // The ID of the assigned stand int standId; // The source of the assignment (user, reservation_allocator, vaa_allocator, system_auto) diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.cpp b/src/plugin/stands/StandColourConfigurationMenuItem.cpp new file mode 100644 index 000000000..ff97b58eb --- /dev/null +++ b/src/plugin/stands/StandColourConfigurationMenuItem.cpp @@ -0,0 +1,70 @@ +#include "StandColourConfigurationMenuItem.h" +#include "StandColourConfiguration.h" +#include "StandAssignmentSource.h" +#include "helper/HelperFunctions.h" +#include "plugin/PopupMenuItem.h" +#include +#include + +using UKControllerPlugin::Plugin::PopupMenuItem; +using UKControllerPlugin::HelperFunctions; + +namespace UKControllerPlugin::Stands { + + StandColourConfigurationMenuItem::StandColourConfigurationMenuItem( + std::shared_ptr colourConfiguration, int callbackFunctionId) + : colourConfiguration(std::move(colourConfiguration)), callbackFunctionId(callbackFunctionId) + { + } + + void StandColourConfigurationMenuItem::Configure(int functionId, std::string subject, RECT area) + { + if (!this->colourConfiguration) { + LogWarning("StandColourConfigurationMenuItem: Colour configuration is null"); + return; + } + + // Define the assignment sources to configure + std::array sources = { + std::string(StandAssignmentSource::SOURCE_USER), + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), + std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + + // Allow user to pick colours for each source + CHOOSECOLOR chooseColor{}; + COLORREF customColours[16] = {}; + chooseColor.lStructSize = sizeof(CHOOSECOLOR); + chooseColor.hwndOwner = GetActiveWindow(); + chooseColor.lpCustColors = customColours; + chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN; + + for (size_t i = 0; i < sources.size(); ++i) { + chooseColor.rgbResult = this->colourConfiguration->GetColourForSource(sources[i]); + + if (ChooseColor(&chooseColor) == TRUE) { + this->colourConfiguration->SetColourForSource(sources[i], chooseColor.rgbResult); + LogInfo("Stand colour updated for source: " + sources[i]); + } else { + // User cancelled, stop the colour selection process + break; + } + } + + // Save the new colours to user settings + this->colourConfiguration->SaveToUserSettings(); + LogInfo("Stand colours saved to user settings"); + } + + auto StandColourConfigurationMenuItem::GetConfigurationMenuItem() const -> PopupMenuItem + { + PopupMenuItem returnVal; + returnVal.firstValue = this->itemDescription; + returnVal.secondValue = ""; + returnVal.callbackFunctionId = this->callbackFunctionId; + returnVal.checked = 2; // No checkbox + returnVal.disabled = false; + returnVal.fixedPosition = false; + return returnVal; + } +} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.h b/src/plugin/stands/StandColourConfigurationMenuItem.h new file mode 100644 index 000000000..bd293cb19 --- /dev/null +++ b/src/plugin/stands/StandColourConfigurationMenuItem.h @@ -0,0 +1,33 @@ +#pragma once +#include "radarscreen/ConfigurableDisplayInterface.h" +#include "plugin/PopupMenuItem.h" + +namespace UKControllerPlugin::Stands { + class StandColourConfiguration; + + /* + Menu item for configuring stand assignment source colours. + Allows users to customize the colours used for different stand assignment sources + (User, Reservation Allocator, VAA, System) without requiring a plugin reload. + */ + class StandColourConfigurationMenuItem : public UKControllerPlugin::RadarScreen::ConfigurableDisplayInterface + { + public: + StandColourConfigurationMenuItem( + std::shared_ptr colourConfiguration, int callbackFunctionId); + + // Inherited via ConfigurableDisplayInterface + void Configure(int functionId, std::string subject, RECT area) override; + [[nodiscard]] auto GetConfigurationMenuItem() const -> UKControllerPlugin::Plugin::PopupMenuItem override; + + private: + // The colour configuration to customize + std::shared_ptr colourConfiguration; + + // The item description + const std::string itemDescription = "Configure Stand Colours"; + + // The callback function ID + const int callbackFunctionId; + }; +} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 774069f35..7df45aa0a 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -3,7 +3,9 @@ #include "StandModule.h" #include "StandSerializer.h" #include "StandColourConfiguration.h" +#include "StandColourConfigurationMenuItem.h" #include "bootstrap/PersistenceContainer.h" +#include "radarscreen/ConfigurableDisplayCollection.h" #include "dependency/DependencyLoaderInterface.h" #include "euroscope/CallbackFunction.h" #include "flightplan/FlightPlanEventHandlerCollection.h" @@ -36,9 +38,10 @@ namespace UKControllerPlugin::Stands { // Load stand colour configuration from EuroScope user settings // If pluginUserSettingHandler is not available (e.g., in tests), creates default-only config - auto colourConfiguration = container.pluginUserSettingHandler - ? std::make_shared(*container.pluginUserSettingHandler) - : std::make_shared(); + container.standColourConfiguration = container.pluginUserSettingHandler + ? std::make_shared(*container.pluginUserSettingHandler) + : std::make_shared(); + auto colourConfiguration = container.standColourConfiguration; // Create the event handler auto standSelectedCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); @@ -88,6 +91,20 @@ namespace UKControllerPlugin::Stands { container.pluginFunctionHandlers->RegisterFunctionCall(openStandAssignmentEditBox); + // Create the colour configuration menu item and register its callback + const int colourConfigurationCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); + auto colourConfigurationMenuItem = std::make_shared( + colourConfiguration, colourConfigurationCallbackId); + container.standColourConfigurationMenuItem = colourConfigurationMenuItem; + + const UKControllerPlugin::Euroscope::CallbackFunction colourConfigCallback( + colourConfigurationCallbackId, + "Stand Colour Configuration", + [colourConfigurationMenuItem](int functionId, std::string subject, RECT screenObjectArea) { + colourConfigurationMenuItem->Configure(functionId, std::move(subject), screenObjectArea); + }); + container.pluginFunctionHandlers->RegisterFunctionCall(colourConfigCallback); + // Assign to handlers container.flightplanHandler->RegisterHandler(eventHandler); container.tagHandler->RegisterTagItem(StandEventHandler::assignedStandTagItemId, eventHandler); @@ -97,6 +114,19 @@ namespace UKControllerPlugin::Stands { container.integrationModuleContainer->inboundMessageHandler->AddProcessor(eventHandler); } + void BootstrapRadarScreen( + const Bootstrap::PersistenceContainer& container, + UKControllerPlugin::RadarScreen::ConfigurableDisplayCollection& configurableDisplays) + { + if (!container.standColourConfigurationMenuItem) { + LogWarning("StandModule::BootstrapRadarScreen: Stand colour configuration menu item not available"); + return; + } + + // Register the colour configuration menu item with the configurableDisplays collection + configurableDisplays.RegisterDisplay(container.standColourConfigurationMenuItem); + } + auto GetDependencyKey() -> std::string { return "DEPENDENCY_STANDS"; diff --git a/src/plugin/stands/StandModule.h b/src/plugin/stands/StandModule.h index 0a7d6cff8..72d836678 100644 --- a/src/plugin/stands/StandModule.h +++ b/src/plugin/stands/StandModule.h @@ -7,15 +7,25 @@ namespace UKControllerPlugin { namespace Dependency { class DependencyLoaderInterface; } // namespace Dependency + namespace RadarScreen { + class ConfigurableDisplayCollection; + } // namespace RadarScreen } // namespace UKControllerPlugin namespace UKControllerPlugin::Stands { /* - Bootstraps everything to do with stand assignment + Bootstraps everything to do with stand assignment at the plugin level */ void BootstrapPlugin( UKControllerPlugin::Bootstrap::PersistenceContainer& container, UKControllerPlugin::Dependency::DependencyLoaderInterface& dependencies); + /* + Bootstraps everything to do with stand assignment at the radar screen level + */ + void BootstrapRadarScreen( + const UKControllerPlugin::Bootstrap::PersistenceContainer& container, + UKControllerPlugin::RadarScreen::ConfigurableDisplayCollection& configurableDisplays); + [[nodiscard]] auto GetDependencyKey() -> std::string; } // namespace UKControllerPlugin::Stands From 7a35e4d129c46042b24a07aaf40e3de26f6f6799 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Tue, 17 Mar 2026 17:55:52 +0000 Subject: [PATCH 12/59] Fix Test and Color chooser titles --- .../StandColourConfigurationMenuItem.cpp | 42 ++++++++++++++++--- .../stands/StandColourConfigurationMenuItem.h | 8 ++++ src/plugin/stands/StandModule.cpp | 13 +++--- test/plugin/stands/StandModuleTest.cpp | 5 ++- 4 files changed, 56 insertions(+), 12 deletions(-) diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.cpp b/src/plugin/stands/StandColourConfigurationMenuItem.cpp index ff97b58eb..ee5078eaf 100644 --- a/src/plugin/stands/StandColourConfigurationMenuItem.cpp +++ b/src/plugin/stands/StandColourConfigurationMenuItem.cpp @@ -6,11 +6,29 @@ #include #include -using UKControllerPlugin::Plugin::PopupMenuItem; using UKControllerPlugin::HelperFunctions; +using UKControllerPlugin::Plugin::PopupMenuItem; namespace UKControllerPlugin::Stands { + namespace { + auto CALLBACK ChooseColorTitleHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> UINT_PTR + { + if (msg != WM_INITDIALOG) { + return 0; + } + + const auto* chooseColor = reinterpret_cast(lParam); + if (chooseColor == nullptr || chooseColor->lCustData == 0) { + return 0; + } + + const auto* title = reinterpret_cast(chooseColor->lCustData); + SetWindowTextA(hwnd, title); + return 1; + } + } // namespace + StandColourConfigurationMenuItem::StandColourConfigurationMenuItem( std::shared_ptr colourConfiguration, int callbackFunctionId) : colourConfiguration(std::move(colourConfiguration)), callbackFunctionId(callbackFunctionId) @@ -31,24 +49,38 @@ namespace UKControllerPlugin::Stands { std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + std::array sourceLabels = { + "User", + "Reservation Allocator", + "VAA Allocator", + "System"}; + // Allow user to pick colours for each source CHOOSECOLOR chooseColor{}; - COLORREF customColours[16] = {}; chooseColor.lStructSize = sizeof(CHOOSECOLOR); chooseColor.hwndOwner = GetActiveWindow(); - chooseColor.lpCustColors = customColours; - chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN; + chooseColor.lpCustColors = this->customColours.data(); + chooseColor.lpfnHook = ChooseColorTitleHook; + chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK; - for (size_t i = 0; i < sources.size(); ++i) { + for (size_t offset = 0; offset < sources.size(); ++offset) { + const size_t i = (this->lastSelectedSourceIndex + offset) % sources.size(); chooseColor.rgbResult = this->colourConfiguration->GetColourForSource(sources[i]); + const auto dialogTitle = std::string("Stand Colour Configuration - ") + sourceLabels[i]; + chooseColor.lCustData = reinterpret_cast(dialogTitle.c_str()); if (ChooseColor(&chooseColor) == TRUE) { this->colourConfiguration->SetColourForSource(sources[i], chooseColor.rgbResult); LogInfo("Stand colour updated for source: " + sources[i]); } else { + this->lastSelectedSourceIndex = i; // User cancelled, stop the colour selection process break; } + + if (offset == sources.size() - 1) { + this->lastSelectedSourceIndex = 0; + } } // Save the new colours to user settings diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.h b/src/plugin/stands/StandColourConfigurationMenuItem.h index bd293cb19..822168114 100644 --- a/src/plugin/stands/StandColourConfigurationMenuItem.h +++ b/src/plugin/stands/StandColourConfigurationMenuItem.h @@ -1,6 +1,8 @@ #pragma once #include "radarscreen/ConfigurableDisplayInterface.h" #include "plugin/PopupMenuItem.h" +#include +#include namespace UKControllerPlugin::Stands { class StandColourConfiguration; @@ -29,5 +31,11 @@ namespace UKControllerPlugin::Stands { // The callback function ID const int callbackFunctionId; + + // The source index to start from next time user opens the configuration + size_t lastSelectedSourceIndex = 0; + + // Persistent custom colours for the Windows colour picker + std::array customColours{}; }; } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 7df45aa0a..735ec1cae 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -38,9 +38,12 @@ namespace UKControllerPlugin::Stands { // Load stand colour configuration from EuroScope user settings // If pluginUserSettingHandler is not available (e.g., in tests), creates default-only config - container.standColourConfiguration = container.pluginUserSettingHandler - ? std::make_shared(*container.pluginUserSettingHandler) - : std::make_shared(); + if (container.pluginUserSettingHandler) { + container.standColourConfiguration = + std::make_shared(*container.pluginUserSettingHandler); + } else { + container.standColourConfiguration = std::make_shared(); + } auto colourConfiguration = container.standColourConfiguration; // Create the event handler @@ -93,8 +96,8 @@ namespace UKControllerPlugin::Stands { // Create the colour configuration menu item and register its callback const int colourConfigurationCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); - auto colourConfigurationMenuItem = std::make_shared( - colourConfiguration, colourConfigurationCallbackId); + auto colourConfigurationMenuItem = + std::make_shared(colourConfiguration, colourConfigurationCallbackId); container.standColourConfigurationMenuItem = colourConfigurationMenuItem; const UKControllerPlugin::Euroscope::CallbackFunction colourConfigCallback( diff --git a/test/plugin/stands/StandModuleTest.cpp b/test/plugin/stands/StandModuleTest.cpp index d7becd003..e79d37aaf 100644 --- a/test/plugin/stands/StandModuleTest.cpp +++ b/test/plugin/stands/StandModuleTest.cpp @@ -92,15 +92,16 @@ namespace UKControllerPluginTest::Stands { { BootstrapPlugin(this->container, this->dependencyLoader); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasTagFunction(9007)); - EXPECT_EQ(1, this->container.pluginFunctionHandlers->CountCallbacks()); + EXPECT_EQ(2, this->container.pluginFunctionHandlers->CountCallbacks()); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasCallbackByDescription("Stand Selected")); + EXPECT_TRUE(this->container.pluginFunctionHandlers->HasCallbackByDescription("Stand Colour Configuration")); } TEST_F(StandModuleTest, ItRegistersTheStandAssignmentEditBoxFunction) { BootstrapPlugin(this->container, this->dependencyLoader); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasTagFunction(9008)); - EXPECT_EQ(1, this->container.pluginFunctionHandlers->CountCallbacks()); + EXPECT_EQ(2, this->container.pluginFunctionHandlers->CountCallbacks()); } TEST_F(StandModuleTest, ItRegistersForExternalMessages) From b4ed9af11b4f262bb1f2f30e4fc3d762f2bf17dd Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Tue, 17 Mar 2026 17:58:12 +0000 Subject: [PATCH 13/59] Formatting --- src/plugin/stands/StandColourConfigurationMenuItem.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.cpp b/src/plugin/stands/StandColourConfigurationMenuItem.cpp index ee5078eaf..a2b887a1c 100644 --- a/src/plugin/stands/StandColourConfigurationMenuItem.cpp +++ b/src/plugin/stands/StandColourConfigurationMenuItem.cpp @@ -49,11 +49,7 @@ namespace UKControllerPlugin::Stands { std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - std::array sourceLabels = { - "User", - "Reservation Allocator", - "VAA Allocator", - "System"}; + std::array sourceLabels = {"User", "Reservation Allocator", "VAA Allocator", "System"}; // Allow user to pick colours for each source CHOOSECOLOR chooseColor{}; From 7ed5e637d351533b242cb6b0e3706141ffbdd7d3 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Tue, 17 Mar 2026 18:52:53 +0000 Subject: [PATCH 14/59] Restrict color selector Restricted color Selector to just User and System Auto for now until functionality is worked in on API end --- src/plugin/stands/StandColourConfigurationMenuItem.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.cpp b/src/plugin/stands/StandColourConfigurationMenuItem.cpp index a2b887a1c..c33f58283 100644 --- a/src/plugin/stands/StandColourConfigurationMenuItem.cpp +++ b/src/plugin/stands/StandColourConfigurationMenuItem.cpp @@ -43,13 +43,11 @@ namespace UKControllerPlugin::Stands { } // Define the assignment sources to configure - std::array sources = { + std::array sources = { std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - std::array sourceLabels = {"User", "Reservation Allocator", "VAA Allocator", "System"}; + std::array sourceLabels = {"User", "System Auto"}; // Allow user to pick colours for each source CHOOSECOLOR chooseColor{}; From 14df7544638364f11929e542796cbc89455f0de9 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 11:34:31 +0000 Subject: [PATCH 15/59] Removal of UI and Save components leaving load for customisation --- src/plugin/CMakeLists.txt | 2 - src/plugin/bootstrap/PersistenceContainer.h | 6 -- src/plugin/radarscreen/RadarScreenFactory.cpp | 2 - .../stands/StandColourConfiguration.cpp | 87 +---------------- src/plugin/stands/StandColourConfiguration.h | 16 ---- .../StandColourConfigurationMenuItem.cpp | 96 ------------------- .../stands/StandColourConfigurationMenuItem.h | 41 -------- src/plugin/stands/StandEventHandler.cpp | 5 +- src/plugin/stands/StandModule.cpp | 39 +------- src/plugin/stands/StandModule.h | 10 -- test/plugin/stands/StandModuleTest.cpp | 5 +- 11 files changed, 7 insertions(+), 302 deletions(-) delete mode 100644 src/plugin/stands/StandColourConfigurationMenuItem.cpp delete mode 100644 src/plugin/stands/StandColourConfigurationMenuItem.h diff --git a/src/plugin/CMakeLists.txt b/src/plugin/CMakeLists.txt index cfa931f2e..dd818321f 100644 --- a/src/plugin/CMakeLists.txt +++ b/src/plugin/CMakeLists.txt @@ -909,8 +909,6 @@ set(src__stands "stands/StandAssignmentSource.h" "stands/StandColourConfiguration.cpp" "stands/StandColourConfiguration.h" - "stands/StandColourConfigurationMenuItem.cpp" - "stands/StandColourConfigurationMenuItem.h" "stands/StandEventHandler.cpp" "stands/StandEventHandler.h" "stands/StandModule.cpp" diff --git a/src/plugin/bootstrap/PersistenceContainer.h b/src/plugin/bootstrap/PersistenceContainer.h index 45195ca29..10e8e06f1 100644 --- a/src/plugin/bootstrap/PersistenceContainer.h +++ b/src/plugin/bootstrap/PersistenceContainer.h @@ -138,10 +138,6 @@ namespace UKControllerPlugin { class SquawkEventHandler; class SquawkGenerator; } // namespace Squawk - namespace Stands { - class StandColourConfiguration; - class StandColourConfigurationMenuItem; - } // namespace Stands namespace Tag { class TagItemCollection; } // namespace Tag @@ -240,8 +236,6 @@ namespace UKControllerPlugin::Bootstrap { std::unique_ptr holdDisplayFactory; std::shared_ptr notificationsMenuItem; std::shared_ptr departureReleaseHandler; - std::shared_ptr standColourConfiguration; - std::shared_ptr standColourConfigurationMenuItem; // Collections that are spawned multiple times. std::vector> allRadarRenders; diff --git a/src/plugin/radarscreen/RadarScreenFactory.cpp b/src/plugin/radarscreen/RadarScreenFactory.cpp index c43593948..743f675c4 100644 --- a/src/plugin/radarscreen/RadarScreenFactory.cpp +++ b/src/plugin/radarscreen/RadarScreenFactory.cpp @@ -25,7 +25,6 @@ #include "releases/ReleaseModule.h" #include "sectorfile/SectorFileBootstrap.h" #include "srd/SrdModule.h" -#include "stands/StandModule.h" #include "wake/WakeModule.h" using UKControllerPlugin::Api::BootstrapConfigurationMenuItem; @@ -110,7 +109,6 @@ namespace UKControllerPlugin::RadarScreen { configurableDisplays, renderers, userSettingHandlers, commandHandlers, this->persistence); Srd::BootstrapRadarScreen(configurableDisplays); - Stands::BootstrapRadarScreen(this->persistence, configurableDisplays); Notifications::BootstrapRadarScreen(this->persistence, configurableDisplays); Releases::BootstrapRadarScreen(this->persistence, renderers); PrenoteModule::BootstrapRadarScreen(this->persistence, renderers); diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index bbe258a66..d7b9ead4c 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,28 +2,23 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" -#include -#include -#include +#include namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& setting) : userSetting(&setting) { - // Initialize with default colours sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = DEFAULT_SYSTEM_COLOUR; - // Try to load from UserSettings LoadFromUserSettings(); } StandColourConfiguration::StandColourConfiguration() : userSetting(nullptr) { - // Initialize with default colours (no persistence without UserSetting) sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; @@ -46,28 +41,24 @@ namespace UKControllerPlugin::Stands { } try { - // Load user colour std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_USER); if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = this->userSetting->GetColourEntry(key, DEFAULT_USER_COLOUR); } - // Load reservation allocator colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = this->userSetting->GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); } - // Load VAA allocator colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = this->userSetting->GetColourEntry(key, DEFAULT_VAA_COLOUR); } - // Load system colour key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_SYSTEM); if (this->userSetting->HasEntry(key)) { sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = @@ -80,80 +71,4 @@ namespace UKControllerPlugin::Stands { } } - void StandColourConfiguration::SaveToUserSettings() - { - if (!this->userSetting) { - return; - } - - try { - for (const auto& [source, colour] : sourceColours) { - const std::string key = std::string(SETTING_PREFIX) + source; - this->userSetting->Save(key, "Stand assignment source colour for " + source, colour); - } - LogInfo("Saved stand assignment source colours to UserSettings"); - } catch (const std::exception& e) { - LogWarning("Failed to save stand colours to UserSettings: " + std::string(e.what())); - } - } - - void StandColourConfiguration::SetColourForSource(const std::string& source, COLORREF colour) - { - sourceColours[source] = colour; - // Immediately save to UserSettings - if (!this->userSetting) { - return; - } - - try { - const std::string key = std::string(SETTING_PREFIX) + source; - this->userSetting->Save(key, "Stand assignment source colour for " + source, colour); - } catch (const std::exception& e) { - LogWarning("Failed to save stand colour for '" + source + "': " + std::string(e.what())); - } - } - - auto StandColourConfiguration::HexToColorref(const std::string& hex) -> COLORREF - { - std::string colourStr = hex; - - // Remove '#' if present - if (!colourStr.empty() && colourStr[0] == '#') { - colourStr = colourStr.substr(1); - } - - // Validate hex string length - if (colourStr.length() != 6) { - throw std::invalid_argument("Hex colour must be 6 characters (without #)"); - } - - // Parse hex values - try { - // Windows COLORREF is BGR, not RGB, so we parse as RGB and convert - const uint32_t rgbValue = std::stoul(colourStr, nullptr, 16); - const auto r = static_cast((rgbValue >> 16) & 0xFF); - const auto g = static_cast((rgbValue >> 8) & 0xFF); - const auto b = static_cast(rgbValue & 0xFF); - - return RGB(r, g, b); - } catch (const std::invalid_argument& e) { - throw std::invalid_argument(std::string("Invalid hex colour format: ") + e.what()); - } catch (const std::out_of_range& e) { - throw std::invalid_argument(std::string("Hex colour value out of range: ") + e.what()); - } - } - - auto StandColourConfiguration::ColourrefToHex(COLORREF colour) -> std::string - { - // COLORREF is BGR format, convert to RGB for hex - const auto b = static_cast((colour >> 0) & 0xFF); - const auto g = static_cast((colour >> 8) & 0xFF); - const auto r = static_cast((colour >> 16) & 0xFF); - - return std::format( - "#{:02x}{:02x}{:02x}", - static_cast(r), - static_cast(g), - static_cast(b)); - } } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index e757037af..cbe9e1e17 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -30,23 +30,7 @@ namespace UKControllerPlugin::Stands { */ void LoadFromUserSettings(); - /* - Save colours to UserSettings. - */ - void SaveToUserSettings(); - - /* - Set a colour for a specific source (runtime change). - */ - void SetColourForSource(const std::string& source, COLORREF colour); - private: - // Converts a hex colour string (e.g. "#FF00FF") to a COLORREF - [[nodiscard]] static auto HexToColorref(const std::string& hex) -> COLORREF; - - // Converts COLORREF to hex string - [[nodiscard]] static auto ColourrefToHex(COLORREF colour) -> std::string; - // Reference to user settings for persistence (null if not available) UKControllerPlugin::Euroscope::UserSetting* userSetting; diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.cpp b/src/plugin/stands/StandColourConfigurationMenuItem.cpp deleted file mode 100644 index c33f58283..000000000 --- a/src/plugin/stands/StandColourConfigurationMenuItem.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "StandColourConfigurationMenuItem.h" -#include "StandColourConfiguration.h" -#include "StandAssignmentSource.h" -#include "helper/HelperFunctions.h" -#include "plugin/PopupMenuItem.h" -#include -#include - -using UKControllerPlugin::HelperFunctions; -using UKControllerPlugin::Plugin::PopupMenuItem; - -namespace UKControllerPlugin::Stands { - - namespace { - auto CALLBACK ChooseColorTitleHook(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -> UINT_PTR - { - if (msg != WM_INITDIALOG) { - return 0; - } - - const auto* chooseColor = reinterpret_cast(lParam); - if (chooseColor == nullptr || chooseColor->lCustData == 0) { - return 0; - } - - const auto* title = reinterpret_cast(chooseColor->lCustData); - SetWindowTextA(hwnd, title); - return 1; - } - } // namespace - - StandColourConfigurationMenuItem::StandColourConfigurationMenuItem( - std::shared_ptr colourConfiguration, int callbackFunctionId) - : colourConfiguration(std::move(colourConfiguration)), callbackFunctionId(callbackFunctionId) - { - } - - void StandColourConfigurationMenuItem::Configure(int functionId, std::string subject, RECT area) - { - if (!this->colourConfiguration) { - LogWarning("StandColourConfigurationMenuItem: Colour configuration is null"); - return; - } - - // Define the assignment sources to configure - std::array sources = { - std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_SYSTEM)}; - - std::array sourceLabels = {"User", "System Auto"}; - - // Allow user to pick colours for each source - CHOOSECOLOR chooseColor{}; - chooseColor.lStructSize = sizeof(CHOOSECOLOR); - chooseColor.hwndOwner = GetActiveWindow(); - chooseColor.lpCustColors = this->customColours.data(); - chooseColor.lpfnHook = ChooseColorTitleHook; - chooseColor.Flags = CC_RGBINIT | CC_FULLOPEN | CC_ENABLEHOOK; - - for (size_t offset = 0; offset < sources.size(); ++offset) { - const size_t i = (this->lastSelectedSourceIndex + offset) % sources.size(); - chooseColor.rgbResult = this->colourConfiguration->GetColourForSource(sources[i]); - const auto dialogTitle = std::string("Stand Colour Configuration - ") + sourceLabels[i]; - chooseColor.lCustData = reinterpret_cast(dialogTitle.c_str()); - - if (ChooseColor(&chooseColor) == TRUE) { - this->colourConfiguration->SetColourForSource(sources[i], chooseColor.rgbResult); - LogInfo("Stand colour updated for source: " + sources[i]); - } else { - this->lastSelectedSourceIndex = i; - // User cancelled, stop the colour selection process - break; - } - - if (offset == sources.size() - 1) { - this->lastSelectedSourceIndex = 0; - } - } - - // Save the new colours to user settings - this->colourConfiguration->SaveToUserSettings(); - LogInfo("Stand colours saved to user settings"); - } - - auto StandColourConfigurationMenuItem::GetConfigurationMenuItem() const -> PopupMenuItem - { - PopupMenuItem returnVal; - returnVal.firstValue = this->itemDescription; - returnVal.secondValue = ""; - returnVal.callbackFunctionId = this->callbackFunctionId; - returnVal.checked = 2; // No checkbox - returnVal.disabled = false; - returnVal.fixedPosition = false; - return returnVal; - } -} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfigurationMenuItem.h b/src/plugin/stands/StandColourConfigurationMenuItem.h deleted file mode 100644 index 822168114..000000000 --- a/src/plugin/stands/StandColourConfigurationMenuItem.h +++ /dev/null @@ -1,41 +0,0 @@ -#pragma once -#include "radarscreen/ConfigurableDisplayInterface.h" -#include "plugin/PopupMenuItem.h" -#include -#include - -namespace UKControllerPlugin::Stands { - class StandColourConfiguration; - - /* - Menu item for configuring stand assignment source colours. - Allows users to customize the colours used for different stand assignment sources - (User, Reservation Allocator, VAA, System) without requiring a plugin reload. - */ - class StandColourConfigurationMenuItem : public UKControllerPlugin::RadarScreen::ConfigurableDisplayInterface - { - public: - StandColourConfigurationMenuItem( - std::shared_ptr colourConfiguration, int callbackFunctionId); - - // Inherited via ConfigurableDisplayInterface - void Configure(int functionId, std::string subject, RECT area) override; - [[nodiscard]] auto GetConfigurationMenuItem() const -> UKControllerPlugin::Plugin::PopupMenuItem override; - - private: - // The colour configuration to customize - std::shared_ptr colourConfiguration; - - // The item description - const std::string itemDescription = "Configure Stand Colours"; - - // The callback function ID - const int callbackFunctionId; - - // The source index to start from next time user opens the configuration - size_t lastSelectedSourceIndex = 0; - - // Persistent custom colours for the Windows colour picker - std::array customColours{}; - }; -} // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 690da0efb..ece6e46a7 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -310,13 +310,10 @@ namespace UKControllerPlugin::Stands { return; } - // Tag item: Show stand identifier with colour based on source if (tagData.GetItemCode() == assignedStandTagItemId) { tagData.SetItemString(stand->identifier); tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); - } - // Tag item: Show assignment source shorthand - else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { + } else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 735ec1cae..774069f35 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -3,9 +3,7 @@ #include "StandModule.h" #include "StandSerializer.h" #include "StandColourConfiguration.h" -#include "StandColourConfigurationMenuItem.h" #include "bootstrap/PersistenceContainer.h" -#include "radarscreen/ConfigurableDisplayCollection.h" #include "dependency/DependencyLoaderInterface.h" #include "euroscope/CallbackFunction.h" #include "flightplan/FlightPlanEventHandlerCollection.h" @@ -38,13 +36,9 @@ namespace UKControllerPlugin::Stands { // Load stand colour configuration from EuroScope user settings // If pluginUserSettingHandler is not available (e.g., in tests), creates default-only config - if (container.pluginUserSettingHandler) { - container.standColourConfiguration = - std::make_shared(*container.pluginUserSettingHandler); - } else { - container.standColourConfiguration = std::make_shared(); - } - auto colourConfiguration = container.standColourConfiguration; + auto colourConfiguration = container.pluginUserSettingHandler + ? std::make_shared(*container.pluginUserSettingHandler) + : std::make_shared(); // Create the event handler auto standSelectedCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); @@ -94,20 +88,6 @@ namespace UKControllerPlugin::Stands { container.pluginFunctionHandlers->RegisterFunctionCall(openStandAssignmentEditBox); - // Create the colour configuration menu item and register its callback - const int colourConfigurationCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); - auto colourConfigurationMenuItem = - std::make_shared(colourConfiguration, colourConfigurationCallbackId); - container.standColourConfigurationMenuItem = colourConfigurationMenuItem; - - const UKControllerPlugin::Euroscope::CallbackFunction colourConfigCallback( - colourConfigurationCallbackId, - "Stand Colour Configuration", - [colourConfigurationMenuItem](int functionId, std::string subject, RECT screenObjectArea) { - colourConfigurationMenuItem->Configure(functionId, std::move(subject), screenObjectArea); - }); - container.pluginFunctionHandlers->RegisterFunctionCall(colourConfigCallback); - // Assign to handlers container.flightplanHandler->RegisterHandler(eventHandler); container.tagHandler->RegisterTagItem(StandEventHandler::assignedStandTagItemId, eventHandler); @@ -117,19 +97,6 @@ namespace UKControllerPlugin::Stands { container.integrationModuleContainer->inboundMessageHandler->AddProcessor(eventHandler); } - void BootstrapRadarScreen( - const Bootstrap::PersistenceContainer& container, - UKControllerPlugin::RadarScreen::ConfigurableDisplayCollection& configurableDisplays) - { - if (!container.standColourConfigurationMenuItem) { - LogWarning("StandModule::BootstrapRadarScreen: Stand colour configuration menu item not available"); - return; - } - - // Register the colour configuration menu item with the configurableDisplays collection - configurableDisplays.RegisterDisplay(container.standColourConfigurationMenuItem); - } - auto GetDependencyKey() -> std::string { return "DEPENDENCY_STANDS"; diff --git a/src/plugin/stands/StandModule.h b/src/plugin/stands/StandModule.h index 72d836678..2aa6691c8 100644 --- a/src/plugin/stands/StandModule.h +++ b/src/plugin/stands/StandModule.h @@ -7,9 +7,6 @@ namespace UKControllerPlugin { namespace Dependency { class DependencyLoaderInterface; } // namespace Dependency - namespace RadarScreen { - class ConfigurableDisplayCollection; - } // namespace RadarScreen } // namespace UKControllerPlugin namespace UKControllerPlugin::Stands { @@ -20,12 +17,5 @@ namespace UKControllerPlugin::Stands { UKControllerPlugin::Bootstrap::PersistenceContainer& container, UKControllerPlugin::Dependency::DependencyLoaderInterface& dependencies); - /* - Bootstraps everything to do with stand assignment at the radar screen level - */ - void BootstrapRadarScreen( - const UKControllerPlugin::Bootstrap::PersistenceContainer& container, - UKControllerPlugin::RadarScreen::ConfigurableDisplayCollection& configurableDisplays); - [[nodiscard]] auto GetDependencyKey() -> std::string; } // namespace UKControllerPlugin::Stands diff --git a/test/plugin/stands/StandModuleTest.cpp b/test/plugin/stands/StandModuleTest.cpp index e79d37aaf..d7becd003 100644 --- a/test/plugin/stands/StandModuleTest.cpp +++ b/test/plugin/stands/StandModuleTest.cpp @@ -92,16 +92,15 @@ namespace UKControllerPluginTest::Stands { { BootstrapPlugin(this->container, this->dependencyLoader); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasTagFunction(9007)); - EXPECT_EQ(2, this->container.pluginFunctionHandlers->CountCallbacks()); + EXPECT_EQ(1, this->container.pluginFunctionHandlers->CountCallbacks()); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasCallbackByDescription("Stand Selected")); - EXPECT_TRUE(this->container.pluginFunctionHandlers->HasCallbackByDescription("Stand Colour Configuration")); } TEST_F(StandModuleTest, ItRegistersTheStandAssignmentEditBoxFunction) { BootstrapPlugin(this->container, this->dependencyLoader); EXPECT_TRUE(this->container.pluginFunctionHandlers->HasTagFunction(9008)); - EXPECT_EQ(2, this->container.pluginFunctionHandlers->CountCallbacks()); + EXPECT_EQ(1, this->container.pluginFunctionHandlers->CountCallbacks()); } TEST_F(StandModuleTest, ItRegistersForExternalMessages) From b6870e280ee66bd0af5897424817a98f64c0d7d8 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 12:19:12 +0000 Subject: [PATCH 16/59] remove code smells from sonarqube --- src/plugin/stands/StandColourConfiguration.cpp | 4 ++-- src/plugin/stands/StandEventHandler.cpp | 12 +++++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index d7b9ead4c..ce5b11158 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,7 +2,7 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" -#include +#include namespace UKControllerPlugin::Stands { @@ -66,7 +66,7 @@ namespace UKControllerPlugin::Stands { } LogInfo("Loaded stand assignment source colours from UserSettings"); - } catch (const std::exception& e) { + } catch (const std::out_of_range& e) { LogWarning("Failed to load stand colours from UserSettings: " + std::string(e.what())); } } diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index ece6e46a7..7c6d39e3c 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -524,11 +524,13 @@ namespace UKControllerPlugin::Stands { this->standAssignments[callsign] = {stand.id, source}; this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); - LogInfo( - "Stand id " + std::to_string(stand.id) + "(" + stand.airfieldCode + "/" + stand.identifier + - ") " - "assigned to " + - callsign + " (source: " + source + ")"); + LogInfo(std::format( + "Stand id {}({}/{}) assigned to {} (source: {})", + stand.id, + stand.airfieldCode, + stand.identifier, + callsign, + source)); } auto StandEventHandler::ActionsToProcess() const -> std::vector { From d3e0c79c0d14c612aa1a41920756a344d1c60bdd Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 12:24:08 +0000 Subject: [PATCH 17/59] formatting --- src/plugin/stands/StandEventHandler.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 7c6d39e3c..1e96eb706 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -525,12 +525,8 @@ namespace UKControllerPlugin::Stands { this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); LogInfo(std::format( - "Stand id {}({}/{}) assigned to {} (source: {})", - stand.id, - stand.airfieldCode, - stand.identifier, - callsign, - source)); + "Stand id {}({}/{}) assigned to {} (source: {})", stand.id, stand.airfieldCode, stand.identifier, + callsign, source)); } auto StandEventHandler::ActionsToProcess() const -> std::vector { From 18c8efe3e5c8ecd52b7f9b2baf45dd4b97bdd8b6 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 12:29:19 +0000 Subject: [PATCH 18/59] formatting fix hopefully --- src/plugin/stands/StandEventHandler.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 1e96eb706..092c6081b 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -524,9 +524,10 @@ namespace UKControllerPlugin::Stands { this->standAssignments[callsign] = {stand.id, source}; this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); - LogInfo(std::format( - "Stand id {}({}/{}) assigned to {} (source: {})", stand.id, stand.airfieldCode, stand.identifier, - callsign, source)); + const auto logMessage = + std::format("Stand id {}({}/{}) assigned to {} (source: {})", stand.id, stand.airfieldCode, + stand.identifier, callsign, source); + LogInfo(logMessage); } auto StandEventHandler::ActionsToProcess() const -> std::vector { From 4abd622e13f06175cc27fe4fa28fffa074899080 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 12:45:06 +0000 Subject: [PATCH 19/59] Format fix --- src/plugin/stands/StandEventHandler.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 092c6081b..bfbb3d7cc 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -362,8 +362,8 @@ namespace UKControllerPlugin::Stands { Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from its origin. */ - auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const - -> std::string + auto + StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const -> std::string { return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() : flightplan.GetDestination(); @@ -524,9 +524,13 @@ namespace UKControllerPlugin::Stands { this->standAssignments[callsign] = {stand.id, source}; this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); - const auto logMessage = - std::format("Stand id {}({}/{}) assigned to {} (source: {})", stand.id, stand.airfieldCode, - stand.identifier, callsign, source); + const auto logMessage = std::format( + "Stand id {}({}/{}) assigned to {} (source: {})", + stand.id, + stand.airfieldCode, + stand.identifier, + callsign, + source); LogInfo(logMessage); } auto StandEventHandler::ActionsToProcess() const -> std::vector From 7dbcca4d8ba8048ebc5c47b706bf8a1ff8b03b88 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 12:48:38 +0000 Subject: [PATCH 20/59] ok this is after running clang-format --- src/plugin/stands/StandEventHandler.h | 10 ++++------ test/plugin/stands/StandEventHandlerTest.cpp | 10 +++++----- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index b38f8bc7a..696a1574a 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -110,9 +110,8 @@ namespace UKControllerPlugin::Stands { private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); void AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source); - [[nodiscard]] auto - AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) - -> std::string; + [[nodiscard]] auto AssignStandInApi( + const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; void RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); void RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); void RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); @@ -123,9 +122,8 @@ namespace UKControllerPlugin::Stands { [[nodiscard]] static auto GetAssignmentSourceShorthand(const std::string& source) -> std::string; auto CanAssignStand(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool; static auto UnassignmentMessageValid(const nlohmann::json& message) -> bool; - auto - GetAirfieldForStandAssignment(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const - -> std::string; + auto GetAirfieldForStandAssignment( + UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> std::string; auto LockStandMap() -> std::lock_guard; // The last airfield that was used to populate the stand menu, used when we receive the callback diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index a951b0c7d..2ccdf7bb0 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -50,9 +50,9 @@ namespace UKControllerPluginTest { class StandEventHandlerTest : public ApiTestCase { public: - [[nodiscard]] static auto - MakeActiveCallsign(const UKControllerPlugin::Controller::ControllerPosition& controller, bool isUser) - -> std::shared_ptr + [[nodiscard]] static auto MakeActiveCallsign( + const UKControllerPlugin::Controller::ControllerPosition& controller, + bool isUser) -> std::shared_ptr { return std::make_shared( "LON_S_CTR", "Test", controller, isUser); @@ -172,8 +172,8 @@ namespace UKControllerPluginTest { // Creates a mock flightplan registered for "BAW123", sets up the // AnnotateFlightStrip(3,"1L") expectation, and expects the integration event. - [[nodiscard]] auto MakeSyncFlightplanForBaw123Stand1() - -> std::shared_ptr> + [[nodiscard]] auto + MakeSyncFlightplanForBaw123Stand1() -> std::shared_ptr> { auto fp = std::make_shared>(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(fp)); From 57aadd3626f48dab03e6bf81eba6203877e4da0e Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 13:08:49 +0000 Subject: [PATCH 21/59] would help if i removed dryrun --- src/plugin/stands/StandEventHandler.cpp | 4 ++-- test/plugin/stands/StandEventHandlerTest.cpp | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index bfbb3d7cc..e1e67724f 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -362,8 +362,8 @@ namespace UKControllerPlugin::Stands { Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from its origin. */ - auto - StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const -> std::string + auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const + -> std::string { return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() : flightplan.GetDestination(); diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 2ccdf7bb0..a951b0c7d 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -50,9 +50,9 @@ namespace UKControllerPluginTest { class StandEventHandlerTest : public ApiTestCase { public: - [[nodiscard]] static auto MakeActiveCallsign( - const UKControllerPlugin::Controller::ControllerPosition& controller, - bool isUser) -> std::shared_ptr + [[nodiscard]] static auto + MakeActiveCallsign(const UKControllerPlugin::Controller::ControllerPosition& controller, bool isUser) + -> std::shared_ptr { return std::make_shared( "LON_S_CTR", "Test", controller, isUser); @@ -172,8 +172,8 @@ namespace UKControllerPluginTest { // Creates a mock flightplan registered for "BAW123", sets up the // AnnotateFlightStrip(3,"1L") expectation, and expects the integration event. - [[nodiscard]] auto - MakeSyncFlightplanForBaw123Stand1() -> std::shared_ptr> + [[nodiscard]] auto MakeSyncFlightplanForBaw123Stand1() + -> std::shared_ptr> { auto fp = std::make_shared>(); ON_CALL(this->plugin, GetFlightplanForCallsign("BAW123")).WillByDefault(Return(fp)); From df008d321931534ad5b0ddd17c862c0d46c1d630 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 18 Mar 2026 13:13:50 +0000 Subject: [PATCH 22/59] formatting --- src/plugin/stands/StandEventHandler.h | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 696a1574a..b38f8bc7a 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -110,8 +110,9 @@ namespace UKControllerPlugin::Stands { private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); void AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source); - [[nodiscard]] auto AssignStandInApi( - const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; + [[nodiscard]] auto + AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) + -> std::string; void RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); void RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); void RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan); @@ -122,8 +123,9 @@ namespace UKControllerPlugin::Stands { [[nodiscard]] static auto GetAssignmentSourceShorthand(const std::string& source) -> std::string; auto CanAssignStand(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool; static auto UnassignmentMessageValid(const nlohmann::json& message) -> bool; - auto GetAirfieldForStandAssignment( - UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> std::string; + auto + GetAirfieldForStandAssignment(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const + -> std::string; auto LockStandMap() -> std::lock_guard; // The last airfield that was used to populate the stand menu, used when we receive the callback From 0888907482aacb8ea067aab5ce2772a086f7765b Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Thu, 19 Mar 2026 12:34:02 +0000 Subject: [PATCH 23/59] attempt at deduplication --- test/plugin/stands/StandEventHandlerTest.cpp | 638 ++++--------------- 1 file changed, 116 insertions(+), 522 deletions(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index a951b0c7d..7435f9989 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -209,6 +209,65 @@ namespace UKControllerPluginTest { airfieldOwnership->SetProvidersForAirfield(airfield, provisions); } + void SetupAutoStandSelectionMenu(const std::string& destination = "EGGW", double distance = 1.0) + { + SetupFlightplan(false, false, true, distance); + ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return(destination)); + this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); + } + + [[nodiscard]] auto MakeSelectedFlightplanForAutoRequest( + const std::string& destination, double distanceFromOrigin, const std::string& aircraftType = "") + -> std::shared_ptr> + { + auto pluginReturnedFp = std::make_shared>(); + + ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); + ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); + ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); + ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); + ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return(destination)); + ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(distanceFromOrigin)); + + if (!aircraftType.empty()) { + ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return(aircraftType)); + } + + ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + return pluginReturnedFp; + } + + void SetupRadarTargetForCallsign(const std::string& callsign, double latitude = 123, double longitude = 456) + { + auto pluginReturnedRt = std::make_shared>(); + + EuroScopePlugIn::CPosition position; + position.m_Latitude = latitude; + position.m_Longitude = longitude; + ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); + + ON_CALL(this->plugin, GetRadarTargetForCallsign(callsign)).WillByDefault(Return(pluginReturnedRt)); + } + + void SelectAutoAndExpectNoStandAssigned() + { + this->handler.StandSelected(1, "AUTO", {}); + this->AwaitApiCallCompletion(); + EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + } + + void ExpectProcessActionFailureNoAssignment( + const std::shared_ptr& message) + { + bool successCalled = false; + std::vector failureMessages; + CallProcessAction(message, successCalled, failureMessages); + + EXPECT_FALSE(successCalled); + EXPECT_FALSE(failureMessages.empty()); + EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + } + [[nodiscard]] static auto DepartureStandRequestBody() -> nlohmann::json { return nlohmann::json{ @@ -1342,95 +1401,46 @@ namespace UKControllerPluginTest { auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", "55"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignMissing) { auto message = MakeInboundMessage("assign_stand", {{"airfield", "EGKK"}, {"stand", "55"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfCallsignNotString) { auto message = MakeInboundMessage("assign_stand", {{"callsign", 123}, {"airfield", "EGKK"}, {"stand", "55"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldMissing) { auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"stand", "55"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfAirfieldNotString) { auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", 123}, {"stand", "55"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandMissing) { auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItFailsAssignmentFromMessageIfStandNotString) { auto message = MakeInboundMessage("assign_stand", {{"callsign", "BAW123"}, {"airfield", "EGKK"}, {"stand", 55}}); - - bool successCalled = false; - std::vector failureMessages; - CallProcessAction(message, successCalled, failureMessages); - - EXPECT_FALSE(successCalled); - EXPECT_FALSE(failureMessages.empty()); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + ExpectProcessActionFailureNoAssignment(message); } TEST_F(StandEventHandlerTest, ItRequestsADepartureStandFromApi) @@ -1438,38 +1448,9 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() ->Post() @@ -1489,38 +1470,9 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() ->Post() @@ -1528,10 +1480,7 @@ namespace UKControllerPluginTest { .WithBody(DepartureStandRequestBody()) .WillReturnForbidden(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUnknownStandId) @@ -1539,38 +1488,9 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() ->Post() @@ -1579,10 +1499,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesStandIdNotInteger) @@ -1590,38 +1507,9 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() ->Post() @@ -1630,10 +1518,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesNoStandIdInJson) @@ -1641,38 +1526,9 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() ->Post() @@ -1681,10 +1537,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesNotFoundRadarTarget) @@ -1692,37 +1545,14 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(nullptr)); this->ExpectNoApiRequests(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUnknownDistanceFromOrigin) @@ -1730,45 +1560,13 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 0.0); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(0.0)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 0.0); + MakeSelectedFlightplanForAutoRequest("EGGW", 0.0); + SetupRadarTargetForCallsign("BAW123"); this->ExpectNoApiRequests(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, DepartureStandRequestsHandlesUserNotProvidingDelivery) @@ -1776,45 +1574,13 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGKK", UKControllerPlugin::Ownership::ServiceType::Ground); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(1)); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); - - std::shared_ptr> pluginReturnedRt = - std::make_shared>(); - - EuroScopePlugIn::CPosition position; - position.m_Latitude = 123; - position.m_Longitude = 456; - ON_CALL(*pluginReturnedRt, GetPosition()).WillByDefault(Return(position)); - - ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(pluginReturnedRt)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 1); + SetupRadarTargetForCallsign("BAW123"); this->ExpectNoApiRequests(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ItRequestsAnArrivalStandFromApi) @@ -1822,30 +1588,8 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1865,30 +1609,8 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1896,10 +1618,7 @@ namespace UKControllerPluginTest { .WithBody(ArrivalStandRequestBody()) .WillReturnServerError(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesInvalidStandIdInJson) @@ -1907,30 +1626,8 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1939,10 +1636,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", 999}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesNonIntegerStandIdInJson) @@ -1950,30 +1644,8 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1982,10 +1654,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"stand_id", "abc"}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesNoStandIdInJson) @@ -1993,30 +1662,8 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -2025,10 +1672,7 @@ namespace UKControllerPluginTest { .WillReturnCreated() .WithResponseBody(nlohmann::json{{"not_stand_id", 3}}); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesZeroDistanceToOrigin) @@ -2036,37 +1680,12 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW"); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(0.0)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 0.0, "B738"); this->ExpectNoApiRequests(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } TEST_F(StandEventHandlerTest, ArrivalStandRequestHandlesUserNotProvidingDelivery) @@ -2074,37 +1693,12 @@ namespace UKControllerPluginTest { // Make "us" the delivery controller SetProviderForAirfield("EGGW", UKControllerPlugin::Ownership::ServiceType::Ground); - // Trigger the menu first to set the last airport - SetupFlightplan(false, false, true, 1); - ON_CALL(this->flightplan, GetDestination()).WillByDefault(Return("EGGW")); - - this->handler.DisplayStandSelectionMenu(this->flightplan, this->radarTarget, "", {0, 0}); - - std::shared_ptr> pluginReturnedFp = - std::make_shared>(); - - ON_CALL(*pluginReturnedFp, IsTracked()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, IsTrackedByUser()).WillByDefault(Return(true)); - - ON_CALL(*pluginReturnedFp, GetCallsign()).WillByDefault(Return("BAW123")); - - ON_CALL(*pluginReturnedFp, GetDistanceFromOrigin()).WillByDefault(Return(55)); - - ON_CALL(*pluginReturnedFp, GetAircraftType()).WillByDefault(Return("B738")); - - ON_CALL(*pluginReturnedFp, GetOrigin()).WillByDefault(Return("EGKK")); - - ON_CALL(*pluginReturnedFp, GetDestination()).WillByDefault(Return("EGGW")); - - ON_CALL(this->plugin, GetSelectedFlightplan()).WillByDefault(Return(pluginReturnedFp)); + SetupAutoStandSelectionMenu("EGGW", 1); + MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectNoApiRequests(); - this->handler.StandSelected(1, "AUTO", {}); - - this->AwaitApiCallCompletion(); - EXPECT_EQ(this->handler.noStandAssigned, this->handler.GetAssignedStandForCallsign("BAW123")); + SelectAutoAndExpectNoStandAssigned(); } } // namespace Stands } // namespace UKControllerPluginTest From 0d784e28a4e01de7b4e89b8410be0f7f7f008200 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Thu, 19 Mar 2026 13:16:25 +0000 Subject: [PATCH 24/59] attempt fix --- test/plugin/stands/StandEventHandlerTest.cpp | 30 ++++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 7435f9989..c83ceac3e 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -1449,7 +1449,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() @@ -1471,7 +1471,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() @@ -1489,7 +1489,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() @@ -1508,7 +1508,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() @@ -1527,7 +1527,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectApiRequest() @@ -1546,7 +1546,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); ON_CALL(this->plugin, GetRadarTargetForCallsign("BAW123")).WillByDefault(Return(nullptr)); @@ -1561,7 +1561,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK"); SetupAutoStandSelectionMenu("EGGW", 0.0); - MakeSelectedFlightplanForAutoRequest("EGGW", 0.0); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 0.0); SetupRadarTargetForCallsign("BAW123"); this->ExpectNoApiRequests(); @@ -1575,7 +1575,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGKK", UKControllerPlugin::Ownership::ServiceType::Ground); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 1); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 1); SetupRadarTargetForCallsign("BAW123"); this->ExpectNoApiRequests(); @@ -1589,7 +1589,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1610,7 +1610,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1627,7 +1627,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1645,7 +1645,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1663,7 +1663,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectApiRequest() ->Post() @@ -1681,7 +1681,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW"); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 0.0, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 0.0, "B738"); this->ExpectNoApiRequests(); @@ -1694,7 +1694,7 @@ namespace UKControllerPluginTest { SetProviderForAirfield("EGGW", UKControllerPlugin::Ownership::ServiceType::Ground); SetupAutoStandSelectionMenu("EGGW", 1); - MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); + [[maybe_unused]] const auto selectedFlightplan = MakeSelectedFlightplanForAutoRequest("EGGW", 55, "B738"); this->ExpectNoApiRequests(); From c0c6eff1bf67f576868d58bc8e4479c96488f08e Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sat, 21 Mar 2026 19:58:06 +0000 Subject: [PATCH 25/59] Some fixes from review --- docs/TAG_ITEMS.md | 1 + src/plugin/stands/StandAssignmentSource.h | 49 ++++++++++-- .../stands/StandColourConfiguration.cpp | 74 ++++++++++--------- src/plugin/stands/StandColourConfiguration.h | 5 +- src/plugin/stands/StandEventHandler.cpp | 30 +++++--- src/plugin/stands/StandEventHandler.h | 11 ++- src/plugin/stands/StandModule.h | 2 +- test/plugin/stands/StandEventHandlerTest.cpp | 18 ++--- 8 files changed, 123 insertions(+), 67 deletions(-) diff --git a/docs/TAG_ITEMS.md b/docs/TAG_ITEMS.md index e99f7cc92..c0beac924 100644 --- a/docs/TAG_ITEMS.md +++ b/docs/TAG_ITEMS.md @@ -32,3 +32,4 @@ 130 - Missed Approach Indicator 131 - Relevant ECFMP Flow Measures 132 - Glideslope Deviation +132 - Stand Assignment Source diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index f48ad7aaa..f7bf125fd 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -8,15 +8,54 @@ namespace UKControllerPlugin::Stands { */ struct StandAssignmentSource { + enum class Source + { + User, + ReservationAllocator, + VaaAllocator, + SystemAuto, + }; + int standId; // The source of the assignment (user, reservation_allocator, vaa_allocator, system_auto) - std::string source; + Source source; // The four possible sources for stand assignments - static constexpr std::string_view SOURCE_USER = "user"; - static constexpr std::string_view SOURCE_RESERVATION_ALLOCATOR = "reservation_allocator"; - static constexpr std::string_view SOURCE_VAA_ALLOCATOR = "vaa_allocator"; - static constexpr std::string_view SOURCE_SYSTEM = "system_auto"; + static constexpr Source SOURCE_USER = Source::User; + static constexpr Source SOURCE_RESERVATION_ALLOCATOR = Source::ReservationAllocator; + static constexpr Source SOURCE_VAA_ALLOCATOR = Source::VaaAllocator; + static constexpr Source SOURCE_SYSTEM = Source::SystemAuto; + + [[nodiscard]] static constexpr auto ToString(Source source) -> std::string_view + { + switch (source) { + case Source::User: + return "user"; + case Source::ReservationAllocator: + return "reservation_allocator"; + case Source::VaaAllocator: + return "vaa_allocator"; + case Source::SystemAuto: + return "system_auto"; + } + + return "system_auto"; + } + + [[nodiscard]] static constexpr auto FromString(std::string_view source) -> Source + { + if (source == "user") { + return Source::User; + } + if (source == "reservation_allocator") { + return Source::ReservationAllocator; + } + if (source == "vaa_allocator") { + return Source::VaaAllocator; + } + + return Source::SystemAuto; + } }; } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index ce5b11158..20853d46f 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -6,26 +6,32 @@ namespace UKControllerPlugin::Stands { + namespace { + auto DefaultSourceColours() -> std::map + { + return { + {StandAssignmentSource::SOURCE_USER, RGB(255, 255, 255)}, + {StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR, RGB(255, 255, 0)}, + {StandAssignmentSource::SOURCE_VAA_ALLOCATOR, RGB(0, 255, 255)}, + {StandAssignmentSource::SOURCE_SYSTEM, RGB(180, 180, 180)}}; + } + } // namespace + StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& setting) : userSetting(&setting) { - sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = DEFAULT_SYSTEM_COLOUR; + sourceColours = DefaultSourceColours(); LoadFromUserSettings(); } StandColourConfiguration::StandColourConfiguration() : userSetting(nullptr) { - sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = DEFAULT_USER_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = DEFAULT_RESERVATION_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = DEFAULT_VAA_COLOUR; - sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = DEFAULT_SYSTEM_COLOUR; + sourceColours = DefaultSourceColours(); + LoadFromUserSettings(); } - auto StandColourConfiguration::GetColourForSource(const std::string& source) const -> COLORREF + auto StandColourConfiguration::GetColourForSource(StandAssignmentSource::Source source) const -> COLORREF { if (auto it = sourceColours.find(source); it != sourceColours.cend()) { return it->second; @@ -40,35 +46,35 @@ namespace UKControllerPlugin::Stands { return; } - try { - std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_USER); - if (this->userSetting->HasEntry(key)) { - sourceColours[std::string(StandAssignmentSource::SOURCE_USER)] = - this->userSetting->GetColourEntry(key, DEFAULT_USER_COLOUR); - } - - key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR); - if (this->userSetting->HasEntry(key)) { - sourceColours[std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)] = - this->userSetting->GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); - } + std::string key = std::string(SETTING_PREFIX) + + std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_USER)); + if (this->userSetting->HasEntry(key)) { + sourceColours[StandAssignmentSource::SOURCE_USER] = + this->userSetting->GetColourEntry(key, DEFAULT_USER_COLOUR); + } - key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR); - if (this->userSetting->HasEntry(key)) { - sourceColours[std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)] = - this->userSetting->GetColourEntry(key, DEFAULT_VAA_COLOUR); - } + key = std::string(SETTING_PREFIX) + + std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); + if (this->userSetting->HasEntry(key)) { + sourceColours[StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR] = + this->userSetting->GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); + } - key = std::string(SETTING_PREFIX) + std::string(StandAssignmentSource::SOURCE_SYSTEM); - if (this->userSetting->HasEntry(key)) { - sourceColours[std::string(StandAssignmentSource::SOURCE_SYSTEM)] = - this->userSetting->GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); - } + key = std::string(SETTING_PREFIX) + + std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); + if (this->userSetting->HasEntry(key)) { + sourceColours[StandAssignmentSource::SOURCE_VAA_ALLOCATOR] = + this->userSetting->GetColourEntry(key, DEFAULT_VAA_COLOUR); + } - LogInfo("Loaded stand assignment source colours from UserSettings"); - } catch (const std::out_of_range& e) { - LogWarning("Failed to load stand colours from UserSettings: " + std::string(e.what())); + key = std::string(SETTING_PREFIX) + + std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_SYSTEM)); + if (this->userSetting->HasEntry(key)) { + sourceColours[StandAssignmentSource::SOURCE_SYSTEM] = + this->userSetting->GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); } + + LogInfo("Loaded stand assignment source colours from UserSettings"); } } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index cbe9e1e17..d3261a511 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -1,4 +1,5 @@ #pragma once +#include "StandAssignmentSource.h" #include #include #include @@ -23,7 +24,7 @@ namespace UKControllerPlugin::Stands { Get the colour for a given assignment source. Returns a default grey if source is not found or not set. */ - [[nodiscard]] auto GetColourForSource(const std::string& source) const -> COLORREF; + [[nodiscard]] auto GetColourForSource(StandAssignmentSource::Source source) const -> COLORREF; /* Load colours from UserSettings, with fallback to defaults. @@ -35,7 +36,7 @@ namespace UKControllerPlugin::Stands { UKControllerPlugin::Euroscope::UserSetting* userSetting; // Map of source to RGB colour - std::map> sourceColours; + std::map sourceColours; // Default colour (grey) for unknown sources static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index e1e67724f..7cc8bae81 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -117,7 +117,7 @@ namespace UKControllerPlugin::Stands { } // Assign that stand - this->AssignStandToAircraft(callsign, *stand, std::string(StandAssignmentSource::SOURCE_USER)); + this->AssignStandToAircraft(callsign, *stand, StandAssignmentSource::SOURCE_USER); int standId = stand->id; auto callsignForRequest = callsign; @@ -219,10 +219,16 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId) { - this->standAssignments[callsign] = {standId, std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + this->standAssignments[callsign] = {standId, StandAssignmentSource::SOURCE_SYSTEM}; } void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, const std::string& source) + { + this->SetAssignedStand(callsign, standId, StandAssignmentSource::FromString(source)); + } + + void + StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, StandAssignmentSource::Source source) { this->standAssignments[callsign] = {standId, source}; } @@ -326,16 +332,17 @@ namespace UKControllerPlugin::Stands { this->stands.find(message.at("stand_id").get()) != this->stands.cend(); } - auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> std::string + auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) + -> StandAssignmentSource::Source { if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { - return message.at("assignment_source").get(); + return StandAssignmentSource::FromString(message.at("assignment_source").get()); } - return std::string(StandAssignmentSource::SOURCE_SYSTEM); + return StandAssignmentSource::SOURCE_SYSTEM; } - auto StandEventHandler::GetAssignmentSourceShorthand(const std::string& source) -> std::string + auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignmentSource::Source source) -> std::string { if (source == StandAssignmentSource::SOURCE_USER) { return "USER"; @@ -349,7 +356,6 @@ namespace UKControllerPlugin::Stands { if (source == StandAssignmentSource::SOURCE_SYSTEM) { return "AUTO"; } - return "UNK "; } @@ -514,23 +520,23 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) { - this->AssignStandToAircraft(callsign, stand, std::string(StandAssignmentSource::SOURCE_SYSTEM)); + this->AssignStandToAircraft(callsign, stand, StandAssignmentSource::SOURCE_SYSTEM); } - void - StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source) + void StandEventHandler::AssignStandToAircraft( + const std::string& callsign, const Stand& stand, StandAssignmentSource::Source source) { this->AnnotateFlightStrip(callsign, stand.id); this->standAssignments[callsign] = {stand.id, source}; this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); const auto logMessage = std::format( - "Stand id {}({}/{}) assigned to {} (source: {})", + "Stand id {} ({}/{}) assigned to {} (source: {})", stand.id, stand.airfieldCode, stand.identifier, callsign, - source); + StandAssignmentSource::ToString(source)); LogInfo(logMessage); } auto StandEventHandler::ActionsToProcess() const -> std::vector diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index b38f8bc7a..389b187f8 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -74,6 +74,7 @@ namespace UKControllerPlugin::Stands { void RemoveFlightStripAnnotation(const std::string& callsign) const; void SetAssignedStand(const std::string& callsign, int standId); void SetAssignedStand(const std::string& callsign, int standId, const std::string& source); + void SetAssignedStand(const std::string& callsign, int standId, StandAssignmentSource::Source source); void StandSelected(int functionId, std::string context, RECT); void DisplayStandAssignmentEditBox( UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan, @@ -105,11 +106,12 @@ namespace UKControllerPlugin::Stands { // Tag item IDs for stand display and source indication inline static const int assignedStandTagItemId = 110; - inline static const int standAssignmentSourceTagItemId = 200; + inline static const int standAssignmentSourceTagItemId = 132; private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); - void AssignStandToAircraft(const std::string& callsign, const Stand& stand, const std::string& source); + void + AssignStandToAircraft(const std::string& callsign, const Stand& stand, StandAssignmentSource::Source source); [[nodiscard]] auto AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; @@ -119,8 +121,9 @@ namespace UKControllerPlugin::Stands { void DoApiStandRequest(const std::string& callsign, const nlohmann::json data); void UnassignStandForAircraft(const std::string& callsign); [[nodiscard]] auto AssignmentMessageValid(const nlohmann::json& message) const -> bool; - [[nodiscard]] static auto GetAssignmentSourceFromMessage(const nlohmann::json& message) -> std::string; - [[nodiscard]] static auto GetAssignmentSourceShorthand(const std::string& source) -> std::string; + [[nodiscard]] static auto GetAssignmentSourceFromMessage(const nlohmann::json& message) + -> StandAssignmentSource::Source; + [[nodiscard]] static auto GetAssignmentSourceShorthand(StandAssignmentSource::Source source) -> std::string; auto CanAssignStand(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool; static auto UnassignmentMessageValid(const nlohmann::json& message) -> bool; auto diff --git a/src/plugin/stands/StandModule.h b/src/plugin/stands/StandModule.h index 2aa6691c8..0a7d6cff8 100644 --- a/src/plugin/stands/StandModule.h +++ b/src/plugin/stands/StandModule.h @@ -11,7 +11,7 @@ namespace UKControllerPlugin { namespace UKControllerPlugin::Stands { /* - Bootstraps everything to do with stand assignment at the plugin level + Bootstraps everything to do with stand assignment */ void BootstrapPlugin( UKControllerPlugin::Bootstrap::PersistenceContainer& container, diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index c83ceac3e..6ed0545cc 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -91,7 +91,7 @@ namespace UKControllerPluginTest { return stands; } - void SetAssignedStandWithSource(int standId, const std::string& source) + void SetAssignedStandWithSource(int standId, StandAssignmentSource::Source source) { this->handler.SetAssignedStand("BAW123", standId, source); } @@ -109,7 +109,7 @@ namespace UKControllerPluginTest { &this->fontSize); } - void ExpectTagItem200Shorthand(const std::string& source, const std::string& expectedShorthand) + void ExpectTagItem200Shorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) { this->SetAssignedStandWithSource(1, source); auto sourceTagData = this->CreateSourceTagData(); @@ -117,7 +117,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedShorthand, sourceTagData.GetItemString()); } - void ExpectTagItem110ColourForSource(const std::string& source) + void ExpectTagItem110ColourForSource(StandAssignmentSource::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -125,7 +125,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); } - void ExpectTagItem200ColourForSource(const std::string& source) + void ExpectTagItem200ColourForSource(StandAssignmentSource::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -183,13 +183,13 @@ namespace UKControllerPluginTest { return fp; } - [[nodiscard]] static auto AllSources() -> std::array + [[nodiscard]] static auto AllSources() -> std::array { return { - std::string(StandAssignmentSource::SOURCE_USER), - std::string(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_VAA_ALLOCATOR), - std::string(StandAssignmentSource::SOURCE_SYSTEM)}; + StandAssignmentSource::SOURCE_USER, + StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR, + StandAssignmentSource::SOURCE_VAA_ALLOCATOR, + StandAssignmentSource::SOURCE_SYSTEM}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From 25f50a34be8a03be6501a9575ea3051bbf26a589 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sat, 21 Mar 2026 20:19:05 +0000 Subject: [PATCH 26/59] further review fixes --- .../stands/StandColourConfiguration.cpp | 11 +++---- src/plugin/stands/StandColourConfiguration.h | 2 ++ src/plugin/stands/StandEventHandler.cpp | 7 +++-- src/plugin/stands/StandEventHandler.h | 9 ++---- src/plugin/stands/StandModule.cpp | 3 +- test/plugin/stands/StandEventHandlerTest.cpp | 29 +++++++------------ 6 files changed, 27 insertions(+), 34 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 20853d46f..95e5e4414 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -18,16 +18,17 @@ namespace UKControllerPlugin::Stands { } // namespace StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& setting) - : userSetting(&setting) + : StandColourConfiguration(&setting) { - sourceColours = DefaultSourceColours(); + } - LoadFromUserSettings(); + StandColourConfiguration::StandColourConfiguration() : StandColourConfiguration(nullptr) + { } - StandColourConfiguration::StandColourConfiguration() : userSetting(nullptr) + StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) + : userSetting(userSetting), sourceColours(DefaultSourceColours()) { - sourceColours = DefaultSourceColours(); LoadFromUserSettings(); } diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index d3261a511..75ecaddc1 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -32,6 +32,8 @@ namespace UKControllerPlugin::Stands { void LoadFromUserSettings(); private: + explicit StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting); + // Reference to user settings for persistence (null if not available) UKControllerPlugin::Euroscope::UserSetting* userSetting; diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 7cc8bae81..9905ea40c 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -34,10 +34,11 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - StandEventHandlerConfig config) + int standSelectedCallbackId, + std::shared_ptr colourConfiguration) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - colourConfiguration(std::move(config.colourConfiguration)), integrationEventHandler(integrationEventHandler), - ownership(ownership), standSelectedCallbackId(config.standSelectedCallbackId) + colourConfiguration(std::move(colourConfiguration)), integrationEventHandler(integrationEventHandler), + ownership(ownership), standSelectedCallbackId(standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 389b187f8..cc89f8d54 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -27,12 +27,6 @@ namespace UKControllerPlugin { namespace UKControllerPlugin::Stands { class StandColourConfiguration; - struct StandEventHandlerConfig - { - int standSelectedCallbackId; - std::shared_ptr colourConfiguration; - }; - /* Handles events related to stands. */ @@ -50,7 +44,8 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - StandEventHandlerConfig config); + int standSelectedCallbackId, + std::shared_ptr colourConfiguration); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 774069f35..374507c46 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -49,7 +49,8 @@ namespace UKControllerPlugin::Stands { *container.integrationModuleContainer->outboundMessageHandler, container.airfieldOwnership, stands, - StandEventHandlerConfig{standSelectedCallbackId, colourConfiguration}); + standSelectedCallbackId, + colourConfiguration); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 6ed0545cc..ade56520e 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -32,7 +32,6 @@ using UKControllerPlugin::Stands::StandAssignedMessage; using UKControllerPlugin::Stands::StandAssignmentSource; using UKControllerPlugin::Stands::StandColourConfiguration; using UKControllerPlugin::Stands::StandEventHandler; -using UKControllerPlugin::Stands::StandEventHandlerConfig; using UKControllerPlugin::Stands::StandUnassignedMessage; using UKControllerPlugin::Tag::TagData; using UKControllerPluginTest::Api::MockApiInterface; @@ -68,13 +67,7 @@ namespace UKControllerPluginTest { colourConfiguration(std::make_shared(userSetting)), tagData(flightplan, radarTarget, 110, 1, itemString, &euroscopeColourCode, &tagColour, &fontSize), handler( - api, - taskRunner, - plugin, - mockIntegration, - airfieldOwnership, - GetStands(), - StandEventHandlerConfig{1, colourConfiguration}) + api, taskRunner, plugin, mockIntegration, airfieldOwnership, GetStands(), 1, colourConfiguration) { ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); ON_CALL(this->mockUserSettingProvider, KeyExists(_)).WillByDefault(Return(false)); @@ -101,7 +94,7 @@ namespace UKControllerPluginTest { return TagData( this->flightplan, this->radarTarget, - 200, + 132, 1, this->itemString, &this->euroscopeColourCode, @@ -109,7 +102,7 @@ namespace UKControllerPluginTest { &this->fontSize); } - void ExpectTagItem200Shorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) + void ExpectTagItem132Shorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) { this->SetAssignedStandWithSource(1, source); auto sourceTagData = this->CreateSourceTagData(); @@ -125,7 +118,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); } - void ExpectTagItem200ColourForSource(StandAssignmentSource::Source source) + void ExpectTagItem132ColourForSource(StandAssignmentSource::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -335,22 +328,22 @@ namespace UKControllerPluginTest { EXPECT_EQ("Foooooo", this->tagData.GetItemString()); } - TEST_F(StandEventHandlerTest, ItReturnsDescriptionForTagItem200) + TEST_F(StandEventHandlerTest, ItReturnsDescriptionForTagItem132) { - EXPECT_EQ("Stand Assignment Source", this->handler.GetTagItemDescription(200)); + EXPECT_EQ("Stand Assignment Source", this->handler.GetTagItemDescription(132)); } - TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForTagItem200) + TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForTagItem132) { const auto sources = AllSources(); const std::array expectedShorthand = {"USER", "RES ", "VAA ", "AUTO"}; for (size_t i = 0; i < std::size(sources); ++i) { - this->ExpectTagItem200Shorthand(sources[i], expectedShorthand[i]); + this->ExpectTagItem132Shorthand(sources[i], expectedShorthand[i]); } } - TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem200IfStandNotAssigned) + TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem132IfStandNotAssigned) { auto sourceTagData = this->CreateSourceTagData(); this->handler.SetTagItemData(sourceTagData); @@ -366,12 +359,12 @@ namespace UKControllerPluginTest { } } - TEST_F(StandEventHandlerTest, TagItem200UsesSourceColours) + TEST_F(StandEventHandlerTest, TagItem132UsesSourceColours) { const auto sources = AllSources(); for (const auto& source : sources) { - this->ExpectTagItem200ColourForSource(source); + this->ExpectTagItem132ColourForSource(source); } } From 70c7c32ff7e274f570c65d7a09867eedd20f092e Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 09:09:04 +0000 Subject: [PATCH 27/59] Update StandEventHandler.cpp --- src/plugin/stands/StandEventHandler.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 9905ea40c..6cf12374a 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -319,11 +319,12 @@ namespace UKControllerPlugin::Stands { if (tagData.GetItemCode() == assignedStandTagItemId) { tagData.SetItemString(stand->identifier); - tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); - tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); + } else { + return; } + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool From 8ac14b6c4816d607f25107da090d5a6cc4a38383 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 09:27:38 +0000 Subject: [PATCH 28/59] Sonarqube Fixes --- src/plugin/stands/StandAssignmentSource.h | 20 ++++++++++++-------- src/plugin/stands/StandEventHandler.cpp | 7 +++---- src/plugin/stands/StandEventHandler.h | 9 +++++++-- src/plugin/stands/StandModule.cpp | 3 +-- 4 files changed, 23 insertions(+), 16 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index f7bf125fd..587013bad 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -29,14 +29,16 @@ namespace UKControllerPlugin::Stands { [[nodiscard]] static constexpr auto ToString(Source source) -> std::string_view { + using enum Source; + switch (source) { - case Source::User: + case User: return "user"; - case Source::ReservationAllocator: + case ReservationAllocator: return "reservation_allocator"; - case Source::VaaAllocator: + case VaaAllocator: return "vaa_allocator"; - case Source::SystemAuto: + case SystemAuto: return "system_auto"; } @@ -45,17 +47,19 @@ namespace UKControllerPlugin::Stands { [[nodiscard]] static constexpr auto FromString(std::string_view source) -> Source { + using enum Source; + if (source == "user") { - return Source::User; + return User; } if (source == "reservation_allocator") { - return Source::ReservationAllocator; + return ReservationAllocator; } if (source == "vaa_allocator") { - return Source::VaaAllocator; + return VaaAllocator; } - return Source::SystemAuto; + return SystemAuto; } }; } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 6cf12374a..ceb8e0fcf 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -34,11 +34,10 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId, - std::shared_ptr colourConfiguration) + ConstructorOptions options) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - colourConfiguration(std::move(colourConfiguration)), integrationEventHandler(integrationEventHandler), - ownership(ownership), standSelectedCallbackId(standSelectedCallbackId) + colourConfiguration(std::move(options.colourConfiguration)), integrationEventHandler(integrationEventHandler), + ownership(ownership), standSelectedCallbackId(options.standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index cc89f8d54..d4acc851a 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -37,6 +37,12 @@ namespace UKControllerPlugin::Stands { public Integration::IntegrationActionProcessor { public: + struct ConstructorOptions + { + int standSelectedCallbackId; + std::shared_ptr colourConfiguration; + }; + StandEventHandler( const UKControllerPlugin::Api::ApiInterface& api, TaskManager::TaskRunnerInterface& taskRunner, @@ -44,8 +50,7 @@ namespace UKControllerPlugin::Stands { Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId, - std::shared_ptr colourConfiguration); + ConstructorOptions options); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 374507c46..4da00b878 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -49,8 +49,7 @@ namespace UKControllerPlugin::Stands { *container.integrationModuleContainer->outboundMessageHandler, container.airfieldOwnership, stands, - standSelectedCallbackId, - colourConfiguration); + StandEventHandler::ConstructorOptions{standSelectedCallbackId, colourConfiguration}); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( From e5850526eae0889e1ae93ae3219a55e733a5a2c9 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 09:42:20 +0000 Subject: [PATCH 29/59] Build fix for test --- test/plugin/stands/StandEventHandlerTest.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index ade56520e..81cdaab16 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -67,7 +67,13 @@ namespace UKControllerPluginTest { colourConfiguration(std::make_shared(userSetting)), tagData(flightplan, radarTarget, 110, 1, itemString, &euroscopeColourCode, &tagColour, &fontSize), handler( - api, taskRunner, plugin, mockIntegration, airfieldOwnership, GetStands(), 1, colourConfiguration) + api, + taskRunner, + plugin, + mockIntegration, + airfieldOwnership, + GetStands(), + StandEventHandler::ConstructorOptions{1, colourConfiguration}) { ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); ON_CALL(this->mockUserSettingProvider, KeyExists(_)).WillByDefault(Return(false)); From b1d430b405ba25be163e0acf90c8a4ac96395465 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 10:01:01 +0000 Subject: [PATCH 30/59] Woops Tag overlap --- docs/TAG_ITEMS.md | 2 +- src/plugin/stands/StandEventHandler.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/TAG_ITEMS.md b/docs/TAG_ITEMS.md index c0beac924..c9f9ba5a7 100644 --- a/docs/TAG_ITEMS.md +++ b/docs/TAG_ITEMS.md @@ -32,4 +32,4 @@ 130 - Missed Approach Indicator 131 - Relevant ECFMP Flow Measures 132 - Glideslope Deviation -132 - Stand Assignment Source +133 - Stand Assignment Source diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index d4acc851a..0a40eda3b 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -106,7 +106,7 @@ namespace UKControllerPlugin::Stands { // Tag item IDs for stand display and source indication inline static const int assignedStandTagItemId = 110; - inline static const int standAssignmentSourceTagItemId = 132; + inline static const int standAssignmentSourceTagItemId = 133; private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); From d0cd44713d3d71322251f7b2aab12978d2613b69 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 10:27:42 +0000 Subject: [PATCH 31/59] Correct tests and rename Web Services to Technology --- docs/UserGuide/GettingHelp/Help.md | 2 +- src/loader/dllmain.cpp | 4 ++-- src/loader/loader/loader.cpp | 8 +++---- src/plugin/api/ApiConfigurationMenuItem.cpp | 2 +- src/plugin/bootstrap/DllInterface.cpp | 4 ++-- src/utils/api/ApiAuthChecker.cpp | 2 +- test/plugin/stands/StandEventHandlerTest.cpp | 22 +++++++++++--------- 7 files changed, 23 insertions(+), 21 deletions(-) diff --git a/docs/UserGuide/GettingHelp/Help.md b/docs/UserGuide/GettingHelp/Help.md index c51e9cbc2..c56c206d1 100644 --- a/docs/UserGuide/GettingHelp/Help.md +++ b/docs/UserGuide/GettingHelp/Help.md @@ -2,5 +2,5 @@ To get help with the UK Controller Plugin, you have a number of options: -- Submitting a ticket to Web Services on the [VATSIM UK Helpdesk](https://helpdesk.vatsim.uk) +- Submitting a ticket to Technology on the [VATSIM UK Helpdesk](https://helpdesk.vatsim.uk) - Asking on the `#uk_controller_plugin_help` channel on the VATSIM UK Discord server diff --git a/src/loader/dllmain.cpp b/src/loader/dllmain.cpp index 1ecaa5503..d178b912b 100644 --- a/src/loader/dllmain.cpp +++ b/src/loader/dllmain.cpp @@ -61,7 +61,7 @@ UKCP_LOADER_API void EuroScopePlugInInit(EuroScopePlugIn::CPlugIn** ppPlugInInst LogError("Failed to load plugin binary"); UnloadPluginLibrary(pluginDllInstance, *windows); std::wstring message = L"Unable to load the UKControllerPluginCore DLL.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n\r\n"; auto lastError = GetLastError(); if (lastError == 126 || lastError == 127 || lastError == 128) { @@ -80,7 +80,7 @@ UKCP_LOADER_API void EuroScopePlugInInit(EuroScopePlugIn::CPlugIn** ppPlugInInst EuroScopePlugIn::CPlugIn* pluginInstance = LoadPlugin(pluginDllInstance, *windows); if (!pluginInstance) { std::wstring message = L"Unable to load the plugin from the core binary.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n"; MessageBox(GetActiveWindow(), message.c_str(), L"UKCP Bootstrap Failed", MB_OK | MB_ICONSTOP); throw std::exception("UKCP broke"); diff --git a/src/loader/loader/loader.cpp b/src/loader/loader/loader.cpp index ef530d3c1..e68ad177d 100644 --- a/src/loader/loader/loader.cpp +++ b/src/loader/loader/loader.cpp @@ -18,7 +18,7 @@ void RunUpdater(UKControllerPlugin::Windows::WinApiInterface& windows) if (!updaterHandle) { LogInfo("Unable to run the updater, binary does not exist."); std::wstring message = L"Unable to start updater.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n"; windows.OpenMessageBox(message.c_str(), L"UKCP Update Failed", MB_OK | MB_ICONSTOP); throw std::exception("UKCP broke"); @@ -60,7 +60,7 @@ LoadPlugin(HINSTANCE pluginLibraryHandle, UKControllerPlugin::Windows::WinApiInt if (!LoadPlugin) { LogError("Cannot find LoadPlugin function in Core binary"); std::wstring message = L"Unable find LoadPlugin function in Core Binary.\r\n\r\n"; - message += L"Please contact the Web Services Department."; + message += L"Please contact the Technology Department."; DisplayLoaderError(windows, message); return nullptr; } @@ -82,7 +82,7 @@ void UnloadPlugin(HINSTANCE pluginLibraryHandle, UKControllerPlugin::Windows::Wi if (!UnloadPlugin) { LogError("Cannot find UnloadPlugin function in Core binary"); std::wstring message = L"Unable find UnloadPlugin function in Core Binary.\r\n\r\n"; - message += L"Please contact the Web Services Department."; + message += L"Please contact the Technology Department."; DisplayLoaderError(windows, message); return; } @@ -149,7 +149,7 @@ bool DisplayFirstTimeDownloadMessage(UKControllerPlugin::Windows::WinApiInterfac void DisplayFirstTimeDownloadFailedMessage(UKControllerPlugin::Windows::WinApiInterface& windows) { std::wstring message = L"Unable to perform first time download of the UKCP updater.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n"; DisplayLoaderError(windows, message); } diff --git a/src/plugin/api/ApiConfigurationMenuItem.cpp b/src/plugin/api/ApiConfigurationMenuItem.cpp index e3ad10294..eb122d40d 100644 --- a/src/plugin/api/ApiConfigurationMenuItem.cpp +++ b/src/plugin/api/ApiConfigurationMenuItem.cpp @@ -39,7 +39,7 @@ namespace UKControllerPlugin::Api { if (UKControllerPluginUtils::Http::IsAuthenticationError(exception.StatusCode())) { windows.OpenMessageBox( L"API authentication failed. Please try to replace your credentials again. " - "If this problem persists, please contact the Web Services Department. Some " + "If this problem persists, please contact the Technology Department. Some " "functionality such as stand and squawk allocations may not work as expected.", L"UKCP API Config Invalid", MB_OK | MB_ICONWARNING); diff --git a/src/plugin/bootstrap/DllInterface.cpp b/src/plugin/bootstrap/DllInterface.cpp index b7e246718..a874ed59f 100644 --- a/src/plugin/bootstrap/DllInterface.cpp +++ b/src/plugin/bootstrap/DllInterface.cpp @@ -44,7 +44,7 @@ UKCP_CORE_API auto LoadPlugin() -> EuroScopePlugIn::CPlugIn* std::string typeId = typeid(e).name(); std::wstring message = L"Exception thrown when bootstrapping UKCP.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n"; message += L"Type: " + std::wstring(typeId.cbegin(), typeId.cend()) + L"\r\n"; message += L"Message: " + std::wstring(what.cbegin(), what.cend()) + L"\r\n"; ; @@ -71,7 +71,7 @@ UKCP_CORE_API void UnloadPlugin(void) std::string what = e.what(); std::wstring message = L"Exception thrown when shutting down UKCP.\r\n"; - message += L"Please contact the VATSIM UK Web Services Department.\r\n"; + message += L"Please contact the VATSIM UK Technology Department.\r\n"; message += L"Message: " + std::wstring(what.cbegin(), what.cend()); MessageBox(GetActiveWindow(), message.c_str(), L"UKCP Shutdown Failed", MB_OK | MB_ICONSTOP); diff --git a/src/utils/api/ApiAuthChecker.cpp b/src/utils/api/ApiAuthChecker.cpp index a6379c2c7..e91a1f0da 100644 --- a/src/utils/api/ApiAuthChecker.cpp +++ b/src/utils/api/ApiAuthChecker.cpp @@ -51,7 +51,7 @@ namespace UKControllerPlugin { // Something weird is going on. std::wstring message; message += L"Unable to access the API. Core functionality will be disabled. \r\n\r\n"; - message += L"If the problem persists, please contact the VATSIM UK Web Services Department."; + message += L"If the problem persists, please contact the VATSIM UK Technology Department."; windows.OpenMessageBox(message.c_str(), L"UKCP API Availability Warning", MB_OK | MB_ICONWARNING); LogCritical("The API returned a non-standard response when authenticating: " + std::string(api.what())); return false; diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 81cdaab16..7341b2b66 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -100,7 +100,7 @@ namespace UKControllerPluginTest { return TagData( this->flightplan, this->radarTarget, - 132, + StandEventHandler::standAssignmentSourceTagItemId, 1, this->itemString, &this->euroscopeColourCode, @@ -108,7 +108,7 @@ namespace UKControllerPluginTest { &this->fontSize); } - void ExpectTagItem132Shorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) + void ExpectSourceTagItemShorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) { this->SetAssignedStandWithSource(1, source); auto sourceTagData = this->CreateSourceTagData(); @@ -124,7 +124,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); } - void ExpectTagItem132ColourForSource(StandAssignmentSource::Source source) + void ExpectSourceTagItemColourForSource(StandAssignmentSource::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -334,22 +334,24 @@ namespace UKControllerPluginTest { EXPECT_EQ("Foooooo", this->tagData.GetItemString()); } - TEST_F(StandEventHandlerTest, ItReturnsDescriptionForTagItem132) + TEST_F(StandEventHandlerTest, ItReturnsDescriptionForSourceTagItem) { - EXPECT_EQ("Stand Assignment Source", this->handler.GetTagItemDescription(132)); + EXPECT_EQ( + "Stand Assignment Source", + this->handler.GetTagItemDescription(StandEventHandler::standAssignmentSourceTagItemId)); } - TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForTagItem132) + TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForSourceTagItem) { const auto sources = AllSources(); const std::array expectedShorthand = {"USER", "RES ", "VAA ", "AUTO"}; for (size_t i = 0; i < std::size(sources); ++i) { - this->ExpectTagItem132Shorthand(sources[i], expectedShorthand[i]); + this->ExpectSourceTagItemShorthand(sources[i], expectedShorthand[i]); } } - TEST_F(StandEventHandlerTest, ItReturnsNothingForTagItem132IfStandNotAssigned) + TEST_F(StandEventHandlerTest, ItReturnsNothingForSourceTagItemIfStandNotAssigned) { auto sourceTagData = this->CreateSourceTagData(); this->handler.SetTagItemData(sourceTagData); @@ -365,12 +367,12 @@ namespace UKControllerPluginTest { } } - TEST_F(StandEventHandlerTest, TagItem132UsesSourceColours) + TEST_F(StandEventHandlerTest, SourceTagItemUsesSourceColours) { const auto sources = AllSources(); for (const auto& source : sources) { - this->ExpectTagItem132ColourForSource(source); + this->ExpectSourceTagItemColourForSource(source); } } From b6b1b914fceb01777c028e77324effbb71850ab6 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 10:37:33 +0000 Subject: [PATCH 32/59] Formatting --- test/plugin/stands/StandEventHandlerTest.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 7341b2b66..15b62dfc1 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -108,7 +108,8 @@ namespace UKControllerPluginTest { &this->fontSize); } - void ExpectSourceTagItemShorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) + void + ExpectSourceTagItemShorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) { this->SetAssignedStandWithSource(1, source); auto sourceTagData = this->CreateSourceTagData(); From e10e3fb9aff48b7f792912ab7add14837db83f95 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Sun, 22 Mar 2026 10:52:19 +0000 Subject: [PATCH 33/59] revert web services change --- docs/UserGuide/GettingHelp/Help.md | 2 +- src/loader/dllmain.cpp | 4 ++-- src/loader/loader/loader.cpp | 8 ++++---- src/plugin/api/ApiConfigurationMenuItem.cpp | 2 +- src/plugin/bootstrap/DllInterface.cpp | 4 ++-- src/utils/api/ApiAuthChecker.cpp | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/UserGuide/GettingHelp/Help.md b/docs/UserGuide/GettingHelp/Help.md index c56c206d1..c51e9cbc2 100644 --- a/docs/UserGuide/GettingHelp/Help.md +++ b/docs/UserGuide/GettingHelp/Help.md @@ -2,5 +2,5 @@ To get help with the UK Controller Plugin, you have a number of options: -- Submitting a ticket to Technology on the [VATSIM UK Helpdesk](https://helpdesk.vatsim.uk) +- Submitting a ticket to Web Services on the [VATSIM UK Helpdesk](https://helpdesk.vatsim.uk) - Asking on the `#uk_controller_plugin_help` channel on the VATSIM UK Discord server diff --git a/src/loader/dllmain.cpp b/src/loader/dllmain.cpp index d178b912b..1ecaa5503 100644 --- a/src/loader/dllmain.cpp +++ b/src/loader/dllmain.cpp @@ -61,7 +61,7 @@ UKCP_LOADER_API void EuroScopePlugInInit(EuroScopePlugIn::CPlugIn** ppPlugInInst LogError("Failed to load plugin binary"); UnloadPluginLibrary(pluginDllInstance, *windows); std::wstring message = L"Unable to load the UKControllerPluginCore DLL.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n\r\n"; auto lastError = GetLastError(); if (lastError == 126 || lastError == 127 || lastError == 128) { @@ -80,7 +80,7 @@ UKCP_LOADER_API void EuroScopePlugInInit(EuroScopePlugIn::CPlugIn** ppPlugInInst EuroScopePlugIn::CPlugIn* pluginInstance = LoadPlugin(pluginDllInstance, *windows); if (!pluginInstance) { std::wstring message = L"Unable to load the plugin from the core binary.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n"; MessageBox(GetActiveWindow(), message.c_str(), L"UKCP Bootstrap Failed", MB_OK | MB_ICONSTOP); throw std::exception("UKCP broke"); diff --git a/src/loader/loader/loader.cpp b/src/loader/loader/loader.cpp index e68ad177d..ef530d3c1 100644 --- a/src/loader/loader/loader.cpp +++ b/src/loader/loader/loader.cpp @@ -18,7 +18,7 @@ void RunUpdater(UKControllerPlugin::Windows::WinApiInterface& windows) if (!updaterHandle) { LogInfo("Unable to run the updater, binary does not exist."); std::wstring message = L"Unable to start updater.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n"; windows.OpenMessageBox(message.c_str(), L"UKCP Update Failed", MB_OK | MB_ICONSTOP); throw std::exception("UKCP broke"); @@ -60,7 +60,7 @@ LoadPlugin(HINSTANCE pluginLibraryHandle, UKControllerPlugin::Windows::WinApiInt if (!LoadPlugin) { LogError("Cannot find LoadPlugin function in Core binary"); std::wstring message = L"Unable find LoadPlugin function in Core Binary.\r\n\r\n"; - message += L"Please contact the Technology Department."; + message += L"Please contact the Web Services Department."; DisplayLoaderError(windows, message); return nullptr; } @@ -82,7 +82,7 @@ void UnloadPlugin(HINSTANCE pluginLibraryHandle, UKControllerPlugin::Windows::Wi if (!UnloadPlugin) { LogError("Cannot find UnloadPlugin function in Core binary"); std::wstring message = L"Unable find UnloadPlugin function in Core Binary.\r\n\r\n"; - message += L"Please contact the Technology Department."; + message += L"Please contact the Web Services Department."; DisplayLoaderError(windows, message); return; } @@ -149,7 +149,7 @@ bool DisplayFirstTimeDownloadMessage(UKControllerPlugin::Windows::WinApiInterfac void DisplayFirstTimeDownloadFailedMessage(UKControllerPlugin::Windows::WinApiInterface& windows) { std::wstring message = L"Unable to perform first time download of the UKCP updater.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n"; DisplayLoaderError(windows, message); } diff --git a/src/plugin/api/ApiConfigurationMenuItem.cpp b/src/plugin/api/ApiConfigurationMenuItem.cpp index eb122d40d..e3ad10294 100644 --- a/src/plugin/api/ApiConfigurationMenuItem.cpp +++ b/src/plugin/api/ApiConfigurationMenuItem.cpp @@ -39,7 +39,7 @@ namespace UKControllerPlugin::Api { if (UKControllerPluginUtils::Http::IsAuthenticationError(exception.StatusCode())) { windows.OpenMessageBox( L"API authentication failed. Please try to replace your credentials again. " - "If this problem persists, please contact the Technology Department. Some " + "If this problem persists, please contact the Web Services Department. Some " "functionality such as stand and squawk allocations may not work as expected.", L"UKCP API Config Invalid", MB_OK | MB_ICONWARNING); diff --git a/src/plugin/bootstrap/DllInterface.cpp b/src/plugin/bootstrap/DllInterface.cpp index a874ed59f..b7e246718 100644 --- a/src/plugin/bootstrap/DllInterface.cpp +++ b/src/plugin/bootstrap/DllInterface.cpp @@ -44,7 +44,7 @@ UKCP_CORE_API auto LoadPlugin() -> EuroScopePlugIn::CPlugIn* std::string typeId = typeid(e).name(); std::wstring message = L"Exception thrown when bootstrapping UKCP.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n"; message += L"Type: " + std::wstring(typeId.cbegin(), typeId.cend()) + L"\r\n"; message += L"Message: " + std::wstring(what.cbegin(), what.cend()) + L"\r\n"; ; @@ -71,7 +71,7 @@ UKCP_CORE_API void UnloadPlugin(void) std::string what = e.what(); std::wstring message = L"Exception thrown when shutting down UKCP.\r\n"; - message += L"Please contact the VATSIM UK Technology Department.\r\n"; + message += L"Please contact the VATSIM UK Web Services Department.\r\n"; message += L"Message: " + std::wstring(what.cbegin(), what.cend()); MessageBox(GetActiveWindow(), message.c_str(), L"UKCP Shutdown Failed", MB_OK | MB_ICONSTOP); diff --git a/src/utils/api/ApiAuthChecker.cpp b/src/utils/api/ApiAuthChecker.cpp index e91a1f0da..a6379c2c7 100644 --- a/src/utils/api/ApiAuthChecker.cpp +++ b/src/utils/api/ApiAuthChecker.cpp @@ -51,7 +51,7 @@ namespace UKControllerPlugin { // Something weird is going on. std::wstring message; message += L"Unable to access the API. Core functionality will be disabled. \r\n\r\n"; - message += L"If the problem persists, please contact the VATSIM UK Technology Department."; + message += L"If the problem persists, please contact the VATSIM UK Web Services Department."; windows.OpenMessageBox(message.c_str(), L"UKCP API Availability Warning", MB_OK | MB_ICONWARNING); LogCritical("The API returned a non-standard response when authenticating: " + std::string(api.what())); return false; From 8cdca490326e85940e0e4c5e6740934fab84701a Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 8 Apr 2026 08:10:47 +0100 Subject: [PATCH 34/59] Potential final push --- src/plugin/stands/StandAssignmentSource.h | 17 ++--- .../stands/StandColourConfiguration.cpp | 66 +++++++++---------- src/plugin/stands/StandColourConfiguration.h | 4 +- src/plugin/stands/StandEventHandler.cpp | 50 +++++++------- src/plugin/stands/StandEventHandler.h | 20 +++--- src/plugin/stands/StandModule.cpp | 10 +-- 6 files changed, 81 insertions(+), 86 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index 587013bad..3402c360e 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -6,10 +6,11 @@ namespace UKControllerPlugin::Stands { /* Represents a stand assignment with its source (how it was assigned). */ - struct StandAssignmentSource + struct StandAssignment { enum class Source { + Unknown, User, ReservationAllocator, VaaAllocator, @@ -21,17 +22,13 @@ namespace UKControllerPlugin::Stands { // The source of the assignment (user, reservation_allocator, vaa_allocator, system_auto) Source source; - // The four possible sources for stand assignments - static constexpr Source SOURCE_USER = Source::User; - static constexpr Source SOURCE_RESERVATION_ALLOCATOR = Source::ReservationAllocator; - static constexpr Source SOURCE_VAA_ALLOCATOR = Source::VaaAllocator; - static constexpr Source SOURCE_SYSTEM = Source::SystemAuto; - [[nodiscard]] static constexpr auto ToString(Source source) -> std::string_view { using enum Source; switch (source) { + case Unknown: + return "unknown"; case User: return "user"; case ReservationAllocator: @@ -59,7 +56,11 @@ namespace UKControllerPlugin::Stands { return VaaAllocator; } - return SystemAuto; + if (source == "system_auto") { + return SystemAuto; + } + + return Unknown; } }; } // namespace UKControllerPlugin::Stands diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 95e5e4414..c2b3e94d3 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,18 +2,36 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" +#include #include namespace UKControllerPlugin::Stands { namespace { - auto DefaultSourceColours() -> std::map + struct SourceColourDefault { - return { - {StandAssignmentSource::SOURCE_USER, RGB(255, 255, 255)}, - {StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR, RGB(255, 255, 0)}, - {StandAssignmentSource::SOURCE_VAA_ALLOCATOR, RGB(0, 255, 255)}, - {StandAssignmentSource::SOURCE_SYSTEM, RGB(180, 180, 180)}}; + StandAssignment::Source source; + COLORREF defaultColour; + }; + + constexpr std::array sourceColourDefaults = {{ + {StandAssignment::Source::User, StandColourConfiguration::DEFAULT_USER_COLOUR}, + {StandAssignment::Source::ReservationAllocator, StandColourConfiguration::DEFAULT_RESERVATION_COLOUR}, + {StandAssignment::Source::VaaAllocator, StandColourConfiguration::DEFAULT_VAA_COLOUR}, + {StandAssignment::Source::SystemAuto, StandColourConfiguration::DEFAULT_SYSTEM_COLOUR}, + }}; + + auto LoadColourFromUserSettings( + UKControllerPlugin::Euroscope::UserSetting& userSetting, + std::map& sourceColours, + StandAssignment::Source source, + COLORREF defaultColour) -> void + { + const std::string key = std::string(StandColourConfiguration::SETTING_PREFIX) + + std::string(StandAssignment::ToString(source)); + if (userSetting.HasEntry(key)) { + sourceColours[source] = userSetting.GetColourEntry(key, defaultColour); + } } } // namespace @@ -27,12 +45,16 @@ namespace UKControllerPlugin::Stands { } StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) - : userSetting(userSetting), sourceColours(DefaultSourceColours()) + : userSetting(userSetting), + sourceColours({{StandAssignment::Source::User, DEFAULT_USER_COLOUR}, + {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, + {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, + {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}}) { LoadFromUserSettings(); } - auto StandColourConfiguration::GetColourForSource(StandAssignmentSource::Source source) const -> COLORREF + auto StandColourConfiguration::GetColourForSource(StandAssignment::Source source) const -> COLORREF { if (auto it = sourceColours.find(source); it != sourceColours.cend()) { return it->second; @@ -47,32 +69,8 @@ namespace UKControllerPlugin::Stands { return; } - std::string key = std::string(SETTING_PREFIX) + - std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_USER)); - if (this->userSetting->HasEntry(key)) { - sourceColours[StandAssignmentSource::SOURCE_USER] = - this->userSetting->GetColourEntry(key, DEFAULT_USER_COLOUR); - } - - key = std::string(SETTING_PREFIX) + - std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR)); - if (this->userSetting->HasEntry(key)) { - sourceColours[StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR] = - this->userSetting->GetColourEntry(key, DEFAULT_RESERVATION_COLOUR); - } - - key = std::string(SETTING_PREFIX) + - std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_VAA_ALLOCATOR)); - if (this->userSetting->HasEntry(key)) { - sourceColours[StandAssignmentSource::SOURCE_VAA_ALLOCATOR] = - this->userSetting->GetColourEntry(key, DEFAULT_VAA_COLOUR); - } - - key = std::string(SETTING_PREFIX) + - std::string(StandAssignmentSource::ToString(StandAssignmentSource::SOURCE_SYSTEM)); - if (this->userSetting->HasEntry(key)) { - sourceColours[StandAssignmentSource::SOURCE_SYSTEM] = - this->userSetting->GetColourEntry(key, DEFAULT_SYSTEM_COLOUR); + for (const auto& entry : sourceColourDefaults) { + LoadColourFromUserSettings(*this->userSetting, this->sourceColours, entry.source, entry.defaultColour); } LogInfo("Loaded stand assignment source colours from UserSettings"); diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 75ecaddc1..20d1511ea 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -24,7 +24,7 @@ namespace UKControllerPlugin::Stands { Get the colour for a given assignment source. Returns a default grey if source is not found or not set. */ - [[nodiscard]] auto GetColourForSource(StandAssignmentSource::Source source) const -> COLORREF; + [[nodiscard]] auto GetColourForSource(StandAssignment::Source source) const -> COLORREF; /* Load colours from UserSettings, with fallback to defaults. @@ -38,7 +38,7 @@ namespace UKControllerPlugin::Stands { UKControllerPlugin::Euroscope::UserSetting* userSetting; // Map of source to RGB colour - std::map sourceColours; + std::map sourceColours; // Default colour (grey) for unknown sources static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index ceb8e0fcf..e88638691 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -31,13 +31,16 @@ namespace UKControllerPlugin::Stands { const ApiInterface& api, TaskRunnerInterface& taskRunner, EuroscopePluginLoopbackInterface& plugin, + UKControllerPlugin::Euroscope::UserSetting* userSetting, Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - ConstructorOptions options) + int standSelectedCallbackId) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - colourConfiguration(std::move(options.colourConfiguration)), integrationEventHandler(integrationEventHandler), - ownership(ownership), standSelectedCallbackId(options.standSelectedCallbackId) + colourConfiguration(userSetting ? std::make_shared(*userSetting) + : std::make_shared()), + integrationEventHandler(integrationEventHandler), ownership(ownership), + standSelectedCallbackId(standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } @@ -117,7 +120,7 @@ namespace UKControllerPlugin::Stands { } // Assign that stand - this->AssignStandToAircraft(callsign, *stand, StandAssignmentSource::SOURCE_USER); + this->AssignStandToAircraft(callsign, *stand, StandAssignment::Source::User); int standId = stand->id; auto callsignForRequest = callsign; @@ -219,16 +222,16 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId) { - this->standAssignments[callsign] = {standId, StandAssignmentSource::SOURCE_SYSTEM}; + this->standAssignments[callsign] = {standId, StandAssignment::Source::SystemAuto}; } void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, const std::string& source) { - this->SetAssignedStand(callsign, standId, StandAssignmentSource::FromString(source)); + this->SetAssignedStand(callsign, standId, StandAssignment::FromString(source)); } void - StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, StandAssignmentSource::Source source) + StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, StandAssignment::Source source) { this->standAssignments[callsign] = {standId, source}; } @@ -320,7 +323,10 @@ namespace UKControllerPlugin::Stands { tagData.SetItemString(stand->identifier); } else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); - } else { + } + + if (tagData.GetItemCode() != assignedStandTagItemId && + tagData.GetItemCode() != standAssignmentSourceTagItemId) { return; } tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); @@ -334,27 +340,27 @@ namespace UKControllerPlugin::Stands { } auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) - -> StandAssignmentSource::Source + -> StandAssignment::Source { if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { - return StandAssignmentSource::FromString(message.at("assignment_source").get()); + return StandAssignment::FromString(message.at("assignment_source").get()); } - return StandAssignmentSource::SOURCE_SYSTEM; + return StandAssignment::Source::Unknown; } - auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignmentSource::Source source) -> std::string + auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { - if (source == StandAssignmentSource::SOURCE_USER) { + switch (source) { + case StandAssignment::Source::Unknown: + return "UNK "; + case StandAssignment::Source::User: return "USER"; - } - if (source == StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR) { + case StandAssignment::Source::ReservationAllocator: return "RES "; - } - if (source == StandAssignmentSource::SOURCE_VAA_ALLOCATOR) { + case StandAssignment::Source::VaaAllocator: return "VAA "; - } - if (source == StandAssignmentSource::SOURCE_SYSTEM) { + case StandAssignment::Source::SystemAuto: return "AUTO"; } return "UNK "; @@ -521,11 +527,11 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) { - this->AssignStandToAircraft(callsign, stand, StandAssignmentSource::SOURCE_SYSTEM); + this->AssignStandToAircraft(callsign, stand, StandAssignment::Source::SystemAuto); } void StandEventHandler::AssignStandToAircraft( - const std::string& callsign, const Stand& stand, StandAssignmentSource::Source source) + const std::string& callsign, const Stand& stand, StandAssignment::Source source) { this->AnnotateFlightStrip(callsign, stand.id); this->standAssignments[callsign] = {stand.id, source}; @@ -537,7 +543,7 @@ namespace UKControllerPlugin::Stands { stand.airfieldCode, stand.identifier, callsign, - StandAssignmentSource::ToString(source)); + StandAssignment::ToString(source)); LogInfo(logMessage); } auto StandEventHandler::ActionsToProcess() const -> std::vector diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index 0a40eda3b..a8d2eae6c 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -15,6 +15,7 @@ namespace UKControllerPlugin { } // namespace Api namespace Euroscope { class EuroscopePluginLoopbackInterface; + class UserSetting; } // namespace Euroscope namespace Ownership { class AirfieldServiceProviderCollection; @@ -37,20 +38,15 @@ namespace UKControllerPlugin::Stands { public Integration::IntegrationActionProcessor { public: - struct ConstructorOptions - { - int standSelectedCallbackId; - std::shared_ptr colourConfiguration; - }; - StandEventHandler( const UKControllerPlugin::Api::ApiInterface& api, TaskManager::TaskRunnerInterface& taskRunner, Euroscope::EuroscopePluginLoopbackInterface& plugin, + UKControllerPlugin::Euroscope::UserSetting* userSetting, Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - ConstructorOptions options); + int standSelectedCallbackId); [[nodiscard]] auto ActionsToProcess() const -> std::vector override; void ProcessAction( std::shared_ptr message, @@ -74,7 +70,7 @@ namespace UKControllerPlugin::Stands { void RemoveFlightStripAnnotation(const std::string& callsign) const; void SetAssignedStand(const std::string& callsign, int standId); void SetAssignedStand(const std::string& callsign, int standId, const std::string& source); - void SetAssignedStand(const std::string& callsign, int standId, StandAssignmentSource::Source source); + void SetAssignedStand(const std::string& callsign, int standId, StandAssignment::Source source); void StandSelected(int functionId, std::string context, RECT); void DisplayStandAssignmentEditBox( UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan, @@ -111,7 +107,7 @@ namespace UKControllerPlugin::Stands { private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); void - AssignStandToAircraft(const std::string& callsign, const Stand& stand, StandAssignmentSource::Source source); + AssignStandToAircraft(const std::string& callsign, const Stand& stand, StandAssignment::Source source); [[nodiscard]] auto AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; @@ -122,8 +118,8 @@ namespace UKControllerPlugin::Stands { void UnassignStandForAircraft(const std::string& callsign); [[nodiscard]] auto AssignmentMessageValid(const nlohmann::json& message) const -> bool; [[nodiscard]] static auto GetAssignmentSourceFromMessage(const nlohmann::json& message) - -> StandAssignmentSource::Source; - [[nodiscard]] static auto GetAssignmentSourceShorthand(StandAssignmentSource::Source source) -> std::string; + -> StandAssignment::Source; + [[nodiscard]] static auto GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string; auto CanAssignStand(UKControllerPlugin::Euroscope::EuroScopeCFlightPlanInterface& flightplan) const -> bool; static auto UnassignmentMessageValid(const nlohmann::json& message) -> bool; auto @@ -147,7 +143,7 @@ namespace UKControllerPlugin::Stands { std::set stands; // The currently assigned stands and who they are assigned to, with source information - std::map> standAssignments; + std::map> standAssignments; // Colour configuration for stand assignment sources std::shared_ptr colourConfiguration; diff --git a/src/plugin/stands/StandModule.cpp b/src/plugin/stands/StandModule.cpp index 4da00b878..2ae48fece 100644 --- a/src/plugin/stands/StandModule.cpp +++ b/src/plugin/stands/StandModule.cpp @@ -2,7 +2,6 @@ #include "StandEventHandler.h" #include "StandModule.h" #include "StandSerializer.h" -#include "StandColourConfiguration.h" #include "bootstrap/PersistenceContainer.h" #include "dependency/DependencyLoaderInterface.h" #include "euroscope/CallbackFunction.h" @@ -34,22 +33,17 @@ namespace UKControllerPlugin::Stands { std::set stands; from_json(dependencies.LoadDependency(GetDependencyKey(), nlohmann::json::object()), stands); - // Load stand colour configuration from EuroScope user settings - // If pluginUserSettingHandler is not available (e.g., in tests), creates default-only config - auto colourConfiguration = container.pluginUserSettingHandler - ? std::make_shared(*container.pluginUserSettingHandler) - : std::make_shared(); - // Create the event handler auto standSelectedCallbackId = container.pluginFunctionHandlers->ReserveNextDynamicFunctionId(); std::shared_ptr eventHandler = std::make_shared( *container.api, *container.taskRunner, *container.plugin, + container.pluginUserSettingHandler.get(), *container.integrationModuleContainer->outboundMessageHandler, container.airfieldOwnership, stands, - StandEventHandler::ConstructorOptions{standSelectedCallbackId, colourConfiguration}); + standSelectedCallbackId); // Create a tag function for the stand assignment popup list and add a callback TagFunction openStandAssignmentPopupMenu( From 5a0b9e50f74e8712678a2008f82b8e4f771c9a1b Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 8 Apr 2026 08:13:42 +0100 Subject: [PATCH 35/59] Formatting --- .../stands/StandColourConfiguration.cpp | 14 +++++++------- src/plugin/stands/StandEventHandler.cpp | 19 +++++++++---------- src/plugin/stands/StandEventHandler.h | 3 +-- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index c2b3e94d3..4c3d867bc 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -27,8 +27,8 @@ namespace UKControllerPlugin::Stands { StandAssignment::Source source, COLORREF defaultColour) -> void { - const std::string key = std::string(StandColourConfiguration::SETTING_PREFIX) + - std::string(StandAssignment::ToString(source)); + const std::string key = + std::string(StandColourConfiguration::SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); if (userSetting.HasEntry(key)) { sourceColours[source] = userSetting.GetColourEntry(key, defaultColour); } @@ -45,11 +45,11 @@ namespace UKControllerPlugin::Stands { } StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) - : userSetting(userSetting), - sourceColours({{StandAssignment::Source::User, DEFAULT_USER_COLOUR}, - {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, - {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, - {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}}) + : userSetting(userSetting), sourceColours( + {{StandAssignment::Source::User, DEFAULT_USER_COLOUR}, + {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, + {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, + {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}}) { LoadFromUserSettings(); } diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index e88638691..1e033dfec 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -31,16 +31,17 @@ namespace UKControllerPlugin::Stands { const ApiInterface& api, TaskRunnerInterface& taskRunner, EuroscopePluginLoopbackInterface& plugin, - UKControllerPlugin::Euroscope::UserSetting* userSetting, + UKControllerPlugin::Euroscope::UserSetting* userSetting, Integration::OutboundIntegrationEventHandler& integrationEventHandler, std::shared_ptr ownership, std::set stands, - int standSelectedCallbackId) + int standSelectedCallbackId) : api(api), taskRunner(taskRunner), plugin(plugin), stands(std::move(stands)), - colourConfiguration(userSetting ? std::make_shared(*userSetting) - : std::make_shared()), - integrationEventHandler(integrationEventHandler), ownership(ownership), - standSelectedCallbackId(standSelectedCallbackId) + colourConfiguration( + userSetting ? std::make_shared(*userSetting) + : std::make_shared()), + integrationEventHandler(integrationEventHandler), ownership(ownership), + standSelectedCallbackId(standSelectedCallbackId) { assert(this->ownership != nullptr && "Ownership must not be null"); } @@ -230,8 +231,7 @@ namespace UKControllerPlugin::Stands { this->SetAssignedStand(callsign, standId, StandAssignment::FromString(source)); } - void - StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, StandAssignment::Source source) + void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, StandAssignment::Source source) { this->standAssignments[callsign] = {standId, source}; } @@ -339,8 +339,7 @@ namespace UKControllerPlugin::Stands { this->stands.find(message.at("stand_id").get()) != this->stands.cend(); } - auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) - -> StandAssignment::Source + auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source { if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { return StandAssignment::FromString(message.at("assignment_source").get()); diff --git a/src/plugin/stands/StandEventHandler.h b/src/plugin/stands/StandEventHandler.h index a8d2eae6c..5b9523940 100644 --- a/src/plugin/stands/StandEventHandler.h +++ b/src/plugin/stands/StandEventHandler.h @@ -106,8 +106,7 @@ namespace UKControllerPlugin::Stands { private: void AssignStandToAircraft(const std::string& callsign, const Stand& stand); - void - AssignStandToAircraft(const std::string& callsign, const Stand& stand, StandAssignment::Source source); + void AssignStandToAircraft(const std::string& callsign, const Stand& stand, StandAssignment::Source source); [[nodiscard]] auto AssignStandInApi(const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string; From a36605d9b157b1fc92c5f98d3e07241a102d5237 Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 8 Apr 2026 08:20:47 +0100 Subject: [PATCH 36/59] Fix for build and sonar --- .../stands/StandColourConfiguration.cpp | 46 +++++++------------ src/plugin/stands/StandEventHandler.cpp | 24 ++++++---- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 4c3d867bc..0a30cf347 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -7,34 +7,6 @@ namespace UKControllerPlugin::Stands { - namespace { - struct SourceColourDefault - { - StandAssignment::Source source; - COLORREF defaultColour; - }; - - constexpr std::array sourceColourDefaults = {{ - {StandAssignment::Source::User, StandColourConfiguration::DEFAULT_USER_COLOUR}, - {StandAssignment::Source::ReservationAllocator, StandColourConfiguration::DEFAULT_RESERVATION_COLOUR}, - {StandAssignment::Source::VaaAllocator, StandColourConfiguration::DEFAULT_VAA_COLOUR}, - {StandAssignment::Source::SystemAuto, StandColourConfiguration::DEFAULT_SYSTEM_COLOUR}, - }}; - - auto LoadColourFromUserSettings( - UKControllerPlugin::Euroscope::UserSetting& userSetting, - std::map& sourceColours, - StandAssignment::Source source, - COLORREF defaultColour) -> void - { - const std::string key = - std::string(StandColourConfiguration::SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); - if (userSetting.HasEntry(key)) { - sourceColours[source] = userSetting.GetColourEntry(key, defaultColour); - } - } - } // namespace - StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting& setting) : StandColourConfiguration(&setting) { @@ -69,8 +41,24 @@ namespace UKControllerPlugin::Stands { return; } + struct SourceColourDefault + { + StandAssignment::Source source; + COLORREF defaultColour; + }; + + constexpr std::array sourceColourDefaults = {{ + {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, + {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, + {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, + {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}, + }}; + for (const auto& entry : sourceColourDefaults) { - LoadColourFromUserSettings(*this->userSetting, this->sourceColours, entry.source, entry.defaultColour); + const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(entry.source)); + if (this->userSetting->HasEntry(key)) { + this->sourceColours[entry.source] = this->userSetting->GetColourEntry(key, entry.defaultColour); + } } LogInfo("Loaded stand assignment source colours from UserSettings"); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 1e033dfec..2e717c356 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -109,6 +109,8 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::AssignStandInApi( const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string { + using enum StandAssignment::Source; + // Find the requested stand auto stand = std::find_if( this->stands.cbegin(), this->stands.cend(), [airfield, identifier](const Stand& stand) -> bool { @@ -121,7 +123,7 @@ namespace UKControllerPlugin::Stands { } // Assign that stand - this->AssignStandToAircraft(callsign, *stand, StandAssignment::Source::User); + this->AssignStandToAircraft(callsign, *stand, User); int standId = stand->id; auto callsignForRequest = callsign; @@ -341,25 +343,29 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source { + using enum StandAssignment::Source; + if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { return StandAssignment::FromString(message.at("assignment_source").get()); } - return StandAssignment::Source::Unknown; + return Unknown; } auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { + using enum StandAssignment::Source; + switch (source) { - case StandAssignment::Source::Unknown: + case Unknown: return "UNK "; - case StandAssignment::Source::User: + case User: return "USER"; - case StandAssignment::Source::ReservationAllocator: + case ReservationAllocator: return "RES "; - case StandAssignment::Source::VaaAllocator: + case VaaAllocator: return "VAA "; - case StandAssignment::Source::SystemAuto: + case SystemAuto: return "AUTO"; } return "UNK "; @@ -526,7 +532,9 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) { - this->AssignStandToAircraft(callsign, stand, StandAssignment::Source::SystemAuto); + using enum StandAssignment::Source; + + this->AssignStandToAircraft(callsign, stand, SystemAuto); } void StandEventHandler::AssignStandToAircraft( From b2593c66cc2189764039b88f3f84a5300e7cc1ed Mon Sep 17 00:00:00 2001 From: Daniel 'MrAdder' Green Date: Wed, 8 Apr 2026 08:35:08 +0100 Subject: [PATCH 37/59] Test fixes --- src/plugin/stands/StandEventHandler.cpp | 24 ++++++++-------- test/plugin/stands/StandEventHandlerTest.cpp | 30 +++++++------------- 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 2e717c356..e44f12c97 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -109,7 +109,7 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::AssignStandInApi( const std::string& callsign, const std::string& airfield, const std::string& identifier) -> std::string { - using enum StandAssignment::Source; + using Source = StandAssignment::Source; // Find the requested stand auto stand = std::find_if( @@ -123,7 +123,7 @@ namespace UKControllerPlugin::Stands { } // Assign that stand - this->AssignStandToAircraft(callsign, *stand, User); + this->AssignStandToAircraft(callsign, *stand, Source::User); int standId = stand->id; auto callsignForRequest = callsign; @@ -343,29 +343,29 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source { - using enum StandAssignment::Source; + using Source = StandAssignment::Source; if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { return StandAssignment::FromString(message.at("assignment_source").get()); } - return Unknown; + return Source::Unknown; } auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { - using enum StandAssignment::Source; + using Source = StandAssignment::Source; switch (source) { - case Unknown: + case Source::Unknown: return "UNK "; - case User: + case Source::User: return "USER"; - case ReservationAllocator: + case Source::ReservationAllocator: return "RES "; - case VaaAllocator: + case Source::VaaAllocator: return "VAA "; - case SystemAuto: + case Source::SystemAuto: return "AUTO"; } return "UNK "; @@ -532,9 +532,9 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) { - using enum StandAssignment::Source; + using Source = StandAssignment::Source; - this->AssignStandToAircraft(callsign, stand, SystemAuto); + this->AssignStandToAircraft(callsign, stand, Source::SystemAuto); } void StandEventHandler::AssignStandToAircraft( diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 15b62dfc1..531c43ce0 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -29,7 +29,7 @@ using UKControllerPlugin::Push::PushEventSubscription; using UKControllerPlugin::Stands::CompareStands; using UKControllerPlugin::Stands::Stand; using UKControllerPlugin::Stands::StandAssignedMessage; -using UKControllerPlugin::Stands::StandAssignmentSource; +using UKControllerPlugin::Stands::StandAssignment; using UKControllerPlugin::Stands::StandColourConfiguration; using UKControllerPlugin::Stands::StandEventHandler; using UKControllerPlugin::Stands::StandUnassignedMessage; @@ -66,14 +66,7 @@ namespace UKControllerPluginTest { userSetting(mockUserSettingProvider), colourConfiguration(std::make_shared(userSetting)), tagData(flightplan, radarTarget, 110, 1, itemString, &euroscopeColourCode, &tagColour, &fontSize), - handler( - api, - taskRunner, - plugin, - mockIntegration, - airfieldOwnership, - GetStands(), - StandEventHandler::ConstructorOptions{1, colourConfiguration}) + handler(api, taskRunner, plugin, &userSetting, mockIntegration, airfieldOwnership, GetStands(), 1) { ON_CALL(this->flightplan, GetCallsign()).WillByDefault(Return("BAW123")); ON_CALL(this->mockUserSettingProvider, KeyExists(_)).WillByDefault(Return(false)); @@ -90,7 +83,7 @@ namespace UKControllerPluginTest { return stands; } - void SetAssignedStandWithSource(int standId, StandAssignmentSource::Source source) + void SetAssignedStandWithSource(int standId, StandAssignment::Source source) { this->handler.SetAssignedStand("BAW123", standId, source); } @@ -108,8 +101,7 @@ namespace UKControllerPluginTest { &this->fontSize); } - void - ExpectSourceTagItemShorthand(StandAssignmentSource::Source source, const std::string& expectedShorthand) + void ExpectSourceTagItemShorthand(StandAssignment::Source source, const std::string& expectedShorthand) { this->SetAssignedStandWithSource(1, source); auto sourceTagData = this->CreateSourceTagData(); @@ -117,7 +109,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedShorthand, sourceTagData.GetItemString()); } - void ExpectTagItem110ColourForSource(StandAssignmentSource::Source source) + void ExpectTagItem110ColourForSource(StandAssignment::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -125,7 +117,7 @@ namespace UKControllerPluginTest { EXPECT_EQ(expectedColour, this->tagData.GetTagColour()); } - void ExpectSourceTagItemColourForSource(StandAssignmentSource::Source source) + void ExpectSourceTagItemColourForSource(StandAssignment::Source source) { this->SetAssignedStandWithSource(3, source); COLORREF expectedColour = this->colourConfiguration->GetColourForSource(source); @@ -183,13 +175,13 @@ namespace UKControllerPluginTest { return fp; } - [[nodiscard]] static auto AllSources() -> std::array + [[nodiscard]] static auto AllSources() -> std::array { return { - StandAssignmentSource::SOURCE_USER, - StandAssignmentSource::SOURCE_RESERVATION_ALLOCATOR, - StandAssignmentSource::SOURCE_VAA_ALLOCATOR, - StandAssignmentSource::SOURCE_SYSTEM}; + StandAssignment::Source::User, + StandAssignment::Source::ReservationAllocator, + StandAssignment::Source::VaaAllocator, + StandAssignment::Source::SystemAuto}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From f8d08b7335d57af17fbac0c56347e9c074ef3bac Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Wed, 8 Apr 2026 16:32:15 +0100 Subject: [PATCH 38/59] Use 'using enum' for StandAssignment::Source --- src/plugin/stands/StandEventHandler.cpp | 12 ++++++------ test/plugin/stands/StandEventHandlerTest.cpp | 10 ++++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index e44f12c97..d6c18c57f 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -354,18 +354,18 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { - using Source = StandAssignment::Source; + using enum StandAssignment::Source; switch (source) { - case Source::Unknown: + case Unknown: return "UNK "; - case Source::User: + case User: return "USER"; - case Source::ReservationAllocator: + case ReservationAllocator: return "RES "; - case Source::VaaAllocator: + case VaaAllocator: return "VAA "; - case Source::SystemAuto: + case SystemAuto: return "AUTO"; } return "UNK "; diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 531c43ce0..25b818a01 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -177,11 +177,13 @@ namespace UKControllerPluginTest { [[nodiscard]] static auto AllSources() -> std::array { + using enum StandAssignment::Source; + return { - StandAssignment::Source::User, - StandAssignment::Source::ReservationAllocator, - StandAssignment::Source::VaaAllocator, - StandAssignment::Source::SystemAuto}; + User, + ReservationAllocator, + VaaAllocator, + SystemAuto}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From 9933b2d8adadcffce0914d255eddb8c44cbb80ef Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Wed, 8 Apr 2026 16:39:13 +0100 Subject: [PATCH 39/59] formatting --- test/plugin/stands/StandEventHandlerTest.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 25b818a01..d6dffec77 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -179,11 +179,7 @@ namespace UKControllerPluginTest { { using enum StandAssignment::Source; - return { - User, - ReservationAllocator, - VaaAllocator, - SystemAuto}; + return {User, ReservationAllocator, VaaAllocator, SystemAuto}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From 52a0c19e439201ba39f6c89fd0e9a8d55fe7075d Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Wed, 8 Apr 2026 16:46:07 +0100 Subject: [PATCH 40/59] sonarqube fixes --- src/plugin/stands/StandAssignmentSource.h | 4 ++-- src/plugin/stands/StandEventHandler.cpp | 3 ++- test/plugin/stands/StandEventHandlerTest.cpp | 1 + 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index 3402c360e..76e29e348 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -37,9 +37,9 @@ namespace UKControllerPlugin::Stands { return "vaa_allocator"; case SystemAuto: return "system_auto"; + default: + return "system_auto"; } - - return "system_auto"; } [[nodiscard]] static constexpr auto FromString(std::string_view source) -> Source diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index d6c18c57f..3ec00f76d 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -367,8 +367,9 @@ namespace UKControllerPlugin::Stands { return "VAA "; case SystemAuto: return "AUTO"; + default: + return "UNK "; } - return "UNK "; } auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index d6dffec77..e5bf1db34 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -177,6 +177,7 @@ namespace UKControllerPluginTest { [[nodiscard]] static auto AllSources() -> std::array { + using Source = StandAssignment::Source; using enum StandAssignment::Source; return {User, ReservationAllocator, VaaAllocator, SystemAuto}; From acbe4cc3eea284f650b58aee3cc390c7b4a0026d Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Wed, 8 Apr 2026 16:55:57 +0100 Subject: [PATCH 41/59] Revert "sonarqube fixes" This reverts commit 52a0c19e439201ba39f6c89fd0e9a8d55fe7075d. --- src/plugin/stands/StandAssignmentSource.h | 4 ++-- src/plugin/stands/StandEventHandler.cpp | 3 +-- test/plugin/stands/StandEventHandlerTest.cpp | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index 76e29e348..3402c360e 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -37,9 +37,9 @@ namespace UKControllerPlugin::Stands { return "vaa_allocator"; case SystemAuto: return "system_auto"; - default: - return "system_auto"; } + + return "system_auto"; } [[nodiscard]] static constexpr auto FromString(std::string_view source) -> Source diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 3ec00f76d..d6c18c57f 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -367,9 +367,8 @@ namespace UKControllerPlugin::Stands { return "VAA "; case SystemAuto: return "AUTO"; - default: - return "UNK "; } + return "UNK "; } auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index e5bf1db34..d6dffec77 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -177,7 +177,6 @@ namespace UKControllerPluginTest { [[nodiscard]] static auto AllSources() -> std::array { - using Source = StandAssignment::Source; using enum StandAssignment::Source; return {User, ReservationAllocator, VaaAllocator, SystemAuto}; From 238c94e76716e7050665325e85fcf5ef52149482 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:01:58 +0100 Subject: [PATCH 42/59] Refactor stand assignment source handling Clean up and normalize handling of stand assignment source data: - Remove redundant return from ToString() in StandAssignmentSource.h. - Set tag colour inside each tag branch (assignedStand / assignmentSource) and remove the later conditional/early-return, ensuring colour is applied consistently. - Trim trailing spaces from assignment source shorthands (e.g. "UNK ">"UNK"). - Replace direct map assignment of standAssignments with SetAssignedStand(...) to centralize assignment logic and any associated side effects. These changes improve code clarity, avoid dead/redundant code, and standardize formatting and behavior. --- src/plugin/stands/StandAssignmentSource.h | 2 -- src/plugin/stands/StandEventHandler.cpp | 18 +++++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index 3402c360e..edc2617ca 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -38,8 +38,6 @@ namespace UKControllerPlugin::Stands { case SystemAuto: return "system_auto"; } - - return "system_auto"; } [[nodiscard]] static constexpr auto FromString(std::string_view source) -> Source diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index d6c18c57f..608e2eada 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -323,15 +323,11 @@ namespace UKControllerPlugin::Stands { if (tagData.GetItemCode() == assignedStandTagItemId) { tagData.SetItemString(stand->identifier); + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } - - if (tagData.GetItemCode() != assignedStandTagItemId && - tagData.GetItemCode() != standAssignmentSourceTagItemId) { - return; - } - tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool @@ -358,17 +354,17 @@ namespace UKControllerPlugin::Stands { switch (source) { case Unknown: - return "UNK "; + return "UNK"; case User: return "USER"; case ReservationAllocator: - return "RES "; + return "RES"; case VaaAllocator: - return "VAA "; + return "VAA"; case SystemAuto: return "AUTO"; } - return "UNK "; + return "UNK"; } auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool @@ -541,7 +537,7 @@ namespace UKControllerPlugin::Stands { const std::string& callsign, const Stand& stand, StandAssignment::Source source) { this->AnnotateFlightStrip(callsign, stand.id); - this->standAssignments[callsign] = {stand.id, source}; + this->SetAssignedStand(callsign, stand.id, source); this->integrationEventHandler.SendEvent( std::make_shared(callsign, stand.airfieldCode, stand.identifier)); const auto logMessage = std::format( From b4bd89a9ffc3c26c6870ea57004c98779795793f Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:03:52 +0100 Subject: [PATCH 43/59] Remove default arg from GetColourEntry call Update StandColourConfiguration to call userSetting->GetColourEntry(key) without passing entry.defaultColour. This aligns the call with the updated GetColourEntry signature and keeps sourceColours populated from the userSetting lookup. Co-Authored-By: Patrick Winters <61561933+19wintersp@users.noreply.github.com> --- src/plugin/stands/StandColourConfiguration.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 0a30cf347..429dcfab8 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -57,7 +57,7 @@ namespace UKControllerPlugin::Stands { for (const auto& entry : sourceColourDefaults) { const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(entry.source)); if (this->userSetting->HasEntry(key)) { - this->sourceColours[entry.source] = this->userSetting->GetColourEntry(key, entry.defaultColour); + this->sourceColours[entry.source] = this->userSetting->GetColourEntry(key); } } From 26c569848dddc7f669193563ec3ff48cc19c8b86 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:08:08 +0100 Subject: [PATCH 44/59] Handle unknown System mode with default case Add a default case returning "UNK" in the System mode switch and remove the redundant return after the switch. This ensures unexpected enum values are handled consistently and avoids potential compiler warnings about missing return paths. --- src/plugin/stands/StandEventHandler.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 608e2eada..6a4772c46 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -363,8 +363,9 @@ namespace UKControllerPlugin::Stands { return "VAA"; case SystemAuto: return "AUTO"; + default: + return "UNK"; } - return "UNK"; } auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool From 3993f592a3e2e860e35a98cfe132d996bfb40096 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:10:12 +0100 Subject: [PATCH 45/59] Return 'unknown' for default allocator case Add a default branch to the switch in src/plugin/stands/StandAssignmentSource.h to return "unknown" for unexpected enum values. This prevents missing-return compiler warnings and ensures a defined string is returned for any unhandled allocator type. --- src/plugin/stands/StandAssignmentSource.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/plugin/stands/StandAssignmentSource.h b/src/plugin/stands/StandAssignmentSource.h index edc2617ca..b6c8f2196 100644 --- a/src/plugin/stands/StandAssignmentSource.h +++ b/src/plugin/stands/StandAssignmentSource.h @@ -37,6 +37,8 @@ namespace UKControllerPlugin::Stands { return "vaa_allocator"; case SystemAuto: return "system_auto"; + default: + return "unknown"; } } From 47a78db827e7e66e1b9ad3cbffa655060709f8c8 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:32:34 +0100 Subject: [PATCH 46/59] Pad source labels with trailing space Update StandEventHandler.cpp to add a trailing space to short source labels ("UNK", "RES", "VAA") so they become 4 characters wide ("UNK ", "RES ", "VAA "). This standardizes the returned label width for logging/formatting consistency; the Unknown/default case was updated as well. --- src/plugin/stands/StandEventHandler.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 6a4772c46..2b84de6ae 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -354,17 +354,17 @@ namespace UKControllerPlugin::Stands { switch (source) { case Unknown: - return "UNK"; + return "UNK "; case User: return "USER"; case ReservationAllocator: - return "RES"; + return "RES "; case VaaAllocator: - return "VAA"; + return "VAA "; case SystemAuto: return "AUTO"; default: - return "UNK"; + return "UNK "; } } From 410e8aa0106373ea969d912c55f601985cffdc47 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:34:22 +0100 Subject: [PATCH 47/59] Revert AircraftFlowMeasureMapTest --- .../ecfmp/AircraftFlowMeasureMapTest.cpp | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp b/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp index e67a47bd9..84748b5b0 100644 --- a/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp +++ b/test/plugin/ecfmp/AircraftFlowMeasureMapTest.cpp @@ -78,27 +78,21 @@ namespace UKControllerPluginTest::ECFMP { map.OnEvent(::ECFMP::Plugin::FlowMeasureActivatedEvent{mockFlowMeasure1}); map.OnEvent(::ECFMP::Plugin::FlowMeasureActivatedEvent{mockFlowMeasure2}); - const auto& baw123FlowMeasures = map.GetFlowMeasuresForCallsign("BAW123"); - const auto& baw456FlowMeasures = map.GetFlowMeasuresForCallsign("BAW456"); - // Check that flightplan 1 has both measures, but flightplan 2 has only the second - EXPECT_EQ(2, baw123FlowMeasures.size()); - EXPECT_TRUE(baw123FlowMeasures.contains(mockFlowMeasure1)); - EXPECT_TRUE(baw123FlowMeasures.contains(mockFlowMeasure2)); - EXPECT_EQ(1, baw456FlowMeasures.size()); - EXPECT_TRUE(baw456FlowMeasures.contains(mockFlowMeasure2)); + EXPECT_EQ(2, map.GetFlowMeasuresForCallsign("BAW123").size()); + EXPECT_EQ(mockFlowMeasure1, *map.GetFlowMeasuresForCallsign("BAW123").begin()); + EXPECT_EQ(mockFlowMeasure2, *(++map.GetFlowMeasuresForCallsign("BAW123").begin())); + EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW456").size()); + EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW456").begin()); // Withdraw the first measure map.OnEvent(::ECFMP::Plugin::FlowMeasureWithdrawnEvent{mockFlowMeasure1}); - const auto& baw123FlowMeasuresAfterWithdrawal = map.GetFlowMeasuresForCallsign("BAW123"); - const auto& baw456FlowMeasuresAfterWithdrawal = map.GetFlowMeasuresForCallsign("BAW456"); - // Check that flightplan 1 now has just the second measure, but flightplan 2 has only the second - EXPECT_EQ(1, baw123FlowMeasuresAfterWithdrawal.size()); - EXPECT_TRUE(baw123FlowMeasuresAfterWithdrawal.contains(mockFlowMeasure2)); - EXPECT_EQ(1, baw456FlowMeasuresAfterWithdrawal.size()); - EXPECT_TRUE(baw456FlowMeasuresAfterWithdrawal.contains(mockFlowMeasure2)); + EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW123").size()); + EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW123").begin()); + EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW456").size()); + EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW456").begin()); } TEST_F(AircraftFlowMeasureMapTest, FlowMeasuresWithdrawingRemovesAllFromActiveAircraftFlowMeasures) @@ -441,4 +435,4 @@ namespace UKControllerPluginTest::ECFMP { EXPECT_EQ(1, map.GetFlowMeasuresForCallsign("BAW456").size()); EXPECT_EQ(mockFlowMeasure2, *map.GetFlowMeasuresForCallsign("BAW456").begin()); } -} // namespace UKControllerPluginTest::ECFMP +} // namespace UKControllerPluginTest::ECFMP \ No newline at end of file From 2661e678fa8144759cb6955b1dd1fa041972e09f Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 12:53:19 +0100 Subject: [PATCH 48/59] Remove trailing spaces from source shorthands Trim trailing spaces from source shorthand strings in StandEventHandler ("UNK ", "RES ", "VAA " -> "UNK", "RES", "VAA") to standardize formatting. Update unit test expectations in StandEventHandlerTest to match the new shorthands. --- src/plugin/stands/StandEventHandler.cpp | 8 ++++---- test/plugin/stands/StandEventHandlerTest.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 2b84de6ae..6a4772c46 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -354,17 +354,17 @@ namespace UKControllerPlugin::Stands { switch (source) { case Unknown: - return "UNK "; + return "UNK"; case User: return "USER"; case ReservationAllocator: - return "RES "; + return "RES"; case VaaAllocator: - return "VAA "; + return "VAA"; case SystemAuto: return "AUTO"; default: - return "UNK "; + return "UNK"; } } diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index d6dffec77..6cbf54a7e 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -335,7 +335,7 @@ namespace UKControllerPluginTest { TEST_F(StandEventHandlerTest, ItReturnsSourceShorthandForSourceTagItem) { const auto sources = AllSources(); - const std::array expectedShorthand = {"USER", "RES ", "VAA ", "AUTO"}; + const std::array expectedShorthand = {"USER", "RES", "VAA", "AUTO"}; for (size_t i = 0; i < std::size(sources); ++i) { this->ExpectSourceTagItemShorthand(sources[i], expectedShorthand[i]); From f1ce398e4b3a92794ebdd49df57d38ce501292b8 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 19:29:59 +0100 Subject: [PATCH 49/59] Refactor stands: colours & event handler Add Unknown source colour and adjust default palette, include logger header, and simplify user-setting loading. - Introduce DEFAULT_UNKNOWN_COLOUR and add StandAssignment::Source::Unknown into the sourceColours defaults and loading loop so unknown assignments have a defined colour. - Update default colours for reservation, VAA and system to new values. - Replace the custom SourceColourDefault struct with a simple array of sources and streamline reading colour entries from UserSetting. - Add utils/log/LoggerFunctions.h and remove an unused stdexcept include. Refactor StandEventHandler for clarity and correctness: - Forward SetAssignedStand(callsign, id) to the source-aware overload to ensure assignments always have a source. - Consolidate tag colour application so tag colour is set consistently. - Reorder and clean up many methods (validation, message parsing, API requests, push event processing, flightplan handling, assignment/unassignment flows) for readability and maintainability without changing external behaviour. - Fix some control flow and API handling points (mass assignment loading, push event processing, async API calls). Overall this change improves colour handling for unknown sources and restructures the event handler code for clarity and consistency. --- .../stands/StandColourConfiguration.cpp | 28 +- src/plugin/stands/StandColourConfiguration.h | 7 +- src/plugin/stands/StandEventHandler.cpp | 621 +++++++++--------- 3 files changed, 326 insertions(+), 330 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 429dcfab8..ef21c88f7 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,8 +2,8 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" +#include "utils/log/LoggerFunctions.h" #include -#include namespace UKControllerPlugin::Stands { @@ -18,7 +18,8 @@ namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) : userSetting(userSetting), sourceColours( - {{StandAssignment::Source::User, DEFAULT_USER_COLOUR}, + {{StandAssignment::Source::Unknown, DEFAULT_UNKNOWN_COLOUR}, + {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}}) @@ -41,23 +42,18 @@ namespace UKControllerPlugin::Stands { return; } - struct SourceColourDefault - { - StandAssignment::Source source; - COLORREF defaultColour; - }; - - constexpr std::array sourceColourDefaults = {{ - {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, - {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, - {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, - {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}, + constexpr std::array sourceColourDefaults = {{ + StandAssignment::Source::Unknown, + StandAssignment::Source::User, + StandAssignment::Source::ReservationAllocator, + StandAssignment::Source::VaaAllocator, + StandAssignment::Source::SystemAuto, }}; - for (const auto& entry : sourceColourDefaults) { - const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(entry.source)); + for (const auto source : sourceColourDefaults) { + const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); if (this->userSetting->HasEntry(key)) { - this->sourceColours[entry.source] = this->userSetting->GetColourEntry(key); + this->sourceColours[source] = this->userSetting->GetColourEntry(key); } } diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 20d1511ea..359357188 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -44,10 +44,11 @@ namespace UKControllerPlugin::Stands { static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); // Default colours if not configured + static constexpr COLORREF DEFAULT_UNKNOWN_COLOUR = RGB(204, 204, 204); // grey static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 255, 255); // white - static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 255, 0); // yellow - static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(0, 255, 255); // cyan - static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(180, 180, 180); // grey + static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 216, 0); // yellow + static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 149, 41); // orange + static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(204, 204, 204); // grey // UserSetting key prefix for colours static constexpr std::string_view SETTING_PREFIX = "stand_colour_"; diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 6a4772c46..aba7eaa69 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -225,7 +225,7 @@ namespace UKControllerPlugin::Stands { void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId) { - this->standAssignments[callsign] = {standId, StandAssignment::Source::SystemAuto}; + this->SetAssignedStand(callsign, standId, StandAssignment::Source::SystemAuto); } void StandEventHandler::SetAssignedStand(const std::string& callsign, int standId, const std::string& source) @@ -323,373 +323,372 @@ namespace UKControllerPlugin::Stands { if (tagData.GetItemCode() == assignedStandTagItemId) { tagData.SetItemString(stand->identifier); - tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } else if (tagData.GetItemCode() == standAssignmentSourceTagItemId) { tagData.SetItemString(GetAssignmentSourceShorthand(assignment.source)); - tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } - } - auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool - { - return message.is_object() && message.contains("callsign") && message.at("callsign").is_string() && - message.contains("stand_id") && message.at("stand_id").is_number_integer() && - this->stands.find(message.at("stand_id").get()) != this->stands.cend(); + tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } +} - auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source - { - using Source = StandAssignment::Source; +auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool +{ + return message.is_object() && message.contains("callsign") && message.at("callsign").is_string() && + message.contains("stand_id") && message.at("stand_id").is_number_integer() && + this->stands.find(message.at("stand_id").get()) != this->stands.cend(); +} - if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { - return StandAssignment::FromString(message.at("assignment_source").get()); - } +auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source +{ + using Source = StandAssignment::Source; - return Source::Unknown; + if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { + return StandAssignment::FromString(message.at("assignment_source").get()); } - auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string - { - using enum StandAssignment::Source; - - switch (source) { - case Unknown: - return "UNK"; - case User: - return "USER"; - case ReservationAllocator: - return "RES"; - case VaaAllocator: - return "VAA"; - case SystemAuto: - return "AUTO"; - default: - return "UNK"; - } - } + return Source::Unknown; +} - auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool - { - return message.is_object() && message.contains("callsign") && message.at("callsign").is_string(); - } +auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string +{ + using enum StandAssignment::Source; - /* - Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from - its origin. - */ - auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const - -> std::string - { - return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() - : flightplan.GetDestination(); + switch (source) { + case Unknown: + return "UNK"; + case User: + return "USER"; + case ReservationAllocator: + return "RES"; + case VaaAllocator: + return "VAA"; + case SystemAuto: + return "AUTO"; + default: + return "UNK"; } +} - /* - Process message to assign stands - */ - auto StandEventHandler::ProcessMessage(std::string message) -> bool - { - std::vector parts; - std::stringstream ss(message); - std::string temp; +auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool +{ + return message.is_object() && message.contains("callsign") && message.at("callsign").is_string(); +} - if (message.substr(0, 6) != "STANDS") { // NOLINT - return false; - } - - while (std::getline(ss, temp, ':')) { - parts.push_back(temp); - } - - if (parts.size() != 4) { - return false; - } - - this->DoStandAssignment(this->plugin.GetFlightplanForCallsign(parts[1]), parts[2], parts[3]); - - return true; - } - - /* - Every time the flightplan updates, keep the annotation up to date if it's - not so. This is needed because there wont be any flightplans to annotate - when the plugin first starts up, so it annotates them as they come along. - */ - void StandEventHandler::FlightPlanEvent( - EuroScopeCFlightPlanInterface& flightPlan, EuroScopeCRadarTargetInterface& radarTarget) - { - auto mapLock = this->LockStandMap(); - if (!this->standAssignments.contains(flightPlan.GetCallsign())) { - return; - } - - const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); - const auto& stand = this->stands.find(assignment.standId); - if (stand == this->stands.cend()) { - LogWarning( - std::format("Assigned stand id {} not found for {}", assignment.standId, flightPlan.GetCallsign())); - return; - } - - if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { - return; - } - - flightPlan.AnnotateFlightStrip(this->annotationIndex, stand->identifier); - } - - void StandEventHandler::FlightPlanDisconnectEvent(EuroScopeCFlightPlanInterface& flightPlan) - { - // Nothing to do - } - - void StandEventHandler::ControllerFlightPlanDataEvent(EuroScopeCFlightPlanInterface& flightPlan, int dataType) - { - // Nothing to do - } - - void StandEventHandler::PluginEventsSynced() - { - this->taskRunner.QueueAsynchronousTask([this]() { - try { - nlohmann::json standAssignments = this->api.GetAssignedStands(); - - if (!standAssignments.is_array()) { - LogWarning("Invalid stand assignment data"); - return; - } - - // Delete all existing assignments - auto mapLock = this->LockStandMap(); - this->standAssignments.clear(); - - for (auto assignment = standAssignments.cbegin(); assignment != standAssignments.cend(); ++assignment) { - if (!AssignmentMessageValid(*assignment)) { - LogWarning("Invalid stand assignment message on mass assignment " + assignment->dump()); - continue; - } - - this->AssignStandToAircraft( - assignment->at("callsign").get(), - *this->stands.find(assignment->at("stand_id").get()), - GetAssignmentSourceFromMessage(*assignment)); - } - LogInfo("Loaded " + std::to_string(this->standAssignments.size()) + " stand assignments"); - } catch (ApiException&) { - LogError("Unable to load stand assignment data"); - } - }); - } - - /* - Process messages from the websocket. - */ - void StandEventHandler::ProcessPushEvent(const Push::PushEvent& message) - { - auto mapLock = this->LockStandMap(); - if (message.event == "App\\Events\\StandAssignedEvent") { - // If a stand has been assigned, assign it here - if (!AssignmentMessageValid(message.data)) { - LogWarning("Invalid stand assignment message " + message.data.dump()); - return; - } +/* + Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from + its origin. +*/ +auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const -> std::string +{ + return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() + : flightplan.GetDestination(); +} - this->AssignStandToAircraft( - message.data.at("callsign").get(), - *this->stands.find(message.data.at("stand_id").get()), - GetAssignmentSourceFromMessage(message.data)); - } else if (message.event == "App\\Events\\StandUnassignedEvent") { - // If a stand has been unassigned, unassign it here - if (!UnassignmentMessageValid(message.data)) { - LogWarning("Invalid stand unassignment message " + message.data.dump()); - return; - } +/* + Process message to assign stands +*/ +auto StandEventHandler::ProcessMessage(std::string message) -> bool +{ + std::vector parts; + std::stringstream ss(message); + std::string temp; - this->UnassignStandForAircraft(message.data.at("callsign").get()); - } + if (message.substr(0, 6) != "STANDS") { // NOLINT + return false; } - auto StandEventHandler::GetPushEventSubscriptions() const -> std::set - { - return {{PushEventSubscription::SUB_TYPE_CHANNEL, "private-stand-assignments"}}; + while (std::getline(ss, temp, ':')) { + parts.push_back(temp); } - auto StandEventHandler::LockStandMap() -> std::lock_guard - { - return std::lock_guard(this->mapMutex); + if (parts.size() != 4) { + return false; } - void StandEventHandler::UnassignStandForAircraft(const std::string& callsign) - { - this->RemoveFlightStripAnnotation(callsign); - this->standAssignments.erase(callsign); - this->integrationEventHandler.SendEvent(std::make_shared(callsign)); - LogInfo("Stand assignment removed for " + callsign); - } + this->DoStandAssignment(this->plugin.GetFlightplanForCallsign(parts[1]), parts[2], parts[3]); - void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) - { - using Source = StandAssignment::Source; + return true; +} - this->AssignStandToAircraft(callsign, stand, Source::SystemAuto); +/* + Every time the flightplan updates, keep the annotation up to date if it's + not so. This is needed because there wont be any flightplans to annotate + when the plugin first starts up, so it annotates them as they come along. +*/ +void StandEventHandler::FlightPlanEvent( + EuroScopeCFlightPlanInterface& flightPlan, EuroScopeCRadarTargetInterface& radarTarget) +{ + auto mapLock = this->LockStandMap(); + if (!this->standAssignments.contains(flightPlan.GetCallsign())) { + return; } - void StandEventHandler::AssignStandToAircraft( - const std::string& callsign, const Stand& stand, StandAssignment::Source source) - { - this->AnnotateFlightStrip(callsign, stand.id); - this->SetAssignedStand(callsign, stand.id, source); - this->integrationEventHandler.SendEvent( - std::make_shared(callsign, stand.airfieldCode, stand.identifier)); - const auto logMessage = std::format( - "Stand id {} ({}/{}) assigned to {} (source: {})", - stand.id, - stand.airfieldCode, - stand.identifier, - callsign, - StandAssignment::ToString(source)); - LogInfo(logMessage); - } - auto StandEventHandler::ActionsToProcess() const -> std::vector - { - return {{"assign_stand", 1}, {"unassign_stand", 1}}; + const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); + const auto& stand = this->stands.find(assignment.standId); + if (stand == this->stands.cend()) { + LogWarning(std::format("Assigned stand id {} not found for {}", assignment.standId, flightPlan.GetCallsign())); + return; } - void StandEventHandler::ProcessAction( - std::shared_ptr message, - std::function success, - std::function)> fail) - { - auto messageData = message->GetMessageData(); - if (message->GetMessageType().type == "assign_stand") { - if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { - fail({"Invalid callsign in message data"}); - return; - } + if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { + return; + } + + flightPlan.AnnotateFlightStrip(this->annotationIndex, stand->identifier); +} + +void StandEventHandler::FlightPlanDisconnectEvent(EuroScopeCFlightPlanInterface& flightPlan) +{ + // Nothing to do +} - if (!messageData.contains("airfield") || !messageData.at("airfield").is_string()) { - fail({"Invalid airfield field in message data"}); +void StandEventHandler::ControllerFlightPlanDataEvent(EuroScopeCFlightPlanInterface& flightPlan, int dataType) +{ + // Nothing to do +} + +void StandEventHandler::PluginEventsSynced() +{ + this->taskRunner.QueueAsynchronousTask([this]() { + try { + nlohmann::json standAssignments = this->api.GetAssignedStands(); + + if (!standAssignments.is_array()) { + LogWarning("Invalid stand assignment data"); return; } - if (!messageData.contains("stand") || !messageData.at("stand").is_string()) { - fail({"Invalid stand field in message data"}); - return; - } - - auto errorMessage = this->DoStandAssignment( - this->plugin.GetFlightplanForCallsign(messageData.at("callsign").get()), - messageData.at("airfield").get(), - messageData.at("stand").get()); + // Delete all existing assignments + auto mapLock = this->LockStandMap(); + this->standAssignments.clear(); - if (errorMessage.empty()) { - success(); - } else { - fail({errorMessage}); - } - } else if (message->GetMessageType().type == "unassign_stand") { - if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { - fail({"Invalid callsign in message data"}); - return; - } + for (auto assignment = standAssignments.cbegin(); assignment != standAssignments.cend(); ++assignment) { + if (!AssignmentMessageValid(*assignment)) { + LogWarning("Invalid stand assignment message on mass assignment " + assignment->dump()); + continue; + } - auto standsGuard = this->LockStandMap(); - auto callsign = messageData.at("callsign").get(); - auto assignedStand = this->GetAssignedStandForCallsign(callsign); - - if (assignedStand != noStandAssigned) { - this->UnassignStandForAircraft(callsign); - this->taskRunner.QueueAsynchronousTask([this, callsign]() { - try { - this->api.DeleteStandAssignmentForAircraft(callsign); - } catch (ApiException&) { - LogError("Failed to delete stand assignment for " + callsign); - } - }); + this->AssignStandToAircraft( + assignment->at("callsign").get(), + *this->stands.find(assignment->at("stand_id").get()), + GetAssignmentSourceFromMessage(*assignment)); } + LogInfo("Loaded " + std::to_string(this->standAssignments.size()) + " stand assignments"); + } catch (ApiException&) { + LogError("Unable to load stand assignment data"); + } + }); +} + +/* + Process messages from the websocket. +*/ +void StandEventHandler::ProcessPushEvent(const Push::PushEvent& message) +{ + auto mapLock = this->LockStandMap(); + if (message.event == "App\\Events\\StandAssignedEvent") { + // If a stand has been assigned, assign it here + if (!AssignmentMessageValid(message.data)) { + LogWarning("Invalid stand assignment message " + message.data.dump()); + return; + } - success(); + this->AssignStandToAircraft( + message.data.at("callsign").get(), + *this->stands.find(message.data.at("stand_id").get()), + GetAssignmentSourceFromMessage(message.data)); + } else if (message.event == "App\\Events\\StandUnassignedEvent") { + // If a stand has been unassigned, unassign it here + if (!UnassignmentMessageValid(message.data)) { + LogWarning("Invalid stand unassignment message " + message.data.dump()); + return; } - } - void StandEventHandler::RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) - { - // If EuroScope wont tell us where they are, do nothing. - if (flightplan.GetDistanceFromOrigin() == 0.0) { + this->UnassignStandForAircraft(message.data.at("callsign").get()); + } +} + +auto StandEventHandler::GetPushEventSubscriptions() const -> std::set +{ + return {{PushEventSubscription::SUB_TYPE_CHANNEL, "private-stand-assignments"}}; +} + +auto StandEventHandler::LockStandMap() -> std::lock_guard +{ + return std::lock_guard(this->mapMutex); +} + +void StandEventHandler::UnassignStandForAircraft(const std::string& callsign) +{ + this->RemoveFlightStripAnnotation(callsign); + this->standAssignments.erase(callsign); + this->integrationEventHandler.SendEvent(std::make_shared(callsign)); + LogInfo("Stand assignment removed for " + callsign); +} + +void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) +{ + using Source = StandAssignment::Source; + + this->AssignStandToAircraft(callsign, stand, Source::SystemAuto); +} + +void StandEventHandler::AssignStandToAircraft( + const std::string& callsign, const Stand& stand, StandAssignment::Source source) +{ + this->AnnotateFlightStrip(callsign, stand.id); + this->SetAssignedStand(callsign, stand.id, source); + this->integrationEventHandler.SendEvent( + std::make_shared(callsign, stand.airfieldCode, stand.identifier)); + const auto logMessage = std::format( + "Stand id {} ({}/{}) assigned to {} (source: {})", + stand.id, + stand.airfieldCode, + stand.identifier, + callsign, + StandAssignment::ToString(source)); + LogInfo(logMessage); +} +auto StandEventHandler::ActionsToProcess() const -> std::vector +{ + return {{"assign_stand", 1}, {"unassign_stand", 1}}; +} + +void StandEventHandler::ProcessAction( + std::shared_ptr message, + std::function success, + std::function)> fail) +{ + auto messageData = message->GetMessageData(); + if (message->GetMessageType().type == "assign_stand") { + if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { + fail({"Invalid callsign in message data"}); return; } - // If they're close to departure and we're providing delivery, assign a stand - if (flightplan.GetDistanceFromOrigin() < this->maxDistanceForDepartureStands && - this->ownership->DeliveryControlProvidedByUser(flightplan.GetOrigin())) { - this->RequestDepartureStandFromApi(flightplan); + if (!messageData.contains("airfield") || !messageData.at("airfield").is_string()) { + fail({"Invalid airfield field in message data"}); + return; } - // Otherwise, assume they're close to arrival - if (!this->ownership->DeliveryControlProvidedByUser(flightplan.GetDestination())) { + if (!messageData.contains("stand") || !messageData.at("stand").is_string()) { + fail({"Invalid stand field in message data"}); return; } - this->RequestArrivalStandFromApi(flightplan); - } - void StandEventHandler::RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) - { - const auto radarTarget = this->plugin.GetRadarTargetForCallsign(flightplan.GetCallsign()); - if (!radarTarget) { + auto errorMessage = this->DoStandAssignment( + this->plugin.GetFlightplanForCallsign(messageData.at("callsign").get()), + messageData.at("airfield").get(), + messageData.at("stand").get()); + + if (errorMessage.empty()) { + success(); + } else { + fail({errorMessage}); + } + } else if (message->GetMessageType().type == "unassign_stand") { + if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { + fail({"Invalid callsign in message data"}); return; } - this->DoApiStandRequest( - flightplan.GetCallsign(), - { - {"callsign", flightplan.GetCallsign()}, - {"departure_airfield", flightplan.GetOrigin()}, - {"assignment_type", "departure"}, - {"latitude", radarTarget->GetPosition().m_Latitude}, - {"longitude", radarTarget->GetPosition().m_Longitude}, + auto standsGuard = this->LockStandMap(); + auto callsign = messageData.at("callsign").get(); + auto assignedStand = this->GetAssignedStandForCallsign(callsign); + + if (assignedStand != noStandAssigned) { + this->UnassignStandForAircraft(callsign); + this->taskRunner.QueueAsynchronousTask([this, callsign]() { + try { + this->api.DeleteStandAssignmentForAircraft(callsign); + } catch (ApiException&) { + LogError("Failed to delete stand assignment for " + callsign); + } }); - } + } - void StandEventHandler::RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) - { - this->DoApiStandRequest( - flightplan.GetCallsign(), - {{"callsign", flightplan.GetCallsign()}, - {"departure_airfield", flightplan.GetOrigin()}, - {"arrival_airfield", flightplan.GetDestination()}, - {"assignment_type", "arrival"}, - {"aircraft_type", flightplan.GetAircraftType()}}); + success(); } +} - void StandEventHandler::DoApiStandRequest(const std::string& callsign, const nlohmann::json data) - { - LogDebug("Requesting stand assignment from API: " + data.dump()); - const std::string requestCallsign = callsign; - ApiRequest() - .Post("stand/assignment/requestauto", data) - .Then([this, requestCallsign](const UKControllerPluginUtils::Api::Response& response) { - auto lock = this->LockStandMap(); - - const auto& data = response.Data(); - if (!data.contains("stand_id") || !data.at("stand_id").is_number_integer()) { - LogWarning("Invalid stand assignment response " + data.dump()); - return; - } +void StandEventHandler::RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) +{ + // If EuroScope wont tell us where they are, do nothing. + if (flightplan.GetDistanceFromOrigin() == 0.0) { + return; + } - const auto standId = data.at("stand_id").get(); - if (!this->stands.contains(standId)) { - LogWarning("Invalid stand assignment response, bad id " + data.dump()); - return; - } + // If they're close to departure and we're providing delivery, assign a stand + if (flightplan.GetDistanceFromOrigin() < this->maxDistanceForDepartureStands && + this->ownership->DeliveryControlProvidedByUser(flightplan.GetOrigin())) { + this->RequestDepartureStandFromApi(flightplan); + } - const auto& stand = this->stands.find(standId); - LogInfo("API generated stand assignment " + std::to_string(standId) + " for " + requestCallsign); + // Otherwise, assume they're close to arrival + if (!this->ownership->DeliveryControlProvidedByUser(flightplan.GetDestination())) { + return; + } - this->AssignStandToAircraft(requestCallsign, *stand); - }) - .Catch([requestCallsign](const UKControllerPluginUtils::Api::ApiRequestException& exception) { - LogError("Failed to request stand assignment for " + requestCallsign + ": " + exception.what()); - }); + this->RequestArrivalStandFromApi(flightplan); +} +void StandEventHandler::RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) +{ + const auto radarTarget = this->plugin.GetRadarTargetForCallsign(flightplan.GetCallsign()); + if (!radarTarget) { + return; } + this->DoApiStandRequest( + flightplan.GetCallsign(), + { + {"callsign", flightplan.GetCallsign()}, + {"departure_airfield", flightplan.GetOrigin()}, + {"assignment_type", "departure"}, + {"latitude", radarTarget->GetPosition().m_Latitude}, + {"longitude", radarTarget->GetPosition().m_Longitude}, + }); +} + +void StandEventHandler::RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) +{ + this->DoApiStandRequest( + flightplan.GetCallsign(), + {{"callsign", flightplan.GetCallsign()}, + {"departure_airfield", flightplan.GetOrigin()}, + {"arrival_airfield", flightplan.GetDestination()}, + {"assignment_type", "arrival"}, + {"aircraft_type", flightplan.GetAircraftType()}}); +} + +void StandEventHandler::DoApiStandRequest(const std::string& callsign, const nlohmann::json data) +{ + LogDebug("Requesting stand assignment from API: " + data.dump()); + const std::string requestCallsign = callsign; + ApiRequest() + .Post("stand/assignment/requestauto", data) + .Then([this, requestCallsign](const UKControllerPluginUtils::Api::Response& response) { + auto lock = this->LockStandMap(); + + const auto& data = response.Data(); + if (!data.contains("stand_id") || !data.at("stand_id").is_number_integer()) { + LogWarning("Invalid stand assignment response " + data.dump()); + return; + } + + const auto standId = data.at("stand_id").get(); + if (!this->stands.contains(standId)) { + LogWarning("Invalid stand assignment response, bad id " + data.dump()); + return; + } + + const auto& stand = this->stands.find(standId); + LogInfo("API generated stand assignment " + std::to_string(standId) + " for " + requestCallsign); + + this->AssignStandToAircraft(requestCallsign, *stand); + }) + .Catch([requestCallsign](const UKControllerPluginUtils::Api::ApiRequestException& exception) { + LogError("Failed to request stand assignment for " + requestCallsign + ": " + exception.what()); + }); +} + } // namespace UKControllerPlugin::Stands From 49c8c1f16fa7400e9a1e14f05c2af7c602dc8d2e Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 19:49:04 +0100 Subject: [PATCH 50/59] Removed extra brace Extra } --- src/plugin/stands/StandEventHandler.cpp | 635 ++++++++++++------------ 1 file changed, 318 insertions(+), 317 deletions(-) diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index aba7eaa69..9cf6c067a 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -329,366 +329,367 @@ namespace UKControllerPlugin::Stands { tagData.SetTagColour(this->colourConfiguration->GetColourForSource(assignment.source)); } -} - -auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool -{ - return message.is_object() && message.contains("callsign") && message.at("callsign").is_string() && - message.contains("stand_id") && message.at("stand_id").is_number_integer() && - this->stands.find(message.at("stand_id").get()) != this->stands.cend(); -} -auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source -{ - using Source = StandAssignment::Source; + auto StandEventHandler::AssignmentMessageValid(const nlohmann::json& message) const -> bool + { + return message.is_object() && message.contains("callsign") && message.at("callsign").is_string() && + message.contains("stand_id") && message.at("stand_id").is_number_integer() && + this->stands.find(message.at("stand_id").get()) != this->stands.cend(); + } - if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { - return StandAssignment::FromString(message.at("assignment_source").get()); - } - - return Source::Unknown; -} - -auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string -{ - using enum StandAssignment::Source; - - switch (source) { - case Unknown: - return "UNK"; - case User: - return "USER"; - case ReservationAllocator: - return "RES"; - case VaaAllocator: - return "VAA"; - case SystemAuto: - return "AUTO"; - default: - return "UNK"; - } -} - -auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool -{ - return message.is_object() && message.contains("callsign") && message.at("callsign").is_string(); -} - -/* - Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from - its origin. -*/ -auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const -> std::string -{ - return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() - : flightplan.GetDestination(); -} - -/* - Process message to assign stands -*/ -auto StandEventHandler::ProcessMessage(std::string message) -> bool -{ - std::vector parts; - std::stringstream ss(message); - std::string temp; - - if (message.substr(0, 6) != "STANDS") { // NOLINT - return false; - } - - while (std::getline(ss, temp, ':')) { - parts.push_back(temp); - } - - if (parts.size() != 4) { - return false; - } - - this->DoStandAssignment(this->plugin.GetFlightplanForCallsign(parts[1]), parts[2], parts[3]); - - return true; -} - -/* - Every time the flightplan updates, keep the annotation up to date if it's - not so. This is needed because there wont be any flightplans to annotate - when the plugin first starts up, so it annotates them as they come along. -*/ -void StandEventHandler::FlightPlanEvent( - EuroScopeCFlightPlanInterface& flightPlan, EuroScopeCRadarTargetInterface& radarTarget) -{ - auto mapLock = this->LockStandMap(); - if (!this->standAssignments.contains(flightPlan.GetCallsign())) { - return; - } - - const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); - const auto& stand = this->stands.find(assignment.standId); - if (stand == this->stands.cend()) { - LogWarning(std::format("Assigned stand id {} not found for {}", assignment.standId, flightPlan.GetCallsign())); - return; - } - - if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { - return; - } - - flightPlan.AnnotateFlightStrip(this->annotationIndex, stand->identifier); -} + auto StandEventHandler::GetAssignmentSourceFromMessage(const nlohmann::json& message) -> StandAssignment::Source + { + using Source = StandAssignment::Source; -void StandEventHandler::FlightPlanDisconnectEvent(EuroScopeCFlightPlanInterface& flightPlan) -{ - // Nothing to do -} + if (message.contains("assignment_source") && message.at("assignment_source").is_string()) { + return StandAssignment::FromString(message.at("assignment_source").get()); + } -void StandEventHandler::ControllerFlightPlanDataEvent(EuroScopeCFlightPlanInterface& flightPlan, int dataType) -{ - // Nothing to do -} - -void StandEventHandler::PluginEventsSynced() -{ - this->taskRunner.QueueAsynchronousTask([this]() { - try { - nlohmann::json standAssignments = this->api.GetAssignedStands(); - - if (!standAssignments.is_array()) { - LogWarning("Invalid stand assignment data"); - return; - } + return Source::Unknown; + } - // Delete all existing assignments - auto mapLock = this->LockStandMap(); - this->standAssignments.clear(); + auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string + { + using enum StandAssignment::Source; + + switch (source) { + case Unknown: + return "UNK"; + case User: + return "USER"; + case ReservationAllocator: + return "RES"; + case VaaAllocator: + return "VAA"; + case SystemAuto: + return "AUTO"; + default: + return "UNK"; + } + } - for (auto assignment = standAssignments.cbegin(); assignment != standAssignments.cend(); ++assignment) { - if (!AssignmentMessageValid(*assignment)) { - LogWarning("Invalid stand assignment message on mass assignment " + assignment->dump()); - continue; - } + auto StandEventHandler::UnassignmentMessageValid(const nlohmann::json& message) -> bool + { + return message.is_object() && message.contains("callsign") && message.at("callsign").is_string(); + } - this->AssignStandToAircraft( - assignment->at("callsign").get(), - *this->stands.find(assignment->at("stand_id").get()), - GetAssignmentSourceFromMessage(*assignment)); - } - LogInfo("Loaded " + std::to_string(this->standAssignments.size()) + " stand assignments"); - } catch (ApiException&) { - LogError("Unable to load stand assignment data"); + /* + Get the airfield to use for stand assignment purposes, depending on how far the aircraft is from + its origin. + */ + auto StandEventHandler::GetAirfieldForStandAssignment(EuroScopeCFlightPlanInterface& flightplan) const + -> std::string + { + return flightplan.GetDistanceFromOrigin() < this->maxDistanceFromDepartureAirport ? flightplan.GetOrigin() + : flightplan.GetDestination(); + } + + /* + Process message to assign stands + */ + auto StandEventHandler::ProcessMessage(std::string message) -> bool + { + std::vector parts; + std::stringstream ss(message); + std::string temp; + + if (message.substr(0, 6) != "STANDS") { // NOLINT + return false; } - }); -} - -/* - Process messages from the websocket. -*/ -void StandEventHandler::ProcessPushEvent(const Push::PushEvent& message) -{ - auto mapLock = this->LockStandMap(); - if (message.event == "App\\Events\\StandAssignedEvent") { - // If a stand has been assigned, assign it here - if (!AssignmentMessageValid(message.data)) { - LogWarning("Invalid stand assignment message " + message.data.dump()); - return; + + while (std::getline(ss, temp, ':')) { + parts.push_back(temp); } - this->AssignStandToAircraft( - message.data.at("callsign").get(), - *this->stands.find(message.data.at("stand_id").get()), - GetAssignmentSourceFromMessage(message.data)); - } else if (message.event == "App\\Events\\StandUnassignedEvent") { - // If a stand has been unassigned, unassign it here - if (!UnassignmentMessageValid(message.data)) { - LogWarning("Invalid stand unassignment message " + message.data.dump()); - return; + if (parts.size() != 4) { + return false; } - this->UnassignStandForAircraft(message.data.at("callsign").get()); - } -} - -auto StandEventHandler::GetPushEventSubscriptions() const -> std::set -{ - return {{PushEventSubscription::SUB_TYPE_CHANNEL, "private-stand-assignments"}}; -} - -auto StandEventHandler::LockStandMap() -> std::lock_guard -{ - return std::lock_guard(this->mapMutex); -} - -void StandEventHandler::UnassignStandForAircraft(const std::string& callsign) -{ - this->RemoveFlightStripAnnotation(callsign); - this->standAssignments.erase(callsign); - this->integrationEventHandler.SendEvent(std::make_shared(callsign)); - LogInfo("Stand assignment removed for " + callsign); -} - -void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) -{ - using Source = StandAssignment::Source; - - this->AssignStandToAircraft(callsign, stand, Source::SystemAuto); -} - -void StandEventHandler::AssignStandToAircraft( - const std::string& callsign, const Stand& stand, StandAssignment::Source source) -{ - this->AnnotateFlightStrip(callsign, stand.id); - this->SetAssignedStand(callsign, stand.id, source); - this->integrationEventHandler.SendEvent( - std::make_shared(callsign, stand.airfieldCode, stand.identifier)); - const auto logMessage = std::format( - "Stand id {} ({}/{}) assigned to {} (source: {})", - stand.id, - stand.airfieldCode, - stand.identifier, - callsign, - StandAssignment::ToString(source)); - LogInfo(logMessage); -} -auto StandEventHandler::ActionsToProcess() const -> std::vector -{ - return {{"assign_stand", 1}, {"unassign_stand", 1}}; -} - -void StandEventHandler::ProcessAction( - std::shared_ptr message, - std::function success, - std::function)> fail) -{ - auto messageData = message->GetMessageData(); - if (message->GetMessageType().type == "assign_stand") { - if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { - fail({"Invalid callsign in message data"}); + this->DoStandAssignment(this->plugin.GetFlightplanForCallsign(parts[1]), parts[2], parts[3]); + + return true; + } + + /* + Every time the flightplan updates, keep the annotation up to date if it's + not so. This is needed because there wont be any flightplans to annotate + when the plugin first starts up, so it annotates them as they come along. + */ + void StandEventHandler::FlightPlanEvent( + EuroScopeCFlightPlanInterface& flightPlan, EuroScopeCRadarTargetInterface& radarTarget) + { + auto mapLock = this->LockStandMap(); + if (!this->standAssignments.contains(flightPlan.GetCallsign())) { return; } - if (!messageData.contains("airfield") || !messageData.at("airfield").is_string()) { - fail({"Invalid airfield field in message data"}); + const auto& assignment = this->standAssignments.at(flightPlan.GetCallsign()); + const auto& stand = this->stands.find(assignment.standId); + if (stand == this->stands.cend()) { + LogWarning( + std::format("Assigned stand id {} not found for {}", assignment.standId, flightPlan.GetCallsign())); return; } - if (!messageData.contains("stand") || !messageData.at("stand").is_string()) { - fail({"Invalid stand field in message data"}); + if (stand->identifier == flightPlan.GetAnnotation(this->annotationIndex)) { return; } - auto errorMessage = this->DoStandAssignment( - this->plugin.GetFlightplanForCallsign(messageData.at("callsign").get()), - messageData.at("airfield").get(), - messageData.at("stand").get()); + flightPlan.AnnotateFlightStrip(this->annotationIndex, stand->identifier); + } - if (errorMessage.empty()) { - success(); - } else { - fail({errorMessage}); - } - } else if (message->GetMessageType().type == "unassign_stand") { - if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { - fail({"Invalid callsign in message data"}); - return; - } + void StandEventHandler::FlightPlanDisconnectEvent(EuroScopeCFlightPlanInterface& flightPlan) + { + // Nothing to do + } - auto standsGuard = this->LockStandMap(); - auto callsign = messageData.at("callsign").get(); - auto assignedStand = this->GetAssignedStandForCallsign(callsign); + void StandEventHandler::ControllerFlightPlanDataEvent(EuroScopeCFlightPlanInterface& flightPlan, int dataType) + { + // Nothing to do + } - if (assignedStand != noStandAssigned) { - this->UnassignStandForAircraft(callsign); - this->taskRunner.QueueAsynchronousTask([this, callsign]() { - try { - this->api.DeleteStandAssignmentForAircraft(callsign); - } catch (ApiException&) { - LogError("Failed to delete stand assignment for " + callsign); + void StandEventHandler::PluginEventsSynced() + { + this->taskRunner.QueueAsynchronousTask([this]() { + try { + nlohmann::json standAssignments = this->api.GetAssignedStands(); + + if (!standAssignments.is_array()) { + LogWarning("Invalid stand assignment data"); + return; } - }); + + // Delete all existing assignments + auto mapLock = this->LockStandMap(); + this->standAssignments.clear(); + + for (auto assignment = standAssignments.cbegin(); assignment != standAssignments.cend(); ++assignment) { + if (!AssignmentMessageValid(*assignment)) { + LogWarning("Invalid stand assignment message on mass assignment " + assignment->dump()); + continue; + } + + this->AssignStandToAircraft( + assignment->at("callsign").get(), + *this->stands.find(assignment->at("stand_id").get()), + GetAssignmentSourceFromMessage(*assignment)); + } + LogInfo("Loaded " + std::to_string(this->standAssignments.size()) + " stand assignments"); + } catch (ApiException&) { + LogError("Unable to load stand assignment data"); + } + }); + } + + /* + Process messages from the websocket. + */ + void StandEventHandler::ProcessPushEvent(const Push::PushEvent& message) + { + auto mapLock = this->LockStandMap(); + if (message.event == "App\\Events\\StandAssignedEvent") { + // If a stand has been assigned, assign it here + if (!AssignmentMessageValid(message.data)) { + LogWarning("Invalid stand assignment message " + message.data.dump()); + return; + } + + this->AssignStandToAircraft( + message.data.at("callsign").get(), + *this->stands.find(message.data.at("stand_id").get()), + GetAssignmentSourceFromMessage(message.data)); + } else if (message.event == "App\\Events\\StandUnassignedEvent") { + // If a stand has been unassigned, unassign it here + if (!UnassignmentMessageValid(message.data)) { + LogWarning("Invalid stand unassignment message " + message.data.dump()); + return; + } + + this->UnassignStandForAircraft(message.data.at("callsign").get()); } + } - success(); + auto StandEventHandler::GetPushEventSubscriptions() const -> std::set + { + return {{PushEventSubscription::SUB_TYPE_CHANNEL, "private-stand-assignments"}}; } -} -void StandEventHandler::RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) -{ - // If EuroScope wont tell us where they are, do nothing. - if (flightplan.GetDistanceFromOrigin() == 0.0) { - return; + auto StandEventHandler::LockStandMap() -> std::lock_guard + { + return std::lock_guard(this->mapMutex); } - // If they're close to departure and we're providing delivery, assign a stand - if (flightplan.GetDistanceFromOrigin() < this->maxDistanceForDepartureStands && - this->ownership->DeliveryControlProvidedByUser(flightplan.GetOrigin())) { - this->RequestDepartureStandFromApi(flightplan); + void StandEventHandler::UnassignStandForAircraft(const std::string& callsign) + { + this->RemoveFlightStripAnnotation(callsign); + this->standAssignments.erase(callsign); + this->integrationEventHandler.SendEvent(std::make_shared(callsign)); + LogInfo("Stand assignment removed for " + callsign); } - // Otherwise, assume they're close to arrival - if (!this->ownership->DeliveryControlProvidedByUser(flightplan.GetDestination())) { - return; + void StandEventHandler::AssignStandToAircraft(const std::string& callsign, const Stand& stand) + { + using Source = StandAssignment::Source; + + this->AssignStandToAircraft(callsign, stand, Source::SystemAuto); } - this->RequestArrivalStandFromApi(flightplan); -} -void StandEventHandler::RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) -{ - const auto radarTarget = this->plugin.GetRadarTargetForCallsign(flightplan.GetCallsign()); - if (!radarTarget) { - return; + void StandEventHandler::AssignStandToAircraft( + const std::string& callsign, const Stand& stand, StandAssignment::Source source) + { + this->AnnotateFlightStrip(callsign, stand.id); + this->SetAssignedStand(callsign, stand.id, source); + this->integrationEventHandler.SendEvent( + std::make_shared(callsign, stand.airfieldCode, stand.identifier)); + const auto logMessage = std::format( + "Stand id {} ({}/{}) assigned to {} (source: {})", + stand.id, + stand.airfieldCode, + stand.identifier, + callsign, + StandAssignment::ToString(source)); + LogInfo(logMessage); + } + auto StandEventHandler::ActionsToProcess() const -> std::vector + { + return {{"assign_stand", 1}, {"unassign_stand", 1}}; } - this->DoApiStandRequest( - flightplan.GetCallsign(), - { - {"callsign", flightplan.GetCallsign()}, - {"departure_airfield", flightplan.GetOrigin()}, - {"assignment_type", "departure"}, - {"latitude", radarTarget->GetPosition().m_Latitude}, - {"longitude", radarTarget->GetPosition().m_Longitude}, - }); -} - -void StandEventHandler::RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) -{ - this->DoApiStandRequest( - flightplan.GetCallsign(), - {{"callsign", flightplan.GetCallsign()}, - {"departure_airfield", flightplan.GetOrigin()}, - {"arrival_airfield", flightplan.GetDestination()}, - {"assignment_type", "arrival"}, - {"aircraft_type", flightplan.GetAircraftType()}}); -} - -void StandEventHandler::DoApiStandRequest(const std::string& callsign, const nlohmann::json data) -{ - LogDebug("Requesting stand assignment from API: " + data.dump()); - const std::string requestCallsign = callsign; - ApiRequest() - .Post("stand/assignment/requestauto", data) - .Then([this, requestCallsign](const UKControllerPluginUtils::Api::Response& response) { - auto lock = this->LockStandMap(); - - const auto& data = response.Data(); - if (!data.contains("stand_id") || !data.at("stand_id").is_number_integer()) { - LogWarning("Invalid stand assignment response " + data.dump()); + void StandEventHandler::ProcessAction( + std::shared_ptr message, + std::function success, + std::function)> fail) + { + auto messageData = message->GetMessageData(); + if (message->GetMessageType().type == "assign_stand") { + if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { + fail({"Invalid callsign in message data"}); + return; + } + + if (!messageData.contains("airfield") || !messageData.at("airfield").is_string()) { + fail({"Invalid airfield field in message data"}); return; } - const auto standId = data.at("stand_id").get(); - if (!this->stands.contains(standId)) { - LogWarning("Invalid stand assignment response, bad id " + data.dump()); + if (!messageData.contains("stand") || !messageData.at("stand").is_string()) { + fail({"Invalid stand field in message data"}); return; } - const auto& stand = this->stands.find(standId); - LogInfo("API generated stand assignment " + std::to_string(standId) + " for " + requestCallsign); + auto errorMessage = this->DoStandAssignment( + this->plugin.GetFlightplanForCallsign(messageData.at("callsign").get()), + messageData.at("airfield").get(), + messageData.at("stand").get()); - this->AssignStandToAircraft(requestCallsign, *stand); - }) - .Catch([requestCallsign](const UKControllerPluginUtils::Api::ApiRequestException& exception) { - LogError("Failed to request stand assignment for " + requestCallsign + ": " + exception.what()); - }); -} + if (errorMessage.empty()) { + success(); + } else { + fail({errorMessage}); + } + } else if (message->GetMessageType().type == "unassign_stand") { + if (!messageData.contains("callsign") || !messageData.at("callsign").is_string()) { + fail({"Invalid callsign in message data"}); + return; + } + + auto standsGuard = this->LockStandMap(); + auto callsign = messageData.at("callsign").get(); + auto assignedStand = this->GetAssignedStandForCallsign(callsign); + + if (assignedStand != noStandAssigned) { + this->UnassignStandForAircraft(callsign); + this->taskRunner.QueueAsynchronousTask([this, callsign]() { + try { + this->api.DeleteStandAssignmentForAircraft(callsign); + } catch (ApiException&) { + LogError("Failed to delete stand assignment for " + callsign); + } + }); + } + + success(); + } + } + + void StandEventHandler::RequestStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) + { + // If EuroScope wont tell us where they are, do nothing. + if (flightplan.GetDistanceFromOrigin() == 0.0) { + return; + } + + // If they're close to departure and we're providing delivery, assign a stand + if (flightplan.GetDistanceFromOrigin() < this->maxDistanceForDepartureStands && + this->ownership->DeliveryControlProvidedByUser(flightplan.GetOrigin())) { + this->RequestDepartureStandFromApi(flightplan); + } + + // Otherwise, assume they're close to arrival + if (!this->ownership->DeliveryControlProvidedByUser(flightplan.GetDestination())) { + return; + } + + this->RequestArrivalStandFromApi(flightplan); + } + void StandEventHandler::RequestDepartureStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) + { + const auto radarTarget = this->plugin.GetRadarTargetForCallsign(flightplan.GetCallsign()); + if (!radarTarget) { + return; + } + + this->DoApiStandRequest( + flightplan.GetCallsign(), + { + {"callsign", flightplan.GetCallsign()}, + {"departure_airfield", flightplan.GetOrigin()}, + {"assignment_type", "departure"}, + {"latitude", radarTarget->GetPosition().m_Latitude}, + {"longitude", radarTarget->GetPosition().m_Longitude}, + }); + } + + void StandEventHandler::RequestArrivalStandFromApi(const Euroscope::EuroScopeCFlightPlanInterface& flightplan) + { + this->DoApiStandRequest( + flightplan.GetCallsign(), + {{"callsign", flightplan.GetCallsign()}, + {"departure_airfield", flightplan.GetOrigin()}, + {"arrival_airfield", flightplan.GetDestination()}, + {"assignment_type", "arrival"}, + {"aircraft_type", flightplan.GetAircraftType()}}); + } + + void StandEventHandler::DoApiStandRequest(const std::string& callsign, const nlohmann::json data) + { + LogDebug("Requesting stand assignment from API: " + data.dump()); + const std::string requestCallsign = callsign; + ApiRequest() + .Post("stand/assignment/requestauto", data) + .Then([this, requestCallsign](const UKControllerPluginUtils::Api::Response& response) { + auto lock = this->LockStandMap(); + + const auto& data = response.Data(); + if (!data.contains("stand_id") || !data.at("stand_id").is_number_integer()) { + LogWarning("Invalid stand assignment response " + data.dump()); + return; + } + + const auto standId = data.at("stand_id").get(); + if (!this->stands.contains(standId)) { + LogWarning("Invalid stand assignment response, bad id " + data.dump()); + return; + } + + const auto& stand = this->stands.find(standId); + LogInfo("API generated stand assignment " + std::to_string(standId) + " for " + requestCallsign); + + this->AssignStandToAircraft(requestCallsign, *stand); + }) + .Catch([requestCallsign](const UKControllerPluginUtils::Api::ApiRequestException& exception) { + LogError("Failed to request stand assignment for " + requestCallsign + ": " + exception.what()); + }); + } } // namespace UKControllerPlugin::Stands From 6cda5826bf180ed2d856b14856e814f3804f027a Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 20:05:48 +0100 Subject: [PATCH 51/59] Fix include path and array size Update include path from utils/log/LoggerFunctions.h to log/LoggerFunctions.h to match refactored headers. Also correct the constexpr sourceColourDefaults array size from 4 to 5 to match the number of initializer elements, preventing mismatched-size/overflow issues. --- src/plugin/stands/StandColourConfiguration.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index ef21c88f7..2c5dd6fa0 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -2,7 +2,7 @@ #include "StandAssignmentSource.h" #include "euroscope/UserSetting.h" #include "helper/HelperFunctions.h" -#include "utils/log/LoggerFunctions.h" +#include "log/LoggerFunctions.h" #include namespace UKControllerPlugin::Stands { @@ -42,7 +42,7 @@ namespace UKControllerPlugin::Stands { return; } - constexpr std::array sourceColourDefaults = {{ + constexpr std::array sourceColourDefaults = {{ StandAssignment::Source::Unknown, StandAssignment::Source::User, StandAssignment::Source::ReservationAllocator, From 047ceecb3b945dbf28a1fbfbb9c85c745b9a06dc Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 9 Apr 2026 22:16:13 +0100 Subject: [PATCH 52/59] Simplify sourceColourDefaults initialization Introduce a local alias `Source` for `StandAssignment::Source` and replace the verbose constexpr array initialization with a compact single-brace initializer for `sourceColourDefaults`. This reduces repetition, removes the extra nested-brace style, and improves readability. --- src/plugin/stands/StandColourConfiguration.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 2c5dd6fa0..6f202f4fb 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -42,13 +42,10 @@ namespace UKControllerPlugin::Stands { return; } - constexpr std::array sourceColourDefaults = {{ - StandAssignment::Source::Unknown, - StandAssignment::Source::User, - StandAssignment::Source::ReservationAllocator, - StandAssignment::Source::VaaAllocator, - StandAssignment::Source::SystemAuto, - }}; + using Source = StandAssignment::Source; + + constexpr std::array sourceColourDefaults = { + {Source::Unknown, Source::User, Source::ReservationAllocator, Source::VaaAllocator, Source::SystemAuto}}; for (const auto source : sourceColourDefaults) { const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); From 24134a5aa4326edb7771017a0c468b22b8e92fd2 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sun, 12 Apr 2026 16:39:58 +0100 Subject: [PATCH 53/59] Use using enum for StandAssignment::Source Replace the type alias with C++20's `using enum StandAssignment::Source` to bring enumerators into scope, and update the constexpr defaults array to use the fully-qualified enum type with unqualified enumerator initializers. This is a non-functional cleanup to reduce redundant qualification and improve readability. --- src/plugin/stands/StandColourConfiguration.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 6f202f4fb..303756cfd 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -42,10 +42,10 @@ namespace UKControllerPlugin::Stands { return; } - using Source = StandAssignment::Source; + using enum StandAssignment::Source; - constexpr std::array sourceColourDefaults = { - {Source::Unknown, Source::User, Source::ReservationAllocator, Source::VaaAllocator, Source::SystemAuto}}; + constexpr std::array sourceColourDefaults = { + {Unknown, User, ReservationAllocator, VaaAllocator, SystemAuto}}; for (const auto source : sourceColourDefaults) { const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); From d9f8727124371010e77ad9e669cd4cc99c1135c6 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sun, 12 Apr 2026 16:49:24 +0100 Subject: [PATCH 54/59] sonar --- src/plugin/stands/StandColourConfiguration.cpp | 10 +++++++--- src/plugin/stands/StandEventHandler.cpp | 12 +++++------- test/plugin/stands/StandEventHandlerTest.cpp | 8 ++++++-- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 303756cfd..4fc9f8d2f 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -42,10 +42,14 @@ namespace UKControllerPlugin::Stands { return; } - using enum StandAssignment::Source; + using AssignmentSource = StandAssignment::Source; - constexpr std::array sourceColourDefaults = { - {Unknown, User, ReservationAllocator, VaaAllocator, SystemAuto}}; + constexpr std::array sourceColourDefaults = { + {AssignmentSource::Unknown, + AssignmentSource::User, + AssignmentSource::ReservationAllocator, + AssignmentSource::VaaAllocator, + AssignmentSource::SystemAuto}}; for (const auto source : sourceColourDefaults) { const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 9cf6c067a..12c28f1bf 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -350,18 +350,16 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { - using enum StandAssignment::Source; - switch (source) { - case Unknown: + case StandAssignment::Source::Unknown: return "UNK"; - case User: + case StandAssignment::Source::User: return "USER"; - case ReservationAllocator: + case StandAssignment::Source::ReservationAllocator: return "RES"; - case VaaAllocator: + case StandAssignment::Source::VaaAllocator: return "VAA"; - case SystemAuto: + case StandAssignment::Source::SystemAuto: return "AUTO"; default: return "UNK"; diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index 6cbf54a7e..e6289cf26 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -177,9 +177,13 @@ namespace UKControllerPluginTest { [[nodiscard]] static auto AllSources() -> std::array { - using enum StandAssignment::Source; + using AssignmentSource = StandAssignment::Source; - return {User, ReservationAllocator, VaaAllocator, SystemAuto}; + return { + AssignmentSource::User, + AssignmentSource::ReservationAllocator, + AssignmentSource::VaaAllocator, + AssignmentSource::SystemAuto}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From f8df1d803a40759d780ca05232122838d63f5901 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sun, 12 Apr 2026 17:01:04 +0100 Subject: [PATCH 55/59] Use using enum for StandAssignment::Source Introduce C++20 'using enum' for StandAssignment::Source to allow unqualified enum constants, simplifying switch cases and initializer lists. Updates made in StandColourConfiguration.cpp, StandEventHandler.cpp and the corresponding test to improve readability with no behavioral changes. Co-Authored-By: Copilot <198982749+Copilot@users.noreply.github.com> --- src/plugin/stands/StandColourConfiguration.cpp | 10 +++------- src/plugin/stands/StandEventHandler.cpp | 12 +++++++----- test/plugin/stands/StandEventHandlerTest.cpp | 8 ++------ 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 4fc9f8d2f..7958971eb 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -42,14 +42,10 @@ namespace UKControllerPlugin::Stands { return; } - using AssignmentSource = StandAssignment::Source; + using enum UKControllerPlugin::Stands::StandAssignment::Source; - constexpr std::array sourceColourDefaults = { - {AssignmentSource::Unknown, - AssignmentSource::User, - AssignmentSource::ReservationAllocator, - AssignmentSource::VaaAllocator, - AssignmentSource::SystemAuto}}; + constexpr std::array sourceColourDefaults = { + {Unknown, User, ReservationAllocator, VaaAllocator, SystemAuto}}; for (const auto source : sourceColourDefaults) { const std::string key = std::string(SETTING_PREFIX) + std::string(StandAssignment::ToString(source)); diff --git a/src/plugin/stands/StandEventHandler.cpp b/src/plugin/stands/StandEventHandler.cpp index 12c28f1bf..de81f6a30 100644 --- a/src/plugin/stands/StandEventHandler.cpp +++ b/src/plugin/stands/StandEventHandler.cpp @@ -350,16 +350,18 @@ namespace UKControllerPlugin::Stands { auto StandEventHandler::GetAssignmentSourceShorthand(StandAssignment::Source source) -> std::string { + using enum UKControllerPlugin::Stands::StandAssignment::Source; + switch (source) { - case StandAssignment::Source::Unknown: + case Unknown: return "UNK"; - case StandAssignment::Source::User: + case User: return "USER"; - case StandAssignment::Source::ReservationAllocator: + case ReservationAllocator: return "RES"; - case StandAssignment::Source::VaaAllocator: + case VaaAllocator: return "VAA"; - case StandAssignment::Source::SystemAuto: + case SystemAuto: return "AUTO"; default: return "UNK"; diff --git a/test/plugin/stands/StandEventHandlerTest.cpp b/test/plugin/stands/StandEventHandlerTest.cpp index e6289cf26..6e17a7c6e 100644 --- a/test/plugin/stands/StandEventHandlerTest.cpp +++ b/test/plugin/stands/StandEventHandlerTest.cpp @@ -177,13 +177,9 @@ namespace UKControllerPluginTest { [[nodiscard]] static auto AllSources() -> std::array { - using AssignmentSource = StandAssignment::Source; + using enum UKControllerPlugin::Stands::StandAssignment::Source; - return { - AssignmentSource::User, - AssignmentSource::ReservationAllocator, - AssignmentSource::VaaAllocator, - AssignmentSource::SystemAuto}; + return {User, ReservationAllocator, VaaAllocator, SystemAuto}; } [[nodiscard]] static auto MakeInboundMessage(const std::string& type, const nlohmann::json& data) From 00d66cd832effbbbfabeaf1a5ac2d7e7e5c61020 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Sat, 18 Apr 2026 11:09:35 +0100 Subject: [PATCH 56/59] Use DEFAULT_COLOUR for Unknown stand source Replace DEFAULT_UNKNOWN_COLOUR with the shared DEFAULT_COLOUR for the Unknown StandAssignment source and remove the now-unused DEFAULT_UNKNOWN_COLOUR constant. This unifies the default gray value and reduces duplicated color definitions (updated StandColourConfiguration.cpp and StandColourConfiguration.h). --- src/plugin/stands/StandColourConfiguration.cpp | 2 +- src/plugin/stands/StandColourConfiguration.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index 7958971eb..ca0dee139 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -18,7 +18,7 @@ namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) : userSetting(userSetting), sourceColours( - {{StandAssignment::Source::Unknown, DEFAULT_UNKNOWN_COLOUR}, + {{StandAssignment::Source::Unknown, DEFAULT_COLOUR}, {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 359357188..2a7ce7e57 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -44,7 +44,6 @@ namespace UKControllerPlugin::Stands { static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); // Default colours if not configured - static constexpr COLORREF DEFAULT_UNKNOWN_COLOUR = RGB(204, 204, 204); // grey static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 255, 255); // white static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 216, 0); // yellow static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 149, 41); // orange From e0eb3da4fc930d4d2d1116b527009daa3cdd9967 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 23 Apr 2026 11:34:01 +0100 Subject: [PATCH 57/59] Update src/plugin/stands/StandColourConfiguration.cpp Co-authored-by: Patrick Winters <61561933+19wintersp@users.noreply.github.com> --- src/plugin/stands/StandColourConfiguration.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index ca0dee139..fd47ae756 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -18,7 +18,6 @@ namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) : userSetting(userSetting), sourceColours( - {{StandAssignment::Source::Unknown, DEFAULT_COLOUR}, {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, From 34abef7b2a0ac57d0166cd84f79e67ca5d043819 Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 23 Apr 2026 11:34:16 +0100 Subject: [PATCH 58/59] Update src/plugin/stands/StandColourConfiguration.h Co-authored-by: Patrick Winters <61561933+19wintersp@users.noreply.github.com> --- src/plugin/stands/StandColourConfiguration.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 2a7ce7e57..39fe5447b 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -41,13 +41,13 @@ namespace UKControllerPlugin::Stands { std::map sourceColours; // Default colour (grey) for unknown sources - static constexpr COLORREF DEFAULT_COLOUR = RGB(180, 180, 180); + static constexpr COLORREF DEFAULT_COLOUR = RGB(204, 204, 204); // Default colours if not configured - static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 255, 255); // white + static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 149, 41); // orange static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 216, 0); // yellow - static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 149, 41); // orange - static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(204, 204, 204); // grey + static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 216, 0); // yellow + static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(255, 255, 255); // white // UserSetting key prefix for colours static constexpr std::string_view SETTING_PREFIX = "stand_colour_"; From e30e2307d6884253651918a3886f3f51c6d14d7d Mon Sep 17 00:00:00 2001 From: Daniel Green Date: Thu, 23 Apr 2026 15:49:35 +0100 Subject: [PATCH 59/59] Fix initializer list and format comments Wrap the source/color entries in an extra set of braces in StandColourConfiguration.cpp so the initializer is correctly interpreted for sourceColours (prevents ambiguous/invalid initializer parsing). Also normalize spacing of inline comments in StandColourConfiguration.h for consistent formatting. --- src/plugin/stands/StandColourConfiguration.cpp | 2 +- src/plugin/stands/StandColourConfiguration.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/plugin/stands/StandColourConfiguration.cpp b/src/plugin/stands/StandColourConfiguration.cpp index fd47ae756..e70a58ff8 100644 --- a/src/plugin/stands/StandColourConfiguration.cpp +++ b/src/plugin/stands/StandColourConfiguration.cpp @@ -18,7 +18,7 @@ namespace UKControllerPlugin::Stands { StandColourConfiguration::StandColourConfiguration(UKControllerPlugin::Euroscope::UserSetting* userSetting) : userSetting(userSetting), sourceColours( - {StandAssignment::Source::User, DEFAULT_USER_COLOUR}, + {{StandAssignment::Source::User, DEFAULT_USER_COLOUR}, {StandAssignment::Source::ReservationAllocator, DEFAULT_RESERVATION_COLOUR}, {StandAssignment::Source::VaaAllocator, DEFAULT_VAA_COLOUR}, {StandAssignment::Source::SystemAuto, DEFAULT_SYSTEM_COLOUR}}) diff --git a/src/plugin/stands/StandColourConfiguration.h b/src/plugin/stands/StandColourConfiguration.h index 39fe5447b..4a8030b8b 100644 --- a/src/plugin/stands/StandColourConfiguration.h +++ b/src/plugin/stands/StandColourConfiguration.h @@ -44,10 +44,10 @@ namespace UKControllerPlugin::Stands { static constexpr COLORREF DEFAULT_COLOUR = RGB(204, 204, 204); // Default colours if not configured - static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 149, 41); // orange + static constexpr COLORREF DEFAULT_USER_COLOUR = RGB(255, 149, 41); // orange static constexpr COLORREF DEFAULT_RESERVATION_COLOUR = RGB(255, 216, 0); // yellow - static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 216, 0); // yellow - static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(255, 255, 255); // white + static constexpr COLORREF DEFAULT_VAA_COLOUR = RGB(255, 216, 0); // yellow + static constexpr COLORREF DEFAULT_SYSTEM_COLOUR = RGB(255, 255, 255); // white // UserSetting key prefix for colours static constexpr std::string_view SETTING_PREFIX = "stand_colour_";