From 438f3e059e351ad371750634c685f73df9c52faa Mon Sep 17 00:00:00 2001 From: KonradBkd <117755498+KonradBkd@users.noreply.github.com> Date: Fri, 20 Dec 2024 09:23:24 +0100 Subject: [PATCH] c-api: Forward specific SIL Kit exceptions (#146) * dev: Forward specific exception through the hourglass --- SilKit/include/silkit/capi/Types.h | 35 ++- .../silkit/detail/impl/ThrowOnError.hpp | 24 +- SilKit/source/capi/CMakeLists.txt | 1 + SilKit/source/capi/CapiImpl.hpp | 40 ++++ SilKit/source/capi/Test_CapiExceptions.cpp | 97 ++++++++ SilKit/source/capi/Test_CapiSilKit.cpp | 225 ++++++++---------- SilKit/source/config/CMakeLists.txt | 1 + .../ParticipantConfiguration_TestCapi.yaml | 6 + docs/CHANGELOG.rst | 7 + 9 files changed, 299 insertions(+), 137 deletions(-) create mode 100644 SilKit/source/capi/Test_CapiExceptions.cpp create mode 100644 SilKit/source/config/TestParticipantConfigs/ParticipantConfiguration_TestCapi.yaml diff --git a/SilKit/include/silkit/capi/Types.h b/SilKit/include/silkit/capi/Types.h index 19e129426..d45266962 100644 --- a/SilKit/include/silkit/capi/Types.h +++ b/SilKit/include/silkit/capi/Types.h @@ -43,15 +43,32 @@ typedef struct SilKit_Experimental_SystemController SilKit_Experimental_SystemCo typedef int32_t SilKit_ReturnCode; -#define SilKit_ReturnCode_SUCCESS ((SilKit_ReturnCode)0) -#define SilKit_ReturnCode_UNSPECIFIEDERROR ((SilKit_ReturnCode)1) -#define SilKit_ReturnCode_NOTSUPPORTED ((SilKit_ReturnCode)2) -#define SilKit_ReturnCode_NOTIMPLEMENTED ((SilKit_ReturnCode)3) -#define SilKit_ReturnCode_BADPARAMETER ((SilKit_ReturnCode)4) -#define SilKit_ReturnCode_BUFFERTOOSMALL ((SilKit_ReturnCode)5) -#define SilKit_ReturnCode_TIMEOUT ((SilKit_ReturnCode)6) -#define SilKit_ReturnCode_UNSUPPORTEDSERVICE ((SilKit_ReturnCode)7) -#define SilKit_ReturnCode_WRONGSTATE ((SilKit_ReturnCode)8) // Returned on exception SilKit::StateError (CapiImpl.h) +#define SilKit_ReturnCode_SUCCESS ((SilKit_ReturnCode)0) +#define SilKit_ReturnCode_UNSPECIFIEDERROR ((SilKit_ReturnCode)1) +#define SilKit_ReturnCode_NOTSUPPORTED ((SilKit_ReturnCode)2) +#define SilKit_ReturnCode_NOTIMPLEMENTED ((SilKit_ReturnCode)3) +#define SilKit_ReturnCode_BADPARAMETER ((SilKit_ReturnCode)4) +#define SilKit_ReturnCode_BUFFERTOOSMALL ((SilKit_ReturnCode)5) +#define SilKit_ReturnCode_TIMEOUT ((SilKit_ReturnCode)6) +#define SilKit_ReturnCode_UNSUPPORTEDSERVICE ((SilKit_ReturnCode)7) + +// The following return codes have an corresponding specific SIL Kit exception. +// If an error occurs and a specific exception is thrown, it is caught in +// CapiImpl.hpp and the code defined here is returned. +// This completes the error handling for the usage of the C-API. + +// For the C++-Api, the return code is translated back to the specific SIL Kit +// exception and thrown in ThrowOnError.hpp. + +#define SilKit_ReturnCode_WRONGSTATE ((SilKit_ReturnCode)8) // SilKit::StateError +#define SilKit_ReturnCode_TYPECONVERSIONERROR ((SilKit_ReturnCode)9) // SilKit::TypeConversionError +#define SilKit_ReturnCode_CONFIGURATIONERROR ((SilKit_ReturnCode)10) // SilKit::ConfigurationError +#define SilKit_ReturnCode_PROTOCOLERROR ((SilKit_ReturnCode)11) // SilKit::ProtocolError +#define SilKit_ReturnCode_ASSERTIONERROR ((SilKit_ReturnCode)12) // SilKit::AssertionError +#define SilKit_ReturnCode_EXTENSIONERROR ((SilKit_ReturnCode)13) // SilKit::ExtensionError +#define SilKit_ReturnCode_LOGICERROR ((SilKit_ReturnCode)14) // SilKit::LogicError +#define SilKit_ReturnCode_LENGTHERROR ((SilKit_ReturnCode)15) // SilKit::LengthError +#define SilKit_ReturnCode_OUTOFRANGEERROR ((SilKit_ReturnCode)16) // SilKit::OutOfRangeError typedef uint64_t SilKit_NanosecondsTime; diff --git a/SilKit/include/silkit/detail/impl/ThrowOnError.hpp b/SilKit/include/silkit/detail/impl/ThrowOnError.hpp index fa159d108..ea381451a 100644 --- a/SilKit/include/silkit/detail/impl/ThrowOnError.hpp +++ b/SilKit/include/silkit/detail/impl/ThrowOnError.hpp @@ -69,7 +69,29 @@ void ThrowOnError(SilKit_ReturnCode returnCode) std::ostringstream os; os << "SIL Kit: " << returnCodeCstr << " (" << returnCode << "): " << lastErrorCstr; - throw SilKitError{os.str()}; + switch (returnCode) + { + case SilKit_ReturnCode_WRONGSTATE: + throw StateError{os.str()}; + case SilKit_ReturnCode_TYPECONVERSIONERROR: + throw TypeConversionError{os.str()}; + case SilKit_ReturnCode_CONFIGURATIONERROR: + throw ConfigurationError{os.str()}; + case SilKit_ReturnCode_PROTOCOLERROR: + throw ProtocolError{os.str()}; + case SilKit_ReturnCode_ASSERTIONERROR: + throw AssertionError{os.str()}; + case SilKit_ReturnCode_EXTENSIONERROR: + throw ExtensionError{os.str()}; + case SilKit_ReturnCode_LOGICERROR: + throw LogicError{os.str()}; + case SilKit_ReturnCode_LENGTHERROR: + throw LengthError{os.str()}; + case SilKit_ReturnCode_OUTOFRANGEERROR: + throw OutOfRangeError{os.str()}; + default: + throw SilKitError{os.str()}; + } } } diff --git a/SilKit/source/capi/CMakeLists.txt b/SilKit/source/capi/CMakeLists.txt index 9d1f0f9d2..08be2cf39 100644 --- a/SilKit/source/capi/CMakeLists.txt +++ b/SilKit/source/capi/CMakeLists.txt @@ -64,4 +64,5 @@ add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiTimeSync.cpp LIBS add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiLin.cpp LIBS S_SilKitImpl I_SilKit_Core_Mock_Participant) add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiSymbols.cpp LIBS S_SilKitImpl) add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiNetSim.cpp LIBS S_SilKitImpl I_SilKit_Core_Mock_Participant) +add_silkit_test_to_executable(SilKitUnitTests SOURCES Test_CapiExceptions.cpp LIBS S_SilKitImpl) diff --git a/SilKit/source/capi/CapiImpl.hpp b/SilKit/source/capi/CapiImpl.hpp index dcd9dbcf0..684af73f3 100644 --- a/SilKit/source/capi/CapiImpl.hpp +++ b/SilKit/source/capi/CapiImpl.hpp @@ -39,6 +39,46 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ SilKit_error_string = e.what(); \ return SilKit_ReturnCode_WRONGSTATE; \ } \ + catch (const SilKit::TypeConversionError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_TYPECONVERSIONERROR; \ + } \ + catch (const SilKit::ConfigurationError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_CONFIGURATIONERROR; \ + } \ + catch (const SilKit::ProtocolError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_PROTOCOLERROR; \ + } \ + catch (const SilKit::AssertionError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_ASSERTIONERROR; \ + } \ + catch (const SilKit::ExtensionError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_EXTENSIONERROR; \ + } \ + catch (const SilKit::LengthError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_LENGTHERROR; \ + } \ + catch (const SilKit::OutOfRangeError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_OUTOFRANGEERROR; \ + } \ + catch (const SilKit::LogicError& e) \ + { \ + SilKit_error_string = e.what(); \ + return SilKit_ReturnCode_LOGICERROR; \ + } \ catch (const SilKit::SilKitError& e) \ { \ SilKit_error_string = e.what(); \ diff --git a/SilKit/source/capi/Test_CapiExceptions.cpp b/SilKit/source/capi/Test_CapiExceptions.cpp new file mode 100644 index 000000000..819efa0bf --- /dev/null +++ b/SilKit/source/capi/Test_CapiExceptions.cpp @@ -0,0 +1,97 @@ +/* Copyright (c) 2022 Vector Informatik GmbH + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +#include "CapiImpl.hpp" +#include "silkit/detail/impl/ThrowOnError.hpp" + +namespace { + +class Test_CapiExceptions : public testing::Test +{ +public: + Test_CapiExceptions() {} +}; + +class UnknownException : public std::exception +{ +public: + UnknownException() {} + UnknownException(const char* /*message*/) {} +}; + +template +SilKit_ReturnCode TestExceptionToErrorCode() +try +{ + throw T{"error msg"}; +} +CAPI_CATCH_EXCEPTIONS + +// Not all compilers support std::exception with const char* initialization, so treat that std::exception separately +SilKit_ReturnCode TestStdExceptionToErrorCode() +try +{ + throw std::exception(); +} +CAPI_CATCH_EXCEPTIONS + + +// Each catch branch of CapiImpl.hpp CAPI_CATCH_EXCEPTIONS is tested for the expected return code +TEST_F(Test_CapiExceptions, catch_exception_macro) +{ + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_BADPARAMETER); + + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_TYPECONVERSIONERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_CONFIGURATIONERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_WRONGSTATE); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_PROTOCOLERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_ASSERTIONERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_EXTENSIONERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_LOGICERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_LENGTHERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_OUTOFRANGEERROR); + + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_UNSPECIFIEDERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_UNSPECIFIEDERROR); + EXPECT_EQ(TestExceptionToErrorCode(), SilKit_ReturnCode_UNSPECIFIEDERROR); + EXPECT_EQ(TestStdExceptionToErrorCode(), SilKit_ReturnCode_UNSPECIFIEDERROR); +} + +// Test that the C-API return code results in the correct exception +TEST_F(Test_CapiExceptions, throw_on_error) +{ + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_TYPECONVERSIONERROR), + SilKit::TypeConversionError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_CONFIGURATIONERROR), SilKit::ConfigurationError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_WRONGSTATE), SilKit::StateError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_PROTOCOLERROR), SilKit::ProtocolError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_ASSERTIONERROR), SilKit::AssertionError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_EXTENSIONERROR), SilKit::ExtensionError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_LOGICERROR), SilKit::LogicError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_LENGTHERROR), SilKit::LengthError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_OUTOFRANGEERROR), SilKit::OutOfRangeError); + EXPECT_THROW(SilKit::_detail_v1::Impl::ThrowOnError(SilKit_ReturnCode_UNSPECIFIEDERROR), SilKit::SilKitError); +} + + +} // namespace diff --git a/SilKit/source/capi/Test_CapiSilKit.cpp b/SilKit/source/capi/Test_CapiSilKit.cpp index 152768a1f..72800110b 100644 --- a/SilKit/source/capi/Test_CapiSilKit.cpp +++ b/SilKit/source/capi/Test_CapiSilKit.cpp @@ -25,48 +25,27 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "MockParticipant.hpp" namespace { -const auto SILKIT_CONFIG_STRING = R"aw( + +const auto SILKIT_CONFIG_STRING = R"( { - "ConfigVersion": "0.0.1", - "ConfigName" : "ConfigDemo", - "Description" : "Sample configuration for testing purposes", - - "SimulationSetup" : { - "Participants": [ - { - "Name": "Participant1", - "Description" : "Demo Participant with nothing going on" - } - ] - }, - - "MiddlewareConfig": { - "ActiveMiddleware": "VAsio" + "ParticipantName": "Participant1", + "Logging":{ + "Sinks":[{"Type":"Stdout","Level":"Info"}] } -} -)aw"; - -const auto SILKIT_MALFORMED_CONFIG_STRING = R"aw( -"ConfigVersion": "0.0.1"," -"ConfigName" : "ConfigDemo"," -"Description" : "Sample configuration for testing purposes", -"SimulationSetup" : { - "Participants": [ - { - "Name": "Participant1", - "Description" : "Demo Participant with nothing going on", - } - ], -}, -"MiddlewareConfig": { - "ActiveMiddleware": "VAsio" -} -} -)aw"; +})"; +const auto SILKIT_MALFORMED_CONFIG_STRING = R"( +{ +{ +{ + "ParticipantName: "Participant1", + "Logging": { + "Sinks":[{"Type":"Stdout","Level":"Info"}] + } +} +)"; using namespace SilKit::Services::Can; - using SilKit::Core::Tests::DummyParticipant; class Test_CapiSilKit : public testing::Test @@ -76,102 +55,94 @@ class Test_CapiSilKit : public testing::Test Test_CapiSilKit() {} }; -TEST_F(Test_CapiSilKit, silkit_function_mapping) +TEST_F(Test_CapiSilKit, silkit_bad_params) { SilKit_ReturnCode returnCode; + + { + // Bad / Invalid Parameter ParticipantConfiguration_FromString + SilKit_ParticipantConfiguration* participantConfigFromString = nullptr; + returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfigFromString, nullptr); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + EXPECT_TRUE(participantConfigFromString == nullptr); + + returnCode = SilKit_ParticipantConfiguration_FromString(nullptr, SILKIT_CONFIG_STRING); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + + returnCode = + SilKit_ParticipantConfiguration_FromString(&participantConfigFromString, SILKIT_MALFORMED_CONFIG_STRING); + EXPECT_EQ(returnCode, SilKit_ReturnCode_CONFIGURATIONERROR); + EXPECT_EQ(participantConfigFromString, nullptr); + } - SilKit_ParticipantConfiguration* participantConfiguration = nullptr; - returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfiguration, SILKIT_CONFIG_STRING); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - EXPECT_NE(participantConfiguration, nullptr); - - SilKit_ParticipantConfiguration* participantConfigurationFromFile = nullptr; - returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfigurationFromFile, - "ParticipantConfiguration_FullIncludes.yaml"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - EXPECT_NE(participantConfigurationFromFile, nullptr); - - SilKit_Participant* participant = nullptr; - returnCode = SilKit_Participant_Create(&participant, participantConfiguration, "Participant1", "42"); - // since there is no SIL Kit Registry, the call should fail - EXPECT_EQ(returnCode, SilKit_ReturnCode_UNSPECIFIEDERROR); - EXPECT_TRUE(participant == nullptr); - - // since there is no SIL Kit Registry with which one could create a Participant, we check against nullptr - returnCode = SilKit_Participant_Destroy(nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - - // destory the participant configuration to satisfy ASAN - returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfiguration); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfigurationFromFile); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); -} + { + // Bad / Invalid Parameter ParticipantConfiguration_FromFile + SilKit_ParticipantConfiguration* participantConfigFromFile = nullptr; + returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfigFromFile, nullptr); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + EXPECT_TRUE(participantConfigFromFile == nullptr); + returnCode = SilKit_ParticipantConfiguration_FromFile(nullptr, "ParticipantConfiguration_TestCapi.yaml"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); -TEST_F(Test_CapiSilKit, silkit_bad_params) -{ - SilKit_ReturnCode returnCode; + returnCode = + SilKit_ParticipantConfiguration_FromFile(&participantConfigFromFile, "this_file_does_not_exist.yaml"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_CONFIGURATIONERROR); + EXPECT_TRUE(participantConfigFromFile == nullptr); + } - SilKit_ParticipantConfiguration* participantConfiguration = nullptr; - - returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfiguration, SILKIT_CONFIG_STRING); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - EXPECT_NE(participantConfiguration, nullptr); - - SilKit_ParticipantConfiguration* participantConfigurationFromAFile = nullptr; - returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfigurationFromAFile, - "ParticipantConfiguration_FullIncludes.yaml"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - EXPECT_NE(participantConfigurationFromAFile, nullptr); - returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfigurationFromAFile); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - - - SilKit_Participant* participant = nullptr; - returnCode = SilKit_Participant_Create(nullptr, participantConfiguration, "Participant1", "42"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - returnCode = SilKit_Participant_Create(&participant, nullptr, "Participant1", "42"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - returnCode = SilKit_Participant_Create(&participant, participantConfiguration, nullptr, "42"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - returnCode = SilKit_Participant_Create(&participant, participantConfiguration, "Participant1", nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - - // Bad Parameter ParticipantConfiguration_FromString - returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfiguration, nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - returnCode = SilKit_ParticipantConfiguration_FromString(nullptr, SILKIT_CONFIG_STRING); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - - // Bad Parameter ParticipantConfiguration_FromFile - returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfigurationFromAFile, nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - returnCode = SilKit_ParticipantConfiguration_FromFile(nullptr, "ParticipantConfiguration_FullIncludes.yaml"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - - returnCode = SilKit_Participant_Create(&participant, participantConfiguration, "ParticipantNotExisting", "42"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_UNSPECIFIEDERROR); - - returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfiguration); - EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); - - returnCode = SilKit_ParticipantConfiguration_Destroy(nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); - - participantConfiguration = nullptr; - - returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfiguration, SILKIT_MALFORMED_CONFIG_STRING); - EXPECT_EQ(returnCode, SilKit_ReturnCode_UNSPECIFIEDERROR); - EXPECT_EQ(participantConfiguration, nullptr); - - returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfiguration, "this_file_does_not_exist.yaml"); - EXPECT_EQ(returnCode, SilKit_ReturnCode_UNSPECIFIEDERROR); - EXPECT_EQ(participantConfiguration, nullptr); - - // since there is no SIL Kit Registry with which one could create a Participant, we check against nullptr - returnCode = SilKit_Participant_Destroy(nullptr); - EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + { + // Bad / Invalid Parameter SilKit_Participant_Create + + // Create valid configuration FromString + SilKit_ParticipantConfiguration* participantConfigFromString = nullptr; + returnCode = SilKit_ParticipantConfiguration_FromString(&participantConfigFromString, SILKIT_CONFIG_STRING); + EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); + EXPECT_NE(participantConfigFromString, nullptr); + + // Create valid configuration FromFile + SilKit_ParticipantConfiguration* participantConfigFromFile = nullptr; + returnCode = SilKit_ParticipantConfiguration_FromFile(&participantConfigFromFile, + "ParticipantConfiguration_TestCapi.yaml"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); + EXPECT_NE(participantConfigFromFile, nullptr); + + SilKit_Participant* participant = nullptr; + returnCode = + SilKit_Participant_Create(nullptr, participantConfigFromString, "Participant1", "silkit://localhost:7"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + + returnCode = SilKit_Participant_Create(&participant, nullptr, "Participant1", "silkit://localhost:7"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + EXPECT_TRUE(participant == nullptr); + + returnCode = + SilKit_Participant_Create(&participant, participantConfigFromFile, nullptr, "silkit://localhost:7"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + EXPECT_TRUE(participant == nullptr); + + returnCode = SilKit_Participant_Create(&participant, participantConfigFromString, "Participant1", nullptr); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + EXPECT_TRUE(participant == nullptr); + + // There is no SIL Kit Registry running on port 7, the call should fail + returnCode = + SilKit_Participant_Create(&participant, participantConfigFromFile, "Participant1", "silkit://localhost:7"); + EXPECT_EQ(returnCode, SilKit_ReturnCode_UNSPECIFIEDERROR); + EXPECT_TRUE(participant == nullptr); + + // Clean up the configs + returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfigFromFile); + EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); + returnCode = SilKit_ParticipantConfiguration_Destroy(participantConfigFromString); + EXPECT_EQ(returnCode, SilKit_ReturnCode_SUCCESS); + } + + { + // Bad Parameter SilKit_Participant_Destroy + returnCode = SilKit_Participant_Destroy(nullptr); + EXPECT_EQ(returnCode, SilKit_ReturnCode_BADPARAMETER); + } } } // namespace diff --git a/SilKit/source/config/CMakeLists.txt b/SilKit/source/config/CMakeLists.txt index 0239b3876..609bfde90 100644 --- a/SilKit/source/config/CMakeLists.txt +++ b/SilKit/source/config/CMakeLists.txt @@ -76,6 +76,7 @@ add_silkit_test_to_executable(SilKitUnitTests ParticipantConfiguration_Full.json ParticipantConfiguration_Full.yaml + TestParticipantConfigs/ParticipantConfiguration_TestCapi.yaml TestParticipantConfigs/ParticipantConfiguration_FullIncludes.yaml TestParticipantConfigs/ParticipantConfiguration_FullIncludes_Reference.yaml diff --git a/SilKit/source/config/TestParticipantConfigs/ParticipantConfiguration_TestCapi.yaml b/SilKit/source/config/TestParticipantConfigs/ParticipantConfiguration_TestCapi.yaml new file mode 100644 index 000000000..d4bd7f6db --- /dev/null +++ b/SilKit/source/config/TestParticipantConfigs/ParticipantConfiguration_TestCapi.yaml @@ -0,0 +1,6 @@ +Description: Example configuration used in Test_CapiSilkit +Logging: + Sinks: + - Type: Stdout + Level: Trace + diff --git a/docs/CHANGELOG.rst b/docs/CHANGELOG.rst index 094732a20..39dfecc68 100644 --- a/docs/CHANGELOG.rst +++ b/docs/CHANGELOG.rst @@ -21,6 +21,13 @@ Fixed does not break the ABI of the shared libraries. +- Aligned C API error return codes ``SilKit_ReturnCode_`` and SIL Kit specific exceptions. + All exceptions are now forwarded through the hourglass and thrown in the C++ API. + For users of the C API, a more detailed error handling is possible with the extended error return codes. + + Before, all execptions ended up as ``SilKitError`` on the user side. + + [4.0.54] - 2024-11-11 ---------------------