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

@@ -1,20 +0,0 @@
/********************************************************************************
* 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
********************************************************************************/
/**
- Default instantiate listener
- Instantiate with specific info
- Multiple instantiate with identical info (failure)
- Multiple instantiate with different info
- Default instantiate client and get connection information
- */

View File

@@ -12,22 +12,22 @@
#*******************************************************************************
# Define project
project (UnitTest_App_Connect VERSION 1.0 LANGUAGES CXX)
project (UnitTest_App_Settings VERSION 1.0 LANGUAGES CXX)
# Compile the source code
add_executable(UnitTest_App_Connect
add_executable(UnitTest_App_Settings
"main.cpp"
"app_connect_local.cpp")
target_link_libraries(UnitTest_App_Connect ${CMAKE_DL_LIBS} GTest::GTest)
"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_Connect COMMAND UnitTest_App_Connect)
add_test(NAME UnitTest_App_Settings COMMAND UnitTest_App_Settings)
# Execute the test
add_custom_command(TARGET UnitTest_App_Connect POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_App_Connect>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_App_Connect.xml
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_Connect dependency_sdv_components)
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");
}

View File

@@ -283,7 +283,7 @@ TEST(CoreLoaderTest, EnvVarLoading)
EXPECT_EQ(executor.Execute(), 1);
}
TEST(CoreLoaderTest, CfgFileLoadingRel)
TEST(CoreLoaderTest, CoreRelocFileLoadingRel)
{
CTestExecute executor;
@@ -291,14 +291,17 @@ TEST(CoreLoaderTest, CfgFileLoadingRel)
fstream << R"cfg(# Some bogus information
unknown_var = 2
[CoreLocation]
Version = 100
# Core library path
directory = "../../../bin")cfg";
Runtime = "../../../bin")cfg";
fstream.close();
EXPECT_EQ(executor.Execute(), 1);
}
TEST(CoreLoaderTest, CfgFileLoadingAbs)
TEST(CoreLoaderTest, CoreRelocFileLoadingAbs)
{
CTestExecute executor;
@@ -306,15 +309,18 @@ TEST(CoreLoaderTest, CfgFileLoadingAbs)
fstream << R"cfg(# Some bogus information
unknown_var = 2
[CoreLocation]
Version = 100
# Core library path
directory = ")cfg" << (executor.GetExeDir() / "../../../bin").lexically_normal().generic_string() << "\"";
Runtime = ")cfg" << (executor.GetExeDir() / "../../../bin").lexically_normal().generic_string() << "\"";
fstream.close();
EXPECT_EQ(executor.Execute(), 1);
}
#ifdef _WIN32
TEST(CoreLoaderTest, CfgFileLoadingRelWin)
TEST(CoreLoaderTest, CoreRelocFileLoadingRelWin)
{
CTestExecute executor;
@@ -322,14 +328,17 @@ TEST(CoreLoaderTest, CfgFileLoadingRelWin)
fstream << R"cfg(# Some bogus information
unknown_var = 2
[CoreLocation]
Version = 100
# Core library path
directory = "..\\..\\..\\bin")cfg";
Runtime = "..\\..\\..\\bin")cfg";
fstream.close();
EXPECT_EQ(executor.Execute(), 1);
}
TEST(CoreLoaderTest, CfgFileLoadingAbsWin)
TEST(CoreLoaderTest, CoreRelocFileLoadingAbsWin)
{
CTestExecute executor;
@@ -352,8 +361,11 @@ TEST(CoreLoaderTest, CfgFileLoadingAbsWin)
fstream << R"cfg(# Some bogus information
unknown_var = 2
[CoreLocation]
Version = 100
# Core library path
directory = ")cfg" << ssDir << "\"";
Runtime = ")cfg" << ssDir << "\"";
fstream.close();
EXPECT_EQ(executor.Execute(), 1);

View File

@@ -156,7 +156,7 @@ TEST_F(CDbcParserTest, SourceContent)
TEST_F(CDbcParserTest, SourceLineColumn)
{
std::string ssSource = R"code(VERSION ""
std::string ssSource = R"dbc(VERSION ""
NS_ :
@@ -169,7 +169,7 @@ NS_ :
CAT_
FILTER
BA_DEF_DEF_
EV_DATA_)code";
EV_DATA_)dbc";
dbc::CDbcSource src(ssSource);
EXPECT_EQ(src.CalcLine(), 1);
@@ -370,10 +370,10 @@ TEST_F(CDbcParserTest, NewSymbols)
EXPECT_NO_THROW(parser.Parse(srcOneNS));
// All symbols
std::string ssAllNS = R"code(NS_ : NS_DESC_ CM_ BA_DEF_ BA_ VAL_ CAT_DEF_ CAT_ FILTER BA_DEF_DEF_ EV_DATA_
std::string ssAllNS = R"dbc(NS_ : NS_DESC_ CM_ BA_DEF_ BA_ VAL_ CAT_DEF_ CAT_ FILTER BA_DEF_DEF_ EV_DATA_
ENVVAR_DATA_ SGTYPE_ SGTYPE_VAL_ BA_DEF_SGTYPE_ BA_SGTYPE_ SIG_TYPE_REF_ VAL_TABLE_ SIG_GROUP_
SIG_VALTYPE_ SIGTYPE_VALTYPE_ BO_TX_BU_ BA_DEF_REL_ BA_REL_ BA_DEF_DEF_REL_ BU_SG_REL_
BU_EV_REL_ BU_BO_REL_ SG_MUL_VAL_)code";
BU_EV_REL_ BU_BO_REL_ SG_MUL_VAL_)dbc";
dbc::CDbcSource srcAllNS(ssAllNS);
EXPECT_NO_THROW(parser.Parse(srcAllNS));
@@ -628,7 +628,7 @@ TEST_F(CDbcParserTest, SignalDef)
EXPECT_TRUE(parser.HasNodeDef("nodeRx2"));
// Message definition
std::string ssValidMsgDef1 = R"code(
std::string ssValidMsgDef1 = R"dbc(
BO_ 1 msg_big_endian: 8 nodeTx
SG_ sig1 : 7|4@0+ (1,0) [0|8191] "Nm" nodeRx1
SG_ sig2 : 3|8@0+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
@@ -651,7 +651,7 @@ TEST_F(CDbcParserTest, SignalDef)
SG_ sig5a m 1: 24|8@1+ (1,0) [0|8191] "Nm" Vector__XXX
SG_ sig2b m 0: 4|32@1+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
SG_ sig6 : 32|32@1+ (1,0) [0|8191] "Nm" Vector__XXX
)code";
)dbc";
dbc::CDbcSource srcValidMsgDef1(ssValidMsgDef1);
EXPECT_NO_THROW(parser.Parse(srcValidMsgDef1));
EXPECT_TRUE(parser.HasSignalDef("msg_big_endian", "sig1"));
@@ -725,32 +725,32 @@ TEST_F(CDbcParserTest, SignalDef)
EXPECT_TRUE(parser.GetSignalDefExtId(3, "sig6").second);
// Duplicate signals
std::string ssDuplicateSigDef1 = R"code(
std::string ssDuplicateSigDef1 = R"dbc(
BO_ 4 msg4: 8 nodeTx
SG_ sig1 : 52|13@0+ (1,0) [0|8191] "Nm" nodeRx1
SG_ sig2 : 36|13@0+ (1,0) [0|8191] "Nm" nodeRx1, nodeRx2
SG_ sig1 : 18|13@0+ (1,0) [0|8191] "Nm" Vector__XXX
)code";
)dbc";
dbc::CDbcSource srcDuplicateSigDef1(ssDuplicateSigDef1);
EXPECT_THROW(parser.Parse(srcDuplicateSigDef1), dbc::SDbcParserException);
// Invalid signals
std::string ssInvalidStartBit = R"code(
std::string ssInvalidStartBit = R"dbc(
BO_ 5 msg5: 8 nodeTx
SG_ sig1 : 64|13@0+ (1,0) [0|8191] "Nm" nodeRx1
)code";
)dbc";
dbc::CDbcSource srcInvalidStartBit(ssInvalidStartBit);
EXPECT_THROW(parser.Parse(srcInvalidStartBit), dbc::SDbcParserException);
std::string ssInvalidLengthLittleEndian = R"code(
std::string ssInvalidLengthLittleEndian = R"dbc(
BO_ 6 msg6: 8 nodeTx
SG_ sig1 : 33|32@1+ (1,0) [0|8191] "Nm" nodeRx1
)code";
)dbc";
dbc::CDbcSource srcInvalidLengthLittleEndian(ssInvalidLengthLittleEndian);
EXPECT_THROW(parser.Parse(srcInvalidLengthLittleEndian), dbc::SDbcParserException);
std::string ssInvalidLengthBigEndian = R"code(
std::string ssInvalidLengthBigEndian = R"dbc(
BO_ 7 msg7: 8 nodeTx
SG_ sig1 : 38|32@0+ (1,0) [0|8191] "Nm" nodeRx1
)code";
)dbc";
dbc::CDbcSource srcInvalidLengthBigEndian(ssInvalidLengthBigEndian);
EXPECT_THROW(parser.Parse(srcInvalidLengthBigEndian), dbc::SDbcParserException);
}
@@ -767,13 +767,13 @@ TEST_F(CDbcParserTest, SignalTypeDef)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg_float: 8 nodeTx
SG_ sig_float : 0|32@1- (1,0) [0|8191] "Nm" nodeRx
SG_ sig_int : 32|32@1+ (1,0) [0|8191] "Nm" nodeRx
BO_ 2 msg_double: 8 nodeTx
SG_ sig_double : 0|64@1- (1,0) [0|8191] "Nm" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
EXPECT_TRUE(parser.HasMsgDef("msg_float"));
@@ -789,11 +789,11 @@ TEST_F(CDbcParserTest, SignalTypeDef)
EXPECT_EQ(prSigDouble.first.eValType, dbc::SSignalDef::EValueType::signed_integer);
// Set the signal value types.
std::string ssSigValType = R"code(
std::string ssSigValType = R"dbc(
SIG_VALTYPE_ 1 sig_float 1;
SIG_VALTYPE_ 1 sig_int 0;
SIG_VALTYPE_ 2 sig_double 2;
)code";
)dbc";
dbc::CDbcSource srcSigValType(ssSigValType);
EXPECT_NO_THROW(parser.Parse(srcSigValType));
@@ -877,11 +877,11 @@ TEST_F(CDbcParserTest, SignalValueDescriptions)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg_enum: 8 nodeTx
SG_ sig_enum : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig_enum_empty : 0|32@1+ (1,0) [0|0] "" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
EXPECT_TRUE(parser.HasMsgDef("msg_enum"));
@@ -933,11 +933,11 @@ TEST_F(CDbcParserTest, EnvironmentVariableDef)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Environment variable definition
std::string ssEnvVarDef = R"code(
std::string ssEnvVarDef = R"dbc(
EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
auto vecEnvVars = parser.GetEnvVarNames();
@@ -996,18 +996,18 @@ TEST_F(CDbcParserTest, EnvVarData)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Environment variable definition
std::string ssEnvVarDef = R"code(
std::string ssEnvVarDef = R"dbc(
EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
// Environment variable data definition
std::string ssEnvVarDataDef = R"code(
std::string ssEnvVarDataDef = R"dbc(
ENVVAR_DATA_ var1 : 10;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDataDef(ssEnvVarDataDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDataDef));
auto prEnvVar = parser.GetEnvVarDef("var1");
@@ -1038,11 +1038,11 @@ TEST_F(CDbcParserTest, EnvVarValueDescriptions)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Environment variable definition
std::string ssEnvVarDef = R"code(
std::string ssEnvVarDef = R"dbc(
EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
@@ -1079,17 +1079,17 @@ TEST_F(CDbcParserTest, ExtSignalTypeDef)
dbc::CDbcParser parser;
// Value table
std::string ssValueTable = R"code(
std::string ssValueTable = R"dbc(
VAL_TABLE_ table1 10 "ten" 20 "twenty";
)code";
)dbc";
dbc::CDbcSource srcValueTable(ssValueTable);
EXPECT_NO_THROW(parser.Parse(srcValueTable));
// Value table type definition
std::string ssValueTableType = R"code(
std::string ssValueTableType = R"dbc(
SGTYPE_ sgtype1 : 32 @ 1+ (1.0, 0) [0|100] "signal unit" 50, table1;
SGTYPE_ sgtype2 : 16 @ 0- (-10.5, 10) [-100|200] "signal unit2" 13, Vector__XXX;
)code";
)dbc";
dbc::CDbcSource srcValueTableType(ssValueTableType);
EXPECT_NO_THROW(parser.Parse(srcValueTableType));
auto vecSignalTypes = parser.GetSignalTypeDefNames();
@@ -1129,17 +1129,17 @@ TEST_F(CDbcParserTest, SignalTypeRef)
dbc::CDbcParser parser;
// Value table
std::string ssValueTable = R"code(
std::string ssValueTable = R"dbc(
VAL_TABLE_ table1 10 "ten" 20 "twenty";
VAL_TABLE_ table2 20 "twenty" 30 "thirty";
)code";
)dbc";
dbc::CDbcSource srcValueTable(ssValueTable);
EXPECT_NO_THROW(parser.Parse(srcValueTable));
// Signal type definition
std::string ssSignalType = R"code(
std::string ssSignalType = R"dbc(
SGTYPE_ sgtype1 : 32 @ 1+ (1.0, 0) [0|100] "signal unit" 50, table1;
)code";
)dbc";
dbc::CDbcSource srcSignalType(ssSignalType);
EXPECT_NO_THROW(parser.Parse(srcSignalType));
@@ -1151,11 +1151,11 @@ TEST_F(CDbcParserTest, SignalTypeRef)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
@@ -1180,20 +1180,20 @@ TEST_F(CDbcParserTest, SignalGroupDef)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
// Signal group definition
std::string ssSignalGroup = R"code(
std::string ssSignalGroup = R"dbc(
SIG_GROUP_ 1 group1 10 : sig1 sig2;
SIG_GROUP_ 1 group2 20 : sig3;
)code";
)dbc";
dbc::CDbcSource srcSignalGroup(ssSignalGroup);
EXPECT_NO_THROW(parser.Parse(srcSignalGroup));
auto vecGroupNames = parser.GetSignalGroupDefNames(1);
@@ -1220,12 +1220,12 @@ TEST_F(CDbcParserTest, GlobalComments)
dbc::CDbcParser parser;
// Global comments
std::string ssComments = R"code(
std::string ssComments = R"dbc(
CM_ "first comment";
CM_ "second comment";
CM_ "third comment";
CM_ "fourth comment";
)code";
)dbc";
dbc::CDbcSource srcComments(ssComments);
EXPECT_NO_THROW(parser.Parse(srcComments));
auto vecComments = parser.GetComments();
@@ -1248,12 +1248,12 @@ TEST_F(CDbcParserTest, NodeComments)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Node comments
std::string ssComments = R"code(
std::string ssComments = R"dbc(
CM_ BU_ nodeTx "first comment";
CM_ BU_ nodeTx "second comment \"with quotes\"";
CM_ BU_ nodeRx "third comment 'with single quotes'";
CM_ BU_ nodeRx "fourth comment";
)code";
)dbc";
dbc::CDbcSource srcComments(ssComments);
EXPECT_NO_THROW(parser.Parse(srcComments));
auto prNode = parser.GetNodeDef("nodeTx");
@@ -1280,22 +1280,22 @@ TEST_F(CDbcParserTest, MessageComments)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
// Message comments
std::string ssComments = R"code(
std::string ssComments = R"dbc(
CM_ BO_ 1 "first comment";
CM_ BO_ 1 "second comment";
CM_ BO_ 1 "third comment";
CM_ BO_ 1 "fourth comment";
)code";
)dbc";
dbc::CDbcSource srcComments(ssComments);
EXPECT_NO_THROW(parser.Parse(srcComments));
auto prMsgDef = parser.GetMsgDef(1);
@@ -1319,22 +1319,22 @@ TEST_F(CDbcParserTest, SignalComments)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Signal definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
// Node comments
std::string ssComments = R"code(
std::string ssComments = R"dbc(
CM_ SG_ 1 sig1 "first comment";
CM_ SG_ 1 sig1 "second comment";
CM_ SG_ 1 sig2 "third comment";
CM_ SG_ 1 sig3 "fourth comment";
)code";
)dbc";
dbc::CDbcSource srcComments(ssComments);
EXPECT_NO_THROW(parser.Parse(srcComments));
auto prSignal = parser.GetSignalDef(1, "sig1");
@@ -1364,21 +1364,21 @@ TEST_F(CDbcParserTest, EnvVarComments)
EXPECT_TRUE(parser.HasNodeDef("nodeRx"));
// Environment variable definition
std::string ssEnvVarDef = R"code(
std::string ssEnvVarDef = R"dbc(
EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
// Env var comments
std::string ssComments = R"code(
std::string ssComments = R"dbc(
CM_ EV_ var1 "first comment";
CM_ EV_ var1 "second comment";
CM_ EV_ var2 "third comment";
CM_ EV_ var3 "fourth comment";
)code";
)dbc";
dbc::CDbcSource srcComments(ssComments);
EXPECT_NO_THROW(parser.Parse(srcComments));
auto prEnvVar = parser.GetEnvVarDef("var1");
@@ -1402,14 +1402,14 @@ TEST_F(CDbcParserTest, AttributeDef)
// Global attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ "attr1" INT 10 20;
BA_DEF_ "attr2" HEX 10 20;
BA_DEF_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ "attr4" STRING;
BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
auto vecAttr = parser.GetAttributeDefNames();
@@ -1470,27 +1470,27 @@ TEST_F(CDbcParserTest, AttributeDefaultValDef)
// Global attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ "attr1" INT 10 20;
BA_DEF_ "attr2" HEX 10 20;
BA_DEF_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ "attr4" STRING;
BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Attribute def default value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrDefDefaultVal = R"code(
std::string ssAttrDefDefaultVal = R"dbc(
BA_DEF_DEF_ "attr1" 15;
BA_DEF_DEF_ "attr2" 15;
BA_DEF_DEF_ "attr3" 5.5;
BA_DEF_DEF_ "attr4" "hello";
BA_DEF_DEF_ "attr5" "def";
BA_DEF_DEF_ "attr6" 6;
)code";
)dbc";
dbc::CDbcSource srcAttrDefDefaultVal(ssAttrDefDefaultVal);
EXPECT_NO_THROW(parser.Parse(srcAttrDefDefaultVal));
@@ -1514,20 +1514,20 @@ TEST_F(CDbcParserTest, GlobalAttributeVal)
// Global attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ "attr1" INT 10 20;
BA_DEF_ "attr2" HEX 10 20;
BA_DEF_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ "attr4" STRING;
BA_DEF_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Attribute value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrVal = R"code(
std::string ssAttrVal = R"dbc(
BA_ "attr1" 11;
BA_ "attr2" 12;
BA_ "attr2" 13;
@@ -1535,7 +1535,7 @@ TEST_F(CDbcParserTest, GlobalAttributeVal)
BA_ "attr4" "hi";
BA_ "attr5" "ghi";
BA_ "attr6" 6;
)code";
)dbc";
dbc::CDbcSource srcAttrVal(ssAttrVal);
EXPECT_NO_THROW(parser.Parse(srcAttrVal));
auto vecAttr = parser.GetAttributes();
@@ -1562,20 +1562,20 @@ TEST_F(CDbcParserTest, NodeAttributeVal)
// Node attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ BU_ "attr1" INT 10 20;
BA_DEF_ BU_ "attr2" HEX 10 20;
BA_DEF_ BU_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ BU_ "attr4" STRING;
BA_DEF_ BU_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ BU_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Attribute value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrVal = R"code(
std::string ssAttrVal = R"dbc(
BA_ "attr1" BU_ nodeTx 11;
BA_ "attr2" BU_ nodeTx 12;
BA_ "attr2" BU_ nodeTx 13;
@@ -1583,7 +1583,7 @@ TEST_F(CDbcParserTest, NodeAttributeVal)
BA_ "attr4" BU_ nodeRx "hi";
BA_ "attr5" BU_ nodeRx "ghi";
BA_ "attr6" BU_ nodeRx 6;
)code";
)dbc";
dbc::CDbcSource srcAttrVal(ssAttrVal);
EXPECT_NO_THROW(parser.Parse(srcAttrVal));
auto prNodeDef = parser.GetNodeDef("nodeTx");
@@ -1612,31 +1612,31 @@ TEST_F(CDbcParserTest, MessageAttributeVal)
// Message attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ BO_ "attr1" INT 10 20;
BA_DEF_ BO_ "attr2" HEX 10 20;
BA_DEF_ BO_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ BO_ "attr4" STRING;
BA_DEF_ BO_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ BO_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
BO_ 2 msg2: 8 nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
// Attribute value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrVal = R"code(
std::string ssAttrVal = R"dbc(
BA_ "attr1" BO_ 1 11;
BA_ "attr2" BO_ 1 12;
BA_ "attr2" BO_ 1 13;
@@ -1644,7 +1644,7 @@ TEST_F(CDbcParserTest, MessageAttributeVal)
BA_ "attr4" BO_ 2 "hi";
BA_ "attr5" BO_ 2 "ghi";
BA_ "attr6" BO_ 2 6;
)code";
)dbc";
dbc::CDbcSource srcAttrVal(ssAttrVal);
EXPECT_NO_THROW(parser.Parse(srcAttrVal));
auto prMsgDef = parser.GetMsgDef(1);
@@ -1673,31 +1673,31 @@ TEST_F(CDbcParserTest, SignalAttributeVal)
// Signal attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ SG_ "attr1" INT 10 20;
BA_DEF_ SG_ "attr2" HEX 10 20;
BA_DEF_ SG_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ SG_ "attr4" STRING;
BA_DEF_ SG_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ SG_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 1 msg: 8 nodeTx
SG_ sig1 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig2 : 0|32@1+ (1,0) [0|0] "" nodeRx
SG_ sig3 : 0|32@1+ (1,0) [0|0] "" nodeRx
BO_ 2 msg2: 8 nodeRx
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
// Attribute value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrVal = R"code(
std::string ssAttrVal = R"dbc(
BA_ "attr1" SG_ 1 sig1 11;
BA_ "attr2" SG_ 1 sig1 12;
BA_ "attr2" SG_ 1 sig2 13;
@@ -1705,7 +1705,7 @@ TEST_F(CDbcParserTest, SignalAttributeVal)
BA_ "attr4" SG_ 1 sig3 "hi";
BA_ "attr5" SG_ 1 sig3 "ghi";
BA_ "attr6" SG_ 1 sig3 6;
)code";
)dbc";
dbc::CDbcSource srcAttrVal(ssAttrVal);
EXPECT_NO_THROW(parser.Parse(srcAttrVal));
auto prSigDef = parser.GetSignalDef(1, "sig1");
@@ -1736,29 +1736,29 @@ TEST_F(CDbcParserTest, EnvVarAttributeVal)
// Environment variable attribute definition
// The use of "n/a" and "not-used" is not part of the official standard.
std::string ssAttribute = R"code(
std::string ssAttribute = R"dbc(
BA_DEF_ EV_ "attr1" INT 10 20;
BA_DEF_ EV_ "attr2" HEX 10 20;
BA_DEF_ EV_ "attr3" FLOAT 1.0 10.9;
BA_DEF_ EV_ "attr4" STRING;
BA_DEF_ EV_ "attr5" ENUM "abc", "def", "ghi";
BA_DEF_ EV_ "attr6" ENUM "abc", "n/a", "not-used", "jkl", "n/a", "not-used", "stu";
)code";
)dbc";
dbc::CDbcSource srcAttribute(ssAttribute);
EXPECT_NO_THROW(parser.Parse(srcAttribute));
// Environment variable definition
std::string ssEnvVarDef = R"code(
std::string ssEnvVarDef = R"dbc(
EV_ var1 : 0 [10|20] "steps" 15 100 DUMMY_NODE_VECTOR3 nodeTx, nodeRx;
EV_ var2 : 1 [0.1|0.2] "tenth steps" 0.5 101 DUMMY_NODE_VECTOR2 nodeTx;
EV_ var3 : 2 [0.0|0.0] "string val" 0.0 102 DUMMY_NODE_VECTOR8001 nodeRx;
)code";
)dbc";
dbc::CDbcSource srcEnvVarDef(ssEnvVarDef);
EXPECT_NO_THROW(parser.Parse(srcEnvVarDef));
// Attribute value
// The use of an index instead of a value for the enum value is not part of the official standard.
std::string ssAttrVal = R"code(
std::string ssAttrVal = R"dbc(
BA_ "attr1" EV_ var1 11;
BA_ "attr2" EV_ var1 12;
BA_ "attr2" EV_ var2 13;
@@ -1766,7 +1766,7 @@ TEST_F(CDbcParserTest, EnvVarAttributeVal)
BA_ "attr4" EV_ var3 "hi";
BA_ "attr5" EV_ var3 "ghi";
BA_ "attr6" EV_ var3 6;
)code";
)dbc";
dbc::CDbcSource srcAttrVal(ssAttrVal);
EXPECT_NO_THROW(parser.Parse(srcAttrVal));
auto prEnvVarDef = parser.GetEnvVarDef("var1");
@@ -1789,7 +1789,7 @@ TEST_F(CDbcParserTest, SignalExtendedMultiplexing)
dbc::CDbcParser parser;
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
BO_ 100 MuxMsg: 1 Vector__XXX
SG_ Mux_4 m2 : 6|2@1+ (1,0) [0|0] "" Vector__XXX
SG_ Mux_3 m3M : 4|2@1+ (1,0) [0|0] "" Vector__XXX
@@ -1799,7 +1799,7 @@ TEST_F(CDbcParserTest, SignalExtendedMultiplexing)
SG_MUL_VAL_ 100 Mux_2 Mux_1 3-3, 5-10;
SG_MUL_VAL_ 100 Mux_3 Mux_2 3-3;
SG_MUL_VAL_ 100 Mux_4 Mux_3 2-2;
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
@@ -1842,7 +1842,7 @@ TEST_F(CDbcParserTest, ExampleDBC1)
dbc::CDbcParser parser;
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
VERSION ""
NS_ :
@@ -1891,7 +1891,7 @@ CM_ "CAN communication matrix for power train electronics
implemented: turn lights, warning lights, windows";
VAL_ 100 IdleRunning 0 "Running" 1 "Idle" ;
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}
@@ -1900,7 +1900,7 @@ TEST_F(CDbcParserTest, ExampleDBC2)
dbc::CDbcParser parser;
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
VERSION ""
@@ -2023,7 +2023,7 @@ VAL_ 1 HMI_Lateral_Long_Ctrl_Req 3 "LONGITUDINAL_CTRL_REQ" 2 "LONGITUDINAL_AND_L
VAL_ 1 HMI_Algo_Variant_Request 4 "NONE" 3 "VARIANT_4" 2 "VARIANT_3" 1 "VARIANT_2" 0 "VARIANT_1" ;
VAL_ 0 MAB_AI4Motion_Algo_Var_Selected 4 "NONE" 3 "VARIANT_4" 2 "VARIANT_3" 1 "VARIANT_2" 0 "VARIANT_1" ;
VAL_ 0 MAB_Activation_AI4Motion 3 "LONGITUDINAL_CTRL_REQ" 2 "LONGITUDINAL_AND_LATERAL" 1 "LATERAL_CTRL_REQ" 0 "NONE" ;
SIG_VALTYPE_ 3221225472 New_Signal_25 : 2; )code";
SIG_VALTYPE_ 3221225472 New_Signal_25 : 2; )dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}
@@ -2032,7 +2032,7 @@ TEST_F(CDbcParserTest, ExampleDBC3)
dbc::CDbcParser parser;
// Message definition
std::string ssMsgDef = R"code(
std::string ssMsgDef = R"dbc(
VERSION ""
@@ -2135,7 +2135,7 @@ VERSION ""
VAL_ 100 DRIVER_HEARTBEAT_cmd 2 "DRIVER_HEARTBEAT_cmd_REBOOT" 1 "DRIVER_HEARTBEAT_cmd_SYNC" 0
"DRIVER_HEARTBEAT_cmd_NOOP" ;
VAL_ 500 IO_DEBUG_test_enum 2 "IO_DEBUG_test2_enum_two" 1 "IO_DEBUG_test2_enum_one" ;
)code";
)dbc";
dbc::CDbcSource srcMsgDef(ssMsgDef);
EXPECT_NO_THROW(parser.Parse(srcMsgDef));
}

View File

@@ -27,6 +27,7 @@
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.cpp"
#include <support/app_control.h>
#if defined(_WIN32) && defined(_UNICODE)

View File

@@ -45,8 +45,10 @@ set_target_properties(UnitTest_IPC_Communication_ps PROPERTIES SUFFIX ".sdv")
# Compile the source code
add_executable(UnitTest_IPC_Communication
"main.cpp"
"ipc_com.cpp"
"ipc_com_sharedmem.cpp"
"ipc_com_uds.cpp"
"include.h"
"ipc_com_uds_tunnel.cpp"
)
target_link_libraries(UnitTest_IPC_Communication ${CMAKE_DL_LIBS} GTest::GTest)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,8 @@ extern "C" int main(int argc, char* argv[])
}
else
{
CProcessWatchdog watchdog;
// Use extended execution time of 10 minutes
CProcessWatchdog watchdog(600u);
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();

View File

@@ -17,8 +17,10 @@ project (UnitTest_IPC_Connect VERSION 1.0 LANGUAGES CXX)
# Compile the source code
add_executable(UnitTest_IPC_Connect
"main.cpp"
"ipc_connect.cpp"
"ipc_connect_shared_mem.cpp"
"ipc_connect_false_positiv.cpp"
"ipc_connect_uds.cpp"
"ipc_connect_uds_tunnel.cpp"
)
target_link_libraries(UnitTest_IPC_Connect ${CMAKE_DL_LIBS} GTest::GTest)

View File

@@ -1,307 +0,0 @@
/********************************************************************************
* 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 "../../include/gtest_custom.h"
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <support/pssup.h>
#include "../../../sdv_services/ipc_connect/listener.h"
#include "../../../sdv_services/ipc_connect/client.h"
TEST(IPC_Connect_Test, InstantiateLocalDefaultListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(R"code([Listener]
Type = "Local"
)code");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Shutdown
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test, InstantiateLocalDedicatedListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(R"code([Listener]
Type = "Local"
Instance = 1234
)code");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Shutdown
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test, InstantiateLocalDefaultClientNoListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start client
CClient client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize("");
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
sdv::TObjectPtr ptrClient = client.Connect(R"code([Client]
Type = "local"
)code");
EXPECT_FALSE(ptrClient);
// Shutdown
ptrClient.Clear();
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test, InstantiateLocalSpecificClientNoListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start client
CClient client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize("");
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
sdv::TObjectPtr ptrClient = client.Connect(R"code([Client]
Type = "local"
Instance = 1234
)code");
EXPECT_FALSE(ptrClient);
// Shutdown
ptrClient.Clear();
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
// Disabled the following test due to an unidentified crash/heap corruption occurring with MINGW on the build-server.
// Bug-report #610009 describes this issue: https://dev.azure.com/SW4ZF/AZP-074_DivDI_SofDCarResearch/_workitems/edit/610009
#ifdef _WIN32
TEST(IPC_Connect_Test, DISABLED_InstantiateLocalDefaultClientAndListener)
#else
TEST(IPC_Connect_Test, InstantiateLocalDefaultClientAndListener)
#endif
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(R"code([Listener]
Type = "Local"
)code");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Start client
CClient client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize("");
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
sdv::TObjectPtr ptrClient = client.Connect(R"code([Client]
Type = "Local"
)code");
EXPECT_TRUE(ptrClient);
// The client is a pointer to the repository. Request the module control service
sdv::core::IObjectAccess* pObjectAccess = ptrClient.GetInterface<sdv::core::IObjectAccess>();
EXPECT_NE(pObjectAccess, nullptr);
sdv::core::IModuleInfo* pModuleInfo = nullptr;
if (pObjectAccess)
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).GetInterface<sdv::core::IModuleInfo>();
EXPECT_NE(pModuleInfo, nullptr);
if (pModuleInfo)
{
EXPECT_FALSE(pModuleInfo->GetModuleList().empty());
}
// Shutdown
ptrClient.Clear();
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
// Disabled the following test due to an unidentified crash/heap corruption occurring with MINGW on the build-server.
// Bug-report #610009 describes this issue: https://dev.azure.com/SW4ZF/AZP-074_DivDI_SofDCarResearch/_workitems/edit/610009
#ifdef _WIN32
TEST(IPC_Connect_Test, DISABLED_InstantiateLocalSpecificClientAndListener)
#else
TEST(IPC_Connect_Test, InstantiateLocalSpecificClientAndListener)
#endif
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemoryChannelControl", {}, {}), 0);
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(R"code([Listener]
Type = "Local"
Instance = 1234
)code");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Start client
CClient client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize("");
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
sdv::TObjectPtr ptrClient = client.Connect(R"code([Client]
Type = "Local"
Instance = 1234
)code");
EXPECT_TRUE(ptrClient);
// The client is a pointer to the repository. Request the module control service
sdv::core::IObjectAccess* pObjectAccess = ptrClient.GetInterface<sdv::core::IObjectAccess>();
EXPECT_NE(pObjectAccess, nullptr);
sdv::core::IModuleInfo* pModuleInfo = nullptr;
if (pObjectAccess)
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).GetInterface<sdv::core::IModuleInfo>();
EXPECT_NE(pModuleInfo, nullptr);
if (pModuleInfo)
{
EXPECT_FALSE(pModuleInfo->GetModuleList().empty());
}
// Shutdown
ptrClient.Clear();
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}

View File

@@ -0,0 +1,86 @@
/********************************************************************************
* 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 <support/app_control.h>
#include <support/pssup.h>
#include <support/sdv_core.h>
#include "../../../sdv_services/ipc_connect/client.h"
#include "../../../sdv_services/ipc_connect/listener.h"
#include "../../include/gtest_custom.h"
TEST(IPC_Connect_Test, InstantiateListenerWithUnknownProvider)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemory", {}, {}), 0);
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sdv::SObjectInfo());
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_failure);
// Shutdown
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_Shared_Mem, InstantiateClientWithoutConfiguration)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
// Start client without configuration
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sdv::SObjectInfo());
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_failure);
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}

View File

@@ -0,0 +1,181 @@
/********************************************************************************
* 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 "../../include/gtest_custom.h"
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <support/pssup.h>
#include <support/interface_ptr.h>
#include "../../../sdv_services/ipc_connect/listener.h"
#include "../../../sdv_services/ipc_connect/client.h"
TEST(IPC_Connect_Test_Shared_Mem, InstantiateListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
Instance = 1234
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
EXPECT_NE(pRepositoryControl->CreateObject("DefaultSharedMemory", {}, {}), 0);
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = R"toml(
[Provider]
Name = "DefaultSharedMemory"
[IpcChannel]
Name = "MyPersonalChannelName"
)toml";
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_EQ(listener.GetProviderName(), "DefaultSharedMemory");
// Shutdown
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_Shared_Mem, InstantiateClientNoListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = R"toml(
[Provider]
Name = "DefaultSharedMemory"
[IpcChannel]
Name = "MyPersonalChannelName"
)toml";
// Start client
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_FALSE(client.Connect());
// Shutdown
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_Shared_Mem, InstantiateClientAndListener)
{
// Initialize system
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
sdv::core::IModuleControl* pModuleControl = sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load("ipc_shared_mem.sdv"), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
sdv::core::IRepositoryControl* pRepositoryControl = sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = R"toml([Provider]
Name = "DefaultSharedMemory"
[IpcChannel]
Name = "CHANNEL_1234"
)toml";
// Start listener
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = R"toml([Provider]
Name = "DefaultSharedMemory"
[IpcChannel]
Name = "CHANNEL_1234"
)toml";
// Start client
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_TRUE(client.Connect());
EXPECT_TRUE(client.IsConnected());
// The client is a pointer to the repository. Request the module control service
sdv::core::IObjectAccess* pObjectAccess =
sdv::TInterfaceAccessPtr(client.GetRemoteRepository()).GetInterface<sdv::core::IObjectAccess>();
EXPECT_NE(pObjectAccess, nullptr);
sdv::core::IModuleInfo* pModuleInfo = nullptr;
if (pObjectAccess)
pModuleInfo = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService")).GetInterface<sdv::core::IModuleInfo>();
EXPECT_NE(pModuleInfo, nullptr);
if (pModuleInfo)
{
EXPECT_FALSE(pModuleInfo->GetModuleList().empty());
}
EXPECT_TRUE(client.Disconnect());
// Shutdown
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}

View File

@@ -0,0 +1,233 @@
/********************************************************************************
* 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:
* Denisa Ros - initial API and implementation
********************************************************************************/
#include "../../include/gtest_custom.h"
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <support/pssup.h>
#include <support/interface_ptr.h>
#include <chrono>
#include <string>
#include <thread>
#include "../../../sdv_services/ipc_connect/listener.h"
#include "../../../sdv_services/ipc_connect/client.h"
namespace
{
const char* GetUdsModuleName()
{
#ifdef _WIN32
return "uds_win_sockets.sdv";
#else
return "uds_unix_sockets.sdv";
#endif
}
const char* GetUdsChannelControlClassName()
{
#ifdef _WIN32
return "WinSocketsChannelControl";
#else
return "UnixSocketsChannelControl";
#endif
}
std::string UniqueSuffix()
{
const auto now = std::chrono::steady_clock::now().time_since_epoch().count();
return std::to_string(static_cast<long long>(now));
}
std::string MakeChannelName(const char* base)
{
return std::string(base) + "_" + UniqueSuffix();
}
std::string MakeUdsConfigByName(const std::string& channelName)
{
return std::string("[Provider]\n")
+ "Name = \"unix_domain_sockets\"\n\n"
+ "[IpcChannel]\n"
+ "Name = \"" + channelName + "\"\n";
}
void LoadRequiredModulesAndObjects(bool createUdsChannelControl = true)
{
auto* pModuleControl =
sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load(GetUdsModuleName()), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
auto* pRepositoryControl =
sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
if (createUdsChannelControl)
{
EXPECT_NE(
pRepositoryControl->CreateObject(GetUdsChannelControlClassName(), {}, {}),
0);
}
}
} // anonymous namespace
TEST(IPC_Connect_Test_UDS, InstantiateListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
Instance = 1234
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("MyPersonalChannelName");
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = MakeUdsConfigByName(channelName);
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_EQ(listener.GetProviderName(), "unix_domain_sockets");
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_UDS, InstantiateClientNoListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("MyPersonalChannelName");
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = MakeUdsConfigByName(channelName);
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
std::cout << "Connecting client..." << std::endl;
EXPECT_FALSE(client.Connect());
std::cout << "Client failed to connect." << std::endl;
EXPECT_FALSE(client.IsConnected());
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_UDS, InstantiateClientAndListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("CHANNEL_1234");
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = MakeUdsConfigByName(channelName);
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetProviderName(), "unix_domain_sockets");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Small delay to avoid startup races between listener init and client connect.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = MakeUdsConfigByName(channelName);
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_TRUE(client.Connect());
EXPECT_TRUE(client.IsConnected());
// The client should expose the remote repository after successful connect.
sdv::core::IObjectAccess* pObjectAccess =
sdv::TInterfaceAccessPtr(client.GetRemoteRepository())
.GetInterface<sdv::core::IObjectAccess>();
EXPECT_NE(pObjectAccess, nullptr);
sdv::core::IModuleInfo* pModuleInfo = nullptr;
if (pObjectAccess)
{
pModuleInfo =
sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService"))
.GetInterface<sdv::core::IModuleInfo>();
}
EXPECT_NE(pModuleInfo, nullptr);
if (pModuleInfo)
{
EXPECT_FALSE(pModuleInfo->GetModuleList().empty());
}
EXPECT_TRUE(client.Disconnect());
std::cout << "Client Shutdown" << std::endl;
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
std::cout << "Listener Shutdown" << std::endl;
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}

View File

@@ -0,0 +1,278 @@
/********************************************************************************
* 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:
* Denisa Ros - initial API and implementation
********************************************************************************/
#include "../../include/gtest_custom.h"
#include <support/sdv_core.h>
#include <support/app_control.h>
#include <support/pssup.h>
#include <support/interface_ptr.h>
#include <chrono>
#include <string>
#include <thread>
#include "../../../sdv_services/ipc_connect/listener.h"
#include "../../../sdv_services/ipc_connect/client.h"
namespace
{
const char* GetTunnelModuleName()
{
#ifdef _WIN32
return "uds_win_tunnel.sdv";
#else
return "uds_unix_tunnel.sdv";
#endif
}
const char* GetTunnelChannelControlClassName()
{
#ifdef _WIN32
return "WinTunnelChannelControl";
#else
return "UnixTunnelChannelControl";
#endif
}
std::string UniqueSuffix()
{
const auto now = std::chrono::steady_clock::now().time_since_epoch().count();
return std::to_string(static_cast<long long>(now));
}
std::string MakeChannelName(const char* base)
{
return std::string(base) + "_" + UniqueSuffix();
}
std::string MakeTunnelName(const char* base)
{
return std::string("t_") + base + "_" + UniqueSuffix();
}
std::string MakeTunnelConfigByName(const std::string& channelName,
const std::string& tunnelName)
{
return std::string("[Provider]\n")
+ "Name = \"unix_domain_sockets_tunnel\"\n\n"
+ "[IpcChannel]\n"
+ "Name = \"" + channelName + "\"\n"
+ "Tunnel = \"" + tunnelName + "\"\n";
}
void LoadRequiredModulesAndObjects(bool createTunnelChannelControl = true)
{
auto* pModuleControl =
sdv::core::GetObject<sdv::core::IModuleControl>("ModuleControlService");
ASSERT_NE(pModuleControl, nullptr);
EXPECT_NE(pModuleControl->Load("ipc_com.sdv"), 0);
EXPECT_NE(pModuleControl->Load(GetTunnelModuleName()), 0);
EXPECT_NE(pModuleControl->Load("core_ps.sdv"), 0);
auto* pRepositoryControl =
sdv::core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
ASSERT_NE(pRepositoryControl, nullptr);
EXPECT_NE(pRepositoryControl->CreateObject("CommunicationControl", {}, {}), 0);
if (createTunnelChannelControl)
{
EXPECT_NE(
pRepositoryControl->CreateObject(GetTunnelChannelControlClassName(), {}, {}),
0);
}
}
} // anonymous namespace
TEST(IPC_Connect_Test_UDS_Tunnel, InstantiateListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
Instance = 1234
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("MyPersonalChannelName");
const std::string tunnelName = MakeTunnelName("listener");
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = MakeTunnelConfigByName(channelName, tunnelName);
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_EQ(listener.GetProviderName(), "unix_domain_sockets_tunnel");
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_UDS_Tunnel, InstantiateClientNoListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("MyPersonalChannelName");
const std::string tunnelName = MakeTunnelName("no_listener");
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = MakeTunnelConfigByName(channelName, tunnelName);
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_FALSE(client.Connect());
EXPECT_FALSE(client.IsConnected());
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_UDS_Tunnel, InstantiateClientAndListener)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
const std::string channelName = MakeChannelName("CHANNEL_1234");
const std::string tunnelName = MakeTunnelName("client_listener");
sdv::SObjectInfo sListenerInfo{};
sListenerInfo.ssConfig = MakeTunnelConfigByName(channelName, tunnelName);
CListener listener;
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialization_pending);
listener.Initialize(sListenerInfo);
EXPECT_EQ(listener.GetProviderName(), "unix_domain_sockets_tunnel");
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::initialized);
// Allow listener endpoint publication to complete before client connect.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = MakeTunnelConfigByName(channelName, tunnelName);
CClientConnect client;
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialization_pending);
client.Initialize(sClientInfo);
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_TRUE(client.Connect());
EXPECT_TRUE(client.IsConnected());
// The client should expose the remote repository after successful connect.
sdv::core::IObjectAccess* pObjectAccess =
sdv::TInterfaceAccessPtr(client.GetRemoteRepository())
.GetInterface<sdv::core::IObjectAccess>();
EXPECT_NE(pObjectAccess, nullptr);
sdv::core::IModuleInfo* pModuleInfo = nullptr;
if (pObjectAccess)
{
pModuleInfo =
sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("ModuleControlService"))
.GetInterface<sdv::core::IModuleInfo>();
}
EXPECT_NE(pModuleInfo, nullptr);
if (pModuleInfo)
{
EXPECT_FALSE(pModuleInfo->GetModuleList().empty());
}
EXPECT_TRUE(client.Disconnect());
client.Shutdown();
EXPECT_EQ(client.GetObjectState(), sdv::EObjectState::destruction_pending);
listener.Shutdown();
EXPECT_EQ(listener.GetObjectState(), sdv::EObjectState::destruction_pending);
appcontrol.Shutdown();
}
TEST(IPC_Connect_Test_UDS_Tunnel, InvalidProvider_ShouldNotInitializeClient)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"config(
[Application]
Mode = "Essential"
[LogHandler]
ViewFilter = "Fatal"
)config"));
ASSERT_TRUE(appcontrol.IsRunning());
LoadRequiredModulesAndObjects(true);
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = R"toml(
[Provider]
Name = "invalid_tunnel_provider"
[IpcChannel]
Name = "CHANNEL_1234"
Tunnel = "t_invalid_provider"
)toml";
CClientConnect client;
client.Initialize(sClientInfo);
EXPECT_NE(client.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_FALSE(client.Connect());
EXPECT_FALSE(client.IsConnected());
client.Shutdown();
appcontrol.Shutdown();
}

View File

@@ -21,6 +21,7 @@
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.cpp"
#include "../../../sdv_services/core/module_control.cpp"
#include "../../../sdv_services/core/module.cpp"
#include "../../../sdv_services/core/app_config.cpp"

View File

@@ -46,6 +46,7 @@ public:
bool IsConsoleSilent() { return true; }
bool IsConsoleVerbose() { return false; }
uint32_t GetInstanceID() { return 1234u; }
std::filesystem::path GetFrameworkDir() const { return GetExecDirectory(); }
std::filesystem::path GetRootDir() const { return GetExecDirectory(); }
std::filesystem::path GetInstallDir() const { return GetExecDirectory(); }
std::vector<std::filesystem::path> GetSystemConfigPaths() const { return {}; }
@@ -117,7 +118,4 @@ inline CRepository& GetRepository()
#include "../../../sdv_services/core/app_settings.h"
#include "../../../sdv_services/core/app_config.h"
//inline std::filesystem::path GetCoreDirectoryMock() { return "../../bin"; }
//#define GetCoreDirectory GetCoreDirectoryMock
#endif // !defined MOCK_H

View File

@@ -17,6 +17,16 @@
#include <chrono>
#include <thread>
#include <atomic>
#include <string>
namespace
{
std::string MakeUniqueMutexName(const char* suffix)
{
return std::string("HELLO_") + suffix + "_" +
std::to_string(std::chrono::high_resolution_clock::now().time_since_epoch().count());
}
}
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
@@ -32,12 +42,14 @@ extern "C" int main(int argc, char* argv[])
TEST(NamedMutexTest, Construction)
{
ipc::named_mutex mtx("HELLO");
ipc::named_mutex mtx(MakeUniqueMutexName("Construction"));
EXPECT_NE(mtx.native_handle(), nullptr);
}
TEST(NamedMutexTest, CritSectSyncManualLock)
{
const std::string mutexName = MakeUniqueMutexName("CritSectSyncManualLock");
// Counter function check for correct counter value.
// The checking is manipulated by the bEnable flag. When disabled, no sync will be done and the check will fail. When enabled,
// sync will be done and the check will succeed.
@@ -46,7 +58,7 @@ TEST(NamedMutexTest, CritSectSyncManualLock)
std::atomic_bool bEnable = false;
auto fn = [&]()
{
ipc::named_mutex mtx("HELLO");
ipc::named_mutex mtx(mutexName);
if (bEnable)
mtx.lock();
@@ -81,12 +93,14 @@ TEST(NamedMutexTest, CritSectSyncManualLock)
TEST(NamedMutexTest, CritSectSyncAutoLock)
{
const std::string mutexName = MakeUniqueMutexName("CritSectSyncAutoLock");
// Counter function check for correct counter value.
int32_t iCnt = 0;
std::atomic_bool bSuccess = true;
auto fn = [&]()
{
ipc::named_mutex mtx("HELLO");
ipc::named_mutex mtx(mutexName);
std::unique_lock<ipc::named_mutex> lock(mtx);
bSuccess = bSuccess && (iCnt == 0);
@@ -108,10 +122,12 @@ TEST(NamedMutexTest, CritSectSyncAutoLock)
TEST(NamedMutexTest, TryLock)
{
const std::string mutexName = MakeUniqueMutexName("TryLock");
std::atomic_bool bRunning = false;
auto fn = [&]()
{
ipc::named_mutex mtx("HELLO");
ipc::named_mutex mtx(mutexName);
mtx.lock();
while (bRunning) std::this_thread::sleep_for(std::chrono::milliseconds(1));
@@ -123,7 +139,7 @@ TEST(NamedMutexTest, TryLock)
std::this_thread::sleep_for(std::chrono::milliseconds(250));
// Try locking; doesn't work since thread still locks.
ipc::named_mutex mtx2("HELLO");
ipc::named_mutex mtx2(mutexName);
EXPECT_FALSE(mtx2.try_lock());
bRunning = false;
@@ -137,7 +153,7 @@ TEST(NamedMutexTest, TryLock)
TEST(NamedMutexTest, Naming)
{
ipc::named_mutex mtx1("HELLO");
ipc::named_mutex mtx1(MakeUniqueMutexName("Naming"));
EXPECT_FALSE(mtx1.name().empty());
ipc::named_mutex mtx2;

View File

@@ -834,22 +834,23 @@ public:
InitParamMap();
}
BEGIN_SDV_PARAM_MAP()
SDV_PARAM_SET_READONLY()
SDV_PARAM_ENTRY(m_i, "my_integer", 10, "int_unit", "My integer")
SDV_PARAM_ENTRY(m_i, "my_integer", 20, "int_unit", "My integer")
SDV_PARAM_RESET_READONLY()
SDV_PARAM_ENTRY(m_d, "my_double", 1234.5, "double_unit", "My double")
SDV_PARAM_SET_READONLY()
SDV_PARAM_ENTRY(m_ss, "my_string", "string_value", "string_unit", "My string")
SDV_PARAM_ENTRY(m_ss, "my_string", "value_string", "string_unit", "My string")
SDV_PARAM_RESET_ATTRIBUTES()
SDV_PARAM_ENTRY(m_b, "my_boolean", true, "no_unit", "My boolean")
END_SDV_PARAM_MAP()
private:
int m_i;
double m_d;
std::string m_ss;
bool m_b;
int m_i = 10; // Read only; will not be overwritten
double m_d = 5432.1; // Writable, will be overwritten
std::string m_ss = "string_value"; // Read only; will not be overwritten
bool m_b = false; // Writable, will be overwritten
};
TEST(ParameterTest, ReadOnlyParamMapStaticInfo)
@@ -869,7 +870,7 @@ TEST(ParameterTest, ReadOnlyParamMapStaticInfo)
EXPECT_EQ(ptrParamInfo->Name(), "my_integer");
EXPECT_EQ(ptrParamInfo->Unit(), "int_unit");
EXPECT_EQ(ptrParamInfo->Description(), "My integer");
EXPECT_EQ(ptrParamInfo->DefaultVal(), 10);
EXPECT_EQ(ptrParamInfo->DefaultVal(), 20);
EXPECT_TRUE(ptrParamInfo->ReadOnly());
// Get parameter #1 global information
@@ -889,7 +890,7 @@ TEST(ParameterTest, ReadOnlyParamMapStaticInfo)
EXPECT_EQ(ptrParamInfo->Name(), "my_string");
EXPECT_EQ(ptrParamInfo->Unit(), "string_unit");
EXPECT_EQ(ptrParamInfo->Description(), "My string");
EXPECT_EQ(ptrParamInfo->DefaultVal(), "string_value");
EXPECT_EQ(ptrParamInfo->DefaultVal(), "value_string");
EXPECT_TRUE(ptrParamInfo->ReadOnly());
// Get parameter #3 global information
@@ -922,7 +923,7 @@ TEST(ParameterTest, ReadOnlyParamMapObjectInfo)
EXPECT_TRUE(ptrParamInfo->Numeric());
EXPECT_EQ(ptrParamInfo->Unit(), "int_unit");
EXPECT_EQ(ptrParamInfo->Description(), "My integer");
EXPECT_EQ(ptrParamInfo->DefaultVal(), 10);
EXPECT_EQ(ptrParamInfo->DefaultVal(), 20);
EXPECT_TRUE(ptrParamInfo->ReadOnly());
// Get parameter #1 global information
@@ -940,7 +941,7 @@ TEST(ParameterTest, ReadOnlyParamMapObjectInfo)
EXPECT_TRUE(ptrParamInfo->String());
EXPECT_EQ(ptrParamInfo->Unit(), "string_unit");
EXPECT_EQ(ptrParamInfo->Description(), "My string");
EXPECT_EQ(ptrParamInfo->DefaultVal(), "string_value");
EXPECT_EQ(ptrParamInfo->DefaultVal(), "value_string");
EXPECT_TRUE(ptrParamInfo->ReadOnly());
// Get parameter #3 global information
@@ -971,7 +972,7 @@ TEST(ParameterTest, ReadOnlyParamMapObjectInfoIndirect)
EXPECT_TRUE(info.Numeric());
EXPECT_EQ(info.Unit(), "int_unit");
EXPECT_EQ(info.Description(), "My integer");
EXPECT_EQ(info.DefaultVal(), 10);
EXPECT_EQ(info.DefaultVal(), 20);
EXPECT_TRUE(info.ReadOnly());
// Get parameter #1 global information
@@ -987,7 +988,7 @@ TEST(ParameterTest, ReadOnlyParamMapObjectInfoIndirect)
EXPECT_TRUE(info.String());
EXPECT_EQ(info.Unit(), "string_unit");
EXPECT_EQ(info.Description(), "My string");
EXPECT_EQ(info.DefaultVal(), "string_value");
EXPECT_EQ(info.DefaultVal(), "value_string");
EXPECT_TRUE(info.ReadOnly());
// Get parameter #2 global information

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_PermissionControl VERSION 1.0 LANGUAGES CXX)
# Compile the source code
add_executable(UnitTest_PermissionControl
"main.cpp"
"permission_control_tests.cpp")
target_link_libraries(UnitTest_PermissionControl ${CMAKE_DL_LIBS} GTest::GTest)
# Add the IDL Compiler unittest
add_test(NAME UnitTest_PermissionControl COMMAND UnitTest_PermissionControl)
# Execute the test
add_custom_command(TARGET UnitTest_PermissionControl POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_PermissionControl>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_PermissionControl.xml
VERBATIM
)
# Build dependencies
add_dependencies(UnitTest_PermissionControl dependency_sdv_components)

View File

@@ -13,7 +13,7 @@
#include <gtest/gtest.h>
#include "../../../global/process_watchdog.h"
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/permission_control.cpp"
/**
* @brief Main function
@@ -26,7 +26,6 @@ extern "C" int main(int argc, char* argv[])
{
CProcessWatchdog watchdog;
CLocalMemMgr memmgr;
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,264 @@
/********************************************************************************
* 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 <optional>
#include "../../include/gtest_custom.h"
#include "../../../sdv_services/core/permission_control.h"
TEST(PermissionControl, DefaultRestriction)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
}
TEST(PermissionControl, SetRestrictionInternal)
{
CPermissionControl control;
std::vector<CAccessPermission> vecPermissions;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Full access
vecPermissions.emplace_back(control.CreatePermissionObject(sdv::core::EAccessPermission::full_access));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Reduce access to local access
vecPermissions.emplace_back(control.CreatePermissionObject(sdv::core::EAccessPermission::local_access));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
// Reduce access to remote access
vecPermissions.emplace_back(control.CreatePermissionObject(sdv::core::EAccessPermission::remote_access));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Reduce access to restricted access
vecPermissions.emplace_back(control.CreatePermissionObject(sdv::core::EAccessPermission::restricted_access));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Try increase access to full access - this should not have any change
vecPermissions.emplace_back(control.CreatePermissionObject(sdv::core::EAccessPermission::full_access));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Remove the local access index #1 - this should not have any change
EXPECT_EQ(vecPermissions[1].Permission(), sdv::core::EAccessPermission::local_access);
vecPermissions.erase(vecPermissions.begin() + 1);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Remove first full access index #0 - this should not have any change
EXPECT_EQ(vecPermissions[0].Permission(), sdv::core::EAccessPermission::full_access);
vecPermissions.erase(vecPermissions.begin());
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Remove remote access new index #0 - this should not have any change
EXPECT_EQ(vecPermissions[0].Permission(), sdv::core::EAccessPermission::remote_access);
vecPermissions.erase(vecPermissions.begin());
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Remove restricted access new index #0 - access will change to full access
EXPECT_EQ(vecPermissions[0].Permission(), sdv::core::EAccessPermission::restricted_access);
vecPermissions.erase(vecPermissions.begin());
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Remove the remaining access - this would change to (default) restricted access again
vecPermissions.clear();
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
}
TEST(PermissionControl, SetRestrictionExternal)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Try to set external permission to full access; this will not work
EXPECT_EQ(control.RestrictAccessPermission(sdv::core::EAccessPermission::full_access), 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Try to set external permission to local access; this will not work
EXPECT_EQ(control.RestrictAccessPermission(sdv::core::EAccessPermission::local_access), 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Try to set external permission to remote access; this will not work
EXPECT_EQ(control.RestrictAccessPermission(sdv::core::EAccessPermission::remote_access), 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Try to set external permission to restricted access; this will not work
EXPECT_EQ(control.RestrictAccessPermission(sdv::core::EAccessPermission::restricted_access), 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
}
TEST(PermissionControl, InitializeRestrictionInternal_SetRestrictionExternal)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set restriction to full access
std::optional<CAccessPermission> optPermission = control.CreatePermissionObject(sdv::core::EAccessPermission::full_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Set external permission to local access
sdv::core::TPermissionID permidLocalAccess = control.RestrictAccessPermission(sdv::core::EAccessPermission::local_access);
EXPECT_NE(permidLocalAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
// Set external permission to remote access
sdv::core::TPermissionID permidRemoteAccess = control.RestrictAccessPermission(sdv::core::EAccessPermission::remote_access);
EXPECT_NE(permidRemoteAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Set external permission to restricted access
sdv::core::TPermissionID permidRestrictedAccess =
control.RestrictAccessPermission(sdv::core::EAccessPermission::restricted_access);
EXPECT_NE(permidRestrictedAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set external permission to full access - this will not change the access
sdv::core::TPermissionID permidFullAccess = control.RestrictAccessPermission(sdv::core::EAccessPermission::full_access);
EXPECT_NE(permidFullAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Release not existing access ID - should not work
EXPECT_FALSE(control.ReleaseAccessPermission(0));
EXPECT_FALSE(control.ReleaseAccessPermission(1));
// Release local, restricted and full access - this will change access to remote access
EXPECT_TRUE(control.ReleaseAccessPermission(permidLocalAccess));
EXPECT_TRUE(control.ReleaseAccessPermission(permidRestrictedAccess));
EXPECT_TRUE(control.ReleaseAccessPermission(permidFullAccess));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Release local again - should not work
EXPECT_FALSE(control.ReleaseAccessPermission(permidLocalAccess));
// Terminate internal full access - access should stay with remote access
optPermission.reset();
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Release remote access - the access permission will change to restricted access again
EXPECT_TRUE(control.ReleaseAccessPermission(permidRemoteAccess));
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
}
TEST(PermissionControl, DefaultThreadPermission)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set restriction to full access
CAccessPermission permission = control.CreatePermissionObject(sdv::core::EAccessPermission::full_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Start new thread - access should be restricted
std::thread thread([&]()
{
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
});
thread.join();
}
TEST(PermissionControl, InternalSetThreadPermission)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set restriction to local access
CAccessPermission permission = control.CreatePermissionObject(sdv::core::EAccessPermission::local_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
// Start new thread - access should be restricted
std::thread thread([&]()
{
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set full access permission
CAccessPermission permissionFullAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::full_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Set local access permission
CAccessPermission permissionLocalAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::local_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
// Set remote access permission
CAccessPermission permissionRemoteAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::remote_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Set restricted access permission
CAccessPermission permissionRestrictedAccess =
control.CreatePermissionObject(sdv::core::EAccessPermission::restricted_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
});
thread.join();
// Access permissions on main thread should still be local
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
}
TEST(PermissionControl, TransferThreadPermission)
{
CPermissionControl control;
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Set restriction to full access
CAccessPermission permissionFullAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::full_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
sdv::core::TPermissionID transferFullAccess = control.TransferCurrentPermission();
EXPECT_NE(transferFullAccess, 0u);
// Set restriction to local access
CAccessPermission permissionLocalAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::local_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
sdv::core::TPermissionID transferLocalAccess = control.TransferCurrentPermission();
EXPECT_NE(transferLocalAccess, 0u);
// Set restriction to remote access
CAccessPermission permissionRemoteAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::remote_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
sdv::core::TPermissionID transferRemoteAccess = control.TransferCurrentPermission();
EXPECT_NE(transferRemoteAccess, 0u);
// Set restriction to restricted access
CAccessPermission permissionRestrictedAccess = control.CreatePermissionObject(sdv::core::EAccessPermission::restricted_access);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
sdv::core::TPermissionID transferRestrictedAccess = control.TransferCurrentPermission();
EXPECT_NE(transferRestrictedAccess, 0u);
// Start new thread - access should be restricted
std::thread thread([&]()
{
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// Tets bogus transfer IDs
EXPECT_FALSE(control.SetAccessPermission(0));
EXPECT_FALSE(control.SetAccessPermission(1));
// Set full access permission from transfer ID
sdv::core::TPermissionID permidFullAccess = control.SetAccessPermission(transferFullAccess);
EXPECT_NE(permidFullAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::full_access);
// Set local access permission from transfer ID
sdv::core::TPermissionID permidLocalAccess = control.SetAccessPermission(transferLocalAccess);
EXPECT_NE(permidLocalAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::local_access);
// Set remote access permission from transfer ID
sdv::core::TPermissionID permidRemoteAccess = control.SetAccessPermission(transferRemoteAccess);
EXPECT_NE(permidRemoteAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::remote_access);
// Set restricted access permission from transfer ID
sdv::core::TPermissionID permidRestrictedAccess = control.SetAccessPermission(transferRestrictedAccess);
EXPECT_NE(permidRestrictedAccess, 0u);
EXPECT_EQ(control.GetCurrentPermission(), sdv::core::EAccessPermission::restricted_access);
// At the end of the thread, the IDs will be cleaned up automatically.
});
thread.join();
}

View File

@@ -44,8 +44,8 @@ extern "C" int main(int argc, char* argv[])
EOperatingmode eMode = static_cast<EOperatingmode>(std::atoi(sdv::MakeAnsiString(argv[1]).c_str()));
sdv::app::CAppControl appcontrol;
if (!appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"))
if (!appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"))
{
std::cout << GetTimestamp() << "Failed to start app control..." << std::endl;
return -1;
@@ -89,7 +89,7 @@ Mode="Maintenance")code"))
std::cout << GetTimestamp() << "Waiting for process with PID#" << std::dec << tProcessID << std::endl;
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
uint32_t uiMon = control.RegisterMonitor(tProcessID, &monitor);
if (!uiMon)
{
@@ -134,7 +134,7 @@ Mode="Maintenance")code"))
std::cout << GetTimestamp() << "Terminate process with PID#" << std::dec << tProcessID << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100)); // Make certain, that the first process is actually running...
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
nResult = control.Terminate(tProcessID) ? 0 : -20;
control.Shutdown(); // Needed to prevent clash with core
}

View File

@@ -23,8 +23,8 @@
TEST(ProcessControlTest, Instantiate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessControl control;
EXPECT_EQ(control.GetProcessID(), static_cast<sdv::process::TProcessID>(getpid()));
@@ -35,11 +35,11 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -61,11 +61,11 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteProcessEmergencyExit)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -87,13 +87,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteProcessNormalShutdownWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -119,13 +119,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteProcessEmergencyExitWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -151,14 +151,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteMultiProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -198,14 +198,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteMultiEmergencyAccess)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -244,13 +244,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteProcessAndTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -265,7 +265,7 @@ Mode="Maintenance")code"));
EXPECT_NE(uiCookie, 0u);
bool bTerminateResult = false;
std::thread thread([&]()
sdv::core::secure_thread thread([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
bTerminateResult = control.Terminate(tProcessID);
@@ -285,14 +285,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ParentRightsExecuteMultiTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -330,11 +330,11 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -356,11 +356,11 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteProcessEmergencyExit)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -382,13 +382,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteProcessNormalShutdownWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -414,13 +414,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteProcessEmergencyExitWithMonitor)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -446,14 +446,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteMultiProcessNormalShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -491,14 +491,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteMultiEmergencyAccess)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -537,13 +537,13 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteProcessAndTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -558,7 +558,7 @@ Mode="Maintenance")code"));
EXPECT_NE(uiCookie, 0u);
bool bTerminateResult = false;
std::thread thread([&]()
sdv::core::secure_thread thread([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(250));
bTerminateResult = control.Terminate(tProcessID);
@@ -578,14 +578,14 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ReducedRightsExecuteMultiTerminate)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else
@@ -623,15 +623,15 @@ Mode="Maintenance")code"));
TEST(ProcessControlTest, ExecuteProcessNormalShutdownWithMultipleMonitors)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode="Maintenance")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode="Maintenance")toml"));
CProcessMonitorHelper monitor1;
CProcessMonitorHelper monitor2;
CProcessMonitorHelper monitor3;
CProcessControl control;
control.Initialize(""); // Needed since local instantiation
control.Initialize(sdv::SObjectInfo()); // Needed since local instantiation
#ifdef _WIN32
const std::string ssModule = "UnitTest_ProcessControlApp.exe";
#else

View File

@@ -21,9 +21,11 @@
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.cpp"
#include "../../../sdv_services/core/module_control.cpp"
#include "../../../sdv_services/core/module.cpp"
#include "../../../sdv_services/core/repository.cpp"
#include "../../../sdv_services/core/permission_control.cpp"
#include "../../../sdv_services/core/iso_monitor.cpp"
#include "../../../sdv_services/core/object_lifetime_control.cpp"
#include "../../../sdv_services/core/app_config.cpp"

View File

@@ -15,6 +15,7 @@
#define MOCK_H
#include <interfaces/app.h>
#include <interfaces/permission.h>
#include <support/component_impl.h>
#include "../../../global/exec_dir_helper.h"
#include "../../../sdv_services/core/installation_manifest.h"
@@ -24,6 +25,7 @@
#define APP_CONTROL_H
#define LOGGER_H
#define LOGGER_CONTROL_H
//#define PERMISSION_CONTROL_H
/**
* @brief CAppSettings redefined
@@ -45,6 +47,7 @@ public:
bool IsConsoleSilent() { return true; }
bool IsConsoleVerbose() { return false; }
uint32_t GetInstanceID() { return 1000u; }
std::filesystem::path GetFrameworkDir() const { return GetExecDirectory(); }
std::filesystem::path GetRootDir() const { return GetExecDirectory(); }
std::filesystem::path GetInstallDir() const { return GetExecDirectory(); }
std::vector<std::filesystem::path> GetSystemConfigPaths() const { return {}; }
@@ -105,15 +108,36 @@ inline CLoggerControl& GetLoggerControl()
return logger_control;
}
///**
// * @brief CPermissionControl redefined
// */
//class CPermissionControl : public sdv::IInterfaceAccess
//{
//public:
// BEGIN_SDV_INTERFACE_MAP()
// END_SDV_INTERFACE_MAP()
//
// // CPermissionControl mocked functions
// virtual sdv::core::EAccessPermission GetCurrentPermission() const { return sdv::core::EAccessPermission::full_access; }
//};
//
///**
// * @brief Return the permission control.
// * @return Reference to the permission control.
// */
//inline CPermissionControl& GetPermissionControl()
//{
// static CPermissionControl control;
// return control;
//}
//
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/module_control.h"
#include "../../../sdv_services/core/repository.h"
#include "../../../sdv_services/core/permission_control.h"
#include "../../../sdv_services/core/app_config.h"
//inline std::filesystem::path GetCoreDirectoryMock() { return "../../bin"; }
//#define GetCoreDirectory GetCoreDirectoryMock
class CHelper
{
public:

View File

@@ -29,7 +29,7 @@ public:
SDV_INTERFACE_ENTRY(sdv::IObjectControl)
END_SDV_INTERFACE_MAP()
virtual void Initialize([[maybe_unused]] const sdv::u8string& ssObjectConfig) override
virtual void Initialize([[maybe_unused]] const sdv::SObjectInfo& sObjectInfo) override
{
FAIL() << "Error: Initialize should not be called by Repo Service!";
//m_eObjectState = sdv::EObjectState::initialization_failure;
@@ -91,8 +91,8 @@ TEST(RepositoryTest, CreateNonexistentClass)
CModuleControl modulectrl;
CHelper helper(modulectrl, repository);
ASSERT_TRUE(modulectrl.Load((GetExecDirectory() / "UnitTest_Repository_test_module.sdv").generic_u8string()));
EXPECT_FALSE(repository.CreateObject2("TestFooBar", nullptr, nullptr));
repository.DestroyObject2("TestFooBar");
EXPECT_FALSE(repository.CreateObject("TestFooBar", nullptr, nullptr));
EXPECT_FALSE(repository.DestroyObject("TestFooBar"));
}
TEST(RepositoryTest, GetNonexistentObject)
@@ -100,11 +100,11 @@ TEST(RepositoryTest, GetNonexistentObject)
CRepository repository; // Must be created first
CModuleControl modulectrl;
CHelper helper(modulectrl, repository);
auto permission = GetPermissionControl().CreatePermissionObject(sdv::core::EAccessPermission::full_access);
ASSERT_TRUE(modulectrl.Load((GetExecDirectory() / "UnitTest_Repository_test_module.sdv").generic_u8string()));
bool bRes = repository.CreateObject2("Example_Object", nullptr, nullptr);
EXPECT_TRUE(bRes);
EXPECT_TRUE(repository.CreateObject("Example_Object", nullptr, nullptr));
EXPECT_EQ(nullptr, repository.GetObject("TestFooBar"));
repository.DestroyObject2("Example_Object");
EXPECT_TRUE(repository.DestroyObject("Example_Object"));
}
TEST(RepositoryTest, InstantiateAndGet)
@@ -112,11 +112,12 @@ TEST(RepositoryTest, InstantiateAndGet)
CRepository repository; // Must be created first
CModuleControl modulectrl;
CHelper helper(modulectrl, repository);
auto permission = GetPermissionControl().CreatePermissionObject(sdv::core::EAccessPermission::full_access);
ASSERT_TRUE(modulectrl.Load((GetExecDirectory() / "UnitTest_Repository_test_module.sdv").generic_u8string()));
bool bRes = repository.CreateObject2("Example_Object", nullptr, nullptr);
bool bRes = repository.CreateObject("Example_Object", nullptr, nullptr);
EXPECT_TRUE(bRes);
EXPECT_NE(nullptr, repository.GetObject("Example_Object"));
repository.DestroyObject2("Example_Object");
EXPECT_TRUE(repository.DestroyObject("Example_Object"));
EXPECT_EQ(nullptr, repository.GetObject("Example_Object"));
}
@@ -126,8 +127,7 @@ TEST(RepositoryTest, InstantiateInitFail)
CModuleControl modulectrl;
CHelper helper(modulectrl, repository);
ASSERT_TRUE(modulectrl.Load((GetExecDirectory() / "UnitTest_Repository_test_module.sdv").generic_u8string()));
bool bRes = repository.CreateObject2("TestObject_IObjectControlFail", nullptr, nullptr);
EXPECT_FALSE(bRes);
EXPECT_FALSE(repository.CreateObject("TestObject_IObjectControlFail", nullptr, nullptr));
EXPECT_EQ(nullptr, repository.GetObject("TestObject_IObjectControlFail"));
repository.DestroyObject2("TestObject_IObjectControlFail");
EXPECT_FALSE(repository.DestroyObject("TestObject_IObjectControlFail"));
}

View File

@@ -15,7 +15,7 @@
#include <gtest/gtest.h>
#include <chrono>
#include "../../../global/process_watchdog.h"
#include "../../../global/scheduler/scheduler.cpp"
#include "../../../global/scheduler/scheduler.h"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
@@ -31,7 +31,7 @@ extern "C" int main(int argc, char* argv[])
TEST(TaskSchedulerTest, Construction)
{
CTaskScheduler scheduler(2);
CTaskScheduler<std::thread, 2> scheduler;
EXPECT_EQ(scheduler.GetThreadCount(), 2);
EXPECT_EQ(scheduler.GetBusyThreadCount(), 0);
EXPECT_EQ(scheduler.GetIdleThreadCount(), 2);
@@ -50,7 +50,7 @@ TEST(TaskSchedulerTest, Construction)
TEST(TaskSchedulerTest, PreallocatedConcurrencyExecution)
{
CTaskScheduler scheduler(4);
CTaskScheduler<std::thread, 4> scheduler;
// Schedule tasks onto 4 threads
std::atomic_size_t nExecuted = 0;
@@ -74,7 +74,7 @@ TEST(TaskSchedulerTest, PreallocatedConcurrencyExecution)
TEST(TaskSchedulerTest, AllocateConcurrency)
{
CTaskScheduler scheduler(2);
CTaskScheduler<std::thread, 2> scheduler;
// Schedule 4 tasks onto two threads pre-allocated and two just-in-time-allocated threads
std::atomic_size_t nExecuted = 0;
@@ -98,7 +98,7 @@ TEST(TaskSchedulerTest, AllocateConcurrency)
TEST(TaskSchedulerTest, ConcurrencyAndTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
CTaskScheduler<std::thread, 2, 2> scheduler;
// Schedule 4 tasks onto two threads
std::atomic_size_t nExecuted = 0;
@@ -122,7 +122,7 @@ TEST(TaskSchedulerTest, ConcurrencyAndTaskQueueing)
TEST(TaskSchedulerTest, ConcurrencyAndDisallowTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
CTaskScheduler<std::thread, 2, 2> scheduler;
// Schedule 4 tasks onto two threads.. Disallow the second task to be queued and the fourth task to be queued.
std::atomic_size_t nExecuted = 0;
@@ -133,7 +133,8 @@ TEST(TaskSchedulerTest, ConcurrencyAndDisallowTaskQueueing)
while (bWait)
std::this_thread::sleep_for(std::chrono::milliseconds(100));
nExecuted++;
}, (n % 2 ? CTaskScheduler::EScheduleFlags::no_queue: CTaskScheduler::EScheduleFlags::normal));
},
(n % 2 ? EScheduleFlags::no_queue : EScheduleFlags::normal));
bWait = false;
// Wait until all threads are finalized
@@ -146,7 +147,7 @@ TEST(TaskSchedulerTest, ConcurrencyAndDisallowTaskQueueing)
TEST(TaskSchedulerTest, ConcurrencyAndPrioritizedTaskQueueing)
{
CTaskScheduler scheduler(2, 2);
CTaskScheduler<std::thread, 2, 2> scheduler;
// Schedule 5 tasks onto two threads.. Queue the fifth task with high priority.
std::atomic_size_t nExecuted = 0;
@@ -169,7 +170,7 @@ TEST(TaskSchedulerTest, ConcurrencyAndPrioritizedTaskQueueing)
std::this_thread::sleep_for(std::chrono::milliseconds(300));
nExecuted++;
}, (n == 4 ? CTaskScheduler::EScheduleFlags::priority : CTaskScheduler::EScheduleFlags::normal));
}, (n == 4 ? EScheduleFlags::priority : EScheduleFlags::normal));
bWait = false;
// Wait until all threads are finalized

View File

@@ -36,13 +36,13 @@ public:
m_uiInstanceID(uiInstanceID)
{
// Initialize system
std::string ssStartup = R"code(
std::string ssStartup = R"toml(
[LogHandler]
ViewFilter = "Fatal"
[Application]
Mode = "Maintenance"
)code";
)toml";
if (uiInstanceID) ssStartup += "Instance = " + std::to_string(uiInstanceID) + "\n";
Startup(ssStartup);

View File

@@ -42,7 +42,7 @@ public:
*/
CReceiver()
{
m_threadSender = std::thread(&CReceiver::SendThreadFunc, this);
m_threadSender = sdv::core::secure_thread(&CReceiver::SendThreadFunc, this);
}
/**
@@ -236,7 +236,7 @@ private:
std::queue<sdv::sequence<sdv::pointer<uint8_t>>> m_queueSendData; ///< Queue for sending data.
std::condition_variable m_cvDisconnect; ///< Disconnect event.
std::condition_variable m_cvReceived; ///< Receive event.
std::thread m_threadSender; ///< Thread to send data.
sdv::core::secure_thread m_threadSender; ///< Thread to send data.
std::atomic_bool m_bConnected = false; ///< Set when connected was triggered.
std::atomic_bool m_bDisconnect = false; ///< Set when shutdown was triggered.
std::atomic_bool m_bShutdown = false; ///< Set when shutdown is processed.
@@ -320,9 +320,9 @@ extern "C" int main(int argc, char* argv[])
TRACE("Forced termination of app ", bServer ? "server" : "client", " process is ", bForceTerminate ? "enabled" : "disabled");
TRACE("Long life of app ",bServer ? "server" : "client", " process is ", bLongLife ? "enabled" : "disabled");
// Create an control management channel (if required).
// Create a control management channel (if required).
CSharedMemChannelMgnt mgntControlMgntChannel;
mgntControlMgntChannel.Initialize("");
mgntControlMgntChannel.Initialize(sdv::SObjectInfo());
if (mgntControlMgntChannel.GetObjectState() != sdv::EObjectState::initialized) return -11;
mgntControlMgntChannel.SetOperationMode(sdv::EOperationMode::running);
if (mgntControlMgntChannel.GetObjectState() != sdv::EObjectState::running) return -11;
@@ -349,7 +349,7 @@ extern "C" int main(int argc, char* argv[])
// Create the data management channel.
CSharedMemChannelMgnt mgntDataMgntChannel;
mgntDataMgntChannel.Initialize("");
mgntDataMgntChannel.Initialize(sdv::SObjectInfo());
if (mgntDataMgntChannel.GetObjectState() != sdv::EObjectState::initialized) return -1;
mgntDataMgntChannel.SetOperationMode(sdv::EOperationMode::running);
if (mgntDataMgntChannel.GetObjectState() != sdv::EObjectState::running) return -1;
@@ -360,10 +360,10 @@ extern "C" int main(int argc, char* argv[])
if (bServer)
{
TRACE("Server: Create data endpoint...");
sdv::ipc::SChannelEndpoint sEndpoint = mgntDataMgntChannel.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sEndpoint = mgntDataMgntChannel.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
ptrDataConnection = sEndpoint.pConnection;
sdv::pointer<uint8_t> ptrConnectInfoData;
ptrConnectInfoData.resize(sEndpoint.ssConnectString.size());

View File

@@ -59,7 +59,7 @@ TEST(InProcessMemoryBufferTest, TriggerTestRx)
};
std::unique_lock<std::mutex> lockStart(mtxStart);
std::thread thread(fnWaitForTrigger);
sdv::core::secure_thread thread(fnWaitForTrigger);
cvStart.wait(lockStart);
for (size_t n = 0; n < 20; n++)
@@ -108,7 +108,7 @@ TEST(InProcessMemoryBufferTest, TriggerTestTx)
};
std::unique_lock<std::mutex> lockStart(mtxStart);
std::thread thread(fnWaitForTrigger);
sdv::core::secure_thread thread(fnWaitForTrigger);
cvStart.wait(lockStart);
for (size_t n = 0; n < 20; n++)
@@ -170,8 +170,8 @@ TEST(InProcessMemoryBufferTest, TriggerTestRxTx)
std::unique_lock<std::mutex> lockStartSender(mtxSenderStart);
std::unique_lock<std::mutex> lockStartReceiver(mtxReceiverStart);
std::thread threadSender(fnWaitForTriggerSender);
std::thread threadReceiver(fnWaitForTriggerReceiver);
sdv::core::secure_thread threadSender(fnWaitForTriggerSender);
sdv::core::secure_thread threadReceiver(fnWaitForTriggerReceiver);
cvSenderStart.wait(lockStartSender);
lockStartSender.unlock();
cvReceiverStart.wait(lockStartReceiver);
@@ -340,8 +340,8 @@ TEST(InProcessMemoryBufferTest, ReserveCommitAccessReleaseNonChronologicalOrder)
// Reserve buffers for strings
// The buffer header has 16 bytes
// Each allocation is 8 bytes header, 5 bytes data and 3 bytes alignment
CAccessorTxPacket rgTxPackets[32] = {};
// Each allocation is 8 bytes header, 5 bytes data and 3 bytes alignment
CAccessorTxPacket rgTxPackets[32] = {};
for (int32_t iIndex = 0; iIndex < 15; iIndex++)
{
auto optTxPacket = sender.Reserve(5);
@@ -373,8 +373,8 @@ TEST(InProcessMemoryBufferTest, ReserveCommitAccessReleaseNonChronologicalOrder)
{
// The text should contain the number 0
EXPECT_TRUE(optRxPacket);
EXPECT_NE(optRxPacket->GetData(), nullptr);
EXPECT_EQ(std::to_string(0), optRxPacket->GetData<char>());
EXPECT_NE(optRxPacket->GetData(), nullptr);
EXPECT_EQ(std::to_string(0), optRxPacket->GetData<char>());
optRxPacket->Accept();
}
else
@@ -414,7 +414,7 @@ TEST(InProcessMemoryBufferTest, ReserveCommitAccessReleaseNonChronologicalOrder)
EXPECT_NE(rgRxPackets[iIndex].GetData(), nullptr);
EXPECT_NE(rgRxPackets[iIndex].GetSize(), 0u);
}
if (rgRxPackets[iIndex])
if (rgRxPackets[iIndex])
{
EXPECT_EQ(std::to_string(iIndex), rgRxPackets[iIndex].GetData<char>());
}
@@ -442,33 +442,33 @@ TEST(InProcessMemoryBufferTest, SendReceivePattern)
ASSERT_TRUE(appcontrol.Startup(""));
CInProcMemBufferTx sender;
EXPECT_TRUE(sender.IsValid());
EXPECT_TRUE(sender.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CPatternReceiver pattern_inspector(receiver);
CPatternReceiver pattern_inspector(receiver);
CPatternSender pattern_generator(sender);
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Shutdown
pattern_generator.Shutdown();
pattern_inspector.Shutdown();
pattern_inspector.Shutdown();
std::cout << "Pattern generator: " << pattern_generator.GetCycleCnt() << " cyles, " << pattern_generator.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_inspector.GetByteCnt() << " bytes, " << pattern_inspector.GetErrorCnt()
<< " errors, " << std::endl;
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
}
TEST(InProcessMemoryBufferTest, DelayedSendReceivePattern)
@@ -477,33 +477,33 @@ TEST(InProcessMemoryBufferTest, DelayedSendReceivePattern)
ASSERT_TRUE(appcontrol.Startup(""));
CInProcMemBufferTx sender;
EXPECT_TRUE(sender.IsValid());
EXPECT_TRUE(sender.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CPatternReceiver pattern_inspector(receiver);
CPatternSender pattern_generator(sender, 10);
CPatternReceiver pattern_inspector(receiver);
CPatternSender pattern_generator(sender, 10);
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Shutdown
pattern_generator.Shutdown();
pattern_inspector.Shutdown();
// Shutdown
pattern_generator.Shutdown();
pattern_inspector.Shutdown();
std::cout << "Pattern generator: " << pattern_generator.GetCycleCnt() << " cyles, " << pattern_generator.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_inspector.GetByteCnt() << " bytes, " << pattern_inspector.GetErrorCnt()
<< " errors, " << std::endl;
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
}
TEST(InProcessMemoryBufferTest, SendDelayedReceivePattern)
@@ -512,33 +512,33 @@ TEST(InProcessMemoryBufferTest, SendDelayedReceivePattern)
ASSERT_TRUE(appcontrol.Startup(""));
CInProcMemBufferTx sender;
EXPECT_TRUE(sender.IsValid());
EXPECT_TRUE(sender.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CInProcMemBufferRx receiver(sender.GetConnectionString());
EXPECT_TRUE(receiver.IsValid());
CPatternReceiver pattern_inspector(receiver, 10);
CPatternSender pattern_generator(sender);
CPatternReceiver pattern_inspector(receiver, 10);
CPatternSender pattern_generator(sender);
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Shutdown
pattern_generator.Shutdown();
pattern_inspector.Shutdown();
// Shutdown
pattern_generator.Shutdown();
pattern_inspector.Shutdown();
std::cout << "Pattern generator: " << pattern_generator.GetCycleCnt() << " cyles, " << pattern_generator.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_inspector.GetByteCnt() << " bytes, " << pattern_inspector.GetErrorCnt()
<< " errors, " << std::endl;
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
}
TEST(InProcessMemoryBufferTest, SendRepeatReceivePattern)
@@ -547,50 +547,50 @@ TEST(InProcessMemoryBufferTest, SendRepeatReceivePattern)
ASSERT_TRUE(appcontrol.Startup(""));
// The first process creates a sender and receiver
CInProcMemBufferTx bufferTX;
EXPECT_TRUE(bufferTX.IsValid());
CInProcMemBufferRx bufferRX;
EXPECT_TRUE(bufferRX.IsValid());
CInProcMemBufferTx bufferTX;
EXPECT_TRUE(bufferTX.IsValid());
CInProcMemBufferRx bufferRX;
EXPECT_TRUE(bufferRX.IsValid());
// The connection string containing the RX and TX strings for the repeater
std::string ssConnectionString = bufferTX.GetConnectionString() + "\n" + bufferRX.GetConnectionString();
// The repeater process creates a receiver and sender
CInProcMemBufferRx bufferRepeaterRX(ssConnectionString);
EXPECT_TRUE(bufferRepeaterRX.IsValid());
CInProcMemBufferTx bufferRepeaterTX(ssConnectionString);
EXPECT_TRUE(bufferRepeaterTX.IsValid());
CInProcMemBufferRx bufferRepeaterRX(ssConnectionString);
EXPECT_TRUE(bufferRepeaterRX.IsValid());
CInProcMemBufferTx bufferRepeaterTX(ssConnectionString);
EXPECT_TRUE(bufferRepeaterTX.IsValid());
// Connect the pattern generator and inspector
CPatternReceiver pattern_inspector(bufferRX);
CPatternRepeater pattern_repeater(bufferRepeaterRX, bufferRepeaterTX);
CPatternSender pattern_generator(bufferTX);
CPatternRepeater pattern_repeater(bufferRepeaterRX, bufferRepeaterTX);
CPatternSender pattern_generator(bufferTX);
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Wait for 2 seconds
std::this_thread::sleep_for(std::chrono::seconds(PATTERN_TEST_TIME_S));
// Shutdown
pattern_generator.Shutdown();
pattern_repeater.Shutdown();
pattern_inspector.Shutdown();
// Shutdown
pattern_generator.Shutdown();
pattern_repeater.Shutdown();
pattern_inspector.Shutdown();
std::cout << "Pattern generator: " << pattern_generator.GetCycleCnt() << " cyles, " << pattern_generator.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_generator.GetByteCnt() << " bytes" << std::endl;
std::cout << "Pattern inspector: " << pattern_inspector.GetCycleCnt() << " cyles, " << pattern_inspector.GetPacketCnt()
<< " packets, " << pattern_inspector.GetByteCnt() << " bytes, " << pattern_inspector.GetErrorCnt()
<< " errors, " << std::endl;
std::cout << "Pattern repeater: " << pattern_repeater.GetCycleCnt() << " cyles, " << pattern_repeater.GetPacketCnt()
std::cout << "Pattern repeater: " << pattern_repeater.GetCycleCnt() << " cyles, " << pattern_repeater.GetPacketCnt()
<< " packets, " << pattern_repeater.GetByteCnt() << " bytes, " << pattern_repeater.GetErrorCnt()
<< " errors, " << std::endl;
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
EXPECT_NE(pattern_repeater.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_repeater.GetErrorCnt(), 0u);
EXPECT_NE(pattern_repeater.GetPacketCnt(), 0u);
EXPECT_NE(pattern_repeater.GetByteCnt(), 0ull);
EXPECT_NE(pattern_generator.GetCycleCnt(), 0u);
EXPECT_NE(pattern_generator.GetPacketCnt(), 0u);
EXPECT_NE(pattern_generator.GetByteCnt(), 0ull);
EXPECT_NE(pattern_inspector.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_inspector.GetErrorCnt(), 0u);
EXPECT_NE(pattern_inspector.GetPacketCnt(), 0u);
EXPECT_NE(pattern_inspector.GetByteCnt(), 0ull);
EXPECT_NE(pattern_repeater.GetCycleCnt(), 0u);
EXPECT_EQ(pattern_repeater.GetErrorCnt(), 0u);
EXPECT_NE(pattern_repeater.GetPacketCnt(), 0u);
EXPECT_NE(pattern_repeater.GetByteCnt(), 0ull);
}

View File

@@ -24,7 +24,7 @@ CPatternSender::CPatternSender(CMemBufferAccessorTx& raccessorOut, uint32_t uiDe
m_raccessorOut(raccessorOut), m_uiDelayMs(uiDelayMs)
{
// Start the thread
m_thread = std::thread(&CPatternSender::Process, this);
m_thread = sdv::core::secure_thread(&CPatternSender::Process, this);
// Wait for the thread to run
while (!m_bStarted) std::this_thread::sleep_for(std::chrono::milliseconds(1));
@@ -67,7 +67,7 @@ CPatternReceiver::CPatternReceiver(CMemBufferAccessorRx& raccessorIn, uint32_t u
m_raccessorIn(raccessorIn),m_uiDelayMs(uiDelayMs)
{
// Start the thread
m_thread = std::thread(& CPatternReceiver::Process, this);
m_thread = sdv::core::secure_thread(& CPatternReceiver::Process, this);
// Wait for the thread to run
while (!m_bStarted) std::this_thread::sleep_for(std::chrono::milliseconds(1));
@@ -123,7 +123,7 @@ CPatternRepeater::CPatternRepeater(CMemBufferAccessorRx& raccessorIn, CMemBuffer
m_raccessorIn(raccessorIn), m_raccessorOut(raccessorOut), m_uiDelayMs(uiDelayMs)
{
// Start the thread
m_thread = std::thread(&CPatternRepeater::Process, this);
m_thread = sdv::core::secure_thread(&CPatternRepeater::Process, this);
// Wait for the thread to run
while (!m_bStarted) std::this_thread::sleep_for(std::chrono::milliseconds(1));

View File

@@ -16,6 +16,7 @@
#include <thread>
#include <atomic>
#include <support/local_service_access.h>
#include "../../../sdv_services/ipc_shared_mem/mem_buffer_accessor.h"
/**
@@ -55,14 +56,14 @@ public:
*/
private:
CMemBufferAccessorTx& m_raccessorOut; //!< Reference to the output accessor
std::thread m_thread; //!< Processing thread
std::atomic_bool m_bStarted = false; //!< Set by the thread when started.
std::atomic_bool m_bShutdown = false; //!< When set, shutdown the thread.
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
CMemBufferAccessorTx& m_raccessorOut; //!< Reference to the output accessor
sdv::core::secure_thread m_thread; //!< Processing thread
std::atomic_bool m_bStarted = false; //!< Set by the thread when started.
std::atomic_bool m_bShutdown = false; //!< When set, shutdown the thread.
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
};
class CPatternReceiver
@@ -98,15 +99,15 @@ public:
*/
private:
CMemBufferAccessorRx& m_raccessorIn; //!< Reference to the input accessor
std::thread m_thread; //!< Processing thread
CMemBufferAccessorRx& m_raccessorIn; //!< Reference to the input accessor
sdv::core::secure_thread m_thread; //!< Processing thread
bool m_bStarted = false; //!< Set by the thread when started.
bool m_bShutdown = false; //!< When set, shutdown the thread.
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiErrorCnt = 0u; //!< Amount of counter errors
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiErrorCnt = 0u; //!< Amount of counter errors
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
};
class CPatternRepeater
@@ -143,16 +144,16 @@ public:
*/
private:
CMemBufferAccessorRx& m_raccessorIn; //!< Reference to the input accessor
CMemBufferAccessorTx& m_raccessorOut; //!< Reference to the output accessor
std::thread m_thread; //!< Processing thread
bool m_bStarted = false; //!< Set by the thread when started.
bool m_bShutdown = false; //!< When set, shutdown the thread.
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiErrorCnt = 0u; //!< Amount of counter errors
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
CMemBufferAccessorRx& m_raccessorIn; //!< Reference to the input accessor
CMemBufferAccessorTx& m_raccessorOut; //!< Reference to the output accessor
sdv::core::secure_thread m_thread; //!< Processing thread
bool m_bStarted = false; //!< Set by the thread when started.
bool m_bShutdown = false; //!< When set, shutdown the thread.
uint32_t m_uiDelayMs = 0u; //!< Delay (in ms) to insert while processing.
uint32_t m_uiCycleCnt = 0u; //!< Amount of packets
uint32_t m_uiErrorCnt = 0u; //!< Amount of counter errors
uint32_t m_uiPacketCnt = 0u; //!< Amount of packets
uint64_t m_uiByteCnt = 0ull; //!< Amount of bytes
};
#endif // !defined(PATTERN_GEN_H)

View File

@@ -88,7 +88,7 @@ TEST(SharedMemoryBufferTest, TriggerTestRx)
};
std::unique_lock<std::mutex> lockStart(mtxStart);
std::thread thread(fnWaitForTrigger);
sdv::core::secure_thread thread(fnWaitForTrigger);
cvStart.wait(lockStart);
for (size_t n = 0; n < 20; n++)
@@ -141,7 +141,7 @@ TEST(SharedMemoryBufferTest, TriggerTestTx)
};
std::unique_lock<std::mutex> lockStart(mtxStart);
std::thread thread(fnWaitForTrigger);
sdv::core::secure_thread thread(fnWaitForTrigger);
cvStart.wait(lockStart);
for (size_t n = 0; n < 20; n++)
@@ -208,8 +208,8 @@ TEST(SharedMemoryBufferTest, TriggerTestRxTx)
std::unique_lock<std::mutex> lockStartSender(mtxSenderStart);
std::unique_lock<std::mutex> lockStartReceiver(mtxReceiverStart);
std::thread threadSender(fnWaitForTriggerSender);
std::thread threadReceiver(fnWaitForTriggerReceiver);
sdv::core::secure_thread threadSender(fnWaitForTriggerSender);
sdv::core::secure_thread threadReceiver(fnWaitForTriggerReceiver);
cvSenderStart.wait(lockStartSender);
lockStartSender.unlock();
cvReceiverStart.wait(lockStartReceiver);
@@ -693,8 +693,8 @@ TEST(SharedMemoryBufferTest, SendRepeatReceivePattern)
TEST(SharedMemoryBufferTest, AppProcessSendRepeatReceivePattern)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
CSharedMemBufferTx bufferTX;
@@ -747,8 +747,8 @@ Mode = "Essential")code"));
TEST(SharedMemoryBufferTest, SendRepeatReceivePatternBetweenTwoAppProcesses)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
// test starts 2 app processes, one should be the sender of the pattern, the other is the repeater

View File

@@ -81,7 +81,7 @@ public:
// Start the processing thread if needed
if (!m_threadDecoupledSend.joinable()) m_threadDecoupledSend =
std::thread(&CConnectReceiver::DecoupledSendThread, this);
sdv::core::secure_thread(&CConnectReceiver::DecoupledSendThread, this);
// Store data into the queue for sending.
m_queueDecoupledSend.push(std::move(seqData));
@@ -186,7 +186,7 @@ private:
bool m_bConnectError = false; ///< Connection error ocurred.
bool m_bCommError = false; ///< Communication error occurred.
bool m_bForcedDisconnect = false; ///< Force disconnect.
std::thread m_threadDecoupledSend; ///< Decoupled send thread.
sdv::core::secure_thread m_threadDecoupledSend; ///< Decoupled send thread.
std::queue<sdv::sequence<sdv::pointer<uint8_t>>> m_queueDecoupledSend; ///< Data queue for sending.
std::condition_variable m_cvDecoupledSend; ///< Trigger decoupled sending.
std::atomic_bool m_bShutdown = false; ///< Shutdown send thread.
@@ -203,7 +203,7 @@ TEST(SharedMemChannelService, Instantiate)
ASSERT_TRUE(appcontrol.Startup(""));
CSharedMemChannelMgnt mgnt;
EXPECT_NO_THROW(mgnt.Initialize(""));
EXPECT_NO_THROW(mgnt.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgnt.GetObjectState(), sdv::EObjectState::initialized);
@@ -220,7 +220,7 @@ TEST(SharedMemChannelService, ChannelConfigString)
ASSERT_TRUE(appcontrol.Startup(""));
CSharedMemChannelMgnt mgnt;
EXPECT_NO_THROW(mgnt.Initialize(""));
EXPECT_NO_THROW(mgnt.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgnt.GetObjectState(), sdv::EObjectState::initialized);
@@ -237,7 +237,7 @@ TEST(SharedMemChannelService, CreateRandomEndpoint)
CSharedMemChannelMgnt mgnt;
// Create an endpoint.
EXPECT_NO_THROW(mgnt.Initialize(""));
EXPECT_NO_THROW(mgnt.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgnt.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgnt.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -256,12 +256,12 @@ TEST(SharedMemChannelService, CreateExplicitEndpoint)
CSharedMemChannelMgnt mgnt;
// Create an endpoint.
EXPECT_NO_THROW(mgnt.Initialize(""));
EXPECT_NO_THROW(mgnt.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgnt.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgnt.CreateEndpoint(R"code([IpcChannel]
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgnt.CreateEndpoint(R"toml([IpcChannel]
Name = "CHANNEL_1234"
Size = 10240
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
if (sChannelEndpoint.pConnection) sdv::TObjectPtr(sChannelEndpoint.pConnection);
@@ -278,9 +278,9 @@ TEST(SharedMemChannelService, GetRandomEndpointAccess)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient.Initialize(""));
EXPECT_NO_THROW(mgntClient.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -306,14 +306,14 @@ TEST(SharedMemChannelService, GetExplicitEndpointAccess)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient.Initialize(""));
EXPECT_NO_THROW(mgntClient.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code([IpcChannel]
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml([IpcChannel]
Name = "CHANNEL_1234"
Size = 10240
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
@@ -337,7 +337,7 @@ TEST(SharedMemChannelService, WaitForConnection)
CSharedMemChannelMgnt mgnt;
// Create an endpoint.
EXPECT_NO_THROW(mgnt.Initialize(""));
EXPECT_NO_THROW(mgnt.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgnt.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgnt.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -359,7 +359,7 @@ TEST(SharedMemChannelService, WaitForConnection)
pConnection->GetConnectState() == sdv::ipc::EConnectState::connecting);
// Wait for connection for infinite period with cancel.
std::thread threadCancelWait([&]()
sdv::core::secure_thread threadCancelWait([&]()
{
std::this_thread::sleep_for(std::chrono::milliseconds(500));
pConnection->CancelWait();
@@ -384,9 +384,9 @@ TEST(SharedMemChannelService, AsyncConnect)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient.Initialize(""));
EXPECT_NO_THROW(mgntClient.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -481,9 +481,9 @@ TEST(SharedMemChannelService, EstablishConnectionEvents)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient.Initialize(""));
EXPECT_NO_THROW(mgntClient.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -597,11 +597,11 @@ TEST(SharedMemChannelService, EstablishReconnect)
CSharedMemChannelMgnt mgntServer, mgntClient1, mgntClient2;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient1.Initialize(""));
EXPECT_NO_THROW(mgntClient1.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient1.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient2.Initialize(""));
EXPECT_NO_THROW(mgntClient2.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient2.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -680,11 +680,11 @@ TEST(SharedMemChannelService, EstablishReconnectEvents)
CSharedMemChannelMgnt mgntServer, mgntClient1, mgntClient2;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient1.Initialize(""));
EXPECT_NO_THROW(mgntClient1.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient1.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgntClient2.Initialize(""));
EXPECT_NO_THROW(mgntClient2.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntClient2.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -779,14 +779,14 @@ TEST(SharedMemChannelService, EstablishReconnectEvents)
TEST(SharedMemChannelService, AppEstablishConnection)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
CSharedMemChannelMgnt mgntServer;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -860,14 +860,14 @@ Mode = "Essential")code"));
TEST(SharedMemChannelService, AppGracefullyShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
CSharedMemChannelMgnt mgntServer;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -937,14 +937,14 @@ Mode = "Essential")code"));
TEST(SharedMemChannelService, AppForcedShutdown_Watchdog)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
CSharedMemChannelMgnt mgntServer;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -1019,8 +1019,8 @@ Mode = "Essential")code"));
TEST(SharedMemChannelService, IndirectAppGracefullyShutdown)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
sdv::process::IProcessControl* pProcessControl = sdv::core::GetObject<sdv::process::IProcessControl>("ProcessControlService");
@@ -1030,7 +1030,7 @@ Mode = "Essential")code"));
// Create the first control endpoint.
CSharedMemChannelMgnt mgntControl1;
EXPECT_NO_THROW(mgntControl1.Initialize(""));
EXPECT_NO_THROW(mgntControl1.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl1.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint1 = mgntControl1.CreateEndpoint("");
EXPECT_NE(sEndpoint1.pConnection, nullptr);
@@ -1066,7 +1066,7 @@ Mode = "Essential")code"));
// Create the second control endpoint.
CSharedMemChannelMgnt mgntControl2;
EXPECT_NO_THROW(mgntControl2.Initialize(""));
EXPECT_NO_THROW(mgntControl2.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl2.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint2 = mgntControl2.CreateEndpoint("");
EXPECT_NE(sEndpoint2.pConnection, nullptr);
@@ -1100,8 +1100,8 @@ Mode = "Essential")code"));
TEST(SharedMemChannelService, IndirectAppServerForceShutdown_Watchdog)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
sdv::process::IProcessControl* pProcessControl = sdv::core::GetObject<sdv::process::IProcessControl>("ProcessControlService");
@@ -1113,7 +1113,7 @@ Mode = "Essential")code"));
// Create the first control endpoint.
CSharedMemChannelMgnt mgntControl1;
EXPECT_NO_THROW(mgntControl1.Initialize(""));
EXPECT_NO_THROW(mgntControl1.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl1.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint1 = mgntControl1.CreateEndpoint("");
EXPECT_NE(sEndpoint1.pConnection, nullptr);
@@ -1149,7 +1149,7 @@ Mode = "Essential")code"));
// Create the second control endpoint.
CSharedMemChannelMgnt mgntControl2;
EXPECT_NO_THROW(mgntControl2.Initialize(""));
EXPECT_NO_THROW(mgntControl2.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl2.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint2 = mgntControl2.CreateEndpoint("");
EXPECT_NE(sEndpoint2.pConnection, nullptr);
@@ -1183,8 +1183,8 @@ Mode = "Essential")code"));
TEST(SharedMemChannelService, IndirectAppClientForceShutdown_Watchdog)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code([Application]
Mode = "Essential")code"));
ASSERT_TRUE(appcontrol.Startup(R"toml([Application]
Mode = "Essential")toml"));
LoadSupportServices();
sdv::process::IProcessControl* pProcessControl = sdv::core::GetObject<sdv::process::IProcessControl>("ProcessControlService");
@@ -1194,7 +1194,7 @@ Mode = "Essential")code"));
// Create the first control endpoint.
CSharedMemChannelMgnt mgntControl1;
EXPECT_NO_THROW(mgntControl1.Initialize(""));
EXPECT_NO_THROW(mgntControl1.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl1.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint1 = mgntControl1.CreateEndpoint("");
EXPECT_NE(sEndpoint1.pConnection, nullptr);
@@ -1230,7 +1230,7 @@ Mode = "Essential")code"));
// Create the second control endpoint.
CSharedMemChannelMgnt mgntControl2;
EXPECT_NO_THROW(mgntControl2.Initialize(""));
EXPECT_NO_THROW(mgntControl2.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntControl2.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sEndpoint2 = mgntControl2.CreateEndpoint("");
EXPECT_NE(sEndpoint2.pConnection, nullptr);

View File

@@ -90,7 +90,7 @@ public:
// Start the processing thread if needed
if (!m_threadDecoupledSend.joinable())
m_threadDecoupledSend = std::thread(&CLargeDataReceiver::DecoupledSendThread, this);
m_threadDecoupledSend = sdv::core::secure_thread(&CLargeDataReceiver::DecoupledSendThread, this);
// Store data into the queue for sending.
m_queueDecoupledSend.push(std::move(seqData));
@@ -262,7 +262,7 @@ private:
bool m_bForcedDisconnect = false; ///< Force disconnect.
std::atomic_size_t m_nCount = 0; ///< Receive counter.
std::condition_variable m_cvReceived; ///< Receive event.
std::thread m_threadDecoupledSend; ///< Decoupled send thread.
sdv::core::secure_thread m_threadDecoupledSend; ///< Decoupled send thread.
std::queue<sdv::sequence<sdv::pointer<uint8_t>>> m_queueDecoupledSend; ///< Data queue for sending.
std::condition_variable m_cvDecoupledSend; ///< Trigger decoupled sending.
std::atomic_bool m_bShutdown = false; ///< Shutdown send thread.
@@ -271,27 +271,29 @@ private:
TEST(SharedMemChannelService, CommunicateOneLargeBlock)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code(
ASSERT_TRUE(appcontrol.Startup(R"toml(
[Console]
Report = "Silent"
)code"));
)toml"));
appcontrol.SetConfigMode();
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
mgntServer.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::running);
EXPECT_NO_THROW(mgntClient.Initialize("service = \"client\""));
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = "service = \"client\"";
EXPECT_NO_THROW(mgntClient.Initialize(sClientInfo));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
mgntClient.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::running);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
@@ -376,18 +378,20 @@ TEST(SharedMemChannelService, CommunicateMultiLargeBlock)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
mgntServer.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::running);
EXPECT_NO_THROW(mgntClient.Initialize("service = \"client\""));
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = "service = \"client\"";
EXPECT_NO_THROW(mgntClient.Initialize(sClientInfo));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
mgntClient.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::running);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
@@ -504,18 +508,20 @@ TEST(SharedMemChannelService, CommunicateFragmentedLargeBlock)
CSharedMemChannelMgnt mgntServer, mgntClient;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
mgntServer.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::running);
EXPECT_NO_THROW(mgntClient.Initialize("service = \"client\""));
sdv::SObjectInfo sClientInfo{};
sClientInfo.ssConfig = "service = \"client\"";
EXPECT_NO_THROW(mgntClient.Initialize(sClientInfo));
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::initialized);
mgntClient.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntClient.GetObjectState(), sdv::EObjectState::running);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
@@ -614,23 +620,23 @@ Size = 1024000
TEST(SharedMemChannelService, AppCommunicateOneLargeBlock)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code(
ASSERT_TRUE(appcontrol.Startup(R"toml(
[Application]
Mode="Essential")code"));
Mode="Essential")toml"));
LoadSupportServices();
appcontrol.SetConfigMode();
CSharedMemChannelMgnt mgntServer;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
mgntServer.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::running);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());
@@ -698,23 +704,23 @@ Size = 1024000
TEST(SharedMemChannelService, AppCommunicateMultiLargeBlock)
{
sdv::app::CAppControl appcontrol;
ASSERT_TRUE(appcontrol.Startup(R"code(
ASSERT_TRUE(appcontrol.Startup(R"toml(
[Application]
Mode="Essential")code"));
Mode="Essential")toml"));
LoadSupportServices();
appcontrol.SetConfigMode();
CSharedMemChannelMgnt mgntServer;
// Create an endpoint.
EXPECT_NO_THROW(mgntServer.Initialize(""));
EXPECT_NO_THROW(mgntServer.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::initialized);
mgntServer.SetOperationMode(sdv::EOperationMode::running);
EXPECT_EQ(mgntServer.GetObjectState(), sdv::EObjectState::running);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"code(
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgntServer.CreateEndpoint(R"toml(
[IpcChannel]
Size = 1024000
)code");
)toml");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
EXPECT_FALSE(sChannelEndpoint.ssConnectString.empty());

View File

@@ -0,0 +1,46 @@
#*******************************************************************************
# 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:
# Martin Stimpfl - initial API and implementation
# Erik Verhoeven - writing TOML and whitespace preservation
#*******************************************************************************
# Define project
project (UnitTest_SimpleTOMLParser VERSION 1.0 LANGUAGES CXX)
# Character Reader executable
add_executable(UnitTest_SimpleTOMLParser
"parser_tests.cpp" "main.cpp")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_SimpleTOMLParser GTest::GTest ${CMAKE_THREAD_LIBS_INIT})
if (WIN32)
target_link_libraries(UnitTest_SimpleTOMLParser Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(UnitTest_SimpleTOMLParser ${CMAKE_DL_LIBS} rt)
endif()
else()
target_link_libraries(UnitTest_SimpleTOMLParser GTest::GTest Rpcrt4.lib)
endif()
# Add the Reader unittest
add_test(NAME UnitTest_SimpleTOMLParser COMMAND UnitTest_SimpleTOMLParser)
# Execute the test
add_custom_command(TARGET UnitTest_SimpleTOMLParser POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_SimpleTOMLParser>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_SimpleTOMLParser.xml
VERBATIM
)
# Build dependencies
#add_dependencies(UnitTest_SimpleTOMLParser dependency_sdv_components)

View File

@@ -8,14 +8,21 @@
* SPDX-License-Identifier: Apache-2.0
*
* Contributors:
* Erik Verhoeven - initial API and implementation
* Martin Stimpfl - initial API and implementation
* Erik Verhoeven - writing TOML and whitespace preservation
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/process_watchdog.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#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;
// Test TODO:
// Shift nodes up and down within one container
// Remove formatting from node
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,868 @@
#include <iostream>
#include <gtest/gtest.h>
#include <support/simple_toml.h>
TEST(RecognizeTypes, Root)
{
sdv::toml::simple_parser::CParser parser("");
auto sRoot = parser.Root();
EXPECT_EQ(sRoot.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
}
TEST(RecognizeTypes, Table)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[newTable]
[secondTable.nestedTable]
)toml");
auto sRoot = parser.Root();
auto table1 = sRoot.GetDirect("newTable");
EXPECT_EQ(table1.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(table1.GetName(), "newTable");
EXPECT_EQ(table1.GetValue(), "");
auto table2 = sRoot.GetDirect("secondTable");
EXPECT_EQ(table2.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(table2.GetName(), "secondTable");
EXPECT_EQ(table2.GetValue(), "");
auto table3 = sRoot.GetDirect("secondTable.nestedTable");
EXPECT_EQ(table3.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(table3.GetName(), "nestedTable");
EXPECT_EQ(table3.GetValue(), "");
}
TEST(RecognizeTypes, Key_Value)
{
sdv::toml::simple_parser::CParser parser(R"toml(
name = "Hammer"
id = 42
pi = 3.1415926
boolean = true
array = []
table = {}
)toml");
auto sRoot = parser.Root();
auto value_name = sRoot.GetDirect("name");
EXPECT_EQ(value_name.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(value_name.GetValue(), "Hammer");
auto value_id = sRoot.GetDirect("id");
EXPECT_EQ(value_id.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(value_id.GetValue<int>(), 42);
auto value_pi = sRoot.GetDirect("pi");
EXPECT_EQ(value_pi.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(value_pi.GetValue<double>(), 3.1415926);
auto value_boolean = sRoot.GetDirect("boolean");
EXPECT_EQ(value_boolean.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(value_boolean.GetValue<bool>(), true);
auto value_array = sRoot.GetDirect("array");
EXPECT_EQ(value_array.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
EXPECT_EQ(value_array.GetValue(), "");
auto value_table = sRoot.GetDirect("table");
EXPECT_EQ(value_table.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(value_table.GetValue(), "");
}
TEST(RecognizeTypes, TableArray)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[[newTableArray]]
[[newTableArray]]
[[table.nestedTableArray]]
)toml");
auto sRoot = parser.Root();
auto tableArray1 = sRoot.GetDirect("newTableArray");
EXPECT_EQ(tableArray1.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
EXPECT_EQ(tableArray1.GetName(), "newTableArray");
auto table1 = sRoot.GetDirect("newTableArray[0]");
ASSERT_TRUE(table1);
EXPECT_EQ(table1.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(table1.GetName(), "newTableArray");
auto table2 = sRoot.GetDirect("newTableArray[1]");
ASSERT_TRUE(table2);
EXPECT_EQ(table2.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(table2.GetName(), "newTableArray");
}
TEST(NestedContent, Array)
{
sdv::toml::simple_parser::CParser parser(R"toml(
arr_mixed = [ 1.0, 2, "test string", [ 1, 2 ], { pi = 3.14, e = 2.71828 }, true]
arr_ints = [ 1, 2, 3, 4]
arr_ints_trailing_comma = [ 1, 2, 3, 4, ]
arr_multiline = [
"first line",
"second line",
"third_line",
]
)toml");
auto sRoot = parser.Root();
{
auto array_ints = sRoot.GetDirect("arr_ints");
EXPECT_EQ(array_ints.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
auto array_ints_0 = sRoot.GetDirect("arr_ints[0]");
ASSERT_TRUE(array_ints_0);
EXPECT_EQ(array_ints_0.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_0.GetValue<int>(), 1);
auto array_ints_1 = sRoot.GetDirect("arr_ints[1]");
ASSERT_TRUE(array_ints_1);
EXPECT_EQ(array_ints_1.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_1.GetValue<int>(), 2);
auto array_ints_2 = sRoot.GetDirect("arr_ints[2]");
ASSERT_TRUE(array_ints_2);
EXPECT_EQ(array_ints_2.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_2.GetValue<int>(), 3);
auto array_ints_3 = sRoot.GetDirect("arr_ints[3]");
ASSERT_TRUE(array_ints_3);
EXPECT_EQ(array_ints_3.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_3.GetValue<int>(), 4);
auto array_ints_4 = sRoot.GetDirect("arr_ints[4]");
EXPECT_FALSE(array_ints_4);
}
{
auto array_ints_trailing_comma = sRoot.GetDirect("arr_ints_trailing_comma");
auto array_ints_trailing_comma_0 = sRoot.GetDirect("arr_ints_trailing_comma[0]");
auto array_ints_trailing_comma_1 = sRoot.GetDirect("arr_ints_trailing_comma[1]");
auto array_ints_trailing_comma_2 = sRoot.GetDirect("arr_ints_trailing_comma[2]");
auto array_ints_trailing_comma_3 = sRoot.GetDirect("arr_ints_trailing_comma[3]");
auto array_ints_trailing_comma_4 = sRoot.GetDirect("arr_ints_trailing_comma[4]");
EXPECT_EQ(array_ints_trailing_comma.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
ASSERT_TRUE(array_ints_trailing_comma_0);
EXPECT_EQ(array_ints_trailing_comma_0.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_trailing_comma_0.GetValue<int>(), 1);
ASSERT_TRUE(array_ints_trailing_comma_1);
EXPECT_EQ(array_ints_trailing_comma_1.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_trailing_comma_1.GetValue<int>(), 2);
ASSERT_TRUE(array_ints_trailing_comma_2);
EXPECT_EQ(array_ints_trailing_comma_2.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_trailing_comma_2.GetValue<int>(), 3);
ASSERT_TRUE(array_ints_trailing_comma_3);
EXPECT_EQ(array_ints_trailing_comma_3.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_ints_trailing_comma_3.GetValue<int>(), 4);
EXPECT_FALSE(array_ints_trailing_comma_4);
}
{
auto array_mixed = sRoot.GetDirect("arr_mixed");
auto array_mixed_0 = sRoot.GetDirect("arr_mixed[0]");
auto array_mixed_1 = sRoot.GetDirect("arr_mixed[1]");
auto array_mixed_2 = sRoot.GetDirect("arr_mixed[2]");
auto array_mixed_3 = sRoot.GetDirect("arr_mixed[3]");
auto array_mixed_3_1 = sRoot.GetDirect("arr_mixed[3][0]");
auto array_mixed_3_2 = sRoot.GetDirect("arr_mixed[3][1]");
auto array_mixed_4 = sRoot.GetDirect("arr_mixed[4]");
auto array_mixed_4_pi = sRoot.GetDirect("arr_mixed[4].pi");
auto array_mixed_4_e = sRoot.GetDirect("arr_mixed[4].e");
auto array_mixed_5 = sRoot.GetDirect("arr_mixed[5]");
auto array_mixed_6 = sRoot.GetDirect("arr_mixed[6]");
EXPECT_EQ(array_mixed.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
ASSERT_TRUE(array_mixed_0);
EXPECT_EQ(array_mixed_0.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_0.GetValue<double>(), 1.0);
ASSERT_TRUE(array_mixed_1);
EXPECT_EQ(array_mixed_1.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_1.GetValue<int>(), 2);
ASSERT_TRUE(array_mixed_2);
EXPECT_EQ(array_mixed_2.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_2.GetValue(), "test string");
ASSERT_TRUE(array_mixed_3);
EXPECT_EQ(array_mixed_3.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
EXPECT_EQ(array_mixed_3_1.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_3_1.GetValue<int>(), 1);
EXPECT_EQ(array_mixed_3_2.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_3_2.GetValue<int>(), 2);
ASSERT_TRUE(array_mixed_4);
EXPECT_EQ(array_mixed_4.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
EXPECT_EQ(array_mixed_4_pi.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_4_pi.GetValue<double>(), 3.14);
EXPECT_EQ(array_mixed_4_e.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_4_e.GetValue<double>(), 2.71828);
ASSERT_TRUE(array_mixed_5);
EXPECT_EQ(array_mixed_5.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_mixed_5.GetValue<bool>(), true);
EXPECT_FALSE(array_mixed_6);
}
{
auto array_multiline = sRoot.GetDirect("arr_multiline");
auto array_multiline_0 = sRoot.GetDirect("arr_multiline[0]");
auto array_multiline_1 = sRoot.GetDirect("arr_multiline[1]");
auto array_multiline_2 = sRoot.GetDirect("arr_multiline[2]");
auto array_multiline_3 = sRoot.GetDirect("arr_multiline[3]");
EXPECT_EQ(array_multiline.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
ASSERT_TRUE(array_multiline_0);
EXPECT_EQ(array_multiline_0.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_multiline_0.GetValue(), "first line");
ASSERT_TRUE(array_multiline_1);
EXPECT_EQ(array_multiline_1.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_multiline_1.GetValue(), "second line");
ASSERT_TRUE(array_multiline_2);
EXPECT_EQ(array_multiline_2.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(array_multiline_2.GetValue(), "third_line");
EXPECT_FALSE(array_multiline_3);
}
}
TEST(NestedContent, Table)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[table]
a = 2
b = 1.2
[anotherTable]
a = 4
c = false
[thirdTable.fourthTable]
a = "five"
d = []
)toml");
auto sRoot = parser.Root();
auto table_a = sRoot.GetDirect("table.a");
auto table_b = sRoot.GetDirect("table.b");
auto anotherTable_a = sRoot.GetDirect("anotherTable.a");
auto anotherTable_c = sRoot.GetDirect("anotherTable.c");
auto fourthTable_a = sRoot.GetDirect("thirdTable.fourthTable.a");
auto fourthTable_d = sRoot.GetDirect("thirdTable.fourthTable.d");
ASSERT_TRUE(table_a);
EXPECT_EQ(table_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_a.GetValue<int>(), 2);
ASSERT_TRUE(table_b);
EXPECT_EQ(table_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_b.GetValue<double>(), 1.2);
ASSERT_TRUE(anotherTable_a);
EXPECT_EQ(anotherTable_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(anotherTable_a.GetValue<int>(), 4);
ASSERT_TRUE(anotherTable_c);
EXPECT_EQ(anotherTable_c.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(anotherTable_c.GetValue<bool>(), false);
ASSERT_TRUE(fourthTable_a);
EXPECT_EQ(fourthTable_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(fourthTable_a.GetValue(), "five");
ASSERT_TRUE(fourthTable_d);
EXPECT_EQ(fourthTable_d.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
}
TEST(NestedContent, TableArray)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[[table.test]]
a = 2
b = 1.2
[[table.test]]
a = 4
c = false
[[table.test]]
a = "five"
d = []
)toml");
auto sRoot = parser.Root();
auto table_test_1_a = sRoot.GetDirect("table.test[0].a");
auto table_test_1_b = sRoot.GetDirect("table.test[0].b");
auto table_test_2_a = sRoot.GetDirect("table.test[1].a");
auto table_test_2_c = sRoot.GetDirect("table.test[1].c");
auto table_test_3_a = sRoot.GetDirect("table.test[2].a");
auto table_test_3_d = sRoot.GetDirect("table.test[2].d");
ASSERT_TRUE(table_test_1_a);
EXPECT_EQ(table_test_1_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_test_1_a.GetValue<int>(), 2);
ASSERT_TRUE(table_test_1_b);
EXPECT_EQ(table_test_1_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_test_1_b.GetValue<double>(), 1.2);
ASSERT_TRUE(table_test_2_a);
EXPECT_EQ(table_test_2_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_test_2_a.GetValue<int>(), 4);
ASSERT_TRUE(table_test_2_c);
EXPECT_EQ(table_test_2_c.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_test_2_c.GetValue<bool>(), false);
ASSERT_TRUE(table_test_3_a);
EXPECT_EQ(table_test_3_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table_test_3_a.GetValue(), "five");
ASSERT_TRUE(table_test_3_d);
EXPECT_EQ(table_test_3_d.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
}
TEST(NestedContent, InlineTable)
{
sdv::toml::simple_parser::CParser parser(R"toml(
table1 = { a = 0, b = 1.2, c = "string" }
table2 = { a = [], b = true, e = 2.71828 }
table3 = { a = { a = "a", b = "A" }, b = {a = "b", b = "B"}, e = {a = "e", b = "E"} }
)toml");
auto sRoot = parser.Root();
auto table1_a = sRoot.GetDirect("table1.a");
auto table1_b = sRoot.GetDirect("table1.b");
auto table1_c = sRoot.GetDirect("table1.c");
auto table2_a = sRoot.GetDirect("table2.a");
auto table2_b = sRoot.GetDirect("table2.b");
auto table2_e = sRoot.GetDirect("table2.e");
auto table3_a_a = sRoot.GetDirect("table3.a.a");
auto table3_a_b = sRoot.GetDirect("table3.a.b");
auto table3_b_a = sRoot.GetDirect("table3.b.a");
auto table3_b_b = sRoot.GetDirect("table3.b.b");
auto table3_e_a = sRoot.GetDirect("table3.e.a");
auto table3_e_b = sRoot.GetDirect("table3.e.b");
ASSERT_TRUE(table1_a);
EXPECT_EQ(table1_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table1_a.GetValue<int>(), 0);
ASSERT_TRUE(table1_b);
EXPECT_EQ(table1_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table1_b.GetValue<double>(), 1.2);
ASSERT_TRUE(table1_c);
EXPECT_EQ(table1_c.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table1_c.GetValue(), "string");
ASSERT_TRUE(table2_a);
EXPECT_EQ(table2_a.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
ASSERT_TRUE(table2_b);
EXPECT_EQ(table2_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table2_b.GetValue<bool>(), true);
ASSERT_TRUE(table2_e);
EXPECT_EQ(table2_e.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table2_e.GetValue<double>(), 2.71828);
ASSERT_TRUE(table3_a_a);
EXPECT_EQ(table3_a_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_a_a.GetValue(), "a");
ASSERT_TRUE(table3_a_b);
EXPECT_EQ(table3_a_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_a_b.GetValue(), "A");
ASSERT_TRUE(table3_b_a);
EXPECT_EQ(table3_b_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_b_a.GetValue(), "b");
ASSERT_TRUE(table3_b_b);
EXPECT_EQ(table3_b_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_b_b.GetValue(), "B");
ASSERT_TRUE(table3_e_a);
EXPECT_EQ(table3_e_a.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_e_a.GetValue(), "e");
ASSERT_TRUE(table3_e_b);
EXPECT_EQ(table3_e_b.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(table3_e_b.GetValue(), "E");
}
TEST(NestedContent, InlineTableBreakLine)
{
// The following is not allowed in version 1.0, but is allowed in version 1.1
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
table = { a = 1, b = 2,
c = 3, d = 4 }
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
table = { a = 1, b = 2
,c = 3, d = 4 }
)toml"));
// Line breaks are allowed when part of an array or have multi-line strings
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
array = [{ a = 1, b = 2},
{c = 3, d = 4}]
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
table = { a = 1, b = [2, 3,
4, 5], c = 6, d = 7}
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
table = { x = "abc", y = """def-
ghi""", z = "jkl" }
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
table = { x = 'abc', y = '''def-
ghi''', z = 'jkl' }
)toml"));
}
TEST(SpecialCases, Keys)
{
std::string ssUTF8String = u8R"toml(
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value"
)toml";
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(std::string_view(ssUTF8String)));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value"
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
"" = "blank" # VALID but discouraged
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
'' = 'blank' # VALID but discouraged
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
# This makes the key "fruit" into a table.
fruit.apple.smooth = true
# So then you can add to the table "fruit" like so:
fruit.orange = 2
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
# VALID BUT DISCOURAGED
apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange"
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
3.1415 = 3.1415
)toml"));
{
sdv::toml::simple_parser::CParser parser(R"toml(
3.1415 = 3.1415
)toml");
auto sRoot = parser.Root();
auto table = sRoot.GetDirect("3");
auto pi = sRoot.GetDirect("3.1415");
ASSERT_TRUE(table);
EXPECT_EQ(table.GetType(), sdv::toml::simple_parser::ENodeType::node_table);
ASSERT_TRUE(pi);
EXPECT_EQ(pi.GetType(), sdv::toml::simple_parser::ENodeType::node_value);
EXPECT_EQ(pi.GetValue<double>(), 3.1415);
}
}
TEST(SpecialCases, Arrays)
{
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
string_array = [ "all", 'strings', """are the same""", '''type''' ]
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
]
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
integers3 = [
1,
2, # this is ok
]
)toml"));
}
TEST(SpecialCases, Tables)
{
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
[table-1]
key1 = "some string"
key2 = 123
[table-2]
key1 = "another string"
key2 = 456
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
[dog."tater.man"]
type.name = "pug"
)toml"));
std::string ssUTF8String = u8R"toml(
[a.b.c] # this is best practice
[ d.e.f ] # same as [d.e.f]
[ g . h . i ] # same as [g.h.i]
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
)toml";
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(std::string_view(ssUTF8String)));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
# [x] you
# [x.y] don't
# [x.y.z] need these
[x.y.z.w] # for this to work
[x] # defining a super-table afterward is ok
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
# VALID BUT DISCOURAGED
[fruit.apple]
[animal]
[fruit.orange]
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
[fruit]
apple.color = "red"
apple.taste.sweet = true
[fruit.apple.texture] # you can add sub-tables
)toml"));
}
TEST(SpecialCases, TableArrays)
{
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
[[products]]
name = "Hammer"
sku = 738594937
[[products]] # empty table within the array
[[products]]
name = "Nail"
sku = 284758393
color = "gray"
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
[[fruits]]
name = "apple"
[fruits.physical] # subtable
color = "red"
shape = "round"
[[fruits.varieties]] # nested array of tables
name = "red delicious"
[[fruits.varieties]]
name = "granny smith"
[[fruits]]
name = "banana"
[[fruits.varieties]]
name = "plantain"
)toml"));
EXPECT_NO_THROW(sdv::toml::simple_parser::CParser(R"toml(
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ]
)toml"));
}
TEST(ErrorCases, KeyValue)
{
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(key = # node_invalid)toml"), std::exception);
EXPECT_THROW(
sdv::toml::simple_parser::CParser(R"toml(first = "Tom" last = "Preston-Werner" # node_invalid)toml"), std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(= "no key name" # node_invalid)toml"), std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
name = "Tom"
name = "Pradyun"
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
fruit . flavor = "banana" # same as fruit.flavor
fruit.flavor = "banana"
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
spelling = "favorite"
"spelling" = "favourite"
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
# This defines the value of fruit.apple to be an integer.
fruit.apple = 1
# But then this treats fruit.apple like it's a table.
# You can't turn an integer into a table.
fruit.apple.smooth = true
)toml"),
std::exception);
}
TEST(ErrorCases, Tables)
{
std::string ssUTF8String(u8R"toml(
[ j . "ʞ" . 'l' ]
[j."ʞ".'l']
)toml");
EXPECT_THROW(sdv::toml::simple_parser::CParser(std::string_view(ssUTF8String)), std::exception);
ssUTF8String = u8R"toml(
[ j . "ʞ" . 'l' ]
["j".'ʞ'."l"]
)toml";
EXPECT_THROW(sdv::toml::simple_parser::CParser(std::string_view(ssUTF8String)), std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[fruit]
apple = "red"
[fruit]
orange = "orange"
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[fruit]
apple = "red"
[fruit.apple]
texture = "smooth"
)toml"),
std::exception);
// These two tests are not covered with current implementation.
//EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
// [fruit]
// apple.color = "red"
// apple.taste.sweet = true
// [fruit.apple] # INVALID
// )toml"),
// std::exception);
//EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
// [fruit]
// apple.color = "red"
// apple.taste.sweet = true
// [fruit.apple.taste] # INVALID
// )toml"),
// std::exception);
}
TEST(ErrorCases, InlineTables)
{
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
type = { name = "Nail" }
type.edible = false # INVALID
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[product]
type.name = "Nail"
type = { edible = false } # INVALID
)toml"),
std::exception);
}
TEST(ErrorCases, TableArrays)
{
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[fruit.physical] # subtable, but to which parent element should it belong?
color = "red"
shape = "round"
[[fruit]] # parser must throw an error upon discovering that "fruit" is
# an array rather than a table
name = "apple"
)toml"),
std::exception);
// The following test is not covered with the current implementation
//EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
// fruits = []
// [[fruits]] # Not allowed
// )toml"),
// std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[[fruits]]
name = "apple"
[[fruits.varieties]]
name = "red delicious"
# INVALID: This table conflicts with the previous array of tables
[fruits.varieties]
name = "granny smith"
)toml"),
std::exception);
EXPECT_THROW(sdv::toml::simple_parser::CParser(R"toml(
[[fruits]]
name = "apple"
[fruits.physical]
color = "red"
shape = "round"
# INVALID: This array of tables conflicts with the previous table
[[fruits.physical]]
color = "green"
)toml"),
std::exception);
}
TEST(Ordering, Array)
{
sdv::toml::simple_parser::CParser parser(R"toml(
array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
)toml");
auto sRoot = parser.Root();
auto two = sRoot.GetDirect("array[2]");
auto eleven = sRoot.GetDirect("array[11]");
const auto arr = sRoot.GetDirect("array");
// with direct access
ASSERT_TRUE(two);
EXPECT_EQ(two.GetValue<int>(), 2);
ASSERT_TRUE(eleven);
EXPECT_EQ(eleven.GetValue<int>(), 11);
// with indirect access through iterating
ASSERT_TRUE(arr);
EXPECT_EQ(arr.GetArray().size(), 12u);
size_t nIndex = 0;
for (const auto& rsNode : arr.GetArray())
EXPECT_EQ(rsNode.GetValue<size_t>(), nIndex++);
}
TEST(Ordering, TableAray)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[[tableArray]]
a = 0
[[tableArray]]
a = 1
[[tableArray]]
a = 2
[[tableArray]]
a = 3
[[tableArray]]
a = 4
[[tableArray]]
a = 5
[[tableArray]]
a = 6
[[tableArray]]
a = 7
[[tableArray]]
a = 8
[[tableArray]]
a = 9
[[tableArray]]
a = 10
[[tableArray]]
a = 11
)toml");
auto sRoot = parser.Root();
auto tableArray = sRoot.GetDirect("tableArray");
ASSERT_TRUE(tableArray);
EXPECT_EQ(tableArray.GetArray().size(), 12u);
size_t nIndex = 0;
for (const auto& rsNode : tableArray.GetArray())
EXPECT_EQ(rsNode.GetDirect("a").GetValue<size_t>(), nIndex++);
}
TEST(Ordering, TableArayWithTables)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[topTable]
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 0
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 1
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 2
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 3
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 4
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 5
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 6
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 7
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 8
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 9
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 10
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 11
)toml");
auto sRoot = parser.Root();
auto tableArray = sRoot.GetDirect("topTable.tableArray");
ASSERT_TRUE(tableArray);
EXPECT_EQ(tableArray.GetArray().size(), 12u);
size_t nIndex = 0;
for (const auto& rsNode : tableArray.GetArray())
EXPECT_EQ(rsNode.GetDirect("MyTable.a").GetValue<size_t>(), nIndex++);
}
TEST(Ordering, NodeGetDirect)
{
sdv::toml::simple_parser::CParser parser(R"toml(
[[table.test]]
a = 2
b = 1.2
[[table.test]]
a = 4
c = false
[[table.test]]
a = "five"
d = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 }]
)toml");
auto sRoot = parser.Root();
auto table_test_1_a = sRoot.GetDirect("table.test[0].a");
auto table_test_1_b = sRoot.GetDirect("table.test[0].b");
auto table_test_2_a = sRoot.GetDirect("table.test[1].a");
auto table_test_2_c = sRoot.GetDirect("table.test[1].c");
auto table_test_3_a = sRoot.GetDirect("table.test[2].a");
auto table_test_3_d = sRoot.GetDirect("table.test[2].d");
EXPECT_TRUE(table_test_1_a);
EXPECT_TRUE(table_test_1_b);
EXPECT_EQ(table_test_3_d.GetType(), sdv::toml::simple_parser::ENodeType::node_array);
auto table_test_3 = sRoot.GetDirect("table.test[2]");
auto table_test_3_2nd = table_test_3.GetDirect("d[2].x");
ASSERT_TRUE(table_test_3_2nd);
}

View File

@@ -96,15 +96,15 @@ bool CANSocketTest::vcanIsInstalled = false;
class CTestCANSocket : public CCANSockets
{
public:
virtual void Initialize(const sdv::u8string& ssObjectConfig) override
{
CCANSockets::Initialize(ssObjectConfig);
}
// virtual void OnInitialize(const sdv::ObjectInfo& sObjectInfo) override
// {
// CCANSockets::OnInitialize(sObjectInfo);
// }
virtual void Shutdown() override
{
CCANSockets::Shutdown();
}
// virtual void Shutdown() override
// {
// CCANSockets::Shutdown();
// }
virtual void Send(const sdv::can::SMessage& sMsg, uint32_t uiIfcIndex) override
{
@@ -199,7 +199,9 @@ bool InitializeAppControl(sdv::app::CAppControl* appcontrol, const std::string&
void InitializeCanComObject(CTestCANSocket& canComObj, const std::string config, MockCANReceiver& mockRcv)
{
ASSERT_NO_THROW(canComObj.Initialize(config.c_str()));
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = config;
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
ASSERT_NO_THROW(canComObj.SetOperationMode(sdv::EOperationMode::configuring));
ASSERT_NO_THROW(canComObj.RegisterReceiver(&mockRcv));
@@ -228,9 +230,10 @@ TEST_F(CANSocketTest, ValidConfigString)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(canSockets = "vcan0")"; // vcan0 interface must exist
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = "vcan0")"; // vcan0 interface must exist
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
ASSERT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
ASSERT_NO_THROW(canComObj.Send(testMsg, 0));
@@ -244,9 +247,10 @@ TEST_F(CANSocketTest, InvalidConfigString)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(canSockets = "vcan08")";
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = "vcan08")";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialization_failure);
ASSERT_NO_THROW(canComObj.Shutdown());
@@ -260,9 +264,10 @@ TEST_F(CANSocketTest, ValidConfigArray)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(canSockets = ["vcan0", "vcan1"])";
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = ["vcan0", "vcan1"])";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
ASSERT_NO_THROW(canComObj.Send(testMsg, 0));
@@ -276,9 +281,10 @@ TEST_F(CANSocketTest, InvalidConfigArray)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(canSockets = ["vcan08", "vcan09"])";
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = ["vcan08", "vcan09"])";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialization_failure);
ASSERT_NO_THROW(canComObj.Shutdown());
@@ -292,9 +298,10 @@ TEST_F(CANSocketTest, ValidConfigArrayButUnknownElement)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(canSockets = ["vcan0", "vcan08"])";
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = ["vcan0", "vcan08"])";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
ASSERT_NO_THROW(canComObj.Send(testMsg, 0));
@@ -308,9 +315,10 @@ TEST_F(CANSocketTest, InvalidConfigIdentifier)
sdv::app::CAppControl appControl;
appControl.Startup("");
sdv::u8string ssObjectConfig = R"(invalidCanSockets = ["vcan0", "vcan1"])"; // Invalid config identifier
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(invalidCanSockets = ["vcan0", "vcan1"])"; // Invalid config identifier
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssObjectConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialization_failure);
ASSERT_NO_THROW(canComObj.Shutdown());
@@ -478,11 +486,11 @@ TEST_F(CANSocketTest, StressTestWith3Objects)
std::atomic_bool stopSendThread = false;
std::cout << "Start thread sending messages..." << std::endl;
std::thread thSendThread1(SendThread, std::ref(stopSendThread), std::ref(canComObj1), std::ref(testData1));
sdv::core::secure_thread thSendThread1(SendThread, std::ref(stopSendThread), std::ref(canComObj1), std::ref(testData1));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::thread thSendThread2(SendThread, std::ref(stopSendThread), std::ref(canComObj2), std::ref(testData2));
sdv::core::secure_thread thSendThread2(SendThread, std::ref(stopSendThread), std::ref(canComObj2), std::ref(testData2));
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::thread thSendThread3(SendThread, std::ref(stopSendThread), std::ref(canComObj3), std::ref(testData3));
sdv::core::secure_thread thSendThread3(SendThread, std::ref(stopSendThread), std::ref(canComObj3), std::ref(testData3));
std::this_thread::sleep_for(std::chrono::seconds(10));
@@ -702,9 +710,10 @@ TEST_F(CANSocketTest, ManualSendAndReceiveTestOfMulitpleSockets)
uint32_t vcan2Index = 6;
uint32_t vcan3Index = 1;
uint32_t vcan4Index = 5;
sdv::u8string ssConfig = R"(canSockets = ["vcan0", "vcan3", "vcan8", "vcan1", "vcan9", "vcan4", "vcan2"])";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssConfig.c_str()));
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = ["vcan0", "vcan3", "vcan8", "vcan1", "vcan9", "vcan4", "vcan2"])";
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
// Register a receiver.
@@ -772,9 +781,10 @@ TEST_F(CANSocketTest, ManualSendAndReceiveTestWithDifferentDataSizes)
uint32_t vcan2Index = 6;
uint32_t vcan3Index = 1;
uint32_t vcan4Index = 5;
sdv::u8string ssConfig = R"(canSockets = ["vcan0", "vcan3", "vcan8", "vcan1", "vcan9", "vcan4", "vcan2"])";
sdv::SObjectInfo sObjectInfo{};
sObjectInfo.ssConfig = R"(canSockets = ["vcan0", "vcan3", "vcan8", "vcan1", "vcan9", "vcan4", "vcan2"])";
CTestCANSocket canComObj;
ASSERT_NO_THROW(canComObj.Initialize(ssConfig.c_str()));
ASSERT_NO_THROW(canComObj.Initialize(sObjectInfo));
EXPECT_EQ(canComObj.GetObjectState(), sdv::EObjectState::initialized);
// Register a receiver.

View File

@@ -12,6 +12,9 @@
# Erik Verhoeven - writing TOML and whitespace preservation
#*******************************************************************************
# Define project
project (UnitTest_TOMLParser VERSION 1.0 LANGUAGES CXX)
# Character Reader executable
add_executable(UnitTest_TOMLParser
"character_reader_tests.cpp"
@@ -19,13 +22,17 @@ add_executable(UnitTest_TOMLParser
"parser_tests.cpp"
"main.cpp"
"generate_toml_tests.cpp"
"generate_toml_delete_node.cpp"
"delete_node.cpp"
"statement_boundary_detection.cpp"
"miscellaneous_tests.cpp"
"miscellaneous.cpp"
"generate_toml_with_transfer.cpp"
"generate_toml_switch_inline.cpp"
"generate_toml_getset_comment.cpp"
"generate_toml_insert_node.cpp" "generate_toml_miscellaneous.cpp" "generate_toml_combine_reduce.cpp")
"getset_comment.cpp"
"insert_node.cpp"
"combine_reduce.cpp"
"comparison_tests.cpp"
"make_inline_standard.cpp"
"indexer_tests.cpp" "cascade_insert_node.cpp")
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_TOMLParser GTest::GTest ${CMAKE_THREAD_LIBS_INIT})
if (WIN32)

View File

@@ -0,0 +1,536 @@
/********************************************************************************
* 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/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include <support/toml.h>
TEST(CascadeInsertNode, InsertValueInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
// Insert the value into the new table
EXPECT_TRUE(root.InsertValue("", "standard_table.value_int", 10));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_int = 10)toml");
// Insert the values into the existing table
EXPECT_TRUE(root.InsertValue("", "standard_table.value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_int = 10
value_str = "abc")toml");
EXPECT_TRUE(root.InsertValue("standard_table.value_int", "standard_table.value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_float = 123.456
value_int = 10
value_str = "abc")toml");
}
TEST(CascadeInsertNode, InsertTableInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "standard_table", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert a standard table
EXPECT_TRUE(root.InsertTable("", "standard_table.table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table.table1])toml");
// Insert an inline table before
EXPECT_TRUE(root.InsertTable("standard_table.table1", "standard_table.table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
[standard_table.table1])toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(root.InsertTable("", "standard_table.table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
table3 = {}
[standard_table.table1])toml");
// Insert a standard table in front -> this will have to be printed behind the inline table relative to the elements of the
// standard_table.
EXPECT_TRUE(root.InsertTable("standard_table.table2", "standard_table.table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
table3 = {}
[standard_table.table4]
[standard_table.table1])toml");
}
TEST(CascadeInsertNode, InsertArrayInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "standard_table", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert arrays
EXPECT_TRUE(root.InsertArray("", "standard_table.value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array1 = [])toml");
EXPECT_TRUE(root.InsertArray("", "standard_table.value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array1 = []
value_array2 = [])toml");
EXPECT_TRUE(root.InsertArray("standard_table.value_array1", "standard_table.value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array3 = []
value_array1 = []
value_array2 = [])toml");
}
TEST(CascadeInsertNode, InsertTableArrayInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "standard_table", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert standard table array
EXPECT_TRUE(root.InsertTableArray("", "standard_table.table_array1",
false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[standard_table.table_array1]])toml");
// Insert an inline table array before
EXPECT_TRUE(root.InsertTableArray("standard_table.table_array1", "standard_table.table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
[[standard_table.table_array1]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(root.InsertTableArray("", "standard_table.table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array1]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array relative to the elements
// of the standard_table.
EXPECT_TRUE(root.InsertTableArray("standard_table.table_array2", "standard_table.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array4]]
[[standard_table.table_array1]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(root.InsertTableArray("", "standard_table.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array4]]
[[standard_table.table_array1]]
[[standard_table.table_array4]])toml");
}
TEST(CascadeInsertNode, InsertValueInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "inline_table", true));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert the values into the table
EXPECT_TRUE(root.InsertValue("", "inline_table.value_int", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_int = 10})toml");
EXPECT_TRUE(root.InsertValue("", "inline_table.value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_int = 10, value_str = "abc"})toml");
EXPECT_TRUE(root.InsertValue("inline_table.value_int", "inline_table.value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_float = 123.456, value_int = 10, value_str = "abc"})toml");
}
TEST(CascadeInsertNode, InsertTableInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "inline_table", true));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert a standard table
EXPECT_TRUE(root.InsertTable("", "inline_table.table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table1 = {}})toml");
// Insert an inline table before
EXPECT_TRUE(root.InsertTable("inline_table.table1", "inline_table.table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table2 = {}, table1 = {}})toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(root.InsertTable("", "inline_table.table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table2 = {}, table1 = {}, table3 = {}})toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_TRUE(root.InsertTable("inline_table.table2", "inline_table.table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table4 = {}, table2 = {}, table1 = {}, table3 = {}})toml");
}
TEST(CascadeInsertNode, InsertArrayInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "inline_table",
true));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert arrays
EXPECT_TRUE(root.InsertArray("", "inline_table.value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array1 = []})toml");
EXPECT_TRUE(root.InsertArray("", "inline_table.value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array1 = [], value_array2 = []})toml");
EXPECT_TRUE(root.InsertArray("inline_table.value_array1", "inline_table.value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array3 = [], value_array1 = [], value_array2 = []})toml");
}
TEST(CascadeInsertNode, InsertTableArrayInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "inline_table", true));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert standard table array
EXPECT_TRUE(root.InsertTableArray("", "inline_table.table_array1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array1 = [{}]})toml");
// Insert an inline table array before
EXPECT_TRUE(root.InsertTableArray("inline_table.table_array1", "inline_table.table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array2 = [{}], table_array1 = [{}]})toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(root.InsertTableArray("", "inline_table.table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(root.InsertTableArray("inline_table.table_array2", "inline_table.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML,
R"toml(inline_table = {table_array4 = [{}], table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(root.InsertTableArray("", "inline_table.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML,
R"toml(inline_table = {table_array4 = [{}, {}], table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
}
TEST(CascadeInsertNode, InsertValueInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertArray("", "inline_array"));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert the values into the table (with or without name)
EXPECT_TRUE(root.InsertValue("", "inline_array", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [10])toml");
EXPECT_TRUE(root.InsertValue("", "inline_array", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [10, "abc"])toml");
EXPECT_TRUE(root.InsertValue("inline_array[0]", "inline_array", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [123.456, 10, "abc"])toml");
}
TEST(CascadeInsertNode, InsertTableInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertArray("", "inline_array"));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert a standard table
EXPECT_TRUE(root.InsertTable("", "inline_array", false));
EXPECT_TRUE(root.InsertValue("", "inline_array[0].a", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{a = 10}])toml");
// Insert an inline table before
EXPECT_TRUE(root.InsertTable("inline_array[0]", "inline_array", true));
EXPECT_TRUE(root.InsertValue("", "inline_array[0].b", 20));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{b = 20}, {a = 10}])toml");
// Insert an inline table behind
EXPECT_TRUE(root.InsertTable("", "inline_array", true));
EXPECT_TRUE(root.InsertValue("", "inline_array.c", 30));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{b = 20}, {a = 10}, {c = 30}])toml");
// Insert a standard table in front
EXPECT_TRUE(root.InsertTable("inline_array[0]", "inline_array", false));
ssTOML = parser.GenerateTOML();
EXPECT_TRUE(root.InsertValue("", "inline_array[0].d", 40));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{d = 40}, {b = 20}, {a = 10}, {c = 30}])toml");
}
TEST(CascadeInsertNode, InsertArrayInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertArray("", "inline_array"));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert arrays
EXPECT_TRUE(root.InsertArray("", "inline_array"));
EXPECT_TRUE(root.InsertValue("", "inline_array[0]", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[10]])toml");
EXPECT_TRUE(root.InsertArray("", "inline_array"));
EXPECT_TRUE(root.InsertValue("", "inline_array[1]", 20));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[10], [20]])toml");
EXPECT_TRUE(root.InsertArray("inline_array[0]", "inline_array"));
EXPECT_TRUE(root.InsertValue("", "inline_array[0]", 30));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[30], [10], [20]])toml");
}
TEST(CascadeInsertNode, InsertTableArrayInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertArray("", "inline_array"));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert standard table array
EXPECT_TRUE(root.InsertTableArray("", "inline_array", false));
EXPECT_TRUE(root.InsertValue("", "inline_array[0].a", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{a = 10}]])toml");
// Insert an inline table array before
EXPECT_TRUE(root.InsertTableArray("inline_array[0]", "inline_array", true));
EXPECT_TRUE(root.InsertValue("", "inline_array[0].b", 20));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{b = 20}], [{a = 10}]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(root.InsertTableArray("", "inline_array", true));
EXPECT_TRUE(root.InsertValue("", "inline_array[999].c", 30));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{b = 20}], [{a = 10}], [{c = 30}]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(root.InsertTableArray("inline_array[0]", "inline_array", false));
EXPECT_TRUE(root.InsertValue("", "inline_array[0].d", 40));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{d = 40}], [{b = 20}], [{a = 10}], [{c = 30}]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(root.InsertValue("", "inline_array[0].e", 50));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{d = 40, e = 50}], [{b = 20}], [{a = 10}], [{c = 30}]])toml");
}
TEST(CascadeInsertNode, InsertValueInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTableArray("", "table_array", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert the values into the table
EXPECT_TRUE(root.InsertValue("", "table_array.value_int", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_int = 10)toml");
EXPECT_TRUE(root.InsertValue("", "table_array.value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_int = 10
value_str = "abc")toml");
EXPECT_TRUE(root.InsertValue("table_array[0]", "table_array.value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_float = 123.456
value_int = 10
value_str = "abc")toml");
}
TEST(CascadeInsertNode, InsertTableInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTableArray("", "table_array", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert a standard table
EXPECT_TRUE(root.InsertTable("", "table_array.table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
[table_array.table1])toml");
// Insert an inline table before
EXPECT_TRUE(root.InsertTable("table_array[0]", "table_array.table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
[table_array.table1])toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(root.InsertTable("", "table_array.table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
table3 = {}
[table_array.table1])toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_TRUE(root.InsertTable("table_array[0]", "table_array.table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
table3 = {}
[table_array.table4]
[table_array.table1])toml");
}
TEST(CascadeInsertNode, InsertArrayInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTableArray("", "table_array", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert arrays
EXPECT_TRUE(root.InsertArray("", "table_array.value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array1 = [])toml");
EXPECT_TRUE(root.InsertArray("", "table_array.value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array1 = []
value_array2 = [])toml");
EXPECT_TRUE(root.InsertArray("table_array[0]", "table_array.value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array3 = []
value_array1 = []
value_array2 = [])toml");
}
TEST(CascadeInsertNode, InsertTableArrayInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTableArray("", "table_array", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert standard table array
EXPECT_TRUE(root.InsertTableArray("", "table_array.table_array1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
[[table_array.table_array1]])toml");
// Insert an inline table array before
EXPECT_TRUE(root.InsertTableArray("table_array[0]", "table_array.table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
[[table_array.table_array1]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(root.InsertTableArray("", "table_array.table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array1]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(root.InsertTableArray("table_array[0]", "table_array.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array4]]
[[table_array.table_array1]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(root.InsertTableArray("", "table_array.table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array4]]
[[table_array.table_array1]]
[[table_array.table_array4]])toml");
}

View File

@@ -13,6 +13,7 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.h"
#include "../../../sdv_services/core/toml_parser/exception.h"

View File

@@ -12,11 +12,11 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
TEST(GenerateTOML, CombineRoot)
TEST(CombineReduse, CombineRoot)
{
toml_parser::CParser parser1(R"toml(
val1 = 10
@@ -27,10 +27,10 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
std::string ssCombinedTOML = R"toml(
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -38,7 +38,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineRootComments)
TEST(CombineReduse, CombineRootComments)
{
toml_parser::CParser parser1(R"toml(
val1 = 10 # This is value 1
@@ -49,10 +49,10 @@ val1 = 10 # This is again value 1)toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
std::string ssCombinedTOML = R"toml(
val1 = 10 # This is value 1
val2 = "20" # This is value 2
val3 = 30.0 # This is value 3)code";
val3 = 30.0 # This is value 3)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -60,7 +60,7 @@ val3 = 30.0 # This is value 3)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineRootwithTable)
TEST(CombineReduse, CombineRootwithTableValues)
{
toml_parser::CParser parser1(R"toml(
val1 = 10
@@ -73,10 +73,10 @@ val1 = 10)toml");
ASSERT_TRUE(ptrTable);
EXPECT_TRUE(parser1.Root().Combine(ptrTable->Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
std::string ssCombinedTOML = R"toml(
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -84,7 +84,55 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineTablewithRoot)
TEST(CombineReduse, CombineRootwithStandardTable)
{
toml_parser::CParser parser1(R"toml(
val1 = 10
val2 = "20")toml");
toml_parser::CParser parser2(R"toml([MyTable]
val3 = 30.0
val1 = 10)toml");
auto ptrTable = &parser2.Root();
ASSERT_TRUE(ptrTable);
EXPECT_TRUE(parser1.Root().Combine(ptrTable->Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"toml(
val1 = 10
val2 = "20"
[MyTable]
val3 = 30.0
val1 = 10)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(CombineReduse, CombineRootwithInlineTable)
{
toml_parser::CParser parser1(R"toml(
val1 = 10
val2 = "20")toml");
toml_parser::CParser parser2(R"toml(MyTable = {val3 = 30.0, val1 = 10})toml");
auto ptrTable = &parser2.Root();
ASSERT_TRUE(ptrTable);
EXPECT_TRUE(parser1.Root().Combine(ptrTable->Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"toml(
val1 = 10
val2 = "20"
MyTable = {val3 = 30.0, val1 = 10})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(CombineReduse, CombineTablewithRoot)
{
toml_parser::CParser parser1(R"toml([MyTable]
val1 = 10
@@ -99,10 +147,10 @@ val1 = 10)toml");
ASSERT_TRUE(ptrTable);
EXPECT_TRUE(ptrTable->Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([MyTable]
std::string ssCombinedTOML = R"toml([MyTable]
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -110,7 +158,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineTablewithDifferentTable)
TEST(CombineReduse, CombineTablewithDifferentTable)
{
toml_parser::CParser parser1(R"toml([MyTable1]
val1 = 10
@@ -129,10 +177,10 @@ val1 = 10)toml");
ASSERT_TRUE(ptrTable2);
EXPECT_TRUE(ptrTable1->Combine(ptrTable2));
std::string ssCombinedTOML = R"code([MyTable1]
std::string ssCombinedTOML = R"toml([MyTable1]
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -140,7 +188,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineTablewithIdenticalTable)
TEST(CombineReduse, CombineTablewithIdenticalTable)
{
toml_parser::CParser parser1(R"toml([MyTable]
val1 = 10
@@ -151,10 +199,10 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([MyTable]
std::string ssCombinedTOML = R"toml([MyTable]
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -162,7 +210,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineInlineTablewithDifferentStandardTable)
TEST(CombineReduse, CombineInlineTablewithDifferentStandardTable)
{
toml_parser::CParser parser1(R"toml(MyTable1 = {val1 = 10, val2 = "20"})toml");
toml_parser::CParser parser2(R"toml([MyTable2]
@@ -179,7 +227,7 @@ val1 = 10)toml");
ASSERT_TRUE(ptrTable2);
EXPECT_TRUE(ptrTable1->Combine(ptrTable2));
std::string ssCombinedTOML = R"code(MyTable1 = {val1 = 10, val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(MyTable1 = {val1 = 10, val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -187,7 +235,7 @@ val1 = 10)toml");
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineInlineTablewithIdenticalStandardTable)
TEST(CombineReduse, CombineInlineTablewithIdenticalStandardTable)
{
toml_parser::CParser parser1(R"toml(MyTable = {val1 = 10, val2 = "20"})toml");
toml_parser::CParser parser2(R"toml([MyTable]
@@ -196,7 +244,7 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(MyTable = {val1 = 10, val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(MyTable = {val1 = 10, val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -204,7 +252,7 @@ val1 = 10)toml");
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineStandardTablewithDifferentInlineTable)
TEST(CombineReduse, CombineStandardTablewithDifferentInlineTable)
{
toml_parser::CParser parser1(R"toml([MyTable1]
val1 = 10
@@ -221,10 +269,10 @@ val2 = "20")toml");
ASSERT_TRUE(ptrTable2);
EXPECT_TRUE(ptrTable1->Combine(ptrTable2));
std::string ssCombinedTOML = R"code([MyTable1]
std::string ssCombinedTOML = R"toml([MyTable1]
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -232,7 +280,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineStandardTablewithIdenticalInlineTable)
TEST(CombineReduse, CombineStandardTablewithIdenticalInlineTable)
{
toml_parser::CParser parser1(R"toml([MyTable]
val1 = 10
@@ -241,10 +289,10 @@ val2 = "20")toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([MyTable]
std::string ssCombinedTOML = R"toml([MyTable]
val1 = 10
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -252,7 +300,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineInlineTablewithDifferentInlineTable)
TEST(CombineReduse, CombineInlineTablewithDifferentInlineTable)
{
toml_parser::CParser parser1(R"toml(MyTable1 = {val1 = 10, val2 = "20"})toml");
toml_parser::CParser parser2(R"toml(MyTable2 = {val3 = 30.0, val1 = 10})toml");
@@ -267,7 +315,7 @@ TEST(GenerateTOML, CombineInlineTablewithDifferentInlineTable)
ASSERT_TRUE(ptrTable2);
EXPECT_TRUE(ptrTable1->Combine(ptrTable2));
std::string ssCombinedTOML = R"code(MyTable1 = {val1 = 10, val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(MyTable1 = {val1 = 10, val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -275,14 +323,14 @@ TEST(GenerateTOML, CombineInlineTablewithDifferentInlineTable)
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineInlineTablewithIdenticalInlineTable)
TEST(CombineReduse, CombineInlineTablewithIdenticalInlineTable)
{
toml_parser::CParser parser1(R"toml(MyTable = {val1 = 10, val2 = "20"})toml");
toml_parser::CParser parser2(R"toml(MyTable = {val3 = 30.0, val1 = 10})toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(MyTable = {val1 = 10, val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(MyTable = {val1 = 10, val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -290,7 +338,7 @@ TEST(GenerateTOML, CombineInlineTablewithIdenticalInlineTable)
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineDifferentArrays)
TEST(CombineReduse, CombineDifferentArrays)
{
toml_parser::CParser parser1(R"toml(
val1 = [10, 20]
@@ -301,10 +349,10 @@ val1 = [70, 80])toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
std::string ssCombinedTOML = R"toml(
val1 = [70, 80]
val2 = ["30", "40"]
val3 = [50.0, 60.0])code";
val3 = [50.0, 60.0])toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -312,12 +360,13 @@ val3 = [50.0, 60.0])code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, CombineDifferentTableArrays)
TEST(CombineReduse, CombineDifferentTableArrays)
{
toml_parser::CParser parser1(R"toml([[table_array1]]
val1 = [10, 20]
[[table_array1]]
val2 = ["30", "40"])toml");
toml_parser::CParser parser2(R"toml(
[[table_array2]]
val3 = [50.0, 60.0]
@@ -326,14 +375,14 @@ val1 = [70, 80])toml");
EXPECT_TRUE(parser1.Root().Combine(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([[table_array1]]
std::string ssCombinedTOML = R"toml([[table_array1]]
val1 = [10, 20]
[[table_array1]]
val2 = ["30", "40"]
[[table_array2]]
val3 = [50.0, 60.0]
[[table_array2]]
val1 = [70, 80])code";
val1 = [70, 80])toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -341,7 +390,7 @@ val1 = [70, 80])code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceRoot)
TEST(CombineReduse, ReduceRoot)
{
toml_parser::CParser parser1(R"toml(
val1 = 10
@@ -353,9 +402,8 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
val2 = "20"
val3 = 30.0)code";
std::string ssCombinedTOML = R"toml(val2 = "20"
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -363,7 +411,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceRootComments)
TEST(CombineReduse, ReduceRootComments)
{
toml_parser::CParser parser1(R"toml(
val1 = 10 # This is value 1
@@ -375,9 +423,8 @@ val1 = 10 # This also is value 1)toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(
val2 = "20" # This is value 2
val3 = 30.0 # This is value 3)code";
std::string ssCombinedTOML = R"toml(val2 = "20" # This is value 2
val3 = 30.0 # This is value 3)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -385,7 +432,7 @@ val3 = 30.0 # This is value 3)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceTable)
TEST(CombineReduse, ReduceTable)
{
toml_parser::CParser parser1(R"toml([my_table]
val1 = 10
@@ -397,9 +444,9 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([my_table]
std::string ssCombinedTOML = R"toml([my_table]
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -407,7 +454,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceStandardTableWithInlineTable)
TEST(CombineReduse, ReduceStandardTableWithInlineTable)
{
toml_parser::CParser parser1(R"toml([my_table]
val1 = 10
@@ -417,9 +464,9 @@ val3 = 30.0)toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code([my_table]
std::string ssCombinedTOML = R"toml([my_table]
val2 = "20"
val3 = 30.0)code";
val3 = 30.0)toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -427,7 +474,7 @@ val3 = 30.0)code";
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceInlineTableWithStandardTable)
TEST(CombineReduse, ReduceInlineTableWithStandardTable)
{
toml_parser::CParser parser1(R"toml(my_table = {val1 = 10, val2 = "20", val3 = 30.0})toml");
toml_parser::CParser parser2(R"toml([my_table]
@@ -436,7 +483,7 @@ val1 = 10)toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(my_table = { val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(my_table = { val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -444,14 +491,14 @@ val1 = 10)toml");
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceInlineTable)
TEST(CombineReduse, ReduceInlineTable)
{
toml_parser::CParser parser1(R"toml(my_table = {val1 = 10, val2 = "20", val3 = 30.0})toml");
toml_parser::CParser parser2(R"toml(my_table = {val3 = 35.0, val1 = 10})toml");
EXPECT_TRUE(parser1.Root().Reduce(parser2.Root().Cast<toml_parser::CNodeCollection>()));
std::string ssCombinedTOML = R"code(my_table = { val2 = "20", val3 = 30.0})code";
std::string ssCombinedTOML = R"toml(my_table = { val2 = "20", val3 = 30.0})toml";
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser1.GenerateTOML());
@@ -459,12 +506,12 @@ TEST(GenerateTOML, ReduceInlineTable)
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceDifferentArrays)
TEST(CombineReduse, ReduceDifferentArrays)
{
toml_parser::CParser parser1(R"code(
toml_parser::CParser parser1(R"toml(
val1 = [10, 20]
val2 = ["30", "40"]
val3 = [50.0, 60.0])code");
val3 = [50.0, 60.0])toml");
toml_parser::CParser parser2(R"toml(
val3 = [50.0, 60.0]
val1 = [70, 80])toml");
@@ -482,16 +529,16 @@ val2 = ["30", "40"]
EXPECT_EQ(ssGenerated, ssCombinedTOML);
}
TEST(GenerateTOML, ReduceDifferentTableArrays)
TEST(CombineReduse, ReduceDifferentTableArrays)
{
toml_parser::CParser parser1(R"code([[table_array1]]
toml_parser::CParser parser1(R"toml([[table_array1]]
val1 = [10, 20]
[[table_array1]]
val2 = ["30", "40"]
[[table_array2]]
val3 = [50.0, 60.0]
[[table_array2]]
val1 = [70, 80])code");
val1 = [70, 80])toml");
toml_parser::CParser parser2(R"toml(
[[table_array1]]
val2 = ["30", "40"]

View File

@@ -0,0 +1,386 @@
/********************************************************************************
* 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 implementation
********************************************************************************/
#include <functional>
#include <gtest/gtest.h>
#include <limits>
#include "../../../global/localmemmgr.h"
#include <support/toml.h>
#include "../../../sdv_services/core/toml_parser/exception.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
bool CompareTest(const std::string& rssToml1, const std::string& rssToml2,
uint32_t uiCompareFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all))
{
try
{
toml_parser::CParser parser1(rssToml1);
toml_parser::CParser parser2(rssToml2);
sdv::toml::CNodeCollection collection1(&parser1.Root());
sdv::toml::CNodeCollection collection2(&parser2.Root());
return sdv::toml::internal::CompareNodes(collection1, collection2, uiCompareFlags) ==
sdv::toml::ECompareResult::compare_identical;
}
catch (const toml_parser::XTOMLParseException&)
{
return false;
}
}
TEST(Comparison, CompareInvalid)
{
EXPECT_FALSE(CompareTest("var = A", ""));
EXPECT_FALSE(CompareTest("[[test]", ""));
EXPECT_FALSE(CompareTest(R"toml([test]
test1 = "this is invalid')toml", ""));
}
TEST(Comparison, CompareEmpty)
{
// Identical
uint32_t uiFlags = 0u;
EXPECT_FALSE(CompareTest("var = 1", "", uiFlags));
EXPECT_FALSE(CompareTest("", "var = 2", uiFlags));
EXPECT_TRUE(CompareTest("", "", uiFlags));
EXPECT_FALSE(CompareTest("", R"toml(
)toml", uiFlags));
EXPECT_FALSE(CompareTest("", R"toml(# This is a comment)toml", uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_FALSE(CompareTest("var = 1", "", uiFlags));
EXPECT_FALSE(CompareTest("", "var = 2", uiFlags));
EXPECT_TRUE(CompareTest("", "", uiFlags));
EXPECT_TRUE(CompareTest("", R"toml(
)toml", uiFlags));
EXPECT_FALSE(CompareTest("", R"toml(# This is a comment)toml", uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_FALSE(CompareTest("var = 1", "", uiFlags));
EXPECT_FALSE(CompareTest("", "var = 2", uiFlags));
EXPECT_TRUE(CompareTest("", "", uiFlags));
EXPECT_TRUE(CompareTest("", R"toml(
)toml", uiFlags));
EXPECT_TRUE(CompareTest("", R"toml(# This is a comment)toml", uiFlags));
}
TEST(Comparison, CompareValues)
{
std::string ssVal = "val = 1";
std::string ssVal2 = "val = 2";
std::string ssValSpace = " val = 1";
std::string ssValCommentsBefore = R"toml(# comment
# more comment
val = 1)toml";
std::string ssValCommentsBehind = R"toml( val = 1 # comment
# more comment
# lots more comment)toml";
// Identical
uint32_t uiFlags = 0u;
EXPECT_TRUE(CompareTest(ssVal, ssVal, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssVal2, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssValSpace, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssValCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssValCommentsBehind, uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_TRUE(CompareTest(ssVal, ssVal, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssVal2, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValSpace, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssValCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssValCommentsBehind, uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_TRUE(CompareTest(ssVal, ssVal, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssVal2, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValSpace, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValCommentsBehind, uiFlags));
// Ignore all
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all);
EXPECT_TRUE(CompareTest(ssVal, ssVal, uiFlags));
EXPECT_FALSE(CompareTest(ssVal, ssVal2, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValSpace, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssVal, ssValCommentsBehind, uiFlags));
}
TEST(Comparison, CompareTables)
{
std::string ssStandardTable = R"toml([table1]
val = 1)toml";
std::string ssStandardTable2 = R"toml([table2]
val = 1)toml";
std::string ssStandardTable1_3 = R"toml([table1]
val = 3)toml";
std::string ssInlineTable = R"toml(table1 = {val = 1})toml";
std::string ssTableSpace = R"toml( [table1]
val = 1)toml";
std::string ssTableCommentsBefore = R"toml(# comment
# more comment
[table1]
val = 1)toml";
std::string ssTableCommentsBehind = R"toml( [table1] # comment
val = 1 # comment
# more comment
# lots more comment)toml";
// Identical
uint32_t uiFlags = 0u;
EXPECT_TRUE(CompareTest(ssStandardTable, ssStandardTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssInlineTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableSpace, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBehind, uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_TRUE(CompareTest(ssStandardTable, ssStandardTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssInlineTable, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableSpace, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBehind, uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_TRUE(CompareTest(ssStandardTable, ssStandardTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssInlineTable, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableSpace, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableCommentsBehind, uiFlags));
// Ignore inline
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_inline);
EXPECT_TRUE(CompareTest(ssStandardTable, ssStandardTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable1_3, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssInlineTable, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableSpace, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssTableCommentsBehind, uiFlags));
// Ignore all
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all);
EXPECT_TRUE(CompareTest(ssStandardTable, ssStandardTable, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTable, ssStandardTable1_3, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssInlineTable, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableSpace, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTable, ssTableCommentsBehind, uiFlags));
}
TEST(Comparison, CompareArrays)
{
std::string ssStandardArray = R"toml(array1 = [123, 456])toml";
std::string ssStandardArray2 = R"toml(array2 = [789, 543])toml";
std::string ssArraySpace = R"toml( array1 = [
123,
456 ])toml";
std::string ssArrayCommentsBefore = R"toml(# comment
array1 =
# more comment
[ 123, # xyz
456])toml";
std::string ssArrayCommentsBehind = R"toml( array1 = [123, 456] # comment
# more comment
# lots more comment)toml";
// Identical
uint32_t uiFlags = 0u;
EXPECT_TRUE(CompareTest(ssStandardArray, ssStandardArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssStandardArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssArraySpace, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssArrayCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssArrayCommentsBehind, uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_TRUE(CompareTest(ssStandardArray, ssStandardArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssStandardArray2, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArraySpace, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssArrayCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssArrayCommentsBehind, uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_TRUE(CompareTest(ssStandardArray, ssStandardArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssStandardArray2, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArraySpace, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArrayCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArrayCommentsBehind, uiFlags));
// Ignore all
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all);
EXPECT_TRUE(CompareTest(ssStandardArray, ssStandardArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardArray, ssStandardArray2, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArraySpace, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArrayCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardArray, ssArrayCommentsBehind, uiFlags));
}
TEST(Comparison, CompareTableArrays)
{
std::string ssStandardTableArray = R"toml([[tableArray1]]
val = 1)toml";
std::string ssStandardTableArray2 = R"toml([[tableArray2]]
val = 1)toml";
std::string ssStandardTableArray1_3 = R"toml([[tableArray1]]
val = 3)toml";
std::string ssInlineTableArray = R"toml(tableArray1 = [{val = 1}])toml";
std::string ssTableSpaceArray = R"toml( [[tableArray1]]
val = 1)toml";
std::string ssTableArrayCommentsBefore = R"toml(# comment
# more comment
[[tableArray1]]
val = 1)toml";
std::string ssTableArrayCommentsBehind = R"toml( [[tableArray1]] # comment
val = 1 # comment
# more comment
# lots more comment)toml";
// Identical
uint32_t uiFlags = 0u;
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssStandardTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssInlineTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableSpaceArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBehind, uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssStandardTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssInlineTableArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableSpaceArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBehind, uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssStandardTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray1_3, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssInlineTableArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableSpaceArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBehind, uiFlags));
// Ignore inline
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_inline);
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssStandardTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray1_3, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssInlineTableArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableSpaceArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBefore, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBehind, uiFlags));
// Ignore all
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all);
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssStandardTableArray, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray2, uiFlags));
EXPECT_FALSE(CompareTest(ssStandardTableArray, ssStandardTableArray1_3, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssInlineTableArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableSpaceArray, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBefore, uiFlags));
EXPECT_TRUE(CompareTest(ssStandardTableArray, ssTableArrayCommentsBehind, uiFlags));
}
TEST(Comparison, CompareComplex)
{
std::string ssToml1 = R"toml(# This is a complex TOML file
# Top value description
[Top]
value1 = 1 # Value 1
valueA = "A" # Value A
arrayBCD = [ "B", # Array element B
"C", # Array element C
"D" ] # Array element D
# Table 1
[Top.table1]
value2 = 2 # Value 2
# Table array in table 1
[[Top.table1.table_array]] # Table array
valueE = "E"
[[Top.table1.table_array]] # Table array
valueF = "F"
[Top.table1.other_table]
inline_table = { x = "X", y = "Y", z = "Z" } # Inline table
[[Top.table1.table_array]] # Table array
valueG = "G"
)toml";
std::string ssToml2 = R"toml(
[Top]
value1 = 1
valueA = "A"
arrayBCD = ["B", "C", "D" ]
table1 = { value2 = 2, table_array = [{valueE = "E"}, {valueF = "F"}, {valueG = "G"}], other_table = { inline_table = {x = "X", y = "Y", z = "Z"}}} # Mega table
)toml";
// Identical
uint32_t uiFlags = 0u;
EXPECT_TRUE(CompareTest(ssToml1, ssToml1, uiFlags));
EXPECT_FALSE(CompareTest(ssToml1, ssToml2, uiFlags));
// Ignore whitespace
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_whitespace);
EXPECT_TRUE(CompareTest(ssToml1, ssToml1, uiFlags));
EXPECT_FALSE(CompareTest(ssToml1, ssToml2, uiFlags));
// Ignore comments
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_comments);
EXPECT_TRUE(CompareTest(ssToml1, ssToml1, uiFlags));
EXPECT_FALSE(CompareTest(ssToml1, ssToml2, uiFlags));
// Ignore inline
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_inline);
EXPECT_TRUE(CompareTest(ssToml1, ssToml1, uiFlags));
EXPECT_FALSE(CompareTest(ssToml1, ssToml2, uiFlags));
// Ignore all
uiFlags = static_cast<uint32_t>(sdv::toml::ECompareFlags::compare_ignore_all);
EXPECT_TRUE(CompareTest(ssToml1, ssToml1, uiFlags));
EXPECT_TRUE(CompareTest(ssToml1, ssToml2, uiFlags));
}

View File

@@ -12,7 +12,7 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
@@ -45,321 +45,315 @@
* @param[in] rssOuput Reference to the expected ouput.
* @return Returns 'true' on success.
*/
bool TestDelete(const std::string& rssTOMLInput, const std::string& rssKey, const std::string& rssOutput)
std::string DeleteNode(const std::string& rssTOMLInput, const std::string& rssKey)
{
toml_parser::CParser parser;
bool bRes = true;
EXPECT_NO_THROW(bRes = parser.Process(rssTOMLInput));
EXPECT_TRUE(bRes);
if (!bRes) return bRes;
if (!bRes) return {};
auto ptrNode = parser.Root().Direct(rssKey);
EXPECT_TRUE(ptrNode);
if (!ptrNode) return false;
if (!ptrNode) return {};
EXPECT_TRUE(bRes = ptrNode->DeleteNode());
if (!bRes) return bRes;
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, rssOutput);
if (ssTOML != rssOutput) return false;
return true;
if (!bRes) return {};
return parser.GenerateTOML();
};
TEST(TOMLDeleteNode, DeleteValues)
TEST(DeleteNode, DeleteValues)
{
// Delete a key from the begin (whitespace reduced)
EXPECT_TRUE(TestDelete(R"toml(key = 10 # value key
EXPECT_EQ(DeleteNode(R"toml(key = 10 # value key
bare_key = "value" # value bare_key
bare-key = false # value bare-key)toml",
"key",
"key"),
R"toml(bare_key = "value" # value bare_key
bare-key = false # value bare-key)toml"));
bare-key = false # value bare-key)toml");
// Delete a key from the begin
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10 # value key
bare_key = "value" # value bare_key
bare-key = false # value bare-key
)toml",
"key",
R"toml(
bare_key = "value" # value bare_key
"key"),
R"toml(bare_key = "value" # value bare_key
bare-key = false # value bare-key
)toml"));
)toml");
// Delete a key from the middle
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10 # value key
bare_key = "value" # value bare_key
bare-key = false # value bare-key
)toml",
"bare_key",
"bare_key"),
R"toml(
key = 10 # value key
bare-key = false # value bare-key
)toml"));
)toml");
// Delete a key from the end
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10 # value key
bare_key = "value" # value bare_key
bare-key = false # value bare-key
)toml",
"bare-key",
"bare-key"),
R"toml(
key = 10 # value key
bare_key = "value" # value bare_key
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineTableValues)
TEST(DeleteNode, DeleteInlineTableValues)
{
// Delete key from the inline table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"1234.y",
"1234.y"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"1234.x",
"1234.x"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = { y = 1, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"1234.str",
"1234.str"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2}
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineSubTableValues)
TEST(DeleteNode, DeleteInlineSubTableValues)
{
// Delete key from the inline sub-table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"1234.tbl.b",
"1234.tbl.b"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, c=3}}
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineTables)
TEST(DeleteNode, DeleteInlineTables)
{
// Delete table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"1234.tbl",
"1234.tbl"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"1234",
"1234"),
R"toml(
key = 10
bare_key = "value"
bare-key = false
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteTableValues)
TEST(DeleteNode, DeleteTableValues)
{
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
)toml",
"my_table.key",
"my_table.key"),
R"toml(
[my_table]
bare_key = "value"
bare-key = false
)toml"));
)toml");
// Delete a key from the middle
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
)toml",
"my_table.bare_key",
"my_table.bare_key"),
R"toml(
[my_table]
key = 10
bare-key = false
)toml"));
)toml");
// Delete a key from the end
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
)toml",
"my_table.bare-key",
"my_table.bare-key"),
R"toml(
[my_table]
key = 10
bare_key = "value"
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineTableValueInTable)
TEST(DeleteNode, DeleteInlineTableValueInTable)
{
// Delete key from the inline table in a table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"my_table.1234.y",
"my_table.1234.y"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"my_table.1234.x",
"my_table.1234.x"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = { y = 1, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml",
"my_table.1234.str",
"my_table.1234.str"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2}
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineSubTableValueInTable)
TEST(DeleteNode, DeleteInlineSubTableValueInTable)
{
// Delete key from the inline sub-table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"my_table.1234.tbl.b",
"my_table.1234.tbl.b"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, c=3}}
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteInlineTableInTable)
TEST(DeleteNode, DeleteInlineTableInTable)
{
// Delete table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"my_table.1234.tbl",
"my_table.1234.tbl"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc"}
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
1234 = {x = 0, y = 1, z = 2, str = "abc", tbl={a =1, b=2, c=3}}
)toml",
"my_table.1234",
"my_table.1234"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteValuesInChildTable)
TEST(DeleteNode, DeleteValuesInChildTable)
{
// Delete key from the child-table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
@@ -370,7 +364,7 @@ y = 1
z = 2
str = "abc"
)toml",
"my_table.1234.y",
"my_table.1234.y"),
R"toml(
[my_table]
key = 10
@@ -380,8 +374,8 @@ bare-key = false
x = 0
z = 2
str = "abc"
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
@@ -392,7 +386,7 @@ y = 1
z = 2
str = "abc"
)toml",
"my_table.1234.x",
"my_table.1234.x"),
R"toml(
[my_table]
key = 10
@@ -402,8 +396,8 @@ bare-key = false
y = 1
z = 2
str = "abc"
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
@@ -414,7 +408,7 @@ y = 1
z = 2
str = "abc"
)toml",
"my_table.1234.str",
"my_table.1234.str"),
R"toml(
[my_table]
key = 10
@@ -424,14 +418,14 @@ bare-key = false
x = 0
y = 1
z = 2
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteChildTableInTable)
TEST(DeleteNode, DeleteChildTableInTable)
{
// Delete table
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
@@ -446,7 +440,7 @@ a =1
b=2
c=3
)toml",
"my_table.1234.tbl",
"my_table.1234.tbl"),
R"toml(
[my_table]
key = 10
@@ -457,8 +451,8 @@ x = 0
y = 1
z = 2
str = "abc"
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
[my_table]
key = 10
bare_key = "value"
@@ -473,176 +467,176 @@ a =1
b=2
c=3
)toml",
"my_table.1234",
"my_table.1234"),
R"toml(
[my_table]
key = 10
bare_key = "value"
bare-key = false
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteArrayValues)
TEST(DeleteNode, DeleteArrayValues)
{
// Delete array values
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"key[0]",
"key[0]"),
R"toml(
key = [ 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"key[1]",
"key[1]"),
R"toml(
key = [10, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"key[2]",
"key[2]"),
R"toml(
key = [10, 20]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteArrayValuesWithSucceedingComma)
TEST(DeleteNode, DeleteArrayValuesWithSucceedingComma)
{
// Delete array values with succeeding comma
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare_key[0]",
"bare_key[0]"),
R"toml(
key = [10, 20, 30]
bare_key = [ "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare_key[1]",
"bare_key[1]"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare_key[2]",
"bare_key[2]"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml"));
)toml");
}
TEST(TOMLDeleteNode, DeleteValuesWithComments)
TEST(DeleteNode, DeleteValuesWithComments)
{
// Delete array values with comments
EXPECT_TRUE(TestDelete(R"toml(
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare-key[0]",
"bare-key[0]"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [ 2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare-key[0].a",
"bare-key[0].a"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{ b = true}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare-key[0].b",
"bare-key[0].b"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false}, # value 0
2020, # value 1
]
)toml"));
EXPECT_TRUE(TestDelete(R"toml(
)toml");
EXPECT_EQ(DeleteNode(R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
2020, # value 1
]
)toml",
"bare-key[1]",
"bare-key[1]"),
R"toml(
key = [10, 20, 30]
bare_key = ["value1", "value2", 3030, ]
bare-key = [{a = false, b = true}, # value 0
]
)toml"));
)toml");
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +0,0 @@
/********************************************************************************
* 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/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
// Test TODO:
// Switch to inline and vice versa
TEST(GenerateTOML, SwitchTableToInline)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([table]
key1 = "some string"
key2 = 123)code";
std::string ssTOMLOutput = R"code(table = {key1 = "some string", key2 = 123})code";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
std::string ssGenerated;
EXPECT_NO_THROW(ssGenerated = parser.GenerateTOML());
EXPECT_EQ(ssGenerated, ssTOMLInput);
sdv::TInterfaceAccessPtr ptrTable = parser.Root().GetNodeDirect("table");
EXPECT_TRUE(ptrTable);
sdv::toml::INodeInfo* pInfo = ptrTable.GetInterface<sdv::toml::INodeInfo>();
sdv::toml::INodeCollectionConvert* pConvert = ptrTable.GetInterface<sdv::toml::INodeCollectionConvert>();
ASSERT_NE(pInfo, nullptr);
ASSERT_NE(pConvert, nullptr);
EXPECT_FALSE(pInfo->IsInline());
EXPECT_TRUE(pConvert->CanMakeInline());
EXPECT_TRUE(pConvert->MakeInline());
EXPECT_TRUE(pInfo->IsInline());
EXPECT_NO_THROW(ssGenerated = parser.GenerateTOML());
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}

View File

@@ -12,6 +12,7 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
@@ -19,7 +20,7 @@ TEST(GenerateTOML, Comment)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# This is a full-line comment)code";
std::string ssTOML = R"toml(# This is a full-line comment)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -33,9 +34,9 @@ TEST(GenerateTOML, NodeComment)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# This is a full-line comment
std::string ssTOML = R"toml(# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment")code";
another = "# This is not a comment")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -49,10 +50,10 @@ TEST(GenerateTOML, NodeCommentWithSpaces)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# This is a full-line comment
key = "value" # This is a comment at the end of a line
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -66,13 +67,13 @@ TEST(GenerateTOML, UnattachedComment)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# Comment not belonging to node
std::string ssTOML = R"toml(# Comment not belonging to node
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"
# Comment not belonging to node)code";
# Comment not belonging to node)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -86,10 +87,10 @@ TEST(GenerateTOML, ArrayWhitespace)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
array = [ 1, 2, 3,
4, 5, 6 ]
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -103,7 +104,7 @@ TEST(GenerateTOML, ArrayComment)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# Pre-array
array = [ 1, # Value #1
2, # Value #2
@@ -112,7 +113,7 @@ array = [ 1, # Value #1
5, # Value #5
6, # Value #6
] # Post-array
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -126,7 +127,7 @@ TEST(GenerateTOML, ArrayCommentWithSpace)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# unattached comment
@@ -159,7 +160,7 @@ array = [ 1, # Value #1
# unattached comment
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -174,9 +175,9 @@ TEST(GenerateTOML, InlineTableWhitespace)
toml_parser::CParser parser;
// Note: line-breaks within an inline table are not allowed.
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 }
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -191,10 +192,10 @@ TEST(GenerateTOML, InlineTableComment)
toml_parser::CParser parser;
// Note: line-breaks within an inline table are not allowed.
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# Pre-table
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 } # Post-table
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -208,10 +209,10 @@ TEST(GenerateTOML, Keys)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(key = "value"
std::string ssTOML = R"toml(key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value")code";
1234 = "value")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -225,11 +226,11 @@ TEST(GenerateTOML, QuotedKeys)
{
toml_parser::CParser parser;
std::string ssTOML = u8R"code("127.0.0.1" = "value"
std::string ssTOML = u8R"toml("127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value")code";
'quoted "value"' = "value")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -241,8 +242,8 @@ TEST(GenerateTOML, QuotedKeys)
TEST(GenerateTOML, BlankKeys)
{
std::string ssTOML1 = R"code("" = "blank" # VALID but discouraged)code";
std::string ssTOML2 = R"code('' = 'blank' # VALID but discouraged)code";
std::string ssTOML1 = R"toml("" = "blank" # VALID but discouraged)toml";
std::string ssTOML2 = R"toml('' = 'blank' # VALID but discouraged)toml";
toml_parser::CParser parser1, parser2;
EXPECT_NO_THROW(parser1.Process(ssTOML1));
@@ -259,10 +260,10 @@ TEST(GenerateTOML, DottedKeys)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(name = "Orange"
std::string ssTOML = R"toml(name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true)code";
site."google.com" = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -276,9 +277,9 @@ TEST(GenerateTOML, WhitespaceKeys)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(fruit.name = "banana" # this is best practice
std::string ssTOML = R"toml(fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor)code";
fruit . flavor = "banana" # same as fruit.flavor)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -292,14 +293,14 @@ TEST(GenerateTOML, OutOfOrderKeys)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(apple.type = "fruit"
std::string ssTOML = R"toml(apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange")code";
orange.color = "orange")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -313,7 +314,7 @@ TEST(GenerateTOML, FloatLookingAlikeKeys)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(3.14159 = "pi")code";
std::string ssTOML = R"toml(3.14159 = "pi")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -327,7 +328,7 @@ TEST(GenerateTOML, BasicStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")code";
std::string ssTOML = R"toml(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -341,9 +342,9 @@ TEST(GenerateTOML, MultiLineStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(str1 = """
std::string ssTOML = R"toml(str1 = """
Roses are red
Violets are blue""")code";
Violets are blue""")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -357,7 +358,7 @@ TEST(GenerateTOML, LongMultiLineStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(str1 = "The quick brown fox jumps over the lazy dog."
std::string ssTOML = R"toml(str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
The quick brown \
@@ -370,7 +371,7 @@ str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
""")code";
""")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -384,13 +385,13 @@ TEST(GenerateTOML, QuotingStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(str4 = """Here are two quotation marks: "". Simple enough."""
std::string ssTOML = R"toml(str4 = """Here are two quotation marks: "". Simple enough."""
# str5 = """Here are three quotation marks: """.""" # INVALID
str5 = """Here are three quotation marks: ""\"."""
str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement."""")code";
str7 = """"This," she said, "is just a pointless statement."""")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -404,10 +405,10 @@ TEST(GenerateTOML, LiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(winpath = 'C:\Users\nodejs\templates'
std::string ssTOML = R"toml(winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>')code";
regex = '<\i\c*\s*>')toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -421,13 +422,13 @@ TEST(GenerateTOML, MultiLineLiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(regex2 = '''I [dw]on't need \d{2} apples'''
std::string ssTOML = R"toml(regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
''')code";
''')toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -441,13 +442,13 @@ TEST(GenerateTOML, QuotedLiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
std::string ssTOML = R"toml(quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"
# 'That,' she said, 'is still pointless.'
str = ''''That,' she said, 'is still pointless.'''')code";
str = ''''That,' she said, 'is still pointless.'''')toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -461,10 +462,10 @@ TEST(GenerateTOML, Integers)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(int1 = +99
std::string ssTOML = R"toml(int1 = +99
int2 = 42
int3 = 0
int4 = -17)code";
int4 = -17)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -478,10 +479,10 @@ TEST(GenerateTOML, ReadibleIntegers)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(int5 = 1_000
std::string ssTOML = R"toml(int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221 # Indian number system grouping
int8 = 1_2_3_4_5 # VALID but discouraged)code";
int8 = 1_2_3_4_5 # VALID but discouraged)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -495,7 +496,7 @@ TEST(GenerateTOML, OtherBaseIntegers)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# hexadecimal with prefix `0x`
std::string ssTOML = R"toml(# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
@@ -505,7 +506,7 @@ oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110)code";
bin1 = 0b11010110)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -519,7 +520,7 @@ TEST(GenerateTOML, FloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# fractional
std::string ssTOML = R"toml(# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
@@ -530,7 +531,7 @@ flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34)code";
flt7 = 6.626e-34)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -544,7 +545,7 @@ TEST(GenerateTOML, ReadibleFloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(flt8 = 224_617.445_991_228)code";
std::string ssTOML = R"toml(flt8 = 224_617.445_991_228)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -558,7 +559,7 @@ TEST(GenerateTOML, SpecialFloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# infinity
std::string ssTOML = R"toml(# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
@@ -566,7 +567,7 @@ sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific)code";
sf6 = -nan # valid, actual encoding is implementation-specific)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -580,8 +581,8 @@ TEST(GenerateTOML, Booleans)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(bool1 = true
bool2 = false)code";
std::string ssTOML = R"toml(bool1 = true
bool2 = false)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -595,9 +596,9 @@ TEST(GenerateTOML, DISABLED_OffsetDateTimes)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(odt1 = 1979-05-27T07:32:00Z
std::string ssTOML = R"toml(odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00)code";
odt3 = 1979-05-27T00:32:00.999999-07:00)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -611,7 +612,7 @@ TEST(GenerateTOML, DISABLED_ReadibleOffsetDateTimes)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(odt4 = 1979-05-27 07:32:00Z)code";
std::string ssTOML = R"toml(odt4 = 1979-05-27 07:32:00Z)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -625,8 +626,8 @@ TEST(GenerateTOML, DISABLED_LocalDateTimes)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999)code";
std::string ssTOML = R"toml(ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -640,7 +641,7 @@ TEST(GenerateTOML, DISABLED_LocalDates)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(ld1 = 1979-05-27)code";
std::string ssTOML = R"toml(ld1 = 1979-05-27)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -654,8 +655,8 @@ TEST(GenerateTOML, DISABLED_LocalTimes)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(lt1 = 07:32:00
lt2 = 00:32:00.999999)code";
std::string ssTOML = R"toml(lt1 = 07:32:00
lt2 = 00:32:00.999999)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -669,7 +670,7 @@ TEST(GenerateTOML, Arrays)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(integers = [ 1, 2, 3 ]
std::string ssTOML = R"toml(integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
@@ -681,7 +682,7 @@ contributors =
[
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
])code";
])toml";
parser.Process(ssTOML);
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -696,14 +697,14 @@ TEST(GenerateTOML, MultiLineArrays)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(integers2 = [
std::string ssTOML = R"toml(integers2 = [
1, 2, 3
]
integers3 = [
1,
2, # this is ok
])code";
])toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -717,7 +718,7 @@ TEST(GenerateTOML, Tables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code([table]
std::string ssTOML = R"toml([table]
[table-1]
key1 = "some string"
@@ -725,7 +726,7 @@ key2 = 123
[table-2]
key1 = "another string"
key2 = 456)code";
key2 = 456)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -739,8 +740,8 @@ TEST(GenerateTOML, QuotedKeyTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code([dog."tater.man"]
type.name = "pug")code";
std::string ssTOML = R"toml([dog."tater.man"]
type.name = "pug")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -754,14 +755,14 @@ TEST(GenerateTOML, WhitespaceKeyTables)
{
toml_parser::CParser parser;
std::string ssTOML = u8R"code([a.b.c] # this is best practice
std::string ssTOML = u8R"toml([a.b.c] # this is best practice
x = 1
[ d.e.f ] # same as [d.e.f]
y = 1
[ g . h . i ] # same as [g.h.i]
z = 1
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
a = 1)code";
a = 1)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -775,13 +776,13 @@ TEST(GenerateTOML, MixedOrderTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# VALID BUT DISCOURAGED
std::string ssTOML = R"toml(# VALID BUT DISCOURAGED
[fruit.apple]
a = 1
[animal]
b = 2
[fruit.orange]
aa = 11)code";
aa = 11)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -795,14 +796,14 @@ TEST(GenerateTOML, MixedValueAndTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# Top-level table begins.
std::string ssTOML = R"toml(# Top-level table begins.
name = "Fido"
breed = "pug"
# Top-level table ends.
[owner]
name = "Regina Dogman"
member_since = 1999)code";
member_since = 1999)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -816,10 +817,10 @@ TEST(GenerateTOML, AutomaticTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(fruit.apple.color = "red"
fruit.apple.taste.sweet = true)code";
std::string ssTOMLOutput2 = R"code(apple.color = "red"
apple.taste.sweet = true)code";
std::string ssTOML = R"toml(fruit.apple.color = "red"
fruit.apple.taste.sweet = true)toml";
std::string ssTOMLOutput2 = R"toml(apple.color = "red"
apple.taste.sweet = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -835,7 +836,7 @@ TEST(GenerateTOML, MixedAutomaticTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code([fruit]
std::string ssTOML = R"toml([fruit]
apple.color = "red"
apple.taste.sweet = true
@@ -843,7 +844,7 @@ apple.taste.sweet = true
# [fruit.apple.taste] # INVALID
[fruit.apple.texture] # you can add sub-tables
smooth = true)code";
smooth = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -857,9 +858,9 @@ TEST(GenerateTOML, InlineTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(name = { first = "Tom", last = "Preston-Werner" }
std::string ssTOML = R"toml(name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" })code";
animal = { type.name = "pug" })toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -873,9 +874,9 @@ TEST(GenerateTOML, EmbeddedInlineTables)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(test=[{ first = "Tom", last = "Preston-Werner" },
std::string ssTOML = R"toml(test=[{ first = "Tom", last = "Preston-Werner" },
{ x = 1, y = 2 },
{ type.name = "pug" }])code";
{ type.name = "pug" }])toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -889,7 +890,7 @@ TEST(GenerateTOML, TableArrays)
{
toml_parser::CParser parser;
std::string ssTOML = R"code([[products]]
std::string ssTOML = R"toml([[products]]
name = "Hammer"
sku = 738594937
@@ -899,7 +900,7 @@ sku = 738594937
name = "Nail"
sku = 284758393
color = "gray")code";
color = "gray")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -913,7 +914,7 @@ TEST(GenerateTOML, MixedTableAndTableArrays)
{
toml_parser::CParser parser;
std::string ssTOML = R"code([[fruits]]
std::string ssTOML = R"toml([[fruits]]
name = "apple"
[fruits.physical] # subtable
@@ -931,29 +932,29 @@ name = "granny smith"
name = "banana"
[[fruits.varieties]]
name = "plantain")code";
std::string ssTOMLFruits1Physical = R"code([physical] # subtable
name = "plantain")toml";
std::string ssTOMLFruits1Physical = R"toml([physical] # subtable
color = "red"
shape = "round"
)code";
std::string ssTOMLFruits1Varieties = R"code([[varieties]] # nested array of tables
)toml";
std::string ssTOMLFruits1Varieties = R"toml([[varieties]] # nested array of tables
name = "red delicious"
[[varieties]]
name = "granny smith"
)code";
std::string ssTOMLFruits1Variety1 = R"code([variety] # nested array of tables
)toml";
std::string ssTOMLFruits1Variety1 = R"toml([variety] # nested array of tables
name = "red delicious"
)code";
std::string ssTOMLFruits1Variety2 = R"code([variety]
)toml";
std::string ssTOMLFruits1Variety2 = R"toml([variety]
name = "granny smith"
)code";
std::string ssTOMLFruits2Variety1 = R"code([variety]
name = "plantain")code";
)toml";
std::string ssTOMLFruits2Variety1 = R"toml([variety]
name = "plantain")toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -998,9 +999,9 @@ TEST(GenerateTOML, InlineTableArrays)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(points = [ { x = 1, y = 2, z = 3 },
std::string ssTOML = R"toml(points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ])code";
{ x = 2, y = 4, z = 8 } ])toml";
EXPECT_NO_THROW(parser.Process(ssTOML));

View File

@@ -12,6 +12,7 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
@@ -19,13 +20,13 @@ TEST(GenerateTOML, TransferNodeComment)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# This is a full-line comment
std::string ssTOMLInput = R"toml(# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment")code";
std::string ssTOMLOutput = R"code([tree.branch]
another = "# This is not a comment")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment")code";
another = "# This is not a comment")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -39,15 +40,15 @@ TEST(GenerateTOML, TransferNodeCommentWithSpaces)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
# This is a full-line comment
key = "value" # This is a comment at the end of a line
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# This is a full-line comment
key = "value" # This is a comment at the end of a line
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -61,21 +62,21 @@ TEST(GenerateTOML, TransferUnattachedComment)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# Comment not belonging to node
std::string ssTOMLInput = R"toml(# Comment not belonging to node
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"
# Comment not belonging to node)code";
std::string ssTOMLOutput = R"code([tree.branch]
# Comment not belonging to node)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# Comment not belonging to node
# This is a full-line comment
key = "value" # This is a comment at the end of a line
another = "# This is not a comment"
# Comment not belonging to node)code";
# Comment not belonging to node)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -89,15 +90,15 @@ TEST(GenerateTOML, TransferArrayWhitespace)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
array = [ 1, 2, 3,
4, 5, 6 ]
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
array = [ 1, 2, 3,
4, 5, 6 ]
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -111,7 +112,7 @@ TEST(GenerateTOML, TransferArrayComment)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
# Pre-array
array = [ 1, # Value #1
2, # Value #2
@@ -120,8 +121,8 @@ array = [ 1, # Value #1
5, # Value #5
6, # Value #6
] # Post-array
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# Pre-array
array = [ 1, # Value #1
@@ -131,7 +132,7 @@ array = [ 1, # Value #1
5, # Value #5
6, # Value #6
] # Post-array
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -145,7 +146,7 @@ TEST(GenerateTOML, TransferArrayCommentWithSpace)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
# unattached comment
@@ -178,8 +179,8 @@ array = [ 1, # Value #1
# unattached comment
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# unattached comment
@@ -213,7 +214,7 @@ array = [ 1, # Value #1
# unattached comment
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -228,13 +229,13 @@ TEST(GenerateTOML, TransferInlineTableWhitespace)
toml_parser::CParser parser;
// NOTE: Line-breaks within inline tables are not allowed.
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 }
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 }
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -249,15 +250,15 @@ TEST(GenerateTOML, TransferInlineTableComment)
toml_parser::CParser parser;
// NOTE: Line-breaks within inline tables are not allowed.
std::string ssTOMLInput = R"code(
std::string ssTOMLInput = R"toml(
# Pre-table
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 } # Post-table
)code";
std::string ssTOMLOutput = R"code([tree.branch]
)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# Pre-table
table = { a = 1, b = 2, d = 3, e = 4, f = 5, g = 6 } # Post-table
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -271,15 +272,15 @@ TEST(GenerateTOML, TransferKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(key = "value"
std::string ssTOMLInput = R"toml(key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value")code";
std::string ssTOMLOutput = R"code([tree.branch]
1234 = "value")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
key = "value"
bare_key = "value"
bare-key = "value"
1234 = "value")code";
1234 = "value")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -293,17 +294,17 @@ TEST(GenerateTOML, TransferQuotedKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = u8R"code("127.0.0.1" = "value"
std::string ssTOMLInput = u8R"toml("127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value")code";
std::string ssTOMLOutput = u8R"code([tree.branch]
'quoted "value"' = "value")toml";
std::string ssTOMLOutput = u8R"toml([tree.branch]
"127.0.0.1" = "value"
"character encoding" = "value"
"ʎǝʞ" = "value"
'key2' = "value"
'quoted "value"' = "value")code";
'quoted "value"' = "value")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -315,12 +316,12 @@ TEST(GenerateTOML, TransferQuotedKeys)
TEST(GenerateTOML, TransferBlankKeys)
{
std::string ssTOMLInput1 = R"code("" = "blank" # VALID but discouraged)code";
std::string ssTOMLInput2 = R"code('' = 'blank' # VALID but discouraged)code";
std::string ssTOMLOutput1 = R"code([tree.branch]
"" = "blank" # VALID but discouraged)code";
std::string ssTOMLOutput2 = R"code([tree.branch]
'' = 'blank' # VALID but discouraged)code";
std::string ssTOMLInput1 = R"toml("" = "blank" # VALID but discouraged)toml";
std::string ssTOMLInput2 = R"toml('' = 'blank' # VALID but discouraged)toml";
std::string ssTOMLOutput1 = R"toml([tree.branch]
"" = "blank" # VALID but discouraged)toml";
std::string ssTOMLOutput2 = R"toml([tree.branch]
'' = 'blank' # VALID but discouraged)toml";
toml_parser::CParser parser1, parser2;
EXPECT_NO_THROW(parser1.Process(ssTOMLInput1));
@@ -338,15 +339,15 @@ TEST(GenerateTOML, TransferDottedKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(name = "Orange"
std::string ssTOMLInput = R"toml(name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true)code";
std::string ssTOMLOutput = R"code([tree.branch]
site."google.com" = true)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
name = "Orange"
physical.color = "orange"
physical.shape = "round"
site."google.com" = true)code";
site."google.com" = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -360,13 +361,13 @@ TEST(GenerateTOML, TransferWhitespaceKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(fruit.name = "banana" # this is best practice
std::string ssTOMLInput = R"toml(fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor)code";
std::string ssTOMLOutput = R"code([tree.branch]
fruit . flavor = "banana" # same as fruit.flavor)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
fruit.name = "banana" # this is best practice
fruit. color = "yellow" # same as fruit.color
fruit . flavor = "banana" # same as fruit.flavor)code";
fruit . flavor = "banana" # same as fruit.flavor)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -380,15 +381,15 @@ TEST(GenerateTOML, TransferOutOfOrderKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(apple.type = "fruit"
std::string ssTOMLInput = R"toml(apple.type = "fruit"
orange.type = "fruit"
apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange")code";
std::string ssTOMLOutput = R"code([tree.branch]
orange.color = "orange")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
apple.type = "fruit"
orange.type = "fruit"
@@ -396,7 +397,7 @@ apple.skin = "thin"
orange.skin = "thick"
apple.color = "red"
orange.color = "orange")code";
orange.color = "orange")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -410,9 +411,9 @@ TEST(GenerateTOML, TransferFloatLookingAlikeKeys)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(3.14159 = "pi")code";
std::string ssTOMLOutput = R"code([tree.branch]
3.14159 = "pi")code";
std::string ssTOMLInput = R"toml(3.14159 = "pi")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
3.14159 = "pi")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -426,9 +427,9 @@ TEST(GenerateTOML, TransferBasicStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")code";
std::string ssTOMLOutput = R"code([tree.branch]
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")code";
std::string ssTOMLInput = R"toml(str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
str = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF.")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -442,13 +443,13 @@ TEST(GenerateTOML, TransferMultiLineStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(str1 = """
std::string ssTOMLInput = R"toml(str1 = """
Roses are red
Violets are blue""")code";
std::string ssTOMLOutput = R"code([tree.branch]
Violets are blue""")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
str1 = """
Roses are red
Violets are blue""")code";
Violets are blue""")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -462,7 +463,7 @@ TEST(GenerateTOML, TransferLongMultiLineStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(str1 = "The quick brown fox jumps over the lazy dog."
std::string ssTOMLInput = R"toml(str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
The quick brown \
@@ -475,8 +476,8 @@ str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
""")code";
std::string ssTOMLOutput = R"code([tree.branch]
""")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
str1 = "The quick brown fox jumps over the lazy dog."
str2 = """
@@ -490,7 +491,7 @@ str3 = """\
The quick brown \
fox jumps over \
the lazy dog.\
""")code";
""")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -504,21 +505,21 @@ TEST(GenerateTOML, TransferQuotingStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(str4 = """Here are two quotation marks: "". Simple enough."""
std::string ssTOMLInput = R"toml(str4 = """Here are two quotation marks: "". Simple enough."""
# str5 = """Here are three quotation marks: """.""" # INVALID
str5 = """Here are three quotation marks: ""\"."""
str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement."""")code";
std::string ssTOMLOutput = R"code([tree.branch]
str7 = """"This," she said, "is just a pointless statement."""")toml";
std::string ssTOMLOutput = R"toml([tree.branch]
str4 = """Here are two quotation marks: "". Simple enough."""
# str5 = """Here are three quotation marks: """.""" # INVALID
str5 = """Here are three quotation marks: ""\"."""
str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
# "This," she said, "is just a pointless statement."
str7 = """"This," she said, "is just a pointless statement."""")code";
str7 = """"This," she said, "is just a pointless statement."""")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -532,15 +533,15 @@ TEST(GenerateTOML, TransferLiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(winpath = 'C:\Users\nodejs\templates'
std::string ssTOMLInput = R"toml(winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>')code";
std::string ssTOMLOutput = R"code([tree.branch]
regex = '<\i\c*\s*>')toml";
std::string ssTOMLOutput = R"toml([tree.branch]
winpath = 'C:\Users\nodejs\templates'
winpath2 = '\\ServerX\admin$\system32\'
quoted = 'Tom "Dubs" Preston-Werner'
regex = '<\i\c*\s*>')code";
regex = '<\i\c*\s*>')toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -554,21 +555,21 @@ TEST(GenerateTOML, TransferMultiLineLiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(regex2 = '''I [dw]on't need \d{2} apples'''
std::string ssTOMLInput = R"toml(regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
''')code";
std::string ssTOMLOutput = R"code([tree.branch]
''')toml";
std::string ssTOMLOutput = R"toml([tree.branch]
regex2 = '''I [dw]on't need \d{2} apples'''
lines = '''
The first newline is
trimmed in raw strings.
All other whitespace
is preserved.
''')code";
''')toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -582,21 +583,21 @@ TEST(GenerateTOML, TransferQuotedLiteralStrings)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
std::string ssTOMLInput = R"toml(quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"
# 'That,' she said, 'is still pointless.'
str = ''''That,' she said, 'is still pointless.'''')code";
std::string ssTOMLOutput = R"code([tree.branch]
str = ''''That,' she said, 'is still pointless.'''')toml";
std::string ssTOMLOutput = R"toml([tree.branch]
quot15 = '''Here are fifteen quotation marks: """""""""""""""'''
# apos15 = '''Here are fifteen apostrophes: '''''''''''''''''' # INVALID
apos15 = "Here are fifteen apostrophes: '''''''''''''''"
# 'That,' she said, 'is still pointless.'
str = ''''That,' she said, 'is still pointless.'''')code";
str = ''''That,' she said, 'is still pointless.'''')toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -610,15 +611,15 @@ TEST(GenerateTOML, TransferIntegers)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(int1 = +99
std::string ssTOMLInput = R"toml(int1 = +99
int2 = 42
int3 = 0
int4 = -17)code";
std::string ssTOMLOutput = R"code([tree.branch]
int4 = -17)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
int1 = +99
int2 = 42
int3 = 0
int4 = -17)code";
int4 = -17)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -632,15 +633,15 @@ TEST(GenerateTOML, TransferReadibleIntegers)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(int5 = 1_000
std::string ssTOMLInput = R"toml(int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221 # Indian number system grouping
int8 = 1_2_3_4_5 # VALID but discouraged)code";
std::string ssTOMLOutput = R"code([tree.branch]
int8 = 1_2_3_4_5 # VALID but discouraged)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
int5 = 1_000
int6 = 5_349_221
int7 = 53_49_221 # Indian number system grouping
int8 = 1_2_3_4_5 # VALID but discouraged)code";
int8 = 1_2_3_4_5 # VALID but discouraged)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -654,7 +655,7 @@ TEST(GenerateTOML, TransferOtherBaseIntegers)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# hexadecimal with prefix `0x`
std::string ssTOMLInput = R"toml(# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
hex3 = 0xdead_beef
@@ -664,8 +665,8 @@ oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110)code";
std::string ssTOMLOutput = R"code([tree.branch]
bin1 = 0b11010110)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# hexadecimal with prefix `0x`
hex1 = 0xDEADBEEF
hex2 = 0xdeadbeef
@@ -676,7 +677,7 @@ oct1 = 0o01234567
oct2 = 0o755 # useful for Unix file permissions
# binary with prefix `0b`
bin1 = 0b11010110)code";
bin1 = 0b11010110)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -690,7 +691,7 @@ TEST(GenerateTOML, TransferFloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# fractional
std::string ssTOMLInput = R"toml(# fractional
flt1 = +1.0
flt2 = 3.1415
flt3 = -0.01
@@ -701,8 +702,8 @@ flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34)code";
std::string ssTOMLOutput = R"code([tree.branch]
flt7 = 6.626e-34)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# fractional
flt1 = +1.0
flt2 = 3.1415
@@ -714,7 +715,7 @@ flt5 = 1e06
flt6 = -2E-2
# both
flt7 = 6.626e-34)code";
flt7 = 6.626e-34)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -728,9 +729,9 @@ TEST(GenerateTOML, TransferReadibleFloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(flt8 = 224_617.445_991_228)code";
std::string ssTOMLOutput = R"code([tree.branch]
flt8 = 224_617.445_991_228)code";
std::string ssTOMLInput = R"toml(flt8 = 224_617.445_991_228)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
flt8 = 224_617.445_991_228)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -744,7 +745,7 @@ TEST(GenerateTOML, TransferSpecialFloatingPoints)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# infinity
std::string ssTOMLInput = R"toml(# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
sf3 = -inf # negative infinity
@@ -752,8 +753,8 @@ sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific)code";
std::string ssTOMLOutput = R"code([tree.branch]
sf6 = -nan # valid, actual encoding is implementation-specific)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# infinity
sf1 = inf # positive infinity
sf2 = +inf # positive infinity
@@ -762,7 +763,7 @@ sf3 = -inf # negative infinity
# not a number
sf4 = nan # actual sNaN/qNaN encoding is implementation-specific
sf5 = +nan # same as `nan`
sf6 = -nan # valid, actual encoding is implementation-specific)code";
sf6 = -nan # valid, actual encoding is implementation-specific)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -776,11 +777,11 @@ TEST(GenerateTOML, TransferBooleans)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(bool1 = true
bool2 = false)code";
std::string ssTOMLOutput = R"code([tree.branch]
std::string ssTOMLInput = R"toml(bool1 = true
bool2 = false)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
bool1 = true
bool2 = false)code";
bool2 = false)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -794,13 +795,13 @@ TEST(GenerateTOML, DISABLED_TransferOffsetDateTimes)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(odt1 = 1979-05-27T07:32:00Z
std::string ssTOMLInput = R"toml(odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00)code";
std::string ssTOMLOutput = R"code([tree.branch]
odt3 = 1979-05-27T00:32:00.999999-07:00)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
odt1 = 1979-05-27T07:32:00Z
odt2 = 1979-05-27T00:32:00-07:00
odt3 = 1979-05-27T00:32:00.999999-07:00)code";
odt3 = 1979-05-27T00:32:00.999999-07:00)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -814,9 +815,9 @@ TEST(GenerateTOML, DISABLED_TransferReadibleOffsetDateTimes)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(odt4 = 1979-05-27 07:32:00Z)code";
std::string ssTOMLOutput = R"code([tree.branch]
odt4 = 1979-05-27 07:32:00Z)code";
std::string ssTOMLInput = R"toml(odt4 = 1979-05-27 07:32:00Z)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
odt4 = 1979-05-27 07:32:00Z)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -830,11 +831,11 @@ TEST(GenerateTOML, DISABLED_TransferLocalDateTimes)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999)code";
std::string ssTOMLOutput = R"code([tree.branch]
std::string ssTOMLInput = R"toml(ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
ldt1 = 1979-05-27T07:32:00
ldt2 = 1979-05-27T00:32:00.999999)code";
ldt2 = 1979-05-27T00:32:00.999999)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -848,9 +849,9 @@ TEST(GenerateTOML, DISABLED_TransferLocalDates)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(ld1 = 1979-05-27)code";
std::string ssTOMLOutput = R"code([tree.branch]
ld1 = 1979-05-27)code";
std::string ssTOMLInput = R"toml(ld1 = 1979-05-27)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
ld1 = 1979-05-27)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -864,11 +865,11 @@ TEST(GenerateTOML, DISABLED_TransferLocalTimes)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(lt1 = 07:32:00
lt2 = 00:32:00.999999)code";
std::string ssTOMLOutput = R"code([tree.branch]
std::string ssTOMLInput = R"toml(lt1 = 07:32:00
lt2 = 00:32:00.999999)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
lt1 = 07:32:00
lt2 = 00:32:00.999999)code";
lt2 = 00:32:00.999999)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -882,7 +883,7 @@ TEST(GenerateTOML, TransferArrays)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(integers = [ 1, 2, 3 ]
std::string ssTOMLInput = R"toml(integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
nested_mixed_array = [ [ 1, 2 ], ["a", "b", "c"] ]
@@ -893,8 +894,8 @@ numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
])code";
std::string ssTOMLOutput = R"code([tree.branch]
])toml";
std::string ssTOMLOutput = R"toml([tree.branch]
integers = [ 1, 2, 3 ]
colors = [ "red", "yellow", "green" ]
nested_arrays_of_ints = [ [ 1, 2 ], [3, 4, 5] ]
@@ -906,7 +907,7 @@ numbers = [ 0.1, 0.2, 0.5, 1, 2, 5 ]
contributors = [
"Foo Bar <foo@example.com>",
{ name = "Baz Qux", email = "bazqux@example.com", url = "https://example.com/bazqux" }
])code";
])toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -920,15 +921,15 @@ TEST(GenerateTOML, TransferMultiLineArrays)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(integers2 = [
std::string ssTOMLInput = R"toml(integers2 = [
1, 2, 3
]
integers3 = [
1,
2, # this is ok
])code";
std::string ssTOMLOutput = R"code([tree.branch]
])toml";
std::string ssTOMLOutput = R"toml([tree.branch]
integers2 = [
1, 2, 3
]
@@ -936,7 +937,7 @@ integers2 = [
integers3 = [
1,
2, # this is ok
])code";
])toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -950,7 +951,7 @@ TEST(GenerateTOML, TransferTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([table]
std::string ssTOMLInput = R"toml([table]
[table-1]
key1 = "some string"
@@ -958,8 +959,8 @@ key2 = 123
[table-2]
key1 = "another string"
key2 = 456)code";
std::string ssTOMLOutput = R"code([tree.branch.table]
key2 = 456)toml";
std::string ssTOMLOutput = R"toml([tree.branch.table]
[tree.branch.table-1]
key1 = "some string"
@@ -967,7 +968,7 @@ key2 = 123
[tree.branch.table-2]
key1 = "another string"
key2 = 456)code";
key2 = 456)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -981,10 +982,10 @@ TEST(GenerateTOML, TransferQuotedKeyTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([dog."tater.man"]
type.name = "pug")code";
std::string ssTOMLOutput = R"code([tree.branch.dog."tater.man"]
type.name = "pug")code";
std::string ssTOMLInput = R"toml([dog."tater.man"]
type.name = "pug")toml";
std::string ssTOMLOutput = R"toml([tree.branch.dog."tater.man"]
type.name = "pug")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -998,22 +999,22 @@ TEST(GenerateTOML, TransferWhitespaceKeyTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = u8R"code([a.b.c] # this is best practice
std::string ssTOMLInput = u8R"toml([a.b.c] # this is best practice
x = 1
[ d.e.f ] # same as [d.e.f]
y = 1
[ g . h . i ] # same as [g.h.i]
z = 1
[ j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
a = 1)code";
std::string ssTOMLOutput = u8R"code([tree.branch.a.b.c] # this is best practice
a = 1)toml";
std::string ssTOMLOutput = u8R"toml([tree.branch.a.b.c] # this is best practice
x = 1
[tree.branch. d.e.f ] # same as [d.e.f]
y = 1
[tree.branch. g . h . i ] # same as [g.h.i]
z = 1
[tree.branch. j . "ʞ" . 'l' ] # same as [j."ʞ".'l']
a = 1)code";
a = 1)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1027,20 +1028,20 @@ TEST(GenerateTOML, TransferMixedOrderTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# VALID BUT DISCOURAGED
std::string ssTOMLInput = R"toml(# VALID BUT DISCOURAGED
[fruit.apple]
a = 1
[animal]
b = 2
[fruit.orange]
aa = 11)code";
std::string ssTOMLOutput = R"code(# VALID BUT DISCOURAGED
aa = 11)toml";
std::string ssTOMLOutput = R"toml(# VALID BUT DISCOURAGED
[tree.branch.fruit.apple]
a = 1
[tree.branch.animal]
b = 2
[tree.branch.fruit.orange]
aa = 11)code";
aa = 11)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1054,15 +1055,15 @@ TEST(GenerateTOML, TransferMixedValueAndTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# Top-level table begins.
std::string ssTOMLInput = R"toml(# Top-level table begins.
name = "Fido"
breed = "pug"
# Top-level table ends.
[owner]
name = "Regina Dogman"
member_since = 1999)code";
std::string ssTOMLOutput = R"code([tree.branch]
member_since = 1999)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
# Top-level table begins.
name = "Fido"
breed = "pug"
@@ -1070,7 +1071,7 @@ breed = "pug"
# Top-level table ends.
[tree.branch.owner]
name = "Regina Dogman"
member_since = 1999)code";
member_since = 1999)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1084,14 +1085,14 @@ TEST(GenerateTOML, TransferAutomaticTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(fruit.apple.color = "red"
fruit.apple.taste.sweet = true)code";
std::string ssTOMLOutput = R"code([tree.branch]
std::string ssTOMLInput = R"toml(fruit.apple.color = "red"
fruit.apple.taste.sweet = true)toml";
std::string ssTOMLOutput = R"toml([tree.branch]
fruit.apple.color = "red"
fruit.apple.taste.sweet = true)code";
std::string ssTOMLOutput2 = R"code([tree.branch]
fruit.apple.taste.sweet = true)toml";
std::string ssTOMLOutput2 = R"toml([tree.branch]
apple.color = "red"
apple.taste.sweet = true)code";
apple.taste.sweet = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1107,7 +1108,7 @@ TEST(GenerateTOML, TransferMixedAutomaticTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([fruit]
std::string ssTOMLInput = R"toml([fruit]
apple.color = "red"
apple.taste.sweet = true
@@ -1115,8 +1116,8 @@ apple.taste.sweet = true
# [fruit.apple.taste] # INVALID
[fruit.apple.texture] # you can add sub-tables
smooth = true)code";
std::string ssTOMLOutput = R"code([tree.branch.fruit]
smooth = true)toml";
std::string ssTOMLOutput = R"toml([tree.branch.fruit]
apple.color = "red"
apple.taste.sweet = true
@@ -1124,7 +1125,7 @@ apple.taste.sweet = true
# [fruit.apple.taste] # INVALID
[tree.branch.fruit.apple.texture] # you can add sub-tables
smooth = true)code";
smooth = true)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1138,13 +1139,13 @@ TEST(GenerateTOML, TransferInlineTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(name = { first = "Tom", last = "Preston-Werner" }
std::string ssTOMLInput = R"toml(name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" })code";
std::string ssTOMLOutput = R"code([tree.branch]
animal = { type.name = "pug" })toml";
std::string ssTOMLOutput = R"toml([tree.branch]
name = { first = "Tom", last = "Preston-Werner" }
point = { x = 1, y = 2 }
animal = { type.name = "pug" })code";
animal = { type.name = "pug" })toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
std::string ssGenerated;
@@ -1157,13 +1158,13 @@ TEST(GenerateTOML, TransferEmbeddedInlineTables)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(test=[{ first = "Tom", last = "Preston-Werner" },
std::string ssTOMLInput = R"toml(test=[{ first = "Tom", last = "Preston-Werner" },
{ x = 1, y = 2 },
{ type.name = "pug" }])code";
std::string ssTOMLOutput = R"code([tree.branch]
{ type.name = "pug" }])toml";
std::string ssTOMLOutput = R"toml([tree.branch]
test=[{ first = "Tom", last = "Preston-Werner" },
{ x = 1, y = 2 },
{ type.name = "pug" }])code";
{ type.name = "pug" }])toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1177,7 +1178,7 @@ TEST(GenerateTOML, TransferTableArrays)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([[products]]
std::string ssTOMLInput = R"toml([[products]]
name = "Hammer"
sku = 738594937
@@ -1187,8 +1188,8 @@ sku = 738594937
name = "Nail"
sku = 284758393
color = "gray")code";
std::string ssTOMLOutput = R"code([[tree.branch.products]]
color = "gray")toml";
std::string ssTOMLOutput = R"toml([[tree.branch.products]]
name = "Hammer"
sku = 738594937
@@ -1198,7 +1199,7 @@ sku = 738594937
name = "Nail"
sku = 284758393
color = "gray")code";
color = "gray")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1212,7 +1213,7 @@ TEST(GenerateTOML, TransferMixedTableAndTableArrays)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code([[fruits]]
std::string ssTOMLInput = R"toml([[fruits]]
name = "apple"
[fruits.physical] # subtable
@@ -1230,8 +1231,8 @@ name = "granny smith"
name = "banana"
[[fruits.varieties]]
name = "plantain")code";
std::string ssTOMLOutput = R"code([[tree.branch.fruits]]
name = "plantain")toml";
std::string ssTOMLOutput = R"toml([[tree.branch.fruits]]
name = "apple"
[tree.branch.fruits.physical] # subtable
@@ -1249,7 +1250,7 @@ name = "granny smith"
name = "banana"
[[tree.branch.fruits.varieties]]
name = "plantain")code";
name = "plantain")toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -1263,13 +1264,13 @@ TEST(GenerateTOML, TransferInlineTableArrays)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(points = [ { x = 1, y = 2, z = 3 },
std::string ssTOMLInput = R"toml(points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ])code";
std::string ssTOMLOutput = R"code([tree.branch]
{ x = 2, y = 4, z = 8 } ])toml";
std::string ssTOMLOutput = R"toml([tree.branch]
points = [ { x = 1, y = 2, z = 3 },
{ x = 7, y = 8, z = 9 },
{ x = 2, y = 4, z = 8 } ])code";
{ x = 2, y = 4, z = 8 } ])toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
std::string ssGenerated;

View File

@@ -12,15 +12,15 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
TEST(GenerateTOML, GetCommentRoot)
TEST(GetSetComment, GetCommentRoot)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# This is a comment)code";
std::string ssTOML = R"toml(# This is a comment)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -34,17 +34,17 @@ TEST(GenerateTOML, GetCommentRoot)
EXPECT_EQ(ssComment, "This is a comment");
}
TEST(GenerateTOML, GetMultiLineCommentRoot)
TEST(GetSetComment, GetMultiLineCommentRoot)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# This is a comment that stretches
# more than one line.
# And here's another comment of more
# than one line.
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
@@ -55,23 +55,23 @@ TEST(GenerateTOML, GetMultiLineCommentRoot)
ssComment = parser.Root().GetComment(sdv::toml::INodeInfo::ECommentType::out_of_scope_comment_before);
EXPECT_TRUE(ssComment.empty());
ssComment = parser.Root().GetComment(sdv::toml::INodeInfo::ECommentType::out_of_scope_comment_behind);
EXPECT_EQ(ssComment, R"code(This is a comment that stretches more than one line.
And here's another comment of more than one line.)code");
EXPECT_EQ(ssComment, R"toml(This is a comment that stretches more than one line.
And here's another comment of more than one line.)toml");
}
TEST(GenerateTOML, SetCommentRoot)
TEST(GetSetComment, SetCommentRoot)
{
toml_parser::CParser parser;
// This will test the SetComment function and overwriting the existing comment.
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code(# This is comment way before
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml(# This is comment way before
# This is comment before
# This is comment way behind
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -93,13 +93,13 @@ TEST(GenerateTOML, SetCommentRoot)
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}
TEST(GenerateTOML, SetMultiLineCommentRoot)
TEST(GetSetComment, SetMultiLineCommentRoot)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code(# This is comment way before
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml(# This is comment way before
# And surprise, also a second line
@@ -109,7 +109,7 @@ TEST(GenerateTOML, SetMultiLineCommentRoot)
# This is comment way behind
# And final, also a second line
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -139,13 +139,13 @@ And final, also a second line)");
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}
TEST(GenerateTOML, RemoveCommentRoot)
TEST(GetSetComment, RemoveCommentRoot)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code()code";
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml()toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -155,16 +155,16 @@ TEST(GenerateTOML, RemoveCommentRoot)
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}
TEST(GenerateTOML, GetCommentRootValue)
TEST(GetSetComment, GetCommentRootValue)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(# This is a separate comment
std::string ssTOML = R"toml(# This is a separate comment
# This is a comment before the value
value = "this is the value text" # Comment following the value
# This is also a separate comment)code";
# This is also a separate comment)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
sdv::TInterfaceAccessPtr ptrValue = parser.Root().GetNodeDirect("value");
@@ -182,11 +182,11 @@ value = "this is the value text" # Comment following the value
EXPECT_EQ(ssComment, "This is also a separate comment");
}
TEST(GenerateTOML, GetMultiLineCommentRootValue)
TEST(GetSetComment, GetMultiLineCommentRootValue)
{
toml_parser::CParser parser;
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# This is a separate comment with several line-breaks before.
@@ -209,7 +209,7 @@ value = "this is the value text" # Comment following the value.
# This is also a separate comment.
# Followed by this text on the same line.
# And another text on a separate line.)code";
# And another text on a separate line.)toml";
EXPECT_NO_THROW(parser.Process(ssTOML));
sdv::TInterfaceAccessPtr ptrValue = parser.Root().GetNodeDirect("value");
@@ -218,32 +218,32 @@ value = "this is the value text" # Comment following the value.
ASSERT_NE(pComment, nullptr);
std::string ssComment = pComment->GetComment(sdv::toml::INodeInfo::ECommentType::comment_before);
EXPECT_EQ(ssComment, R"code(This is a comment before the value. And another comment before the value at the same line.
Note: there was a space after the empty comment line. But that should not influence the comment lines.)code");
EXPECT_EQ(ssComment, R"toml(This is a comment before the value. And another comment before the value at the same line.
Note: there was a space after the empty comment line. But that should not influence the comment lines.)toml");
ssComment = pComment->GetComment(sdv::toml::INodeInfo::ECommentType::comment_behind);
EXPECT_EQ(ssComment, R"code(Comment following the value. More comment following the value. This becomes one line.
But this is a separate line.)code");
EXPECT_EQ(ssComment, R"toml(Comment following the value. More comment following the value. This becomes one line.
But this is a separate line.)toml");
ssComment = pComment->GetComment(sdv::toml::INodeInfo::ECommentType::out_of_scope_comment_before);
EXPECT_EQ(ssComment, R"code(This is a separate comment with several line-breaks before. Followed by this text on the same line.
Note: there was a space after the empty comment line. And another separate comment on a next line.)code");
EXPECT_EQ(ssComment, R"toml(This is a separate comment with several line-breaks before. Followed by this text on the same line.
Note: there was a space after the empty comment line. And another separate comment on a next line.)toml");
ssComment = pComment->GetComment(sdv::toml::INodeInfo::ECommentType::out_of_scope_comment_behind);
EXPECT_EQ(ssComment, R"code(This is also a separate comment. Followed by this text on the same line.
And another text on a separate line.)code");
EXPECT_EQ(ssComment, R"toml(This is also a separate comment. Followed by this text on the same line.
And another text on a separate line.)toml");
}
TEST(GenerateTOML, SetCommentRootValue)
TEST(GetSetComment, SetCommentRootValue)
{
toml_parser::CParser parser;
// This will test the SetComment function and overwriting the existing comment.
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code(# This is comment #3
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml(# This is comment #3
# This is comment #1
# This is comment #4
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -265,13 +265,13 @@ TEST(GenerateTOML, SetCommentRootValue)
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}
TEST(GenerateTOML, SetMultiLineCommentRootValue)
TEST(GetSetComment, SetMultiLineCommentRootValue)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code(# This is comment #3
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml(# This is comment #3
# And surprise, also a second line
@@ -281,7 +281,7 @@ TEST(GenerateTOML, SetMultiLineCommentRootValue)
# This is comment #4
# And final, also a second line
)code";
)toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));
@@ -311,13 +311,13 @@ And final, also a second line)");
EXPECT_EQ(ssGenerated, ssTOMLOutput);
}
TEST(GenerateTOML, RemoveCommentRootValue)
TEST(GetSetComment, RemoveCommentRootValue)
{
toml_parser::CParser parser;
std::string ssTOMLInput = R"code(# This is a double line comment
# This is line two of the double line comment)code";
std::string ssTOMLOutput = R"code()code";
std::string ssTOMLInput = R"toml(# This is a double line comment
# This is line two of the double line comment)toml";
std::string ssTOMLOutput = R"toml()toml";
EXPECT_NO_THROW(parser.Process(ssTOMLInput));

View File

@@ -0,0 +1,119 @@
/********************************************************************************
* 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:
* Martin Stimpfl - initial API and implementation
* Erik Verhoeven - writing TOML and whitespace preservation
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.h"
TEST(IndexerTest, InitializeSingle)
{
toml_parser::CNodeIndexer indexer;
EXPECT_NO_THROW(toml_parser::CNodeIndex index = indexer.CreateIndex());
}
TEST(IndexerTest, CompareOrder)
{
toml_parser::CNodeIndexer indexer;
auto index1 = indexer.CreateIndex();
auto index2 = indexer.CreateIndex();
auto index3 = indexer.CreateIndex();
EXPECT_GT(index2, index1);
EXPECT_GT(index3, index1);
EXPECT_GT(index3, index2);
}
TEST(IndexerTest, SwitchOrder)
{
toml_parser::CNodeIndexer indexer;
auto index1 = indexer.CreateIndex();
auto index2 = indexer.CreateIndex();
auto index3 = indexer.CreateIndex();
index3.MoveBefore(index1);
EXPECT_GT(index2, index1);
EXPECT_LT(index3, index1);
EXPECT_LT(index3, index2);
}
TEST(IndexerTest, SwitchOrderMultipleIndexer)
{
toml_parser::CNodeIndexer indexer1;
toml_parser::CNodeIndexer indexer2;
toml_parser::CNodeIndexer indexer3;
auto index1 = indexer1.CreateIndex();
auto index2 = indexer2.CreateIndex();
auto index3 = indexer3.CreateIndex();
EXPECT_GT(index2, index1);
EXPECT_GT(index3, index1);
EXPECT_GT(index3, index2);
index3.MoveBefore(index1);
EXPECT_GT(index2, index1);
EXPECT_LT(index3, index1);
EXPECT_LT(index3, index2);
index2.MoveBefore(index3);
EXPECT_LT(index2, index1);
EXPECT_LT(index3, index1);
EXPECT_GT(index3, index2);
}
TEST(IndexerTest, IndexLifetime)
{
toml_parser::CNodeIndexer indexer;
auto index1 = indexer.CreateIndex();
size_t nCurrentCnt = indexer.Count();
{
auto index2 = indexer.CreateIndex();
EXPECT_GT(index2, index1);
EXPECT_EQ(indexer.Count(), nCurrentCnt + 1);
}
EXPECT_EQ(indexer.Count(), nCurrentCnt);
auto index3 = indexer.CreateIndex();
EXPECT_GT(index3, index1);
}
TEST(IndexerTest, CopyIndex)
{
toml_parser::CNodeIndexer indexer;
auto index1 = indexer.CreateIndex();
auto index2 = indexer.CreateIndex();
auto index2b = index2;
EXPECT_TRUE(index2b);
EXPECT_TRUE(index2);
EXPECT_GT(index2b, index1);
EXPECT_GT(index2, index1);
EXPECT_EQ(index2, index2b);
auto index3 = indexer.CreateIndex();
EXPECT_GT(index3, index2);
EXPECT_GT(index3, index1);
}
TEST(IndexerTest, MoveIndex)
{
toml_parser::CNodeIndexer indexer;
auto index1 = indexer.CreateIndex();
auto index2 = indexer.CreateIndex();
auto index2b = std::move(index2);
EXPECT_TRUE(index2b);
EXPECT_FALSE(index2);
EXPECT_GT(index2b, index1);
EXPECT_GT(index2, index1); // index 2 is not initialized any more.
EXPECT_GT(index2, index2b);
auto index3 = indexer.CreateIndex();
EXPECT_GT(index3, index2b);
EXPECT_GT(index3, index1);
EXPECT_GT(index2, index3);
}

View File

@@ -0,0 +1,990 @@
/********************************************************************************
* 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/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include <support/toml.h>
// Test TODO:
// - Inserted and straight away deleted
// - Inserted with false/deleted reference --error
// - Inserted values before (okay) and behind (error) tables
// - Inserted duplicate value -- error
// - Smart insert (comments/whitespace around)
// Insert as TOML, but only partly correct.
TEST(InsertNode, InsertValuesRoot)
{
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertValue("", "value_int", 10));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_int = 10)toml");
EXPECT_TRUE(root.InsertValue("", "value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_int = 10
value_str = "abc")toml");
EXPECT_NE(parser.Root().InsertValue(root.GetNodeNameByIndex(0), "value_float", 123.456), nullptr);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_float = 123.456
value_int = 10
value_str = "abc")toml");
}
TEST(InsertNode, InsertTableRoot)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTable("", "table1", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([table1])toml");
// Insert an inline table before
EXPECT_TRUE(root.InsertTable(root.GetNodeNameByIndex(0), "table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table2 = {}
[table1])toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(root.InsertTable("", "table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table2 = {}
table3 = {}
[table1])toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_TRUE(root.InsertTable(root.GetNodeNameByIndex(0), "table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table2 = {}
table3 = {}
[table4]
[table1])toml");
}
TEST(InsertNode, InsertArrayRoot)
{
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertArray("", "value_array1"));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_array1 = [])toml");
EXPECT_TRUE(root.InsertArray("", "value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_array1 = []
value_array2 = [])toml");
EXPECT_TRUE(root.InsertArray(root.GetNodeNameByIndex(0), "value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_array3 = []
value_array1 = []
value_array2 = [])toml");
}
TEST(InsertNode, InsertTableArrayRoot)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_TRUE(root.InsertTableArray("", "table_array1", false));
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array1]])toml");
// Insert an inline table array before
EXPECT_TRUE(root.InsertTableArray(root.GetNodeNameByIndex(0), "table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{}]
[[table_array1]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(root.InsertTableArray("", "table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{}]
table_array3 = [{}]
[[table_array1]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(root.InsertTableArray(root.GetNodeNameByIndex(0), "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{}]
table_array3 = [{}]
[[table_array4]]
[[table_array1]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(root.InsertTableArray("", "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{}]
table_array3 = [{}]
[[table_array4]]
[[table_array1]]
[[table_array4]])toml");
}
TEST(InsertNode, InsertValueInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableStandard = root.InsertTable("", "standard_table", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert the values into the table
EXPECT_TRUE(tableStandard.InsertValue("", "value_int", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_int = 10)toml");
EXPECT_TRUE(tableStandard.InsertValue("", "value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_int = 10
value_str = "abc")toml");
EXPECT_TRUE(tableStandard.InsertValue(tableStandard.GetNodeNameByIndex(0), "value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_float = 123.456
value_int = 10
value_str = "abc")toml");
}
TEST(InsertNode, InsertTableInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableStandard = root.InsertTable("", "standard_table", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert a standard table
EXPECT_TRUE(tableStandard.InsertTable("", "table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table.table1])toml");
// Insert an inline table before
EXPECT_TRUE(tableStandard.InsertTable(tableStandard.GetNodeNameByIndex(0), "table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
[standard_table.table1])toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(tableStandard.InsertTable("", "table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
table3 = {}
[standard_table.table1])toml");
// Insert a standard table in front -> this will have to be printed behind the inline table relative to the elements of the
// standard_table.
EXPECT_TRUE(tableStandard.InsertTable(tableStandard.GetNodeNameByIndex(0), "table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table2 = {}
table3 = {}
[standard_table.table4]
[standard_table.table1])toml");
}
TEST(InsertNode, InsertArrayInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableStandard = root.InsertTable("", "standard_table", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert arrays
EXPECT_TRUE(tableStandard.InsertArray("", "value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array1 = [])toml");
EXPECT_TRUE(tableStandard.InsertArray("", "value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array1 = []
value_array2 = [])toml");
EXPECT_TRUE(tableStandard.InsertArray(tableStandard.GetNodeNameByIndex(0), "value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
value_array3 = []
value_array1 = []
value_array2 = [])toml");
}
TEST(InsertNode, InsertTableArrayInStandardTable)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableStandard = root.InsertTable("", "standard_table", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
// Insert standard table array
EXPECT_TRUE(tableStandard.InsertTableArray("", "table_array1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[standard_table.table_array1]])toml");
// Insert an inline table array before
EXPECT_TRUE(tableStandard.InsertTableArray(tableStandard.GetNodeNameByIndex(0), "table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
[[standard_table.table_array1]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(tableStandard.InsertTableArray("", "table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array1]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array relative to the elements
// of the standard_table.
EXPECT_TRUE(tableStandard.InsertTableArray(tableStandard.GetNodeNameByIndex(0), "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array4]]
[[standard_table.table_array1]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(tableStandard.InsertTableArray("", "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([standard_table]
table_array2 = [{}]
table_array3 = [{}]
[[standard_table.table_array4]]
[[standard_table.table_array1]]
[[standard_table.table_array4]])toml");
}
TEST(InsertNode, InsertValueInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableInline = root.InsertTable("", "inline_table", true);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert the values into the table
EXPECT_TRUE(tableInline.InsertValue("", "value_int", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_int = 10})toml");
EXPECT_TRUE(tableInline.InsertValue("", "value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_int = 10, value_str = "abc"})toml");
EXPECT_TRUE(tableInline.InsertValue(tableInline.GetNodeNameByIndex(0), "value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_float = 123.456, value_int = 10, value_str = "abc"})toml");
}
TEST(InsertNode, InsertTableInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableInline = root.InsertTable("", "inline_table", true);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert a standard table
EXPECT_TRUE(tableInline.InsertTable("", "table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table1 = {}})toml");
// Insert an inline table before
EXPECT_TRUE(tableInline.InsertTable(tableInline.GetNodeNameByIndex(0), "table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table2 = {}, table1 = {}})toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(tableInline.InsertTable("", "table3",
true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table2 = {}, table1 = {}, table3 = {}})toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_TRUE(tableInline.InsertTable(tableInline.GetNodeNameByIndex(0), "table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table4 = {}, table2 = {}, table1 = {}, table3 = {}})toml");
}
TEST(InsertNode, InsertArrayInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableInline = root.InsertTable("", "inline_table", true);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert arrays
EXPECT_TRUE(tableInline.InsertArray("", "value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array1 = []})toml");
EXPECT_TRUE(tableInline.InsertArray("", "value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array1 = [], value_array2 = []})toml");
EXPECT_TRUE(tableInline.InsertArray(tableInline.GetNodeNameByIndex(0), "value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {value_array3 = [], value_array1 = [], value_array2 = []})toml");
}
TEST(InsertNode, InsertTableArrayInInlineTable)
{
// Insert an inline table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection tableInline = root.InsertTable("", "inline_table", true);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {})toml");
// Insert standard table array
EXPECT_TRUE(tableInline.InsertTableArray("", "table_array1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array1 = [{}]})toml");
// Insert an inline table array before
EXPECT_TRUE(tableInline.InsertTableArray(tableInline.GetNodeNameByIndex(0), "table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array2 = [{}], table_array1 = [{}]})toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(tableInline.InsertTableArray("", "table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_table = {table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(tableInline.InsertTableArray(tableInline.GetNodeNameByIndex(0), "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML,
R"toml(inline_table = {table_array4 = [{}], table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(tableInline.InsertTableArray("", "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML,
R"toml(inline_table = {table_array4 = [{}, {}], table_array2 = [{}], table_array1 = [{}], table_array3 = [{}]})toml");
}
TEST(InsertNode, InsertValueInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection arrayInline = root.InsertArray("", "inline_array");
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert the values into the table (with or without name)
EXPECT_TRUE(arrayInline.InsertValue("", "", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [10])toml");
EXPECT_TRUE(arrayInline.InsertValue("", "", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [10, "abc"])toml");
EXPECT_TRUE(arrayInline.InsertValue(arrayInline.GetNodeNameByIndex(0), "", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [123.456, 10, "abc"])toml");
}
TEST(InsertNode, InsertTableInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection arrayInline = root.InsertArray("", "inline_array");
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert a standard table
sdv::toml::CNodeCollection table = arrayInline.InsertTable("", "", false);
EXPECT_TRUE(table);
table.InsertValue("", "a", 10);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{a = 10}])toml");
// Insert an inline table before
table = arrayInline.InsertTable(arrayInline.GetNodeNameByIndex(0), "", true);
EXPECT_TRUE(table);
table.InsertValue("", "b", 20);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{b = 20}, {a = 10}])toml");
// Insert an inline table behind
table = arrayInline.InsertTable("", "", true);
EXPECT_TRUE(table);
table.InsertValue("", "c", 30);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{b = 20}, {a = 10}, {c = 30}])toml");
// Insert a standard table in front
table = arrayInline.InsertTable(arrayInline.GetNodeNameByIndex(0), "", false);
EXPECT_TRUE(table);
table.InsertValue("", "d", 40);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [{d = 40}, {b = 20}, {a = 10}, {c = 30}])toml");
}
TEST(InsertNode, InsertArrayInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection arrayInline = root.InsertArray("", "inline_array");
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert arrays
sdv::toml::CNodeCollection array = arrayInline.InsertArray("", "");
EXPECT_TRUE(array);
array.InsertValue("", "", 10);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[10]])toml");
array = arrayInline.InsertArray("", "");
EXPECT_TRUE(array);
array.InsertValue("", "", 20);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[10], [20]])toml");
array = arrayInline.InsertArray(arrayInline.GetNodeNameByIndex(0), "");
EXPECT_TRUE(array);
array.InsertValue("", "", 30);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[30], [10], [20]])toml");
}
TEST(InsertNode, InsertTableArrayInArray)
{
// Insert an array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection arrayInline = root.InsertArray("", "inline_array");
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [])toml");
// Insert standard table array
sdv::toml::CNodeCollection table = arrayInline.InsertTableArray("", "", false);
EXPECT_TRUE(table);
table.InsertValue("", "a", 10);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{a = 10}]])toml");
// Insert an inline table array before
table = arrayInline.InsertTableArray(arrayInline.GetNodeNameByIndex(0), "", true);
EXPECT_TRUE(table);
table.InsertValue("", "b", 20);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{b = 20}], [{a = 10}]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
table = arrayInline.InsertTableArray("", "", true);
EXPECT_TRUE(table);
table.InsertValue("", "c", 30);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{b = 20}], [{a = 10}], [{c = 30}]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
table = arrayInline.InsertTableArray(arrayInline.GetNodeNameByIndex(0), "", false);
EXPECT_TRUE(table);
table.InsertValue("", "d", 40);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{d = 40}], [{b = 20}], [{a = 10}], [{c = 30}]])toml");
// Add an additional table array entry for table array #4
sdv::toml::CNodeCollection array = arrayInline.Get(0);
EXPECT_TRUE(array);
table = array.InsertTable("", "", false);
EXPECT_TRUE(table);
table.InsertValue("", "e", 50);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(inline_array = [[{d = 40}, {e = 50}], [{b = 20}], [{a = 10}], [{c = 30}]])toml");
}
TEST(InsertNode, InsertValueInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection table = root.InsertTableArray("", "table_array", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert the values into the table
EXPECT_TRUE(table.InsertValue("", "value_int", 10));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_int = 10)toml");
EXPECT_TRUE(table.InsertValue("", "value_str", u8"abc"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_int = 10
value_str = "abc")toml");
EXPECT_TRUE(table.InsertValue(table.GetNodeNameByIndex(0), "value_float", 123.456));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_float = 123.456
value_int = 10
value_str = "abc")toml");
}
TEST(InsertNode, InsertTableInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection table = root.InsertTableArray("", "table_array", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert a standard table
EXPECT_TRUE(table.InsertTable("", "table1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
[table_array.table1])toml");
// Insert an inline table before
EXPECT_TRUE(table.InsertTable(table.GetNodeNameByIndex(0), "table2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
[table_array.table1])toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_TRUE(table.InsertTable("", "table3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
table3 = {}
[table_array.table1])toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_TRUE(table.InsertTable(table.GetNodeNameByIndex(0), "table4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table2 = {}
table3 = {}
[table_array.table4]
[table_array.table1])toml");
}
TEST(InsertNode, InsertArrayInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection table = root.InsertTableArray("", "table_array", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert arrays
EXPECT_TRUE(table.InsertArray("", "value_array1"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array1 = [])toml");
EXPECT_TRUE(table.InsertArray("", "value_array2"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array1 = []
value_array2 = [])toml");
EXPECT_TRUE(table.InsertArray(table.GetNodeNameByIndex(0), "value_array3"));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
value_array3 = []
value_array1 = []
value_array2 = [])toml");
}
TEST(InsertNode, InsertTableArrayInTableArray)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
sdv::toml::CNodeCollection table = root.InsertTableArray("", "table_array", false);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]])toml");
// Insert standard table array
EXPECT_TRUE(table.InsertTableArray("", "table_array1", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
[[table_array.table_array1]])toml");
// Insert an inline table array before
EXPECT_TRUE(table.InsertTableArray(table.GetNodeNameByIndex(0), "table_array2", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
[[table_array.table_array1]])toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_TRUE(table.InsertTableArray("", "table_array3", true));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array1]])toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_TRUE(table.InsertTableArray(table.GetNodeNameByIndex(0), "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array4]]
[[table_array.table_array1]])toml");
// Add an additional table array entry for table array #4
EXPECT_TRUE(table.InsertTableArray("", "table_array4", false));
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array]]
table_array2 = [{}]
table_array3 = [{}]
[[table_array.table_array4]]
[[table_array.table_array1]]
[[table_array.table_array4]])toml");
}
TEST(InsertNode, InsertValuesRootAsTOML)
{
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_EQ(root.InsertTOML("", R"toml(# This is the first value
value_int = 10)toml", true), 1);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is the first value
value_int = 10)toml");
EXPECT_EQ(root.InsertTOML("", R"toml(value_str = "abc" # This is the second value
# Comment in between
# And the third value
value_float = 123.456
# Some
# Final
# Words :-)
)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is the first value
value_int = 10
value_str = "abc" # This is the second value
# Comment in between
# And the third value
value_float = 123.456
# Some
# Final
# Words :-)
)toml");
}
TEST(InsertNode, InsertTableRootAsTOML)
{
// Insert a standard table
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_EQ(root.InsertTOML("", R"toml([table1] # This is table 1
a = 10
b = 20.30)toml", true), 1);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([table1] # This is table 1
a = 10
b = 20.30)toml");
// Insert an inline table before
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml(# This is table 2
table2 = {c = 40, d = "50"})toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is table 2
table2 = {c = 40, d = "50"}
[table1] # This is table 1
a = 10
b = 20.30)toml");
// Insert an inline table behind -> this will have to be printed before the standard table
EXPECT_EQ(root.InsertTOML("", R"toml(table3 = {e = '60'} # This is table 3
)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is table 2
table2 = {c = 40, d = "50"}
table3 = {e = '60'} # This is table 3
[table1] # This is table 1
a = 10
b = 20.30)toml");
// Insert a standard table in front -> this will have to be printed behind the inline table
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml(
# And this is table 4
[table4]
f = 70
g = 80.90)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is table 2
table2 = {c = 40, d = "50"}
table3 = {e = '60'} # This is table 3
# And this is table 4
[table4]
f = 70
g = 80.90
[table1] # This is table 1
a = 10
b = 20.30)toml");
}
TEST(InsertNode, InsertArrayRootAsTOML)
{
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_EQ(root.InsertTOML("", R"toml(value_array1 = [10, 20, 30] # This is array 1)toml", true),
1);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(value_array1 = [10, 20, 30] # This is array 1)toml");
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml(# This is array 2
value_array2 = [
40, # This is an integer value
50.60, # This is a float value
"70", # This is a string value
])toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is array 2
value_array2 = [
40, # This is an integer value
50.60, # This is a float value
"70", # This is a string value
]
value_array1 = [10, 20, 30] # This is array 1)toml");
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(1), R"toml(# And finally array 3
value_array3 = [])toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(# This is array 2
value_array2 = [
40, # This is an integer value
50.60, # This is a float value
"70", # This is a string value
]
# And finally array 3
value_array3 = []
value_array1 = [10, 20, 30] # This is array 1)toml");
}
TEST(InsertNode, InsertTableArrayRootAsTOML)
{
// Insert a standard table array
toml_parser::CParser parser;
sdv::toml::CNodeCollection root(&parser.Root());
EXPECT_EQ(root.InsertTOML("", R"toml([[table_array1]]
a = 10
b = 20)toml", true), 1);
std::string ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml([[table_array1]]
a = 10
b = 20)toml");
// Insert an inline table array before
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml(table_array2 = [{c = 30}, {d = 40}])toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
[[table_array1]]
a = 10
b = 20)toml");
// Insert an inline table array behind -> this will have to be printed before the standard table array
EXPECT_EQ(root.InsertTOML("", R"toml(table_array3 =
[
{ e = 50 }
])toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
table_array3 =
[
{ e = 50 }
]
[[table_array1]]
a = 10
b = 20)toml");
// Insert a standard table array in front -> this will have to be printed behind the inline table array
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml([[table_array4]]
f = 60
g = 70)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
table_array3 =
[
{ e = 50 }
]
[[table_array4]]
f = 60
g = 70
[[table_array1]]
a = 10
b = 20)toml");
// Add an additional table array entry for table array #4 (even provided as inline, must be added as standard).
EXPECT_EQ(root.InsertTOML("", R"toml(table_array4 = [{h = 80}])toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
table_array3 =
[
{ e = 50 }
]
[[table_array4]]
f = 60
g = 70
[[table_array1]]
a = 10
b = 20
[[table_array4]]
h = 80)toml");
// Add an additional table array entry for table array #4 (even provided as inline, must be added as standard).
EXPECT_EQ(root.InsertTOML("", R"toml([[table_array3]]
i = 90
[[table_array3]]
j = 100
)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(root.InsertTOML(root.GetNodeNameByIndex(0), R"toml([[table_array3]]
k = 110)toml", true), 1);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
table_array3 =
[{k = 110},
{ e = 50 },
{i = 90}, {j = 100}]
[[table_array4]]
f = 60
g = 70
[[table_array1]]
a = 10
b = 20
[[table_array4]]
h = 80)toml");
root.AutomaticFormat(true);
ssTOML = parser.GenerateTOML();
EXPECT_EQ(ssTOML, R"toml(table_array2 = [{c = 30}, {d = 40}]
table_array3 = [{k = 110}, {e = 50}, {i = 90}, {j = 100}]
[[table_array4]]
f = 60
g = 70
[[table_array1]]
a = 10
b = 20
[[table_array4]]
h = 80)toml");
}
TEST(InsertNode, DISABLED_TestInsertValueInStandardTableAsTOML)
{
//// Insert a standard table
//toml_parser::CParser parser;
//sdv::toml::INodeCollectionInsert* pStandardTable = sdv::TInterfaceAccessPtr(root.InsertTable(
// sdv::toml::npos, "standard_table", false)).
// GetInterface<sdv::toml::INodeCollectionInsert>();
//ASSERT_NE(pStandardTable, nullptr);
//std::string ssTOML = parser.GenerateTOML();
//EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
}
TEST(InsertNode, DISABLED_TestInsertTableInStandardTableAsTOML)
{
//// Insert a standard table
//toml_parser::CParser parser;
//sdv::toml::INodeCollectionInsert* pStandardTable = sdv::TInterfaceAccessPtr(root.InsertTable(
// sdv::toml::npos, "standard_table", false)).
// GetInterface<sdv::toml::INodeCollectionInsert>();
//ASSERT_NE(pStandardTable, nullptr);
//std::string ssTOML = parser.GenerateTOML();
//EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
}
TEST(InsertNode, DISABLED_TestInsertArrayInStandardTableAsTOML)
{
//// Insert a standard table
//toml_parser::CParser parser;
//sdv::toml::INodeCollectionInsert* pStandardTable = sdv::TInterfaceAccessPtr(root.InsertTable(
// sdv::toml::npos, "standard_table", false)).
// GetInterface<sdv::toml::INodeCollectionInsert>();
//ASSERT_NE(pStandardTable, nullptr);
//std::string ssTOML = parser.GenerateTOML();
//EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
}
TEST(InsertNode, DISABLED_TestInsertTableArrayInStandardTableAsTOML)
{
//// Insert a standard table
//toml_parser::CParser parser;
//sdv::toml::INodeCollectionInsert* pStandardTable = sdv::TInterfaceAccessPtr(root.InsertTable(
// sdv::toml::npos, "standard_table", false)).
// GetInterface<sdv::toml::INodeCollectionInsert>();
//ASSERT_NE(pStandardTable, nullptr);
//std::string ssTOML = parser.GenerateTOML();
//EXPECT_EQ(ssTOML, R"toml([standard_table])toml");
}
TEST(InsertNode, DISABLED_TestInsertValueInInlineTableAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableInInlineTableAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertArrayInInlineTableAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableArrayInInlineTableAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertValueInArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableInArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertArrayInArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableArrayInArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertValueInTableArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableInTableArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertArrayInTableArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertTableArrayInTableArrayAsTOML)
{}
TEST(InsertNode, DISABLED_TestInsertMixed)
{}
TEST(InsertNode, DISABLED_TestInsertMixedWithDelete)
{}

View File

@@ -15,6 +15,7 @@
#include <gtest/gtest.h>
#include <limits>
#include <functional>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/lexer_toml.h"
#include "../../../sdv_services/core/toml_parser/exception.h"
@@ -114,7 +115,7 @@
* + Exceptions thrown by the CharacterReaderare caught and result in a token_terminated-Token and no further lexing will be done
*/
TEST(TOMLLexerTest, Keys)
TEST(Lexer, Keys)
{
using namespace std::string_literals;
// U+1F92B is the Finger-On-Lips Shushing emoji with UTF-8 byte representation 0xF09FA4AB
@@ -169,7 +170,7 @@ TEST(TOMLLexerTest, Keys)
EXPECT_EQ("1234", key8.StringValue());
}
TEST(TOMLLexerTest, SyntaxToken_NewLine)
TEST(Lexer, SyntaxToken_NewLine)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -187,7 +188,7 @@ TEST(TOMLLexerTest, SyntaxToken_NewLine)
EXPECT_EQ(toml_parser::ETokenCategory::token_syntax_new_line, newLine2.Category());
}
TEST(TOMLLexerTest, SyntaxToken_Bracket)
TEST(Lexer, SyntaxToken_Bracket)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -240,7 +241,7 @@ TEST(TOMLLexerTest, SyntaxToken_Bracket)
EXPECT_EQ(toml_parser::ETokenCategory::token_syntax_table_array_close, tableArrayBracketClose.Category());
}
TEST(TOMLLexerTest, SyntaxToken_Assignment)
TEST(Lexer, SyntaxToken_Assignment)
{
using namespace std::string_literals;
toml_parser::CLexer lexerNormal(R"(
@@ -279,7 +280,7 @@ TEST(TOMLLexerTest, SyntaxToken_Assignment)
EXPECT_EQ(rValueNoSpace.StringValue(), "value");
}
TEST(TOMLLexerTest, Comments)
TEST(Lexer, Comments)
{
using namespace std::string_literals;
toml_parser::CLexer lexerNormal(R"(
@@ -414,7 +415,7 @@ TEST(TOMLLexerTest, Comments)
EXPECT_EQ(toml_parser::ETokenCategory::token_comment, rNoSpaceTableClose.Next().Category());
}
TEST(TOMLLexerTest, SyntaxToken_Dot)
TEST(Lexer, SyntaxToken_Dot)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -451,7 +452,7 @@ TEST(TOMLLexerTest, SyntaxToken_Dot)
EXPECT_EQ(toml_parser::ETokenCategory::token_syntax_dot, dot6.Category());
}
TEST(TOMLLexerTest, SyntaxToken_Braces)
TEST(Lexer, SyntaxToken_Braces)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -511,7 +512,7 @@ TEST(TOMLLexerTest, SyntaxToken_Braces)
EXPECT_EQ(toml_parser::ETokenCategory::token_key, emptyTable.Category());
}
TEST(TOMLLexerTest, SyntaxToken_ArrayTable)
TEST(Lexer, SyntaxToken_ArrayTable)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -588,7 +589,7 @@ TEST(TOMLLexerTest, SyntaxToken_ArrayTable)
EXPECT_EQ(toml_parser::ETokenCategory::token_syntax_table_array_close, tableArrayClose5.Category());
}
TEST(TOMLLexerTest, Datatype_Integer)
TEST(Lexer, Datatype_Integer)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -758,7 +759,7 @@ TEST(TOMLLexerTest, Datatype_Integer)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, intErr10.Category());
}
TEST(TOMLLexerTest, Datatype_Float)
TEST(Lexer, Datatype_Float)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -945,7 +946,7 @@ TEST(TOMLLexerTest, Datatype_Float)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, errFloat28.Category());
}
TEST(TOMLLexerTest, Datatype_Boolean)
TEST(Lexer, Datatype_Boolean)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -966,7 +967,7 @@ TEST(TOMLLexerTest, Datatype_Boolean)
EXPECT_FALSE(falseToken.BooleanValue());
}
TEST(TOMLLexerTest, Datatype_String_BasicString)
TEST(Lexer, Datatype_String_BasicString)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1045,7 +1046,7 @@ TEST(TOMLLexerTest, Datatype_String_BasicString)
EXPECT_EQ("Musical eighth note: 𝅘𝅥𝅮", string_esc9.StringValue());
}
TEST(TOMLLexerTest, Datatype_String_BasicStringMultiline)
TEST(Lexer, Datatype_String_BasicStringMultiline)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1170,7 +1171,7 @@ multiline string"""
EXPECT_EQ("Musical eighth note: 𝅘𝅥𝅮 multiline", string_esc9.StringValue());
}
TEST(TOMLLexerTest, Datatype_String_LiteralString)
TEST(Lexer, Datatype_String_LiteralString)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1208,7 +1209,7 @@ TEST(TOMLLexerTest, Datatype_String_LiteralString)
EXPECT_EQ("<\\i\\c*\\s*>", regex.StringValue());
}
TEST(TOMLLexerTest, Datatype_String_LiteralStringMultiline)
TEST(Lexer, Datatype_String_LiteralStringMultiline)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1257,27 +1258,27 @@ str = ''''That,' she said, 'is still pointless.''''
EXPECT_EQ("'That,' she said, 'is still pointless.'", str.StringValue());
}
// TEST(TOMLLexerTest, Datatype_OffsetDateTime)
// TEST(Lexer, Datatype_OffsetDateTime)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Datatype_DateTime)
// TEST(Lexer, Datatype_DateTime)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Datatype_LocalDate)
// TEST(Lexer, Datatype_LocalDate)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Datatype_LocalTime)
// TEST(Lexer, Datatype_LocalTime)
// {
// ASSERT_TRUE(false);
// }
TEST(TOMLLexerTest, Invalid_Key)
TEST(Lexer, Invalid_Key)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1306,7 +1307,7 @@ TEST(TOMLLexerTest, Invalid_Key)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, invQuotedKey3.Category());
}
TEST(TOMLLexerTest, Invalid_String)
TEST(Lexer, Invalid_String)
{
using namespace std::string_literals;
toml_parser::CLexer lexer1(R"(key1 = "invalid escape sequence \h)"s);
@@ -1332,7 +1333,7 @@ TEST(TOMLLexerTest, Invalid_String)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, invString4.Category());
}
TEST(TOMLLexerTest, Invalid_Integer)
TEST(Lexer, Invalid_Integer)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1406,7 +1407,7 @@ TEST(TOMLLexerTest, Invalid_Integer)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, invInteger15.Category());
}
TEST(TOMLLexerTest, Invalid_Float)
TEST(Lexer, Invalid_Float)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1440,7 +1441,7 @@ TEST(TOMLLexerTest, Invalid_Float)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, invFloat5.Category());
}
TEST(TOMLLexerTest, Invalid_Boolean)
TEST(Lexer, Invalid_Boolean)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1459,27 +1460,27 @@ TEST(TOMLLexerTest, Invalid_Boolean)
EXPECT_EQ(toml_parser::ETokenCategory::token_error, invBool2.Category());
}
// TEST(TOMLLexerTest, Invalid_OffsetDateTime)
// TEST(Lexer, Invalid_OffsetDateTime)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Invalid_LocalDateTime)
// TEST(Lexer, Invalid_LocalDateTime)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Invalid_LocalDate)
// TEST(Lexer, Invalid_LocalDate)
// {
// ASSERT_TRUE(false);
// }
// TEST(TOMLLexerTest, Invalid_LocalTime)
// TEST(Lexer, Invalid_LocalTime)
// {
// ASSERT_TRUE(false);
// }
TEST(TOMLLexerTest, Peek_NoAdvance)
TEST(Lexer, Peek_NoAdvance)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1500,7 +1501,7 @@ TEST(TOMLLexerTest, Peek_NoAdvance)
EXPECT_EQ(toml_parser::ETokenCategory::token_key, lexer.Peek(1).Category());
}
TEST(TOMLLexerTest, Consume_Advance)
TEST(Lexer, Consume_Advance)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1525,7 +1526,7 @@ TEST(TOMLLexerTest, Consume_Advance)
EXPECT_EQ(toml_parser::ETokenCategory::token_syntax_assignment, ptr.Category());
}
TEST(TOMLLexerTest, PeekConsume_BoundsCheck)
TEST(Lexer, PeekConsume_BoundsCheck)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"(
@@ -1544,7 +1545,7 @@ TEST(TOMLLexerTest, PeekConsume_BoundsCheck)
EXPECT_FALSE(lexer.Consume(0));
}
TEST(TOMLLexerTest, PeekConsume_EmptyInput)
TEST(Lexer, PeekConsume_EmptyInput)
{
using namespace std::string_literals;
toml_parser::CLexer lexer(R"()"s);
@@ -1555,7 +1556,7 @@ TEST(TOMLLexerTest, PeekConsume_EmptyInput)
EXPECT_FALSE(lexer.Consume(1));
}
TEST(TOMLLexerTest, ExceptionHandling)
TEST(Lexer, ExceptionHandling)
{
using namespace std::string_literals;
toml_parser::CLexer lexer;
@@ -1577,7 +1578,7 @@ TEST(TOMLLexerTest, ExceptionHandling)
EXPECT_FALSE(lexer.Consume(0));
}
TEST(TOMLLexerTest, DISABLED_RegenerateTOML)
TEST(Lexer, DISABLED_RegenerateTOML)
{
using namespace std::string_literals;
std::string ssOrginal = R"(

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include "../../../global/process_watchdog.h"
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/character_reader_utf_8.cpp"
#include "../../../sdv_services/core/toml_parser/lexer_toml.cpp"
#include "../../../sdv_services/core/toml_parser/lexer_toml_token.cpp"
@@ -21,6 +22,8 @@
#include "../../../sdv_services/core/toml_parser/parser_node_toml.cpp"
#include "../../../sdv_services/core/toml_parser/miscellaneous.cpp"
#include "../../../sdv_services/core/toml_parser/code_snippet.cpp"
#include "../../../sdv_services/core/toml_parser/parser_node_indexer.cpp"
#if defined(_WIN32) && defined(_UNICODE)
extern "C" int wmain(int argc, wchar_t* argv[])
@@ -30,6 +33,7 @@ extern "C" int main(int argc, char* argv[])
{
CProcessWatchdog watchdog;
CLocalMemMgr memmgr;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,289 @@
/********************************************************************************
* 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 implementation
********************************************************************************/
#include <functional>
#include <gtest/gtest.h>
#include <limits>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/exception.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include <support/toml.h>
TEST(MakeInline, Value)
{
std::string ssTomlIn = R"toml(value1 = 1)toml";
std::string ssTomlOut = R"toml(value1 = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, Value)
{
std::string ssTomlIn = R"toml(value1 = 1)toml";
std::string ssTomlOut = R"toml(value1 = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_FALSE(parser.Root().CanMakeStandard());
EXPECT_FALSE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, Array)
{
std::string ssTomlIn = R"toml(value1 = ["abc", "def", "ghi"])toml";
std::string ssTomlOut = R"toml(value1 = ["abc", "def", "ghi"])toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, Array)
{
std::string ssTomlIn = R"toml(value1 = ["abc", "def", "ghi"])toml";
std::string ssTomlOut = R"toml(value1 = ["abc", "def", "ghi"])toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_FALSE(parser.Root().CanMakeStandard());
EXPECT_FALSE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, StandardTable)
{
std::string ssTomlIn = R"toml([table1]
value = 1)toml";
std::string ssTomlOut = R"toml(table1 = {value = 1})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, StandardTable)
{
std::string ssTomlIn = R"toml([table1]
value = 1)toml";
std::string ssTomlOut = R"toml([table1]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, InlineTable)
{
std::string ssTomlIn = R"toml(table1 = {value = 1})toml";
std::string ssTomlOut = R"toml(table1 = {value = 1})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, InlineTable)
{
std::string ssTomlIn = R"toml(table1 = {value = 1})toml";
std::string ssTomlOut = R"toml([table1]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, StandardTableArray)
{
std::string ssTomlIn = R"toml([[table_array1]]
value = 1)toml";
std::string ssTomlOut = R"toml(table_array1 = [{value = 1}])toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, StandardTableArray)
{
std::string ssTomlIn = R"toml([[table_array1]]
value = 1)toml";
std::string ssTomlOut = R"toml([[table_array1]]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, InlineTableArray)
{
std::string ssTomlIn = R"toml(table_array1 = [{value = 1}])toml";
std::string ssTomlOut = R"toml(table_array1 = [{value = 1}])toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, InlineTableArray)
{
std::string ssTomlIn = R"toml(table_array1 = [{value = 1}])toml";
std::string ssTomlOut = R"toml([[table_array1]]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, StandardTableImplicit)
{
std::string ssTomlIn = R"toml([root_table.table1]
value = 1)toml";
std::string ssTomlOut = R"toml(root_table.table1 = {value = 1})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, StandardTableImplicit)
{
std::string ssTomlIn = R"toml([root_table.table1]
value = 1)toml";
std::string ssTomlOut = R"toml([root_table.table1]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, InlineTableImplicit)
{
std::string ssTomlIn = R"toml(root_table.table1 = {value = 1})toml";
std::string ssTomlOut = R"toml(root_table.table1 = {value = 1})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, InlineTableImplicit)
{
std::string ssTomlIn = R"toml(root_table.table1 = {value = 1})toml";
std::string ssTomlOut = R"toml([root_table.table1]
value = 1)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, StandardTableNested)
{
std::string ssTomlIn = R"toml([table1]
value1 = 1
[table1.table2]
value2 = 2
[table1.table3.table4]
value3 = 3
value4 = 4)toml";
std::string ssTomlOut = R"toml(table1 = {value1 = 1, table2 = {value2 = 2}, table3.table4 = {value3 = 3, value4 = 4}})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, StandardTableNested)
{
std::string ssTomlIn = R"toml([table1]
value = 1
[table1.table2]
value = 2)toml";
std::string ssTomlOut = R"toml([table1]
value = 1
[table1.table2]
value = 2)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeInline, InlineTableNested)
{
std::string ssTomlIn = R"toml(table1 = {value = 1, table2 = {value = 2}})toml";
std::string ssTomlOut = R"toml(table1 = {value = 1, table2 = {value = 2}})toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeInline());
EXPECT_TRUE(parser.Root().MakeInline());
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}
TEST(MakeStandard, InlineTableNested)
{
std::string ssTomlIn = R"toml(table1 = {value = 1, table2 = {value = 2}})toml";
std::string ssTomlOut = R"toml([table1]
value = 1
[table1.table2]
value = 2)toml";
toml_parser::CParser parser(ssTomlIn);
EXPECT_TRUE(parser.Root().CanMakeStandard());
EXPECT_TRUE(parser.Root().MakeStandard(true));
std::string ssOut = parser.Root().GetTOML();
EXPECT_EQ(ssTomlOut, ssOut);
}

View File

@@ -15,11 +15,16 @@
#include <functional>
#include <gtest/gtest.h>
#include <limits>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/exception.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
TEST(TOMLMiscellaneousTests, Hex2Dec)
// Test TODO:
// Shift nodes up and down within one container
// Remove formatting from node
// Compare TOMLs
TEST(Miscellaneous, Hex2Dec)
{
// No string
std::string ssEmpty;
@@ -47,7 +52,7 @@ TEST(TOMLMiscellaneousTests, Hex2Dec)
EXPECT_EQ(toml_parser::HexadecimalToDecimal("10xyz"), 16u);
}
TEST(TOMLMiscellaneousTests, Dec2Dec)
TEST(Miscellaneous, Dec2Dec)
{
// No string
std::string ssEmpty;
@@ -75,7 +80,7 @@ TEST(TOMLMiscellaneousTests, Dec2Dec)
EXPECT_EQ(toml_parser::DecimalToDecimal("10xyz"), 10u);
}
TEST(TOMLMiscellaneousTests, Oct2Dec)
TEST(Miscellaneous, Oct2Dec)
{
// No string
std::string ssEmpty;
@@ -103,7 +108,7 @@ TEST(TOMLMiscellaneousTests, Oct2Dec)
EXPECT_EQ(toml_parser::OctalToDecimal("12xyz"), 10u);
}
TEST(TOMLMiscellaneousTests, Bin2Dec)
TEST(Miscellaneous, Bin2Dec)
{
// No string
std::string ssEmpty;
@@ -131,7 +136,7 @@ TEST(TOMLMiscellaneousTests, Bin2Dec)
EXPECT_EQ(toml_parser::BinaryToDecimal("1010yz"), 10u);
}
TEST(TOMLMiscellaneousTests, UnicodeCharacter)
TEST(Miscellaneous, UnicodeCharacter)
{
// No string
std::string ssEmpty;
@@ -147,7 +152,7 @@ TEST(TOMLMiscellaneousTests, UnicodeCharacter)
EXPECT_EQ(toml_parser::EscapedUnicodeCharacterToUTF8("0001F600"), u8"\U0001F600");
}
TEST(TOMLMiscellaneousTests, SplitKeyStringEmpty)
TEST(Miscellaneous, SplitKeyStringEmpty)
{
std::string ssKeyEmpty;
auto prSplittedKey = toml_parser::SplitNodeKey(ssKeyEmpty);
@@ -155,7 +160,7 @@ TEST(TOMLMiscellaneousTests, SplitKeyStringEmpty)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitKeyFirstPartOnly)
TEST(Miscellaneous, SplitKeyFirstPartOnly)
{
std::string ssKey = "abc";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -196,7 +201,7 @@ TEST(TOMLMiscellaneousTests, SplitKeyFirstPartOnly)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitStandardBareKey)
TEST(Miscellaneous, SplitStandardBareKey)
{
std::string ssKey = "abc.def";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -236,7 +241,7 @@ TEST(TOMLMiscellaneousTests, SplitStandardBareKey)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitBareKeyWithSpace)
TEST(Miscellaneous, SplitBareKeyWithSpace)
{
std::string ssKey = " abc.def";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -265,7 +270,7 @@ TEST(TOMLMiscellaneousTests, SplitBareKeyWithSpace)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitLiteralKey)
TEST(Miscellaneous, SplitLiteralKey)
{
std::string ssKey = "'abc'";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -309,7 +314,7 @@ TEST(TOMLMiscellaneousTests, SplitLiteralKey)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitQuotedKey)
TEST(Miscellaneous, SplitQuotedKey)
{
std::string ssKey = "\"abc\"";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -348,7 +353,7 @@ TEST(TOMLMiscellaneousTests, SplitQuotedKey)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitEscapedQuotedKey)
TEST(Miscellaneous, SplitEscapedQuotedKey)
{
std::string ssKey = "\"abc\\bdef\"";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -413,7 +418,7 @@ TEST(TOMLMiscellaneousTests, SplitEscapedQuotedKey)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SplitTableKey)
TEST(Miscellaneous, SplitTableKey)
{
std::string ssKey = "abc.def";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -431,7 +436,7 @@ TEST(TOMLMiscellaneousTests, SplitTableKey)
EXPECT_EQ(prSplittedKey.second, "def.ghi");
}
TEST(TOMLMiscellaneousTests, SplitArrayKey)
TEST(Miscellaneous, SplitArrayKey)
{
std::string ssKey = "abc[1]";
auto prSplittedKey = toml_parser::SplitNodeKey(ssKey);
@@ -493,7 +498,7 @@ TEST(TOMLMiscellaneousTests, SplitArrayKey)
EXPECT_TRUE(prSplittedKey.second.empty());
}
TEST(TOMLMiscellaneousTests, SmartQuoteBareKeys)
TEST(Miscellaneous, SmartQuoteBareKeys)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::smart_key), "abc");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::smart_key), "123");
@@ -502,7 +507,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteBareKeys)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::smart_key), "ABC-DEF");
}
TEST(TOMLMiscellaneousTests, SmartQuoteSpecialCharsKeys)
TEST(Miscellaneous, SmartQuoteSpecialCharsKeys)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::smart_key), "\"\"");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::smart_key), "\"abc def\"");
@@ -515,7 +520,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteSpecialCharsKeys)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::smart_key), "\"abc/\"");
}
TEST(TOMLMiscellaneousTests, SmartQuoteEscapeCharsKeys)
TEST(Miscellaneous, SmartQuoteEscapeCharsKeys)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::smart_key), "\"abc\\tdef\"");
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::smart_key), "\"abc\\\\def\"");
@@ -527,7 +532,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteEscapeCharsKeys)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::smart_key), "\"abc\\rdef\"");
}
TEST(TOMLMiscellaneousTests, SmartQuoteControlCharsKeys)
TEST(Miscellaneous, SmartQuoteControlCharsKeys)
{
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::smart_key), "\"\\u0000\"");
EXPECT_EQ(toml_parser::QuoteText("\u0001", toml_parser::EQuoteRequest::smart_key), "\"\\u0001\"");
@@ -567,7 +572,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteControlCharsKeys)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, SmartQuoteText)
TEST(Miscellaneous, SmartQuoteText)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::smart_text), "\"abc\"");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::smart_text), "\"123\"");
@@ -576,7 +581,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteText)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::smart_text), "\"ABC-DEF\"");
}
TEST(TOMLMiscellaneousTests, SmartQuoteSpecialCharsText)
TEST(Miscellaneous, SmartQuoteSpecialCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::smart_text), "\"\"");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::smart_text), "\"abc def\"");
@@ -589,7 +594,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteSpecialCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::smart_text), "\"abc/\"");
}
TEST(TOMLMiscellaneousTests, SmartQuoteEscapeCharsText)
TEST(Miscellaneous, SmartQuoteEscapeCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::smart_text), "\"abc\\tdef\"");
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::smart_text), "'abc\\def'");
@@ -601,7 +606,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteEscapeCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::smart_text), "\"abc\\rdef\"");
}
TEST(TOMLMiscellaneousTests, SmartQuoteControlCharsText)
TEST(Miscellaneous, SmartQuoteControlCharsText)
{
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::smart_text), "\"\\u0000\"");
EXPECT_EQ(toml_parser::QuoteText("\u0001", toml_parser::EQuoteRequest::smart_text), "\"\\u0001\"");
@@ -641,7 +646,7 @@ TEST(TOMLMiscellaneousTests, SmartQuoteControlCharsText)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, QuotedText)
TEST(Miscellaneous, QuotedText)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::quoted_text), "\"abc\"");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::quoted_text), "\"123\"");
@@ -650,7 +655,7 @@ TEST(TOMLMiscellaneousTests, QuotedText)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::quoted_text), "\"ABC-DEF\"");
}
TEST(TOMLMiscellaneousTests, QuotedSpecialCharsText)
TEST(Miscellaneous, QuotedSpecialCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::quoted_text), "\"\"");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::quoted_text), "\"abc def\"");
@@ -663,7 +668,7 @@ TEST(TOMLMiscellaneousTests, QuotedSpecialCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::quoted_text), "\"abc/\"");
}
TEST(TOMLMiscellaneousTests, QuotedEscapeCharsText)
TEST(Miscellaneous, QuotedEscapeCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::quoted_text), "\"abc\\tdef\"");
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::quoted_text), "\"abc\\\\def\"");
@@ -675,7 +680,7 @@ TEST(TOMLMiscellaneousTests, QuotedEscapeCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::quoted_text), "\"abc\\rdef\"");
}
TEST(TOMLMiscellaneousTests, QuotedControlCharsText)
TEST(Miscellaneous, QuotedControlCharsText)
{
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::quoted_text), "\"\\u0000\"");
EXPECT_EQ(toml_parser::QuoteText("\u0001", toml_parser::EQuoteRequest::quoted_text), "\"\\u0001\"");
@@ -715,7 +720,7 @@ TEST(TOMLMiscellaneousTests, QuotedControlCharsText)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, LiteralText)
TEST(Miscellaneous, LiteralText)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::literal_text), "'abc'");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::literal_text), "'123'");
@@ -724,7 +729,7 @@ TEST(TOMLMiscellaneousTests, LiteralText)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::literal_text), "'ABC-DEF'");
}
TEST(TOMLMiscellaneousTests, LiteralSpecialCharsText)
TEST(Miscellaneous, LiteralSpecialCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::literal_text), "''");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::literal_text), "'abc def'");
@@ -737,7 +742,7 @@ TEST(TOMLMiscellaneousTests, LiteralSpecialCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::literal_text), "'abc/'");
}
TEST(TOMLMiscellaneousTests, LiteralEscapeCharsText)
TEST(Miscellaneous, LiteralEscapeCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::literal_text), "\"abc\\tdef\""); // Becomes quoted
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::literal_text), "'abc\\def'");
@@ -749,7 +754,7 @@ TEST(TOMLMiscellaneousTests, LiteralEscapeCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::literal_text), "\"abc\\rdef\""); // Becomes quoted
}
TEST(TOMLMiscellaneousTests, LiteralControlCharsText)
TEST(Miscellaneous, LiteralControlCharsText)
{
// All become quoted insteda of literal (due to control character).
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::literal_text), "\"\\u0000\"");
@@ -790,7 +795,7 @@ TEST(TOMLMiscellaneousTests, LiteralControlCharsText)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, MultiLineQuotedText)
TEST(Miscellaneous, MultiLineQuotedText)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc\"\"\"");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"123\"\"\"");
@@ -799,7 +804,7 @@ TEST(TOMLMiscellaneousTests, MultiLineQuotedText)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"ABC-DEF\"\"\"");
}
TEST(TOMLMiscellaneousTests, MultiLineQuotedSpecialCharsText)
TEST(Miscellaneous, MultiLineQuotedSpecialCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"\"\"\"");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc def\"\"\"");
@@ -812,7 +817,7 @@ TEST(TOMLMiscellaneousTests, MultiLineQuotedSpecialCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc/\"\"\"");
}
TEST(TOMLMiscellaneousTests, MultiLineQuotedEscapeCharsText)
TEST(Miscellaneous, MultiLineQuotedEscapeCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc\\tdef\"\"\"");
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc\\\\def\"\"\"");
@@ -826,7 +831,7 @@ TEST(TOMLMiscellaneousTests, MultiLineQuotedEscapeCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"abc\rdef\"\"\"");
}
TEST(TOMLMiscellaneousTests, MultiLineQuotedControlCharsText)
TEST(Miscellaneous, MultiLineQuotedControlCharsText)
{
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"\\u0000\"\"\"");
EXPECT_EQ(toml_parser::QuoteText("\u0001", toml_parser::EQuoteRequest::multi_line_quoted_text), "\"\"\"\\u0001\"\"\"");
@@ -866,7 +871,7 @@ TEST(TOMLMiscellaneousTests, MultiLineQuotedControlCharsText)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, MultiLineLiteralText)
TEST(Miscellaneous, MultiLineLiteralText)
{
EXPECT_EQ(toml_parser::QuoteText("abc", toml_parser::EQuoteRequest::multi_line_literal_text), "'''abc'''");
EXPECT_EQ(toml_parser::QuoteText("123", toml_parser::EQuoteRequest::multi_line_literal_text), "'''123'''");
@@ -875,7 +880,7 @@ TEST(TOMLMiscellaneousTests, MultiLineLiteralText)
EXPECT_EQ(toml_parser::QuoteText("ABC-DEF", toml_parser::EQuoteRequest::multi_line_literal_text), "'''ABC-DEF'''");
}
TEST(TOMLMiscellaneousTests, MultiLineLiteralSpecialCharsText)
TEST(Miscellaneous, MultiLineLiteralSpecialCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("", toml_parser::EQuoteRequest::multi_line_literal_text), "''''''");
EXPECT_EQ(toml_parser::QuoteText("abc def", toml_parser::EQuoteRequest::multi_line_literal_text), "'''abc def'''");
@@ -888,7 +893,7 @@ TEST(TOMLMiscellaneousTests, MultiLineLiteralSpecialCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc/", toml_parser::EQuoteRequest::multi_line_literal_text), "'''abc/'''");
}
TEST(TOMLMiscellaneousTests, MultiLineLiteralEscapeCharsText)
TEST(Miscellaneous, MultiLineLiteralEscapeCharsText)
{
EXPECT_EQ(toml_parser::QuoteText("abc\tdef", toml_parser::EQuoteRequest::multi_line_literal_text), "\"\"\"abc\\tdef\"\"\""); // Becomes quoted
EXPECT_EQ(toml_parser::QuoteText("abc\\def", toml_parser::EQuoteRequest::multi_line_literal_text), "'''abc\\def'''");
@@ -901,7 +906,7 @@ TEST(TOMLMiscellaneousTests, MultiLineLiteralEscapeCharsText)
EXPECT_EQ(toml_parser::QuoteText("abc\rdef", toml_parser::EQuoteRequest::multi_line_literal_text), "'''abc\rdef'''");
}
TEST(TOMLMiscellaneousTests, MultiLineLiteralControlCharsText)
TEST(Miscellaneous, MultiLineLiteralControlCharsText)
{
// All become quoted insteda of literal (due to control character).
EXPECT_EQ(toml_parser::QuoteText(std::string(1, '\0'), toml_parser::EQuoteRequest::multi_line_literal_text), "\"\"\"\\u0000\"\"\"");
@@ -942,7 +947,7 @@ TEST(TOMLMiscellaneousTests, MultiLineLiteralControlCharsText)
// 0080... and higher are treated as unicode character (quotation needed)
}
TEST(TOMLMiscellaneousTests, ExtractBareKeyName)
TEST(Miscellaneous, ExtractBareKeyName)
{
EXPECT_EQ(toml_parser::ExtractKeyName(""), "");
EXPECT_EQ(toml_parser::ExtractKeyName("abc.def"), "def");
@@ -955,7 +960,7 @@ TEST(TOMLMiscellaneousTests, ExtractBareKeyName)
EXPECT_EQ(toml_parser::ExtractKeyName("1234"), "1234");
}
TEST(TOMLMiscellaneousTests, ExtractQuotedKeyName)
TEST(Miscellaneous, ExtractQuotedKeyName)
{
EXPECT_EQ(toml_parser::ExtractKeyName("\"\""), "");
EXPECT_EQ(toml_parser::ExtractKeyName("\"abc\""), "abc");
@@ -968,7 +973,7 @@ TEST(TOMLMiscellaneousTests, ExtractQuotedKeyName)
EXPECT_EQ(toml_parser::ExtractKeyName("abc\"def\""), ""); // Failure
}
TEST(TOMLMiscellaneousTests, ExtractLiteralKeyName)
TEST(Miscellaneous, ExtractLiteralKeyName)
{
EXPECT_EQ(toml_parser::ExtractKeyName("''"), "");
EXPECT_EQ(toml_parser::ExtractKeyName("'abc'"), "abc");
@@ -982,7 +987,7 @@ TEST(TOMLMiscellaneousTests, ExtractLiteralKeyName)
EXPECT_EQ(toml_parser::ExtractKeyName("abc'def"), ""); // Failure
}
TEST(TOMLMiscellaneousTests, ExtractIndexKeyName)
TEST(Miscellaneous, ExtractIndexKeyName)
{
EXPECT_EQ(toml_parser::ExtractKeyName("[0]"), "0");
EXPECT_EQ(toml_parser::ExtractKeyName("[0][1]"), "1");

View File

@@ -13,6 +13,7 @@
********************************************************************************/
#include <gtest/gtest.h>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/parser_toml.h"
#include "../../../sdv_services/core/toml_parser/parser_node_toml.h"
@@ -444,32 +445,32 @@ TEST(NestedContent, InlineTable)
TEST(NestedContent, InlineTableBreakLine)
{
// The following are not allowed
EXPECT_THROW(toml_parser::CParser(R"code(
EXPECT_THROW(toml_parser::CParser(R"toml(
table = { a = 1, b = 2,
c = 3, d = 4 }
)code"), sdv::toml::XTOMLParseException);
EXPECT_THROW(toml_parser::CParser(R"code(
)toml"), sdv::toml::XTOMLParseException);
EXPECT_THROW(toml_parser::CParser(R"toml(
table = { a = 1, b = 2
,c = 3, d = 4 }
)code"), sdv::toml::XTOMLParseException);
)toml"), sdv::toml::XTOMLParseException);
// Line breaks are allowed when part of an array or have multi-line strings
EXPECT_NO_THROW(toml_parser::CParser(R"code(
EXPECT_NO_THROW(toml_parser::CParser(R"toml(
array = [{ a = 1, b = 2},
{c = 3, d = 4}]
)code"));
EXPECT_NO_THROW(toml_parser::CParser(R"code(
)toml"));
EXPECT_NO_THROW(toml_parser::CParser(R"toml(
table = { a = 1, b = [2, 3,
4, 5], c = 6, d = 7}
)code"));
EXPECT_NO_THROW(toml_parser::CParser(R"code(
)toml"));
EXPECT_NO_THROW(toml_parser::CParser(R"toml(
table = { x = "abc", y = """def-
ghi""", z = "jkl" }
)code"));
EXPECT_NO_THROW(toml_parser::CParser(R"code(
)toml"));
EXPECT_NO_THROW(toml_parser::CParser(R"toml(
table = { x = 'abc', y = '''def-
ghi''', z = 'jkl' }
)code"));
)toml"));
}
TEST(SpecialCases, Keys)
@@ -865,6 +866,60 @@ TEST(Ordering, TableAray)
EXPECT_EQ(ptrArray->Get(uiIndex)->Cast<toml_parser::CTable>()->Direct("a")->GetValue(), (int64_t) uiIndex);
}
TEST(Ordering, TableArayWithTables)
{
using namespace std::string_literals;
toml_parser::CParser parser(R"(
[topTable]
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 0
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 1
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 2
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 3
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 4
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 5
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 6
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 7
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 8
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 9
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 10
[[topTable.tableArray]]
[topTable.tableArray.MyTable]
a = 11
)"s);
auto tableArray = parser.Root().Direct("topTable.tableArray");
ASSERT_NE(tableArray, nullptr);
auto ptrArray = tableArray->Cast<toml_parser::CArray>();
EXPECT_EQ(ptrArray->GetCount(), 12u);
for (uint32_t uiIndex = 0; uiIndex < ptrArray->GetCount(); uiIndex++)
{
EXPECT_EQ(ptrArray->Get(uiIndex)->Cast<toml_parser::CTable>()->Direct("MyTable.a")->GetValue(), (int64_t)uiIndex);
}
}
TEST(Ordering, NodeGetDirect)
{
using namespace std::string_literals;

View File

@@ -14,6 +14,7 @@
#include <gtest/gtest.h>
#include <limits>
#include <functional>
#include "../../../global/localmemmgr.h"
#include "../../../sdv_services/core/toml_parser/lexer_toml.h"
#include "../../../sdv_services/core/toml_parser/exception.h"
#include "../../../sdv_services/core/toml_parser/miscellaneous.h"
@@ -445,7 +446,7 @@ bool FindAndExtendToken(toml_parser::CLexer& rlexer, const std::string& rssKey,
return false; // When coming here, the key was not found
}
TEST(TOMLLexerStatementBoundaryTests, CheckEmptyRange)
TEST(StatementBoundary, CheckEmptyRange)
{
std::string ssEmpty;
@@ -459,11 +460,11 @@ TEST(TOMLLexerStatementBoundaryTests, CheckEmptyRange)
EXPECT_THROW(lexerEmpty.SmartExtendNodeRange(rangeEmpty), sdv::toml::XTOMLParseException);
}
TEST(TOMLLexerStatementBoundaryTests, CheckInvalidRange)
TEST(StatementBoundary, CheckInvalidRange)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_a = 10
)code";
)toml";
std::string ssOther = ssCode;
// Process the code
@@ -477,11 +478,11 @@ token_a = 10
EXPECT_THROW(lexerCode.SmartExtendNodeRange(rangeOther), sdv::toml::XTOMLParseException);
}
TEST(TOMLLexerStatementBoundaryTests, StandardIntegerAssignment)
TEST(StatementBoundary, StandardIntegerAssignment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_a = 10
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -497,11 +498,11 @@ token_a = 10
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, StandardStringAssignment)
TEST(StatementBoundary, StandardStringAssignment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_b = "abc"
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -516,16 +517,16 @@ token_b = "abc"
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentWithIndependentComment)
TEST(StatementBoundary, AssignmentWithIndependentComment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_c = 30.1
# middle followed by double lines
token_d = "def"
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -541,9 +542,9 @@ token_d = "def"
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentCommentsNotPartOfIt)
TEST(StatementBoundary, AssignmentCommentsNotPartOfIt)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_c = 30.1
# middle followed by double lines
@@ -554,7 +555,7 @@ token_d = "def"
# before
# more before
token_e = [10, 20, 30]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -570,9 +571,9 @@ token_e = [10, 20, 30]
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, ArrayAssignmentWithPreceedingComment)
TEST(StatementBoundary, ArrayAssignmentWithPreceedingComment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_d = "def"
# before
@@ -581,7 +582,7 @@ token_e = [10, 20, 30]
token_f = "ghi" # after
# more after
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -609,14 +610,14 @@ token_f = "ghi" # after
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentWithFollowingComment)
TEST(StatementBoundary, AssignmentWithFollowingComment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_f = "ghi" # after
# more after
# belonging to next
[token_g]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -636,9 +637,9 @@ token_f = "ghi" # after
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentWithFollowingComment2)
TEST(StatementBoundary, AssignmentWithFollowingComment2)
{
std::string ssTOML = R"code(
std::string ssTOML = R"toml(
# This is a separate comment with several line-breaks before.
@@ -661,7 +662,7 @@ value = "this is the value text" # Comment following the value.
# This is also a separate comment.
# Followed by this text on the same line.
# And another text on a separate line.)code";
# And another text on a separate line.)toml";
// Process the code
toml_parser::CLexer lexerCode(ssTOML);
@@ -701,15 +702,15 @@ value = "this is the value text" # Comment following the value.
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, TableAssignmentWithDedicatedComment)
TEST(StatementBoundary, TableAssignmentWithDedicatedComment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_f = "ghi" # after
# more after
# belonging to next
[token_g]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -725,14 +726,14 @@ token_f = "ghi" # after
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentWithFollowingCommentWithoutIndentation)
TEST(StatementBoundary, AssignmentWithFollowingCommentWithoutIndentation)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_h = "jkl"#after without whitespace
# more after due to following empty line
[token_i]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -751,16 +752,16 @@ token_h = "jkl"#after without whitespace
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, AssignmentCommentsExcluded)
TEST(StatementBoundary, AssignmentCommentsExcluded)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_h = "jkl"#after without whitespace
# more after due to following empty line
[token_i]
# not after
token_j = 20
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -773,13 +774,13 @@ token_j = 20
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, SmartExtendTokenRange)
TEST(StatementBoundary, SmartExtendTokenRange)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
[token_i]
# not after
token_j = 20
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -796,12 +797,12 @@ token_j = 20
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, StandardAssignmentWithIndentation)
TEST(StatementBoundary, StandardAssignmentWithIndentation)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_k = 30
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -818,11 +819,11 @@ TEST(TOMLLexerStatementBoundaryTests, StandardAssignmentWithIndentation)
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, ArrayOfStringsAssignment)
TEST(StatementBoundary, ArrayOfStringsAssignment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_l = ["abc", "def", "ghi"]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -846,16 +847,16 @@ TEST(TOMLLexerStatementBoundaryTests, ArrayOfStringsAssignment)
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, InlineTableAssignmentWithIndependentComment)
TEST(StatementBoundary, InlineTableAssignmentWithIndependentComment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_m = {x = 10, str = "gfh"}
# middle followed by double newlines
token_n = 100
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -885,9 +886,9 @@ TEST(TOMLLexerStatementBoundaryTests, InlineTableAssignmentWithIndependentCommen
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentNoComments)
TEST(StatementBoundary, IndentedAssignmentNoComments)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
# begin followed by double newlines
@@ -896,7 +897,7 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentNoComments)
# before
# more before
token_o = 123.456
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -913,15 +914,15 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentNoComments)
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentWithCommentsBefore)
TEST(StatementBoundary, IndentedAssignmentWithCommentsBefore)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
# before
# more before
token_o = 123.456
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -944,15 +945,15 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentWithCommentsBefore)
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedBooleanArrayAssignmentWithDedicatedComments)
TEST(StatementBoundary, IndentedBooleanArrayAssignmentWithDedicatedComments)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_p = [true, false] # after
# more after
# belonging to next
token_q = "next"
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -978,15 +979,15 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedBooleanArrayAssignmentWithDedicate
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentWithDedicatedCommentsBefore)
TEST(StatementBoundary, IndentedAssignmentWithDedicatedCommentsBefore)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_p = [true, false] # after
# more after
# belonging to next
token_q = "next"
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1006,14 +1007,14 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentWithDedicatedCommentsBef
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentFollowedByCommentWithoutSpace)
TEST(StatementBoundary, IndentedAssignmentFollowedByCommentWithoutSpace)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
token_r =987#after without whitespace
# more after due to following empty line
[token_s]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1033,13 +1034,13 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedAssignmentFollowedByCommentWithout
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedTableWithoutComments)
TEST(StatementBoundary, IndentedTableWithoutComments)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
[token_s]
# not after
[token_t]
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1053,16 +1054,16 @@ TEST(TOMLLexerStatementBoundaryTests, IndentedTableWithoutComments)
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, IndentedTableWithAndWithoutComments)
TEST(StatementBoundary, IndentedTableWithAndWithoutComments)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
[token_s]
# not after
[token_t]
# comment before a table member (belongs to token_bb)
token_u.token_aa.token_bb = 10 # table token_u has a table token_aa which has a value token_bb
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1080,12 +1081,12 @@ token_u.token_aa.token_bb = 10 # table token_u has a table token_aa which ha
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, InlineTableWithParentChildAssignment)
TEST(StatementBoundary, InlineTableWithParentChildAssignment)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
# comment before a table member (belongs to token_bb)
token_u.token_aa.token_bb = 10 # table token_u has a table token_aa which has a value token_bb
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1116,9 +1117,9 @@ token_u.token_aa.token_bb = 10 # table token_u has a table token_aa which ha
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, ComplexInlineTableWithParentChildAssignmentOfTablesAndMultiDimensionalArrays)
TEST(StatementBoundary, ComplexInlineTableWithParentChildAssignmentOfTablesAndMultiDimensionalArrays)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
# Super inline table with sub-tables and arrays
token_u.token_aa.token_cc = { dd = { ee = 10, ff = 11 }, # this is the comment for dd
gg = [{hh = 1, ii = 2},
@@ -1128,7 +1129,7 @@ token_u.token_aa.token_cc = { dd = { ee = 10, ff = 11 }, # this is the commen
# and this as well
jj = [["abc", "def"], [1, 2, 3], []]}
)code";
)toml";
// NOTE EVE 22.10.2025: the value token_u.token_aa.token_cc.jj is the last value in the table. This means that the scope of
// the value included the comma before the value jj (following value gg). This has the consequence, that the comments, which
@@ -1292,9 +1293,9 @@ token_u.token_aa.token_cc = { dd = { ee = 10, ff = 11 }, # this is the commen
toml_parser::ETokenCategory::token_syntax_array_close}));
}
TEST(TOMLLexerStatementBoundaryTests, ArrayOfTables)
TEST(StatementBoundary, ArrayOfTables)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
[[token_v]]
token_kk = 10
token_ll = 20
@@ -1303,7 +1304,7 @@ token_mm = 30
[[token_v]]
token_kk = 110
token_ll = 120
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);
@@ -1316,15 +1317,15 @@ token_ll = 120
toml_parser::ETokenCategory::token_syntax_new_line}));
}
TEST(TOMLLexerStatementBoundaryTests, ParentChildTable)
TEST(StatementBoundary, ParentChildTable)
{
std::string ssCode = R"code(
std::string ssCode = R"toml(
[[token_v]]
token_kk = 110
token_ll = 120
# Comments before (belongs ot child only)
[token_x.token_nn] # Comments following (belongs to child only)
)code";
)toml";
// Process the code
toml_parser::CLexer lexerCode(ssCode);

View File

@@ -417,7 +417,7 @@ TEST(TraceFifoTest, Simple_Stream_Monitor)
{
std::stringstream sstreamWriter;
CTraceFifoStreamBuffer fifoWriterStreamBuf(9999);
fifoWriterStreamBuf.Open(1000, static_cast<uint32_t>(ETraceFifoOpenFlags::force_create));
fifoWriterStreamBuf.Open(5000, static_cast<uint32_t>(ETraceFifoOpenFlags::force_create));
EXPECT_TRUE(fifoWriterStreamBuf.IsOpened());
fifoWriterStreamBuf.InterceptStream(sstreamWriter);
CTraceFifoReader fifoReader(9999);

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
#*******************************************************************************
# Define project
project(UniqueIDTests VERSION 1.0 LANGUAGES CXX)
# Define target
add_executable(UnitTest_UniqueID unique_id_test.cpp)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
target_link_libraries(UnitTest_UniqueID GTest::GTest)
if (WIN32)
target_link_libraries(UnitTest_UniqueID Ws2_32 Winmm Rpcrt4.lib)
else()
target_link_libraries(UnitTest_UniqueID ${CMAKE_DL_LIBS} rt)
endif()
else()
target_link_libraries(UnitTest_UniqueID GTest::GTest Rpcrt4.lib)
endif()
# Add the test
add_test(NAME UnitTest_UniqueID COMMAND UnitTest_UniqueID WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
# Execute the test
add_custom_command(TARGET UnitTest_UniqueID POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake "$<TARGET_FILE:UnitTest_UniqueID>" --gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_UniqueID.xml
VERBATIM
)
# The unit-test project depends on a proper compilation of sdv components before
add_dependencies(UnitTest_UniqueID dependency_sdv_components)

View File

@@ -0,0 +1,85 @@
/********************************************************************************
* 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 <fstream>
#include <gtest/gtest.h>
#include "../../../global/process_watchdog.h"
#include "../../../global/unique_id.h"
#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;
testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}
TEST(UniqueID, TestSmallID)
{
CUniqueID<int, 4> generator;
// Max 15 ids possible
std::set<int> setUsed;
int iNumber;
for (size_t n = 0; n < 15; n++)
{
iNumber = generator.Generate();
EXPECT_NE(iNumber, 0);
EXPECT_EQ(setUsed.find(iNumber), setUsed.end());
setUsed.insert(iNumber);
}
// One more ID should fail
iNumber = generator.Generate();
EXPECT_EQ(iNumber, 0);
}
TEST(UniqueID, TestSmallID2)
{
CUniqueID<uint8_t> generator;
// Max 255 ids possible
std::set<uint32_t> setUsed;
uint32_t uiNumber = 0;
for (size_t n = 0; n < 255; n++)
{
uiNumber = generator.Generate();
EXPECT_NE(uiNumber, 0u);
EXPECT_EQ(setUsed.find(uiNumber), setUsed.end());
setUsed.insert(uiNumber);
}
// One more ID should fail
uiNumber = generator.Generate();
EXPECT_EQ(uiNumber, 0u);
}
TEST(UniqueID, TestLargeID)
{
CUniqueID<uint64_t> generator;
// Run at the most 20000 times and check whether the number occurs multiple times
std::set<uint64_t> setUsed;
uint64_t uiNumber;
for (size_t n = 0; n < 20000; n++)
{
uiNumber = generator.Generate();
EXPECT_NE(uiNumber, 0u);
EXPECT_EQ(setUsed.find(uiNumber), setUsed.end());
setUsed.insert(uiNumber);
}
}

View File

@@ -33,7 +33,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
${CMAKE_THREAD_LIBS_INIT}
stdc++fs ${CMAKE_DL_LIBS}
rt
uds_unix_sockets
uds_unix_sockets_static
)
else()
target_link_libraries(UnitTest_UnixSocketConnectTests
@@ -41,7 +41,7 @@ else()
Ws2_32
Winmm
Rpcrt4.lib
uds_unix_sockets
uds_unix_sockets_static
)
endif()
@@ -50,13 +50,11 @@ add_test(NAME UnitTest_UnixSocketConnectTests
add_dependencies(UnitTest_UnixSocketConnectTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_UnixSocketConnectTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_UnixSocketConnectTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_UnixSocketConnectTests.xml
VERBATIM
)
endif()
endif()

View File

@@ -204,6 +204,25 @@ private:
// Small helper: convert server connectString to client connectString
static std::string MakeClientCS(std::string cs)
{
const std::string providerKey = "ConnectString = \"";
auto p = cs.find(providerKey);
if (p != std::string::npos)
{
p += providerKey.size();
auto e = cs.find('"', p);
if (e != std::string::npos)
{
std::string inner = cs.substr(p, e - p);
const std::string fromIn = "role=server";
const std::string toIn = "role=client";
auto posIn = inner.find(fromIn);
if (posIn != std::string::npos)
inner.replace(posIn, fromIn.size(), toIn);
cs.replace(p, e - p, inner);
return cs;
}
}
const std::string from = "role=server";
const std::string to = "role=client";
auto pos = cs.find(from);
@@ -215,6 +234,27 @@ static std::string MakeClientCS(std::string cs)
static std::string ExtractPathFromCS(const std::string& cs)
{
const std::string providerKey = "ConnectString = \"";
auto pProvider = cs.find(providerKey);
if (pProvider != std::string::npos)
{
pProvider += providerKey.size();
auto eProvider = cs.find('"', pProvider);
if (eProvider != std::string::npos)
{
std::string inner = cs.substr(pProvider, eProvider - pProvider);
const std::string keyInner = "path=";
auto pInner = inner.find(keyInner);
if (pInner != std::string::npos)
{
auto startInner = pInner + keyInner.size();
auto endInner = inner.find(';', startInner);
if (endInner == std::string::npos) endInner = inner.size();
return inner.substr(startInner, endInner - startInner);
}
}
}
// search "path=" in connect-string
const std::string key = "path=";
auto p = cs.find(key);
@@ -225,6 +265,21 @@ static std::string ExtractPathFromCS(const std::string& cs)
return cs.substr(start, end - start);
}
static std::string MakeServerCS(const std::string& cs)
{
const std::string path = ExtractPathFromCS(cs);
if (!path.empty())
return "proto=uds;role=server;path=" + path + ";";
std::string raw = cs;
const std::string from = "role=client";
const std::string to = "role=server";
auto pos = raw.find(from);
if (pos != std::string::npos)
raw.replace(pos, from.size(), to);
return raw;
}
static std::string MakeRandomSuffix()
{
std::mt19937_64 rng{std::random_device{}()};
@@ -241,7 +296,7 @@ TEST(UnixSocketIPC, Instantiate)
ASSERT_TRUE(appcontrol.Startup(""));
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
@@ -258,7 +313,7 @@ TEST(UnixSocketIPC, ChannelConfigString)
ASSERT_TRUE(appcontrol.Startup(""));
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
@@ -275,7 +330,7 @@ TEST(UnixSocketIPC, CreateRandomEndpoint)
CUnixDomainSocketsChannelMgnt mgr;
// Create an endpoint.
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
sdv::ipc::SChannelEndpoint sChannelEndpoint = mgr.CreateEndpoint("");
EXPECT_NE(sChannelEndpoint.pConnection, nullptr);
@@ -297,7 +352,7 @@ TEST(UnixSocketIPC, BasicConnectDisconnect)
// Create and initialize UDS manager
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -305,7 +360,7 @@ TEST(UnixSocketIPC, BasicConnectDisconnect)
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
std::string serverCS = ep.ssConnectString;
std::string serverCS = MakeServerCS(ep.ssConnectString);
std::string clientCS = MakeClientCS(serverCS);
// SERVER SIDE
@@ -321,7 +376,7 @@ TEST(UnixSocketIPC, BasicConnectDisconnect)
// CLIENT SIDE (thread)
std::atomic<int> clientResult{0};
std::atomic<bool> allowClientDisconnect{false};
std::thread clientThread([&]{
sdv::core::secure_thread clientThread([&]{
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
if (!clientObj) { clientResult = 1; return; }
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
@@ -354,6 +409,9 @@ TEST(UnixSocketIPC, BasicConnectDisconnect)
serverConn->Disconnect();
EXPECT_EQ(serverConn->GetConnectState(), sdv::ipc::EConnectState::disconnected);
// Release object wrappers before shutting down the manager/framework.
serverObj.Clear();
// Shutdown Manager / Framework
EXPECT_NO_THROW(mgr.Shutdown());
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::destruction_pending);
@@ -372,7 +430,7 @@ TEST(UnixSocketIPC, ReconnectAfterDisconnect_SamePath)
//UDS manager
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -380,7 +438,7 @@ TEST(UnixSocketIPC, ReconnectAfterDisconnect_SamePath)
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
// SESSION 1
@@ -397,7 +455,7 @@ TEST(UnixSocketIPC, ReconnectAfterDisconnect_SamePath)
std::atomic<int> clientResult{0};
std::atomic<bool> allowClientDisconnect{false};
std::thread clientThread([&]{
sdv::core::secure_thread clientThread([&]{
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
if (!clientObj) { clientResult = 1; return; }
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
@@ -444,7 +502,7 @@ TEST(UnixSocketIPC, ReconnectAfterDisconnect_SamePath)
std::atomic<int> clientResult2{0};
std::atomic<bool> allowClientDisconnect2{false};
std::thread clientThread2([&]{
sdv::core::secure_thread clientThread2([&]{
sdv::TObjectPtr clientObj2 = mgr.Access(clientCS);
if (!clientObj2) { clientResult2 = 1; return; }
auto* clientConn2 = clientObj2.GetInterface<sdv::ipc::IConnect>();
@@ -490,7 +548,7 @@ TEST(UnixSocketIPC, OperationModeTransitions)
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
// configuring and then running
@@ -514,7 +572,7 @@ TEST(UnixSocketIPC, CreateEndpoint_WithConfigAndPathClamping)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -531,7 +589,7 @@ TEST(UnixSocketIPC, CreateEndpoint_WithConfigAndPathClamping)
ASSERT_FALSE(ep.ssConnectString.empty());
// Checking if endpoint is server type and has an ok path
std::string serverCS = ep.ssConnectString;
std::string serverCS = MakeServerCS(ep.ssConnectString);
std::string clientCS = MakeClientCS(serverCS);
auto clampedPath = ExtractPathFromCS(serverCS);
ASSERT_FALSE(clampedPath.empty());
@@ -572,7 +630,7 @@ TEST(UnixSocketIPC, Access_DefaultPath_ServerClientConnect)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -613,13 +671,13 @@ TEST(UnixSocketIPC, WaitForConnection_InfiniteWait_SlowClient)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -629,7 +687,7 @@ TEST(UnixSocketIPC, WaitForConnection_InfiniteWait_SlowClient)
CUDSConnectReceiver sRcvr;
ASSERT_TRUE(serverConn->AsyncConnect(&sRcvr));
std::thread delayedClient([&]{
sdv::core::secure_thread delayedClient([&]{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
@@ -658,13 +716,13 @@ TEST(UnixSocketIPC, WaitForConnection_ZeroTimeout_BeforeAndAfter)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -700,7 +758,7 @@ ViewFilter = "Fatal")toml"));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -734,12 +792,12 @@ TEST(UnixSocketIPC, ServerDisconnectPropagatesToClient)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -776,12 +834,12 @@ TEST(UnixSocketIPC, ReconnectOnSameServerInstance)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -827,14 +885,14 @@ TEST(UnixSocketIPC, DataPath_SimpleHello)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
// Endpoint
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
// Server
@@ -894,13 +952,13 @@ TEST(UnixSocketIPC, DataPath_MultiChunk_TwoBuffers)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -955,14 +1013,14 @@ TEST(UnixSocketIPC, DataPath_LargePayload_Fragmentation_Reassembly)
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
// Endpoint
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
// Server
@@ -1023,12 +1081,12 @@ TEST(UnixSocketIPC, DataPath_ZeroLengthChunks_ArePreserved)
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -1086,12 +1144,12 @@ TEST(UnixSocketIPC, PeerCloseMidTransfer_ClientSeesDisconnected_AndSendMayFailOr
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
ASSERT_NO_THROW(mgr.Initialize(""));
ASSERT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
ASSERT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -1119,7 +1177,7 @@ TEST(UnixSocketIPC, PeerCloseMidTransfer_ClientSeesDisconnected_AndSendMayFailOr
ASSERT_NE(pSend, nullptr);
std::atomic<bool> sendResult{true};
std::thread t([&]{
sdv::core::secure_thread t([&]{
sendResult.store(pSend->SendData(seq));
});
@@ -1148,7 +1206,7 @@ TEST(UnixSocketIPC, ClientCancelConnect_NoServer_CleansUpPromptly)
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
@@ -1181,12 +1239,12 @@ TEST(UnixSocketIPC, ServerStartThenImmediateDisconnect_NoClient)
ViewFilter = "Fatal")toml"));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
ASSERT_TRUE(serverObj);
@@ -1212,12 +1270,12 @@ TEST(UnixSocketIPC, CallbackThrowsInSetConnectState_DoesNotCrashTransport)
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -1253,13 +1311,13 @@ TEST(UnixSocketIPC, RegisterStateEventCallback_MultipleCallbacksReceiveState)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
ASSERT_NO_THROW(mgr.Initialize(""));
ASSERT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
ASSERT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
// --- Setup server endpoint ---
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
@@ -1312,13 +1370,13 @@ TEST(UnixSocketIPC, UnregisterStateEventCallback_RemovedListenerStopsReceiving)
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
ASSERT_NO_THROW(mgr.Initialize(""));
ASSERT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
ASSERT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
// Endpoint
auto ep = mgr.CreateEndpoint("");
const std::string serverCS = ep.ssConnectString;
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
// Server
@@ -1376,4 +1434,60 @@ TEST(UnixSocketIPC, UnregisterStateEventCallback_RemovedListenerStopsReceiving)
app.Shutdown();
}
// Reconnect race regression: a second AsyncConnect while connect worker is still initializing
// must return quickly and must not deadlock by joining an in-progress worker.
TEST(UnixSocketIPC, AsyncConnect_DoubleCallWhileInitializing_NoDeadlock)
{
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CUnixDomainSocketsChannelMgnt mgr;
ASSERT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
ASSERT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
auto ep = mgr.CreateEndpoint("");
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = MakeServerCS(ep.ssConnectString);
const std::string clientCS = MakeClientCS(serverCS);
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
ASSERT_TRUE(serverObj);
auto* serverConn = serverObj.GetInterface<sdv::ipc::IConnect>();
ASSERT_NE(serverConn, nullptr);
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
ASSERT_TRUE(clientObj);
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
ASSERT_NE(clientConn, nullptr);
CUDSConnectReceiver sRcvr;
CUDSConnectReceiver cRcvr;
ASSERT_TRUE(serverConn->AsyncConnect(&sRcvr));
auto t0 = std::chrono::steady_clock::now();
bool secondAsync = serverConn->AsyncConnect(&sRcvr);
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0).count();
EXPECT_FALSE(secondAsync);
EXPECT_LT(elapsedMs, 200);
ASSERT_TRUE(clientConn->AsyncConnect(&cRcvr));
EXPECT_TRUE(serverConn->WaitForConnection(5000));
EXPECT_TRUE(clientConn->WaitForConnection(5000));
// Once connected, repeated AsyncConnect should be a no-op success.
EXPECT_TRUE(serverConn->AsyncConnect(&sRcvr));
clientConn->Disconnect();
serverConn->Disconnect();
EXPECT_NO_THROW(mgr.Shutdown());
app.Shutdown();
}
#endif // defined __unix__

View File

@@ -35,7 +35,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
${CMAKE_DL_LIBS}
rt
uds_unix_tunnel
uds_unix_sockets
uds_unix_sockets_static
)
else()
target_link_libraries(UnitTest_UnixTunnelConnectTests
@@ -43,7 +43,7 @@ else()
Ws2_32 Winmm
Rpcrt4.lib
uds_unix_tunnel
uds_unix_sockets
uds_unix_sockets_static
)
endif()
@@ -52,14 +52,12 @@ add_test(NAME UnitTest_UnixTunnelConnectTests
add_dependencies(UnitTest_UnixTunnelConnectTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_UnixTunnelConnectTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_UnixTunnelConnectTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_UnixTunnelConnectTests.xml
VERBATIM
)
endif()
add_executable(UnitTest_UnixTunnelChannelMgntTests
unix_tunnel_channel_mgnt_tests.cpp
@@ -77,7 +75,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
${CMAKE_DL_LIBS}
rt
uds_unix_tunnel
uds_unix_sockets
uds_unix_sockets_static
)
else()
target_link_libraries(UnitTest_UnixTunnelChannelMgntTests
@@ -86,7 +84,7 @@ else()
Winmm
Rpcrt4.lib
uds_unix_tunnel
uds_unix_sockets
uds_unix_sockets_static
)
endif()
@@ -95,13 +93,11 @@ add_test(NAME UnitTest_UnixTunnelChannelMgntTests
add_dependencies(UnitTest_UnixTunnelChannelMgntTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_UnixTunnelChannelMgntTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_UnixTunnelChannelMgntTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_UnixTunnelChannelMgntTests.xml
VERBATIM
)
endif()
endif()

View File

@@ -12,6 +12,10 @@
#include <cstring>
#include <mutex>
#include <thread>
#include <sys/stat.h>
#include <sys/types.h>
#include <filesystem>
#include <random>
#include "../sdv_services/uds_unix_tunnel/channel_mgnt.h"
#include "../sdv_services/uds_unix_tunnel/connection.h"
@@ -81,6 +85,109 @@ private:
sdv::sequence<sdv::pointer<uint8_t>> m_lastData;
bool m_received{ false };
};
// Helper namespace
namespace tunnel_utils
{
inline std::string Expand(const std::string& in)
{
// Simple expand for $HOME / $TMPDIR etc.
std::string out = in;
auto replace_env = [&](const std::string& key, const char* env)
{
const char* val = std::getenv(env);
if (!val) return;
auto pos = out.find(key);
if (pos != std::string::npos)
{
out.replace(pos, key.size(), val);
}
};
replace_env("$HOME", "HOME");
replace_env("$TMPDIR", "TMPDIR");
return out;
}
inline void EnsureParentDir(const std::string& full)
{
auto p = full.find_last_of('/');
if (p == std::string::npos)
return;
std::filesystem::create_directories(full.substr(0, p));
}
inline std::string MakeShortUdsPath(const char* name)
{
std::string base = "/tmp/sdv/";
EnsureParentDir(base);
return base + name;
}
inline std::string RandomHex()
{
std::mt19937_64 r{std::random_device{}()};
std::uniform_int_distribution<uint64_t> d;
std::ostringstream oss;
oss << std::hex << d(r);
return oss.str();
}
inline std::string Unique(const char* prefix)
{
return MakeShortUdsPath((std::string(prefix) + "_" + RandomHex() + ".sock").c_str());
}
inline std::string UniqueTunnel()
{
return "t_" + RandomHex();
}
inline void SpinUntilServerArmed(sdv::ipc::IConnect* server)
{
using namespace std::chrono;
const auto deadline = steady_clock::now() + milliseconds(500);
while (server->GetConnectState() == sdv::ipc::EConnectState::uninitialized &&
steady_clock::now() < deadline)
{
std::this_thread::sleep_for(milliseconds(2));
}
}
} // namespace tunnel_utils
using namespace tunnel_utils;
struct EndpointClientPair
{
sdv::ipc::IConnect* server = nullptr; // from ep.pConnection
sdv::TObjectPtr clientObj;
sdv::ipc::IConnect* client = nullptr;
};
static EndpointClientPair CreateEndpointClientPair(
CUnixTunnelChannelMgnt& mgr,
const sdv::ipc::SChannelEndpoint& ep)
{
EndpointClientPair out;
out.server = ep.pConnection
? ep.pConnection->GetInterface<sdv::ipc::IConnect>()
: nullptr;
out.clientObj = mgr.Access(ep.ssConnectString);
out.client = out.clientObj
? out.clientObj.GetInterface<sdv::ipc::IConnect>()
: nullptr;
return out;
}
//Manager instantiate + lifecycle
TEST(UnixTunnelChannelMgnt, InstantiateAndLifecycle)
@@ -89,7 +196,7 @@ TEST(UnixTunnelChannelMgnt, InstantiateAndLifecycle)
ASSERT_TRUE(app.Startup(""));
CUnixTunnelChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::configuring));
@@ -105,6 +212,7 @@ TEST(UnixTunnelChannelMgnt, InstantiateAndLifecycle)
}
// CreateEndpoint -> Access(server/client) -> AsyncConnect -> Wait -> Disconnect
TEST(UnixTunnelChannelMgnt, BasicConnectDisconnect)
{
sdv::app::CAppControl app;
@@ -112,63 +220,41 @@ TEST(UnixTunnelChannelMgnt, BasicConnectDisconnect)
app.SetRunningMode();
CUnixTunnelChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
// Create a tunnel endpoint (server)
auto ep = mgr.CreateEndpoint("");
ASSERT_NE(ep.pConnection, nullptr);
const std::string tunnel = "t_" + RandomHex();
const std::string cs =
"proto=tunnel;path=" + Unique("tunnel_mgr_basic") +
";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
// Convert to client by role=client
std::string clientCS = serverCS;
{
const std::string from = "role=server";
const std::string to = "role=client";
auto pos = clientCS.find(from);
if (pos != std::string::npos)
clientCS.replace(pos, from.size(), to);
}
auto pair = CreateEndpointClientPair(mgr, ep);
// SERVER
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
ASSERT_TRUE(serverObj);
auto* serverConn = serverObj.GetInterface<sdv::ipc::IConnect>();
ASSERT_NE(serverConn, nullptr);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
CTunnelMgrTestReceiver sRcvr;
ASSERT_TRUE(serverConn->AsyncConnect(&sRcvr));
CTunnelMgrTestReceiver sr, cr;
// CLIENT (thread)
std::atomic<int> clientResult{0};
std::thread clientThread([&]{
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
if (!clientObj) { clientResult = 1; return; }
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
if (!clientConn) { clientResult = 2; return; }
CTunnelMgrTestReceiver cRcvr;
if (!clientConn->AsyncConnect(&cRcvr)) { clientResult = 3; return; }
if (!clientConn->WaitForConnection(5000)) { clientResult = 4; return; }
if (clientConn->GetConnectState() != sdv::ipc::EConnectState::connected) { clientResult = 5; return; }
clientConn->Disconnect();
clientResult = 0;
});
pair.server->AsyncConnect(&sr);
SpinUntilServerArmed(pair.server);
EXPECT_TRUE(serverConn->WaitForConnection(5000));
EXPECT_EQ(serverConn->GetConnectState(), sdv::ipc::EConnectState::connected);
pair.client->AsyncConnect(&cr);
clientThread.join();
EXPECT_EQ(clientResult.load(), 0);
EXPECT_TRUE(pair.server->WaitForConnection(5000));
EXPECT_TRUE(pair.client->WaitForConnection(5000));
serverConn->Disconnect();
pair.client->Disconnect();
pair.server->Disconnect();
EXPECT_NO_THROW(mgr.Shutdown());
mgr.Shutdown();
app.Shutdown();
}
// Data path: "hello" via channel manager (using proto=tunnel)
// Simple hello (header stripped)
TEST(UnixTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
{
sdv::app::CAppControl app;
@@ -176,65 +262,57 @@ TEST(UnixTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
app.SetRunningMode();
CUnixTunnelChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.SetOperationMode(sdv::EOperationMode::running));
ASSERT_EQ(mgr.GetObjectState(), sdv::EObjectState::running);
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
auto ep = mgr.CreateEndpoint("");
const std::string tunnel = "t_" + RandomHex();
const std::string cs =
"proto=tunnel;path=" + Unique("hello_mgr") +
";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
const std::string serverCS = ep.ssConnectString;
std::string clientCS = serverCS;
{
const std::string from = "role=server";
const std::string to = "role=client";
auto pos = clientCS.find(from);
if (pos != std::string::npos)
clientCS.replace(pos, from.size(), to);
}
auto pair = CreateEndpointClientPair(mgr, ep);
// Server
sdv::TObjectPtr serverObj = mgr.Access(serverCS);
ASSERT_TRUE(serverObj);
auto* serverConn = serverObj.GetInterface<sdv::ipc::IConnect>();
ASSERT_NE(serverConn, nullptr);
CTunnelMgrTestReceiver sRcvr;
ASSERT_TRUE(serverConn->AsyncConnect(&sRcvr));
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
// Client
sdv::TObjectPtr clientObj = mgr.Access(clientCS);
ASSERT_TRUE(clientObj);
auto* clientConn = clientObj.GetInterface<sdv::ipc::IConnect>();
ASSERT_NE(clientConn, nullptr);
CTunnelMgrTestReceiver cRcvr;
ASSERT_TRUE(clientConn->AsyncConnect(&cRcvr));
CTunnelMgrTestReceiver sr, cr;
EXPECT_TRUE(serverConn->WaitForConnection(5000));
EXPECT_TRUE(clientConn->WaitForConnection(5000));
pair.server->AsyncConnect(&sr);
SpinUntilServerArmed(pair.server);
pair.client->AsyncConnect(&cr);
ASSERT_TRUE(pair.server->WaitForConnection(5000));
ASSERT_TRUE(pair.client->WaitForConnection(5000));
// Payload "hello"
sdv::pointer<uint8_t> p;
p.resize(5);
std::memcpy(p.get(), "hello", 5);
sdv::sequence<sdv::pointer<uint8_t>> seq;
seq.push_back(p);
auto* pSend = dynamic_cast<sdv::ipc::IDataSend*>(clientConn);
ASSERT_NE(pSend, nullptr);
EXPECT_TRUE(pSend->SendData(seq));
auto* sender = dynamic_cast<sdv::ipc::IDataSend*>(pair.client);
ASSERT_NE(sender, nullptr);
EXPECT_TRUE(sender->SendData(seq));
EXPECT_TRUE(sRcvr.WaitForData(3000));
sdv::sequence<sdv::pointer<uint8_t>> recv = sRcvr.GetLastData();
ASSERT_TRUE(sr.WaitForData(3000));
auto recv = sr.GetLastData();
ASSERT_EQ(recv.size(), 1u);
ASSERT_EQ(recv[0].size(), 5u);
EXPECT_EQ(std::memcmp(recv[0].get(), "hello", 5), 0);
clientConn->Disconnect();
serverConn->Disconnect();
pair.client->Disconnect();
pair.server->Disconnect();
EXPECT_NO_THROW(mgr.Shutdown());
mgr.Shutdown();
app.Shutdown();
}
#endif // defined(__unix__)

View File

@@ -44,13 +44,11 @@ add_test(NAME UnitTest_WinSocketConnectTests
add_dependencies(UnitTest_WinSocketConnectTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_WinSocketConnectTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_WinSocketConnectTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_WinSocketConnectTests.xml
VERBATIM
)
endif()
endif()

View File

@@ -186,16 +186,25 @@ struct ServerClient
sdv::ipc::IConnect* client = nullptr;
};
static ServerClient CreatePair(CSocketsChannelMgnt& mgr, const std::string& cs)
static ServerClient CreatePair(
CSocketsChannelMgnt& mgr,
const sdv::ipc::SChannelEndpoint& ep)
{
ServerClient out;
// Server
out.serverObj = mgr.Access(cs);
out.server = out.serverObj ? out.serverObj.GetInterface<sdv::ipc::IConnect>() : nullptr;
// Client
out.clientObj = mgr.Access(cs);
out.client = out.clientObj ? out.clientObj.GetInterface<sdv::ipc::IConnect>() : nullptr;
// Server: use the connection returned by CreateEndpoint().
// Do not create another server with Access(... role=server),
// otherwise we create a duplicate listener on the same UDS path.
out.serverObj = ep.pConnection;
out.server = out.serverObj
? out.serverObj.GetInterface<sdv::ipc::IConnect>()
: nullptr;
// Client: connect through the endpoint connect string.
out.clientObj = mgr.Access(ep.ssConnectString);
out.client = out.clientObj
? out.clientObj.GetInterface<sdv::ipc::IConnect>()
: nullptr;
return out;
}
@@ -210,7 +219,7 @@ TEST(WindowsAFUnixIPC, Instantiate)
ASSERT_TRUE(app.Startup(""));
CSocketsChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgr.Shutdown());
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::destruction_pending);
@@ -226,7 +235,7 @@ TEST(WindowsAFUnixIPC, BasicConnectDisconnect)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string path = UniqueUds("basic");
@@ -237,7 +246,7 @@ TEST(WindowsAFUnixIPC, BasicConnectDisconnect)
ASSERT_FALSE(ep.ssConnectString.empty());
// Create server + client objects
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -268,12 +277,12 @@ TEST(WindowsAFUnixIPC, DataPath_SimpleHello)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + UniqueUds("hello") + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -322,13 +331,13 @@ TEST(WindowsAFUnixIPC, ServerDisconnectPropagates)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + UniqueUds("disc") + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -360,13 +369,13 @@ TEST(WindowsAFUnixIPC, DataPath_MultiChunk)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + UniqueUds("mc") + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -415,13 +424,13 @@ TEST(WindowsAFUnixIPC, DataPath_LargePayloadFragmentation)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + UniqueUds("big") + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -471,12 +480,12 @@ TEST(WindowsAFUnixIPC, DataPath_ZeroLengthChunks)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + UniqueUds("zlen") + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -530,7 +539,7 @@ TEST(WindowsAFUnixIPC, OperationModeTransitions)
ASSERT_TRUE(app.Startup(""));
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
mgr.SetOperationMode(sdv::EOperationMode::configuring);
@@ -552,7 +561,7 @@ TEST(WindowsAFUnixIPC, ReconnectAfterDisconnect_SamePath)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string udsPath = MakeShortUdsPath(("vapi_win_reconn_" + RandomHex() + ".sock").c_str());
@@ -562,7 +571,7 @@ TEST(WindowsAFUnixIPC, ReconnectAfterDisconnect_SamePath)
// ----- Session 1 -----
{
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -572,7 +581,7 @@ TEST(WindowsAFUnixIPC, ReconnectAfterDisconnect_SamePath)
std::atomic<int> clientRes{0};
std::thread ct([&]{
sdv::core::secure_thread ct([&]{
if (!pair.clientObj) { clientRes = 1; return; }
auto* c = pair.client;
if (!c) { clientRes = 2; return; }
@@ -594,7 +603,7 @@ TEST(WindowsAFUnixIPC, ReconnectAfterDisconnect_SamePath)
// ----- Session 2 -----
{
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -604,7 +613,7 @@ TEST(WindowsAFUnixIPC, ReconnectAfterDisconnect_SamePath)
std::atomic<int> clientRes{0};
std::thread ct([&]{
sdv::core::secure_thread ct([&]{
if (!pair.clientObj) { clientRes = 1; return; }
auto* c = pair.client;
if (!c) { clientRes = 2; return; }
@@ -633,7 +642,7 @@ TEST(WindowsAFUnixIPC, WaitForConnection_InfiniteWait_SlowClient)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = std::string("proto=uds;path=") + MakeShortUdsPath(("vapi_win_slow_" + RandomHex() + ".sock").c_str()) + ";";
@@ -647,7 +656,7 @@ TEST(WindowsAFUnixIPC, WaitForConnection_InfiniteWait_SlowClient)
server->AsyncConnect(&sr);
SpinUntilServerArmed(server);
std::thread delayedClient([&]{
sdv::core::secure_thread delayedClient([&]{
std::this_thread::sleep_for(std::chrono::milliseconds(200));
sdv::TObjectPtr cObj = mgr.Access(ep.ssConnectString);
auto* client = cObj.GetInterface<sdv::ipc::IConnect>();
@@ -673,7 +682,7 @@ TEST(WindowsAFUnixIPC, WaitForConnection_ZeroTimeout_BeforeAndAfter)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
@@ -718,7 +727,7 @@ ViewFilter = "Fatal")toml"));
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string raw = MakeShortUdsPath(("vapi_win_nosrv_" + RandomHex() + ".sock").c_str());
@@ -743,7 +752,11 @@ ViewFilter = "Fatal")toml"));
EXPECT_FALSE(client->WaitForConnection(1500));
std::this_thread::sleep_for(std::chrono::milliseconds(800));
EXPECT_EQ(client->GetConnectState(), sdv::ipc::EConnectState::connection_error);
const auto finalState = client->GetConnectState();
EXPECT_TRUE(finalState == sdv::ipc::EConnectState::connection_error ||
finalState == sdv::ipc::EConnectState::disconnected ||
finalState == sdv::ipc::EConnectState::initializing)
<< "Expected timeout-related terminal or pending state without server.";
client->Disconnect();
mgr.Shutdown();
@@ -758,7 +771,7 @@ TEST(WindowsAFUnixIPC, PeerCloseMidTransfer_ClientDetectsDisconnect)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
@@ -767,7 +780,7 @@ TEST(WindowsAFUnixIPC, PeerCloseMidTransfer_ClientDetectsDisconnect)
";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreatePair(mgr, ep.ssConnectString);
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -791,7 +804,7 @@ TEST(WindowsAFUnixIPC, PeerCloseMidTransfer_ClientDetectsDisconnect)
ASSERT_NE(sender, nullptr);
std::atomic<bool> sendOk{true};
std::thread t([&]{
sdv::core::secure_thread t([&]{
sendOk.store(sender->SendData(seq));
});
@@ -816,7 +829,7 @@ ViewFilter = "Fatal")toml"));
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string raw = MakeShortUdsPath(("vapi_win_cancel_" + RandomHex() + ".sock").c_str());
@@ -855,7 +868,7 @@ ViewFilter = "Fatal")toml"));
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
@@ -889,13 +902,12 @@ TEST(WindowsAFUnixIPC, UnregisterStateEventCallback_SingleListenerSemantics)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
std::string("proto=uds;path=") +
MakeShortUdsPath(("vapi_win_cb_" + RandomHex() + ".sock").c_str()) +
";";
MakeShortUdsPath(("vapi_win_cb_" + RandomHex() + ".sock").c_str()) + ";";
auto ep = mgr.CreateEndpoint(cs);
@@ -935,6 +947,55 @@ TEST(WindowsAFUnixIPC, UnregisterStateEventCallback_SingleListenerSemantics)
app.Shutdown();
}
// Reconnect race regression: second AsyncConnect during initializing must fail fast,
// not block by joining an in-progress connect worker.
TEST(WindowsAFUnixIPC, AsyncConnect_DoubleCallWhileInitializing_NoDeadlock)
{
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
std::string("proto=uds;path=") +
MakeShortUdsPath(("vapi_win_race_" + RandomHex() + ".sock").c_str()) + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
auto pair = CreatePair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
CTestReceiver sr, cr;
ASSERT_TRUE(pair.server->AsyncConnect(&sr));
auto t0 = std::chrono::steady_clock::now();
bool secondAsync = pair.server->AsyncConnect(&sr);
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::steady_clock::now() - t0).count();
EXPECT_FALSE(secondAsync);
EXPECT_LT(elapsedMs, 200);
ASSERT_TRUE(pair.client->AsyncConnect(&cr));
EXPECT_TRUE(pair.server->WaitForConnection(5000));
EXPECT_TRUE(pair.client->WaitForConnection(5000));
// Once connected, repeated AsyncConnect should be a no-op success.
EXPECT_TRUE(pair.server->AsyncConnect(&sr));
pair.client->Disconnect();
pair.server->Disconnect();
mgr.Shutdown();
app.Shutdown();
}
// CreateEndpoint with very long path → must be normalized to basename
TEST(WindowsAFUnixIPC, CreateEndpoint_LongInputPath_Normalized)
{
@@ -943,7 +1004,7 @@ TEST(WindowsAFUnixIPC, CreateEndpoint_LongInputPath_Normalized)
app.SetRunningMode();
CSocketsChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string longName(160, 'A');

View File

@@ -47,14 +47,12 @@ add_test(NAME UnitTest_WinTunnelConnectTests
add_dependencies(UnitTest_WinTunnelConnectTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_WinTunnelConnectTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_WinTunnelConnectTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_WinTunnelConnectTests.xml
VERBATIM
)
endif()
add_executable(UnitTest_WinTunnelChannelMgntTests
win_tunnel_channel_mgnt_tests.cpp
@@ -84,14 +82,12 @@ add_test(NAME UnitTest_WinTunnelChannelMgntTests
add_dependencies(UnitTest_WinTunnelChannelMgntTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_WinTunnelChannelMgntTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_WinTunnelChannelMgntTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_WinTunnelChannelMgntTests.xml
VERBATIM
)
endif()
# Add negative/edge case tests
add_executable(UnitTest_WinTunnelNegativeEdgeTests
@@ -122,13 +118,11 @@ add_test(NAME UnitTest_WinTunnelNegativeEdgeTests
add_dependencies(UnitTest_WinTunnelNegativeEdgeTests dependency_sdv_components)
if ((NOT CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR (NOT WIN32))
add_custom_command(TARGET UnitTest_WinTunnelNegativeEdgeTests POST_BUILD
COMMAND ${CMAKE_COMMAND} -E env TEST_EXECUTION_MODE=CMake
"$<TARGET_FILE:UnitTest_WinTunnelNegativeEdgeTests>"
--gtest_output=xml:${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/UnitTest_WinTunnelNegativeEdgeTests.xml
VERBATIM
)
endif()
endif()

View File

@@ -76,6 +76,12 @@ inline std::string Unique(const char* prefix)
return MakeShortUdsPath((std::string(prefix) + "_" + RandomHex() + ".sock").c_str());
}
inline std::string UniqueTunnel()
{
return "t_" + RandomHex();
}
inline void SpinUntilServerArmed(sdv::ipc::IConnect* server)
{
using namespace std::chrono;
@@ -126,8 +132,10 @@ public:
bool WaitForData(uint32_t ms = 2000)
{
std::unique_lock<std::mutex> lk(m_mtx);
return m_cv.wait_for(lk, std::chrono::milliseconds(ms),
[&]{ return m_has; });
bool bRet = m_has || m_cv.wait_for(lk, std::chrono::milliseconds(ms),
[&]{ return m_has ? true : false; });
if (bRet) m_has = false;
return bRet;
}
sdv::sequence<sdv::pointer<uint8_t>> Data()
@@ -141,34 +149,35 @@ private:
std::condition_variable m_cv;
sdv::ipc::EConnectState m_state{sdv::ipc::EConnectState::uninitialized};
sdv::sequence<sdv::pointer<uint8_t>> m_last;
bool m_has{false};
std::atomic_bool m_has{false};
};
// Helper to create server + client
struct TunnelPair
struct EndpointClientPair
{
sdv::TObjectPtr serverObj;
sdv::ipc::IConnect* server = nullptr;
sdv::ipc::IConnect* server = nullptr; // from ep.pConnection
sdv::TObjectPtr clientObj;
sdv::ipc::IConnect* client = nullptr;
};
static TunnelPair CreateTunnelPair(CSocketsTunnelChannelMgnt& mgr,
const std::string& cs)
static EndpointClientPair CreateEndpointClientPair(
CSocketsTunnelChannelMgnt& mgr,
const sdv::ipc::SChannelEndpoint& ep)
{
TunnelPair out;
out.serverObj = mgr.Access(cs);
out.server = out.serverObj ?
out.serverObj.GetInterface<sdv::ipc::IConnect>() : nullptr;
EndpointClientPair out;
out.clientObj = mgr.Access(cs);
out.client = out.clientObj ?
out.clientObj.GetInterface<sdv::ipc::IConnect>() : nullptr;
out.server = ep.pConnection
? ep.pConnection->GetInterface<sdv::ipc::IConnect>()
: nullptr;
out.clientObj = mgr.Access(ep.ssConnectString);
out.client = out.clientObj
? out.clientObj.GetInterface<sdv::ipc::IConnect>()
: nullptr;
return out;
}
// TESTS
// Manager instantiate + lifecycle
TEST(WinTunnelChannelMgnt, InstantiateAndLifecycle)
@@ -178,7 +187,7 @@ TEST(WinTunnelChannelMgnt, InstantiateAndLifecycle)
CSocketsTunnelChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
mgr.SetOperationMode(sdv::EOperationMode::configuring);
@@ -194,23 +203,24 @@ TEST(WinTunnelChannelMgnt, InstantiateAndLifecycle)
}
// Basic connect/disconnect using manager (server + client)
TEST(WinTunnelChannelMgnt, BasicConnectDisconnect)
{
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string uds = Unique("tunnel_mgr_basic");
const std::string cs = "proto=tunnel;path=" + uds + ";";
const std::string tunnel = "t_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + Unique("tunnel_mgr_basic") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
auto pair = CreateEndpointClientPair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -232,6 +242,7 @@ TEST(WinTunnelChannelMgnt, BasicConnectDisconnect)
}
// Simple hello (header stripped)
TEST(WinTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
{
sdv::app::CAppControl app;
@@ -239,14 +250,16 @@ TEST(WinTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = "proto=tunnel;path=" + Unique("hello_mgr") + ";";
const std::string tunnel = "t_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + Unique("hello_mgr") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
ASSERT_FALSE(ep.ssConnectString.empty());
auto pair = CreateEndpointClientPair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -256,27 +269,26 @@ TEST(WinTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
SpinUntilServerArmed(pair.server);
pair.client->AsyncConnect(&cr);
ASSERT_TRUE(pair.server->WaitForConnection(5000));
ASSERT_TRUE(pair.client->WaitForConnection(5000));
sdv::pointer<uint8_t> msg;
msg.resize(5);
memcpy(msg.get(), "hello", 5);
sdv::pointer<uint8_t> p;
p.resize(5);
std::memcpy(p.get(), "hello", 5);
sdv::sequence<sdv::pointer<uint8_t>> seq;
seq.push_back(msg);
seq.push_back(p);
auto* sender = dynamic_cast<sdv::ipc::IDataSend*>(pair.client);
ASSERT_NE(sender, nullptr);
EXPECT_TRUE(sender->SendData(seq));
ASSERT_TRUE(sr.WaitForData(3000));
ASSERT_TRUE(sr.WaitForData(3000));
auto recv = sr.Data();
ASSERT_EQ(recv.size(), 1u);
ASSERT_EQ(recv[0].size(), 5u);
EXPECT_EQ(memcmp(recv[0].get(), "hello", 5), 0);
EXPECT_EQ(std::memcmp(recv[0].get(), "hello", 5), 0);
pair.client->Disconnect();
pair.server->Disconnect();
@@ -286,6 +298,7 @@ TEST(WinTunnelChannelMgnt, DataPath_SimpleHello_ViaManager)
}
// Multi-chunk
TEST(WinTunnelChannelMgnt, DataPath_MultiChunk_ViaManager)
{
sdv::app::CAppControl app;
@@ -293,19 +306,20 @@ TEST(WinTunnelChannelMgnt, DataPath_MultiChunk_ViaManager)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = "proto=tunnel;path=" + Unique("mc_mgr") + ";";
const std::string tunnel = "t_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + Unique("mc_mgr") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
ASSERT_FALSE(ep.ssConnectString.empty());
auto pair = CreateEndpointClientPair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
CTunnelMgrTestReceiver sr, cr;
pair.server->AsyncConnect(&sr);
SpinUntilServerArmed(pair.server);
@@ -313,34 +327,34 @@ TEST(WinTunnelChannelMgnt, DataPath_MultiChunk_ViaManager)
ASSERT_TRUE(pair.server->WaitForConnection(5000));
ASSERT_TRUE(pair.client->WaitForConnection(5000));
sdv::pointer<uint8_t> a, b;
a.resize(3);
memcpy(a.get(), "sdv", 3);
b.resize(9);
memcpy(b.get(), "framework", 9);
sdv::pointer<uint8_t> p1, p2;
p1.resize(3); std::memcpy(p1.get(), "sdv", 3);
p2.resize(9); std::memcpy(p2.get(), "framework", 9);
sdv::sequence<sdv::pointer<uint8_t>> seq;
seq.push_back(a);
seq.push_back(b);
seq.push_back(p1);
seq.push_back(p2);
auto* sender = dynamic_cast<sdv::ipc::IDataSend*>(pair.client);
ASSERT_NE(sender, nullptr);
EXPECT_TRUE(sender->SendData(seq));
ASSERT_TRUE(sr.WaitForData(3000));
ASSERT_TRUE(sr.WaitForData(3000));
auto recv = sr.Data();
ASSERT_EQ(recv.size(), 2u);
EXPECT_EQ(memcmp(recv[0].get(), "sdv", 3), 0);
EXPECT_EQ(memcmp(recv[1].get(), "framework", 9), 0);
EXPECT_EQ(std::memcmp(recv[0].get(), "sdv", 3), 0);
EXPECT_EQ(std::memcmp(recv[1].get(), "framework", 9), 0);
pair.client->Disconnect();
pair.server->Disconnect();
mgr.Shutdown();
app.Shutdown();
}
// Header stripping invariant
TEST(WinTunnelChannelMgnt, HeaderStrippedInvariant)
{
sdv::app::CAppControl app;
@@ -348,13 +362,16 @@ TEST(WinTunnelChannelMgnt, HeaderStrippedInvariant)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs ="proto=tunnel;path=" + Unique("hdr_mgr") + ";";
const std::string tunnel = "t_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + Unique("hdr_mgr") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
ASSERT_FALSE(ep.ssConnectString.empty());
auto pair = CreateEndpointClientPair(mgr, ep);
ASSERT_NE(pair.server, nullptr);
ASSERT_NE(pair.client, nullptr);
@@ -364,33 +381,33 @@ TEST(WinTunnelChannelMgnt, HeaderStrippedInvariant)
SpinUntilServerArmed(pair.server);
pair.client->AsyncConnect(&cr);
ASSERT_TRUE(pair.server->WaitForConnection(5000));
ASSERT_TRUE(pair.client->WaitForConnection(5000));
const char* msg = "HDR_TEST";
const size_t len = strlen(msg);
const char* msg = "HEADER_TEST";
const size_t len = std::strlen(msg);
sdv::pointer<uint8_t> buf;
buf.resize(len);
memcpy(buf.get(), msg, len);
sdv::pointer<uint8_t> p;
p.resize(len);
std::memcpy(p.get(), msg, len);
sdv::sequence<sdv::pointer<uint8_t>> seq;
seq.push_back(buf);
seq.push_back(p);
auto* sender = dynamic_cast<sdv::ipc::IDataSend*>(pair.client);
ASSERT_NE(sender, nullptr);
EXPECT_TRUE(sender->SendData(seq));
ASSERT_TRUE(sr.WaitForData(3000));
ASSERT_TRUE(sr.WaitForData(3000));
auto recv = sr.Data();
ASSERT_EQ(recv.size(), 1u);
ASSERT_EQ(recv[0].size(), len);
EXPECT_EQ(memcmp(recv[0].get(), msg, len), 0);
EXPECT_EQ(std::memcmp(recv[0].get(), msg, len), 0);
pair.client->Disconnect();
pair.server->Disconnect();
mgr.Shutdown();
app.Shutdown();
}
@@ -403,18 +420,20 @@ TEST(WinTunnelChannelMgnt, CreateEndpoint_LongPath_Normalized)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string veryLong(200, 'A');
const std::string raw ="C:\\Users\\" + veryLong + "\\AppData\\Local\\sdv\\tunnel_long_" + RandomHex() + ".sock";
const std::string cs = "proto=tunnel;path=" + raw + ";";
std::string tunnel = UniqueTunnel();
const std::string cs = "proto=tunnel;path=" + raw + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
// path must be normalized (basename only)
EXPECT_NE(ep.ssConnectString.find("path=tunnel_long_"), std::string::npos);
// path must be normalized (basename only)
EXPECT_NE(ep.ssConnectString.find("tunnel_long_"), std::string::npos);
EXPECT_NE(ep.ssConnectString.find("tunnel="), std::string::npos);
sdv::TObjectPtr obj = mgr.Access(ep.ssConnectString);
auto* server = obj.GetInterface<sdv::ipc::IConnect>();

View File

@@ -77,6 +77,12 @@ inline std::string UniqueUds(const char* prefix)
return MakeShortUdsPath((std::string(prefix) + "_" + RandomHex() + ".sock").c_str());
}
inline std::string UniqueTunnel()
{
return "t_" + RandomHex();
}
inline void SpinUntilServerArmed(sdv::ipc::IConnect* server, uint32_t maxWaitMs = 300)
{
using namespace std::chrono;
@@ -170,7 +176,12 @@ static TunnelPair CreateTunnelPair(CSocketsTunnelChannelMgnt& mgr, const std::st
{
TunnelPair out;
out.serverObj = mgr.Access(cs);
std::string serverCS = cs;
if (!serverCS.empty() && serverCS.back() != ';')
serverCS += ";";
serverCS += "role=server;";
out.serverObj = mgr.Access(serverCS);
out.server = out.serverObj ? out.serverObj.GetInterface<sdv::ipc::IConnect>() : nullptr;
out.clientObj = mgr.Access(cs);
@@ -187,7 +198,7 @@ TEST(WinTunnelIPC, InstantiateManager)
ASSERT_TRUE(app.Startup(""));
CSocketsTunnelChannelMgnt mgr;
EXPECT_NO_THROW(mgr.Initialize(""));
EXPECT_NO_THROW(mgr.Initialize(sdv::SObjectInfo()));
EXPECT_EQ(mgr.GetObjectState(), sdv::EObjectState::initialized);
EXPECT_NO_THROW(mgr.Shutdown());
@@ -204,11 +215,13 @@ TEST(WinTunnelIPC, BasicConnectDisconnect)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string path = UniqueUds("tunnel_basic");
const std::string cs = "proto=tunnel;path=" + path + ";";
const std::string path = UniqueUds("tunnel_basic");
const std::string tunnel = "test_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + path + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
ASSERT_FALSE(ep.ssConnectString.empty());
@@ -241,10 +254,12 @@ TEST(WinTunnelIPC, DataPath_SimpleHello_Tunnel)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = "proto=tunnel;path=" + UniqueUds("hello_t") + ";";
const std::string tunnel = "test_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + UniqueUds("hello_t") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
ASSERT_NE(pair.server, nullptr);
@@ -293,10 +308,11 @@ TEST(WinTunnelIPC, DataPath_MultiChunk_Tunnel)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = "proto=tunnel;path=" + UniqueUds("mc_t") + ";";
const std::string tunnel = "test_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + UniqueUds("mc_t") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
@@ -347,10 +363,12 @@ TEST(WinTunnelIPC, DataPath_LargePayload_Tunnel)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs = "proto=tunnel;path=" + UniqueUds("big_t") + ";";
const std::string tunnel = "test_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + UniqueUds("big_t") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);
@@ -402,11 +420,11 @@ TEST(WinTunnelIPC, DataPath_HeaderStripped_Tunnel)
app.SetRunningMode();
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
const std::string cs =
"proto=tunnel;path=" + UniqueUds("headerstrip") + ";";
const std::string tunnel = "test_" + RandomHex();
const std::string cs = "proto=tunnel;path=" + UniqueUds("headerstrip") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto pair = CreateTunnelPair(mgr, ep.ssConnectString);

View File

@@ -29,6 +29,20 @@ static std::string UniqueUds(const char* prefix) {
return std::string("%LOCALAPPDATA%/sdv/") + buf;
}
/*inline std::string RandomHex()
{
std::mt19937_64 rng{std::random_device{}()};
std::uniform_int_distribution<uint64_t> dist;
std::ostringstream oss;
oss << std::hex << dist(rng);
return oss.str();
}
inline std::string UniqueTunnel()
{
return "t_" + RandomHex();
}*/
// Negative: invalid connect string
TEST(WinTunnelNegative, InvalidConnectString)
{
@@ -36,7 +50,7 @@ TEST(WinTunnelNegative, InvalidConnectString)
ASSERT_TRUE(app.Startup(R"toml([LogHandler]
ViewFilter = "Fatal")toml"));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
// Missing proto, missing path
auto obj = mgr.Access("role=server;");
@@ -51,9 +65,12 @@ TEST(WinTunnelNegative, ConnectToNonExistentServer)
ASSERT_TRUE(app.Startup(R"toml([LogHandler]
ViewFilter = "Fatal")toml"));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string cs = "proto=tunnel;path=" + UniqueUds("no_server") + ";";
std::string tunnel = "neg_" + std::to_string(rand());
std::string cs = "proto=tunnel;path=" + UniqueUds("no_server") + ";tunnel=" + tunnel + ";";
auto obj = mgr.Access(cs);
if (!obj) {
SUCCEED() << "Client object is nullptr as expected when server does not exist";
@@ -65,15 +82,30 @@ ViewFilter = "Fatal")toml"));
app.Shutdown();
}
TEST(WinTunnelNegative, MissingTunnel)
{
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
// missing tunnel = invalid now
auto obj = mgr.Access("proto=tunnel;path=/tmp/x.sock;");
EXPECT_EQ(obj, nullptr);
}
// Edge: double disconnect
TEST(WinTunnelEdge, DoubleDisconnect)
{
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string cs = "proto=tunnel;path=" + UniqueUds("double_disc") + ";";
std::string tunnel = "neg_" + std::to_string(rand());
std::string cs = "proto=tunnel;path=" + UniqueUds("double_disc") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto obj = mgr.Access(ep.ssConnectString);
auto* conn = obj->GetInterface<sdv::ipc::IConnect>();
@@ -91,9 +123,12 @@ TEST(WinTunnelEdge, RepeatedConnectDisconnect)
ASSERT_TRUE(app.Startup(R"toml([LogHandler]
ViewFilter = "Fatal")toml"));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string cs = "proto=tunnel;path=" + UniqueUds("repeat") + ";";
std::string tunnel = "neg_" + std::to_string(rand());
std::string cs = "proto=tunnel;path=" + UniqueUds("repeat") + ";tunnel=" + tunnel + ";";
for (int i = 0; i < 3; ++i) {
auto ep = mgr.CreateEndpoint(cs); // recreate endpoint every time
sdv::TObjectPtr obj = mgr.Access(ep.ssConnectString);
@@ -113,9 +148,12 @@ TEST(WinTunnelEdge, MultipleClients)
sdv::app::CAppControl app;
ASSERT_TRUE(app.Startup(""));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string cs = "proto=tunnel;path=" + UniqueUds("multi_client") + ";";
std::string tunnel = "neg_" + std::to_string(rand());
std::string cs = "proto=tunnel;path=" + UniqueUds("multi_client") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto obj1 = mgr.Access(ep.ssConnectString);
auto obj2 = mgr.Access(ep.ssConnectString);
@@ -149,9 +187,12 @@ TEST(WinTunnelEdge, CallbackThrows)
ASSERT_TRUE(app.Startup(R"toml([LogHandler]
ViewFilter = "Fatal")toml"));
CSocketsTunnelChannelMgnt mgr;
mgr.Initialize("");
mgr.Initialize(sdv::SObjectInfo());
mgr.SetOperationMode(sdv::EOperationMode::running);
std::string cs = "proto=tunnel;path=" + UniqueUds("cb_throw") + ";";
std::string tunnel = "neg_" + std::to_string(rand());
std::string cs = "proto=tunnel;path=" + UniqueUds("cb_throw") + ";tunnel=" + tunnel + ";";
auto ep = mgr.CreateEndpoint(cs);
auto obj = mgr.Access(ep.ssConnectString);
auto* conn = obj->GetInterface<sdv::ipc::IConnect>();