diff --git a/.forgejo/workflows/pr_check.yaml b/.forgejo/workflows/pr_check.yaml index b8f8f80..cd9c23a 100644 --- a/.forgejo/workflows/pr_check.yaml +++ b/.forgejo/workflows/pr_check.yaml @@ -134,6 +134,8 @@ jobs: -GNinja -DCMAKE_BUILD_TYPE=Release \ -DENABLE_EXAMPLES=ON \ -DENABLE_TESTS=ON \ + -DMAX_LOG_LEVEL=0 \ + -DTEST_MAX_LOG_LEVEL=0 \ -DCMAKE_CXX_FLAGS="-ftemplate-backtrace-limit=0" cmake --build ${{ github.workspace }}/build_gcc --parallel `nproc` @@ -160,6 +162,8 @@ jobs: -GNinja -DCMAKE_BUILD_TYPE=Release \ -DENABLE_EXAMPLES=ON \ -DENABLE_TESTS=ON \ + -DMAX_LOG_LEVEL=0 \ + -DTEST_MAX_LOG_LEVEL=0 \ -DCMAKE_CXX_FLAGS="-stdlib=libc++ -I/home/LLVM-${LLVM_VER}/include/c++/v1 -fno-modules" echo "::group::compile_commands.json content" diff --git a/.vscode/launch.json b/.vscode/launch.json index fa2cb78..6f11203 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,10 @@ "request": "launch", "name": "Debug: connect", "program": "${workspaceFolder}/build/examples/output/connect", - "args": [], + "args": [ + "--log_level=0" + // --gtest_filter=POSTIVE_PATTERNS[-NEGATIVE_PATTERNS] + ], "cwd": "${workspaceFolder}", "preLaunchTask": "GCC: Build" }, @@ -19,6 +22,7 @@ "name": "Debug: tests", "program": "${workspaceFolder}/build/larra_xmpp_tests", "args": [ + "--log_level=0" // --gtest_filter=POSTIVE_PATTERNS[-NEGATIVE_PATTERNS] // "--gtest_filter=Roster*" ], diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 4720fa7..99fb723 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -79,8 +79,8 @@ "command": [ "cd ${workspaceFolder} &&", "mkdir -p build && cd build &&", - "cmake cmake -Wno-dev ", - " -DCMAKE_BUILD_TYPE=Debug -DENABLE_EXAMPLES=ON -DENABLE_TESTS=ON .." + "cmake -Wno-dev ", + " -DCMAKE_BUILD_TYPE=Debug -DENABLE_EXAMPLES=ON -DENABLE_TESTS=ON -DMAX_LOG_LEVEL=0 -DTEST_MAX_LOG_LEVEL=0 .." ], "options": { "env": { @@ -138,6 +138,7 @@ "mkdir -p build_clang && cd build_clang &&", "cmake -Wno-dev ", " -DCMAKE_BUILD_TYPE=Debug -DENABLE_EXAMPLES=ON -DENABLE_TESTS=ON ", + " -DMAX_LOG_LEVEL=0 -DTEST_MAX_LOG_LEVEL=0", " -DCMAKE_CXX_FLAGS=\"-stdlib=libstdc++\"", " -DCMAKE_EXE_LINKER_FLAGS=\"-L/usr/lib/x86_64-linux-gnu -lstdc++\" .." ], @@ -160,6 +161,7 @@ "mkdir -p build_clang && cd build_clang &&", "cmake -Wno-dev ", " -DCMAKE_BUILD_TYPE=Debug -DENABLE_EXAMPLES=ON -DENABLE_TESTS=ON", + " -DMAX_LOG_LEVEL=0 -DTEST_MAX_LOG_LEVEL=0", // // Uncomment for GCC standart library: libstdc++ //" -DCMAKE_CXX_FLAGS=\"-stdlib=libstdc++ -fno-omit-frame-pointer -g -fsanitize=address,undefined,leak,function,nullability,vptr\"", @@ -211,6 +213,7 @@ "mkdir -p build_clang && cd build_clang &&", "cmake -Wno-dev ", " -DCMAKE_BUILD_TYPE=Debug -DENABLE_EXAMPLES=ON -DENABLE_TESTS=ON ", + " -DMAX_LOG_LEVEL=0 -DTEST_MAX_LOG_LEVEL=0", " -DCMAKE_CXX_FLAGS=\"-stdlib=libstdc++ -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -fsanitize=memory\"", " -DCMAKE_EXE_LINKER_FLAGS=\"-L/usr/lib/x86_64-linux-gnu -lstdc++ -fsanitize-memory-track-origins=2 -fno-omit-frame-pointer -fno-optimize-sibling-calls -g -fsanitize=memory\" ..", ], diff --git a/CMakeLists.txt b/CMakeLists.txt index 3ed51f5..389da96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,8 @@ set(BOOST_INCLUDE_LIBRARIES "pfr;asio;serialization") option(CPM_USE_LOCAL_PACKAGES "Use local packages" ON) option(UTEMPL_USE_LOCAL_PACKAGE "Use utempl local package" OFF) option(BUILD_EXECUTABLE ON) -option(LOG_LEVEL 0 "Available log levels: 0=TRACE, 1=DEBUG,2= INFO,3= WARN, 4=ERROR, 5=CRITICAL, 6=OFF") # Compile program with highest available log levle to trace everything +set(MAX_LOG_LEVEL 2 CACHE STRING "Available log levels: 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=CRITICAL, 6=OFF") +set(TEST_MAX_LOG_LEVEL 2 CACHE STRING "Available log levels: 0=TRACE, 1=DEBUG, 2=INFO, 3=WARN, 4=ERROR, 5=CRITICAL, 6=OFF") set(UTEMPL_URL "https://sha512sum.xyz/git/sha512sum/utempl" CACHE STRING "utempl repository URL") @@ -260,7 +261,7 @@ if(ENABLE_TESTS) target_sources(larra_xmpp_tests PUBLIC ${SOURCES}) target_link_libraries(larra_xmpp_tests GTest::gtest_main larra_xmpp) - target_compile_definitions(larra_xmpp_tests PRIVATE SPDLOG_ACTIVE_LEVEL=0) # SPDLOG_LEVEL_TRACE=0. Check LOG_LEVEL variable and spdlog documentation for more details + target_compile_definitions(larra_xmpp_tests PRIVATE SPDLOG_ACTIVE_LEVEL=${TEST_MAX_LOG_LEVEL}) set_property(TARGET larra_xmpp_tests PROPERTY CXX_STANDARD 23) include(GoogleTest) gtest_discover_tests(larra_xmpp_tests) @@ -272,7 +273,7 @@ if(ENABLE_EXAMPLES) get_filename_component(EXAMPLE_NAME ${EXAMPLE_SRC} NAME_WE) add_executable(${EXAMPLE_NAME} ${EXAMPLE_SRC}) target_link_libraries(${EXAMPLE_NAME} larra_xmpp) - target_compile_definitions(${EXAMPLE_NAME} PRIVATE SPDLOG_ACTIVE_LEVEL=${LOG_LEVEL}) + target_compile_definitions(${EXAMPLE_NAME} PRIVATE SPDLOG_ACTIVE_LEVEL=${TEST_MAX_LOG_LEVEL}) set_property(TARGET ${EXAMPLE_NAME} PROPERTY CXX_STANDARD 23) set_target_properties(${EXAMPLE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/examples/output") diff --git a/tests/iq.cpp b/tests/iq.cpp index 4638ffe..3545e51 100644 --- a/tests/iq.cpp +++ b/tests/iq.cpp @@ -1,10 +1,23 @@ #include +#include #include +#include namespace { -static constexpr auto kExpectedData = "\n37\n"; +static constexpr auto kForbiddenErrorData = R"( + +)"; + +static constexpr auto kExpectedSetData = R"( +37 +)"; + +static constexpr auto kExpectedData = R"( +37 +)"; + struct SomeStruct { int value; constexpr auto operator==(const SomeStruct&) const -> bool = default; @@ -43,4 +56,101 @@ TEST(IQ, Parse) { EXPECT_EQ(S::Parse(node), iq); } +TEST(IQ, ParseForbiddenError) { + std::istringstream xml_stream(kForbiddenErrorData); + + xmlpp::DomParser parser; + parser.parse_stream(xml_stream); + + using S = Serialization>; + xmlpp::Document* doc = parser.get_document(); + auto iqRes = S::Parse(doc->get_root_node()); + + ASSERT_TRUE(std::holds_alternative(iqRes)); + + auto errorRes = std::get(iqRes); + ASSERT_TRUE(std::holds_alternative(errorRes.payload)); +} + +TEST(IQ, IqErrThrowVisitorThrow) { + std::istringstream xml_stream(kForbiddenErrorData); + + xmlpp::DomParser parser; + parser.parse_stream(xml_stream); + + using S = Serialization>; + xmlpp::Document* doc = parser.get_document(); + auto iqRes = S::Parse(doc->get_root_node()); + ASSERT_TRUE(std::holds_alternative(iqRes)); + + static constexpr auto visitorErrMsg = "Test Error"; + static constexpr auto throwErrMsg = "Stanza IQ Error: Forbidden"; + try { + std::visit(utempl::Overloaded([](iq::Result r) {}, IqErrThrowVisitor{visitorErrMsg}), std::move(iqRes)); + } catch(const stanza::error::StanzaBaseError& err) { + ASSERT_STREQ(throwErrMsg, err.what()); + return; + } catch(const std::runtime_error& err) { + ASSERT_TRUE(false) << "Invalid throw type throw"; + } catch(...) { + ASSERT_TRUE(false) << "Unexpected throw"; + } + + ASSERT_TRUE(false) << "Expected throwing an exception due to an error in output"; +} + +TEST(IQ, IqErrThrowVisitorThrowGet) { + std::istringstream xml_stream(kExpectedData); + + xmlpp::DomParser parser; + parser.parse_stream(xml_stream); + + using S = Serialization>; + xmlpp::Document* doc = parser.get_document(); + auto iqRes = S::Parse(doc->get_root_node()); + ASSERT_TRUE(std::holds_alternative>(iqRes)) << "\tERROR: Unexpected parse result"; + + static constexpr auto visitorErrMsg = "Test Error"; + static constexpr auto throwErrMsg = "Test Error: 'Get' is an invalid type for IQ result. Expected 'Result' or 'Error'"; + try { + std::visit(utempl::Overloaded([](iq::Result r) {}, IqErrThrowVisitor{"Test Error"}), std::move(iqRes)); + } catch(const stanza::error::StanzaBaseError& err) { + ASSERT_TRUE(false) << "\tERROR: Invalid throw type throw"; + } catch(const std::runtime_error& err) { + ASSERT_STREQ(throwErrMsg, err.what()); + return; + } catch(...) { + ASSERT_TRUE(false) << "\tERROR: Unexpected throw"; + } + + ASSERT_TRUE(false) << "\tERROR: Expected throwing an exception due to an error in output"; +} + +TEST(IQ, IqErrThrowVisitorThrowSet) { + std::istringstream xml_stream(kExpectedSetData); + + xmlpp::DomParser parser; + parser.parse_stream(xml_stream); + + using S = Serialization>; + xmlpp::Document* doc = parser.get_document(); + auto iqRes = S::Parse(doc->get_root_node()); + ASSERT_TRUE(std::holds_alternative>(iqRes)) << "\tERROR: Unexpected parse result"; + + static constexpr auto visitorErrMsg = "Test Error"; + static constexpr auto throwErrMsg = "Test Error: 'Set' is an invalid type for IQ result. Expected 'Result' or 'Error'"; + try { + std::visit(utempl::Overloaded([](iq::Result r) {}, IqErrThrowVisitor{"Test Error"}), std::move(iqRes)); + } catch(const stanza::error::StanzaBaseError& err) { + ASSERT_TRUE(false) << "\tERROR: Invalid throw type throw"; + } catch(const std::runtime_error& err) { + ASSERT_STREQ(throwErrMsg, err.what()); + return; + } catch(...) { + ASSERT_TRUE(false) << "\tERROR: Unexpected throw"; + } + + ASSERT_TRUE(false) << "\tERROR: Expected throwing an exception due to an error in output"; +} + } // namespace larra::xmpp