connection between 2 systems and bug fixes (#14)

This commit is contained in:
tompzf
2026-07-03 14:53:48 +02:00
committed by GitHub
parent 0fb5660d27
commit 46842200f1
284 changed files with 35200 additions and 8265 deletions

View File

@@ -0,0 +1,33 @@
#*******************************************************************************
# Copyright (c) 2025-2026 ZF Friedrichshafen AG
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
#
# Contributors:
# Erik Verhoeven - initial API and implementation
#*******************************************************************************
# Define project
project (UnitTest_App_Settings VERSION 1.0 LANGUAGES CXX)
# Compile the source code
add_executable(UnitTest_App_Settings
"main.cpp"
"startup_config.cpp" "settings_config.cpp")
target_link_libraries(UnitTest_App_Settings ${CMAKE_DL_LIBS} GTest::GTest)
# Add the IDL Compiler unittest
add_test(NAME UnitTest_App_Settings COMMAND UnitTest_App_Settings)
# Execute the test
add_custom_command(TARGET UnitTest_App_Settings POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_App_Settings>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_App_Settings.xml
VERBATIM
)
# Build dependencies
add_dependencies(UnitTest_App_Settings dependency_sdv_components)

View File

@@ -0,0 +1,41 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/process_watchdog.h"
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/app_settings.cpp"
#include "../../../sdv_services/core/toml_parser/parser_toml.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.cpp"
#include "../../../sdv_services/core/toml_parser/lexer_toml.cpp"
#include "../../../sdv_services/core/toml_parser/lexer_toml_token.cpp"
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.cpp"
#include "../../../sdv_services/core/toml_parser/miscellaneous.cpp"
/**
* @brief Main function
*/
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
#else
extern "C" int main(int argc, char* argv[])
#endif
{
CProcessWatchdog watchdog;
CLocalMemMgr memmgr;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,537 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/exec_dir_helper.h"
#include "../../../sdv_services/core/app_settings.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include <support/toml.h>
// Load settings
// Invalid file
// No file
// Config paths
// Listeners
// Connections
// Save settings
// No file
// Config paths
// Listeners
// Connections
std::filesystem::path GetSettingsFilePath()
{
// The settings file is located at the exe directory with sub-directory 2000.
return GetExecDirectory() / "2000" / "settings.toml";
}
toml_parser::CParser ReadSettingsFile()
{
std::ifstream fstream(GetSettingsFilePath());
if (!fstream.is_open()) return {};
toml_parser::CParser parser(std::string((std::istreambuf_iterator<char>(fstream)), std::istreambuf_iterator<char>()));
fstream.close();
return parser;
}
bool WriteSettingsFile(const std::string& rssSettings)
{
std::filesystem::create_directories(GetSettingsFilePath().remove_filename());
std::ofstream fstream(GetSettingsFilePath(), std::ios::trunc);
if (!fstream.is_open()) return false;
fstream << rssSettings;
return true;
}
void DeleteSettingsFile()
{
if (std::filesystem::exists(GetSettingsFilePath().remove_filename()))
std::filesystem::remove_all(GetSettingsFilePath().remove_filename());
}
TEST(AppSettingsTest_SettingsConfig, LoadInvalidConfig)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
const std::string ssInvalidToml = R"toml([Settings]
Version = hundred # Should be valid number)toml";
const std::string ssInvalidValue = R"toml([Settings]
Version = "hundred" # Invalid value)toml";
const std::string ssInvalidVersion = R"toml([Settings]
Version = 99)toml";
const std::string ssNoVersion = R"toml([Settings])toml";
WriteSettingsFile(ssInvalidToml);
EXPECT_FALSE(settings.LoadSettings());
WriteSettingsFile(ssInvalidValue);
EXPECT_FALSE(settings.LoadSettings());
WriteSettingsFile(ssInvalidVersion);
EXPECT_FALSE(settings.LoadSettings());
WriteSettingsFile(ssNoVersion);
EXPECT_FALSE(settings.LoadSettings());
}
TEST(AppSettingsTest_SettingsConfig, LoadNoConfig)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
// Read empty file - this is not an error
EXPECT_TRUE(settings.LoadSettings());
}
TEST(AppSettingsTest_SettingsConfig, SaveConfigWrongMode)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_TRUE(settings.SaveSettings());
// Verify for a file
EXPECT_FALSE(std::filesystem::exists(GetSettingsFilePath()));
}
TEST(AppSettingsTest_SettingsConfig, SaveDefaultConfig)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_TRUE(settings.SaveSettings());
// Verify for a file
EXPECT_TRUE(std::filesystem::exists(GetSettingsFilePath()));
// Verify settings
auto parser = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings(parser.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings);
EXPECT_EQ(tableSettings.GetDirect("Version").GetValue(), 100u);
sdv::toml::CNode nodePlatformConfig = tableSettings.GetDirect("PlatformConfig");
EXPECT_TRUE(nodePlatformConfig);
sdv::toml::CNode nodeVehIfcConfig = tableSettings.GetDirect("VehIfcConfig");
EXPECT_TRUE(nodeVehIfcConfig);
sdv::toml::CNode nodeVehAbstrConfig = tableSettings.GetDirect("VehAbstrConfig");
EXPECT_TRUE(nodeVehAbstrConfig);
sdv::toml::CNode nodeAppConfig = tableSettings.GetDirect("AppConfig");
EXPECT_TRUE(nodeAppConfig);
sdv::toml::CNodeCollection arrayListener = tableSettings.GetDirect("Listener");
EXPECT_FALSE(arrayListener);
sdv::toml::CNodeCollection arrayConnection = tableSettings.GetDirect("Connection");
EXPECT_FALSE(arrayConnection);
}
TEST(AppSettingsTest_SettingsConfig, LoadSettings_SystemConfigs)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::platform_config), "platform.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_interface_config), "vehicle_ifc.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_abstraction_config), "vehicle_abstract.toml");
WriteSettingsFile(R"toml([Settings]
Version = 100
PlatformConfig = "abc.toml"
VehIfcConfig = "def.toml"
VehAbstrConfig = "ghi.toml")toml");
// Read settings file
EXPECT_TRUE(settings.LoadSettings());
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::platform_config), "abc.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_interface_config), "def.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_abstraction_config), "ghi.toml");
}
TEST(AppSettingsTest_SettingsConfig, SaveSettings_SystemConfigs)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::platform_config), "platform.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_interface_config), "vehicle_ifc.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_abstraction_config), "vehicle_abstract.toml");
settings.DisableConfig(CAppSettings::EConfigType::platform_config);
settings.DisableConfig(CAppSettings::EConfigType::vehicle_interface_config);
settings.DisableConfig(CAppSettings::EConfigType::vehicle_abstraction_config);
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::platform_config), "");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_interface_config), "");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_abstraction_config), "");
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings(parser.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings);
EXPECT_TRUE(tableSettings.GetDirect("PlatformConfig").GetValueAsPath().empty());
EXPECT_TRUE(tableSettings.GetDirect("VehIfcConfig").GetValueAsPath().empty());
EXPECT_TRUE(tableSettings.GetDirect("VehAbstrConfig").GetValueAsPath().empty());
settings.EnableConfig(CAppSettings::EConfigType::platform_config);
settings.EnableConfig(CAppSettings::EConfigType::vehicle_interface_config);
settings.EnableConfig(CAppSettings::EConfigType::vehicle_abstraction_config);
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::platform_config), "platform.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_interface_config), "vehicle_ifc.toml");
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::vehicle_abstraction_config), "vehicle_abstract.toml");
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser2 = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings2(parser2.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings2);
EXPECT_EQ(tableSettings2.GetDirect("PlatformConfig").GetValueAsPath(), "platform.toml");
EXPECT_EQ(tableSettings2.GetDirect("VehIfcConfig").GetValueAsPath(), "vehicle_ifc.toml");
EXPECT_EQ(tableSettings2.GetDirect("VehAbstrConfig").GetValueAsPath(), "vehicle_abstract.toml");
}
TEST(AppSettingsTest_SettingsConfig, LoadSettings_UserConfig)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::user_config), "app_config.toml");
WriteSettingsFile(R"toml([Settings]
Version = 100
AppConfig = "xyz.toml")toml");
// Read settings file
EXPECT_TRUE(settings.LoadSettings());
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::user_config), "xyz.toml");
settings.Reset();
// For all configurations except main, isolated and maintenance, the user config is supplied through the app config.
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Standalone"
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string()) + R"toml(
Config = "klm.toml")toml"));
EXPECT_EQ(settings.GetUserConfigPath(), "klm.toml");
}
TEST(AppSettingsTest_SettingsConfig, SaveSettings_UserConfig)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::user_config), "app_config.toml");
settings.DisableConfig(CAppSettings::EConfigType::user_config);
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::user_config), "");
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings(parser.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings);
EXPECT_TRUE(tableSettings.GetDirect("AppConfig").GetValueAsPath().empty());
settings.EnableConfig(CAppSettings::EConfigType::user_config);
EXPECT_EQ(settings.GetConfigPath(CAppSettings::EConfigType::user_config), "app_config.toml");
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser2 = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings2(parser2.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings2);
EXPECT_EQ(tableSettings2.GetDirect("AppConfig").GetValueAsPath(), "app_config.toml");
}
TEST(AppSettingsTest_SettingsConfig, LoadSettings_Listeners)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
// Default listener shoule be available.
EXPECT_EQ(settings.GetListeners().size(), 1u);
WriteSettingsFile(R"toml([Settings]
Version = 100
[[Settings.Listener]]
Name = "MyListener1"
[Settings.Listener.Provider]
Name = "MyListenerProvider1"
[Settings.Listener.IpcChannel]
abc = "def"
[[Settings.Listener]]
Name = "MyListener2"
[Settings.Listener.Provider]
Name = "MyListenerProvider2"
[Settings.Listener.IpcChannel]
xyz = 1234
)toml");
// Read settings file - note: the listeners are part of a listener map. The order is not fixed.
// There will be an additional default listener.
EXPECT_TRUE(settings.LoadSettings());
auto seqListeners = settings.GetListeners();
ASSERT_EQ(seqListeners.size(), 3u);
EXPECT_TRUE(seqListeners[0] == "MyListener1" || seqListeners[1] == "MyListener1" || seqListeners[2] == "MyListener1");
EXPECT_TRUE(seqListeners[0] == "MyListener2" || seqListeners[1] == "MyListener2" || seqListeners[2] == "MyListener2");
EXPECT_TRUE(seqListeners[0] == "Default" || seqListeners[1] == "Default" || seqListeners[2] == "Default");
EXPECT_TRUE(settings.GetListenerConfig("MyListener0").empty());
EXPECT_TRUE(toml_parser::CompareEqual(settings.GetListenerConfig("MyListener1"), R"toml([Provider]
Name = "MyListenerProvider1"
[IpcChannel]
abc = "def"
)toml"));
EXPECT_TRUE(toml_parser::CompareEqual(settings.GetListenerConfig("MyListener2"), R"toml([Provider]
Name = "MyListenerProvider2"
[IpcChannel]
xyz = 1234
)toml"));
}
TEST(AppSettingsTest_SettingsConfig, SaveSettings_Listeners)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetListeners().size(), 1u);
EXPECT_TRUE(settings.AddListenerConfig("MyListener2", R"toml([Provider]
Name = "MyListenerProvider2"
[IpcChannel]
abc = "def")toml"));
EXPECT_EQ(settings.GetListeners().size(), 2u);
EXPECT_TRUE(settings.AddListenerConfig("MyListener1", R"toml([Provider]
Name = "MyListenerProvider1"
[IpcChannel]
xyz = 1234)toml"));
EXPECT_EQ(settings.GetListeners().size(), 3u);
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings(parser.Root().GetNodeDirect("Settings"));
[[maybe_unused]] std::string ss = parser.GenerateTOML();
EXPECT_TRUE(tableSettings);
sdv::toml::CNodeCollection tableListener = tableSettings.GetDirect("Listener[0]");
if (tableListener.GetDirect("Name").GetValueAsString() != "MyListener1")
tableListener = tableSettings.GetDirect("Listener[1]");
EXPECT_TRUE(tableListener);
EXPECT_EQ(tableListener.GetDirect("Name").GetValueAsString(), "MyListener1");
EXPECT_EQ(tableListener.GetDirect("Provider.Name").GetValueAsString(), "MyListenerProvider1");
EXPECT_EQ(tableListener.GetDirect("IpcChannel.xyz").GetValue(), 1234);
tableListener = tableSettings.GetDirect("Listener[0]");
if (tableListener.GetDirect("Name").GetValueAsString() != "MyListener2")
tableListener = tableSettings.GetDirect("Listener[1]");
EXPECT_TRUE(tableListener);
EXPECT_EQ(tableListener.GetDirect("Name").GetValueAsString(), "MyListener2");
EXPECT_EQ(tableListener.GetDirect("Provider.Name").GetValueAsString(), "MyListenerProvider2");
EXPECT_EQ(tableListener.GetDirect("IpcChannel.abc").GetValueAsString(), "def");
// Remove one listener
settings.RemoveListenerConfig("MyListener1");
EXPECT_EQ(settings.GetListeners().size(), 2u);
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser2 = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings2(parser2.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings2);
tableListener = tableSettings2.GetDirect("Listener[0]");
EXPECT_TRUE(tableListener);
EXPECT_EQ(tableListener.GetDirect("Name").GetValueAsString(), "MyListener2");
EXPECT_EQ(tableListener.GetDirect("Provider.Name").GetValueAsString(), "MyListenerProvider2");
EXPECT_EQ(tableListener.GetDirect("IpcChannel.abc").GetValueAsString(), "def");
}
TEST(AppSettingsTest_SettingsConfig, LoadSettings_Connections)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
// Default connection only
EXPECT_EQ(settings.GetConnections().size(), 1);
WriteSettingsFile(R"toml([Settings]
Version = 100
[[Settings.Connection]]
Name = "MyConnection1"
[Settings.Connection.Provider]
Name = "MyConnectionProvider1"
[Settings.Connection.IpcChannel]
abc = "def"
[[Settings.Connection]]
Name = "MyConnection2"
[Settings.Connection.Provider]
Name = "MyConnectionProvider2"
[Settings.Connection.IpcChannel]
xyz = 1234
)toml");
// Read settings file - note: the order of connections is preserved in the settings file.
// There will be an additional default connection.
EXPECT_TRUE(settings.LoadSettings());
auto seqConnections = settings.GetConnections();
ASSERT_EQ(seqConnections.size(), 3u);
EXPECT_EQ(seqConnections[0], "Default");
EXPECT_EQ(seqConnections[1], "MyConnection1");
EXPECT_EQ(seqConnections[2], "MyConnection2");
EXPECT_TRUE(settings.GetConnectionConfig("MyConnection0").empty());
EXPECT_TRUE(toml_parser::CompareEqual(settings.GetConnectionConfig("MyConnection1"), R"toml([Provider]
Name = "MyConnectionProvider1"
[IpcChannel]
abc = "def"
)toml"));
EXPECT_TRUE(toml_parser::CompareEqual(settings.GetConnectionConfig("MyConnection2"), R"toml([Provider]
Name = "MyConnectionProvider2"
[IpcChannel]
xyz = 1234
)toml"));
}
TEST(AppSettingsTest_SettingsConfig, SaveSettings_Connections)
{
// Settings for the main application with a specific instance ID
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
DeleteSettingsFile(); // Needed to prevent settings file parsing during startup.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetConnections().size(), 1u);
EXPECT_TRUE(settings.AddConnectionConfig("MyConnection2", R"toml([Provider]
Name = "MyConnectionProvider2"
[IpcChannel]
abc = "def")toml"));
EXPECT_EQ(settings.GetConnections().size(), 2u);
EXPECT_TRUE(settings.AddConnectionConfig("MyConnection1", R"toml([Provider]
Name = "MyConnectionProvider1"
[IpcChannel]
xyz = 1234)toml"));
EXPECT_EQ(settings.GetConnections().size(), 3u);
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings(parser.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings);
sdv::toml::CNodeCollection tableConnection = tableSettings.GetDirect("Connection[0]");
EXPECT_TRUE(tableConnection);
EXPECT_EQ(tableConnection.GetDirect("Name").GetValueAsString(), "MyConnection2");
EXPECT_EQ(tableConnection.GetDirect("Provider.Name").GetValueAsString(), "MyConnectionProvider2");
EXPECT_EQ(tableConnection.GetDirect("IpcChannel.abc").GetValueAsString(), "def");
tableConnection = tableSettings.GetDirect("Connection[1]");
EXPECT_TRUE(tableConnection);
EXPECT_EQ(tableConnection.GetDirect("Name").GetValueAsString(), "MyConnection1");
EXPECT_EQ(tableConnection.GetDirect("Provider.Name").GetValueAsString(), "MyConnectionProvider1");
EXPECT_EQ(tableConnection.GetDirect("IpcChannel.xyz").GetValue(), 1234);
// Remove one listener
settings.RemoveConnectionConfig("MyConnection1");
EXPECT_EQ(settings.GetConnections().size(), 2u);
EXPECT_TRUE(settings.SaveSettings());
// Verify settings
auto parser2 = ReadSettingsFile();
sdv::toml::CNodeCollection tableSettings2(parser2.Root().GetNodeDirect("Settings"));
EXPECT_TRUE(tableSettings2);
tableConnection = tableSettings2.GetDirect("Connection[0]");
EXPECT_TRUE(tableConnection);
EXPECT_EQ(tableConnection.GetDirect("Name").GetValueAsString(), "MyConnection2");
EXPECT_EQ(tableConnection.GetDirect("Provider.Name").GetValueAsString(), "MyConnectionProvider2");
EXPECT_EQ(tableConnection.GetDirect("IpcChannel.abc").GetValueAsString(), "def");
}

View File

@@ -0,0 +1,341 @@
/********************************************************************************
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
*
* This program and the accompanying materials are made available under the
* terms of the Apache License Version 2.0 which is available at
* https://www.apache.org/licenses/LICENSE-2.0
*
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../sdv_services/core/app_settings.h"
#include "../../../global/exec_dir_helper.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
// Load startup config
// Invalid config
// Empty config (default config)
// Application types
// Instance ID
// Log handler
// Console output
// Config path
TEST(AppSettingsTest_StartupConfig, InvalidConfig)
{
const std::string ssInvalidToml = R"toml([Application]
Mode = Standalone # Missing quotes)toml";
const std::string ssInvalidValue = R"toml([Application]
Mode = "Supadupa" # Invalid value)toml";
const std::string ssAdditionalValues = R"toml([Application]
Mode = "Standalone"
SpecialAction = "Fly to the moon" # Additional value)toml";
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
EXPECT_FALSE(settings.ProcessAppStartupConfig(ssInvalidToml));
EXPECT_FALSE(settings.ProcessAppStartupConfig(ssInvalidValue));
EXPECT_TRUE(settings.ProcessAppStartupConfig(ssAdditionalValues));
}
TEST(AppSettingsTest_StartupConfig, DefaultConfig)
{
const std::string ssEmptyToml;
CAppSettings settings;
EXPECT_EQ(settings.GetInstanceID(), 0u);
EXPECT_TRUE(settings.ProcessAppStartupConfig(ssEmptyToml));
EXPECT_TRUE(settings.IsStandaloneApplication());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::error);
EXPECT_EQ(settings.GetConsoleReporting(), CAppSettings::EAppConsoleReporting::normal);
EXPECT_EQ(settings.GetInstanceID(), 1000u);
}
TEST(AppSettingsTest_StartupConfig, ApplicationTypes)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::no_context);
EXPECT_TRUE(settings.ProcessAppStartupConfig(""));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::standalone);
EXPECT_TRUE(settings.IsStandaloneApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "External")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::external);
EXPECT_TRUE(settings.IsExternalApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Standalone")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::standalone);
EXPECT_TRUE(settings.IsStandaloneApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Isolated")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::isolated);
EXPECT_TRUE(settings.IsIsolatedApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::main);
EXPECT_TRUE(settings.IsMainApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Essential")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::essential);
EXPECT_TRUE(settings.IsEssentialApplication());
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance")toml"));
EXPECT_EQ(settings.GetContextType(), sdv::app::EAppContext::maintenance);
EXPECT_TRUE(settings.IsMaintenanceApplication());
}
TEST(AppSettingsTest_StartupConfig, InstanceID)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
EXPECT_EQ(settings.GetInstanceID(), 0u);
// Change type to main; no instance ID yet
settings.SetContextType(sdv::app::EAppContext::main);
EXPECT_EQ(settings.GetInstanceID(), 0u);
// Set instance ID, but no type
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Instance = 1234)toml"));
EXPECT_EQ(settings.GetInstanceID(), 1234u);
// Change types, only main, isolated and maintenance should provide the instance ID.
settings.SetContextType(sdv::app::EAppContext::standalone);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.SetContextType(sdv::app::EAppContext::external);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.SetContextType(sdv::app::EAppContext::isolated);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.SetContextType(sdv::app::EAppContext::main);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.SetContextType(sdv::app::EAppContext::essential);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.SetContextType(sdv::app::EAppContext::maintenance);
EXPECT_EQ(settings.GetInstanceID(), 1234u);
settings.Reset();
EXPECT_EQ(settings.GetInstanceID(), 0u);
}
TEST(AppSettingsTest_StartupConfig, LogHandler)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
// No config
EXPECT_TRUE(settings.GetLoggerClass().empty());
EXPECT_TRUE(settings.GetLoggerModulePath().empty());
EXPECT_TRUE(settings.GetLoggerProgramTag().empty());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::error);
// Default config
EXPECT_TRUE(settings.ProcessAppStartupConfig(""));
EXPECT_EQ(settings.GetLoggerClass(), "DefaultLoggerService");
EXPECT_TRUE(settings.GetLoggerModulePath().empty());
EXPECT_TRUE(settings.GetLoggerProgramTag().empty());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::error);
// Default logger when main or isolated
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main")toml"));
EXPECT_EQ(settings.GetLoggerClass(), "DefaultLoggerService");
EXPECT_TRUE(settings.GetLoggerModulePath().empty());
EXPECT_TRUE(settings.GetLoggerProgramTag().empty());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::info);
// Default logger when main or isolated
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Isolated")toml"));
EXPECT_EQ(settings.GetLoggerClass(), "DefaultLoggerService");
EXPECT_TRUE(settings.GetLoggerModulePath().empty());
EXPECT_TRUE(settings.GetLoggerProgramTag().empty());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::info);
// Default logger for all others
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Standalone")toml"));
EXPECT_EQ(settings.GetLoggerClass(), "DefaultLoggerService");
EXPECT_TRUE(settings.GetLoggerModulePath().empty());
EXPECT_TRUE(settings.GetLoggerProgramTag().empty());
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::error);
// Set severity level for logger
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Trace")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::trace);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Debug")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::debug);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Info")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Warning")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::warning);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Error")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::error);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Fatal")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::fatal);
EXPECT_FALSE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Filter = "Wrong")toml"));
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::fatal);
// Set severity level for console
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Trace")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::trace);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Debug")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::debug);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Info")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::info);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Warning")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::warning);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Error")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::error);
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Fatal")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::fatal);
EXPECT_FALSE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
ViewFilter = "Wrong")toml"));
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::fatal);
// Explicit logger
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([LogHandler]
Class = "logger_class"
Path = "logger.xyz"
Tag = "logger_tag"
Filter = "Trace"
ViewFilter = "Warning"
UnkownValue = "hi")toml"));
EXPECT_EQ(settings.GetLoggerClass(), "logger_class");
EXPECT_EQ(settings.GetLoggerModulePath(), "logger.xyz");
EXPECT_EQ(settings.GetLoggerProgramTag(), "logger_tag");
EXPECT_EQ(settings.GetLoggerSeverityFilter(), sdv::core::ELogSeverity::trace);
EXPECT_EQ(settings.GetConsoleSeverityFilter(), sdv::core::ELogSeverity::warning);
}
TEST(AppSettingsTest_StartupConfig, ConnectionRetries)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
// Default is 5 retries
EXPECT_EQ(settings.GetConnectRetries(), 5u);
EXPECT_TRUE(settings.ProcessAppStartupConfig(""));
EXPECT_EQ(settings.GetConnectRetries(), 5u);
// Set 0 retries - this is not an error and minimizes to 3
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Connections]
Retries = 0)toml"));
EXPECT_EQ(settings.GetConnectRetries(), 3u);
// Set 10 retries
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Connections]
Retries = 10)toml"));
EXPECT_EQ(settings.GetConnectRetries(), 10u);
// Set 100 retries - this is not an error and maximizes to 30
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Connections]
Retries = 100)toml"));
EXPECT_EQ(settings.GetConnectRetries(), 30u);
}
TEST(AppSettingsTest_StartupConfig, InstallDir)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
// Empty install directory
EXPECT_TRUE(settings.GetRootDir().empty());
EXPECT_TRUE(settings.GetInstallDir().empty());
// Install directory has significance with main, isolated and maintenance apps only.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_TRUE(settings.GetRootDir().empty());
EXPECT_TRUE(settings.GetInstallDir().empty());
// Use main and a specific instance ID
std::filesystem::remove_all(GetExecDirectory() / "2000"); // Needed to prevent settings file parsing.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Instance = 2000
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetRootDir(), GetExecDirectory());
EXPECT_EQ(settings.GetInstallDir(), GetExecDirectory() / "2000");
// Use isolated and a specific instance ID
std::filesystem::remove_all(GetExecDirectory() / "2001"); // Needed to prevent settings file parsing.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Isolated"
Instance = 2001
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetRootDir(), GetExecDirectory());
EXPECT_EQ(settings.GetInstallDir(), GetExecDirectory() / "2001");
// Use maintenance and a specific instance ID
std::filesystem::remove_all(GetExecDirectory() / "2002"); // Needed to prevent settings file parsing.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2002
InstallDir = )toml" + toml_parser::QuoteText(GetExecDirectory().generic_u8string())));
EXPECT_EQ(settings.GetRootDir(), GetExecDirectory());
EXPECT_EQ(settings.GetInstallDir(), GetExecDirectory() / "2002");
// Relative path
std::filesystem::remove_all(GetExecDirectory() / "2003"); // Needed to prevent settings file parsing.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Instance = 2003
InstallDir = "..")toml"));
EXPECT_EQ(settings.GetRootDir(), GetExecDirectory() / "..");
EXPECT_EQ(settings.GetInstallDir(), GetExecDirectory() / ".." / "2003");
}
TEST(AppSettingsTest_StartupConfig, CustomConfigFile)
{
CAppSettings settings;
settings.SetConsoleReporting(CAppSettings::EAppConsoleReporting::silent);
// Default empty
EXPECT_TRUE(settings.GetUserConfigPath().empty());
// Application config path has no significance with main, isolated and maintenance apps only.
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Config = "abc.def")toml"));
EXPECT_EQ(settings.GetUserConfigPath(), "abc.def");
// Use main
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Main"
Config = "def.hij")toml"));
EXPECT_EQ(settings.GetUserConfigPath(), "abc.def");
// Use isolated
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Isolated"
Config = "hij.klm")toml"));
EXPECT_EQ(settings.GetUserConfigPath(), "abc.def");
// Use maintenance
EXPECT_TRUE(settings.ProcessAppStartupConfig(R"toml([Application]
Mode = "Maintenance"
Config = "klm.nop")toml"));
EXPECT_EQ(settings.GetUserConfigPath(), "abc.def");
}