diff --git a/.gitea/workflows/sonarqube.yml b/.gitea/workflows/sonarqube.yml index 2f481ea..a642d6e 100644 --- a/.gitea/workflows/sonarqube.yml +++ b/.gitea/workflows/sonarqube.yml @@ -41,7 +41,7 @@ jobs: run: | cd ./build-toolmode/Debug . ../../build-toolmode/build/Debug/generators/conanbuild.sh - LLVM_PROFILE_FILE="%p.profraw" xvfb-run ctest --output-on-failure + LLVM_PROFILE_FILE="%p.profraw%c" xvfb-run ctest --output-on-failure . ../../build-toolmode/build/Debug/generators/deactivate_conanbuild.sh - name: Clang-Tidy diff --git a/Bigfoot/Sources/Utils/Include/Utils/Assert/Assert.hpp b/Bigfoot/Sources/Utils/Include/Utils/Assert/Assert.hpp index ef74771..d3364c1 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Assert/Assert.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Assert/Assert.hpp @@ -7,25 +7,21 @@ #ifndef BIGFOOT_UTILS_ASSERT_HPP #define BIGFOOT_UTILS_ASSERT_HPP #include +#include #if defined BIGFOOT_NOT_OPTIMIZED +#include +#include +#include + +#include #include -#include #if defined BIGFOOT_LINUX #include #endif -#define BIGFOOT_FLUSH_LOG \ - do \ - { \ - if (Bigfoot::Singleton::HasInstance()) \ - { \ - Bigfoot::Singleton::GetInstance().Flush(); \ - } \ - } while (false) - #if defined BIGFOOT_WINDOWS #define BREAK \ do \ @@ -42,39 +38,71 @@ } while (false) #endif +namespace Bigfoot +{ +/** + * Assert then break + * + * \param p_condition The condition to check + * \param p_message A function that will return the formatting string describing the issue + * \param p_location The location the assert originates from + */ +template +BIGFOOT_ALWAYS_INLINE void AssertCheck(const bool p_condition, + const eastl::fixed_function<32, eastl::string()>& p_messageFn, + const std::source_location p_location = std::source_location::current()) +{ + if (!p_condition) [[unlikely]] + { + HANDLER::Handle(p_location, p_messageFn()); + BREAK; + } +} + +/** + * Assert then break then kill + * + * \param p_condition The condition to check + * \param p_message A function that will return the formatting string describing the issue + * \param p_location The location the assert originates from + */ +template +BIGFOOT_ALWAYS_INLINE void CriticalAssertCheck(const bool p_condition, + const eastl::fixed_function<32, eastl::string()>& p_messageFn, + const std::source_location p_location = std::source_location::current()) +{ + if (!p_condition) [[unlikely]] + { + HANDLER::Handle(p_location, p_messageFn()); + BREAK; + std::abort(); + } +} +} // namespace Bigfoot + #define ASSERT(HANDLER, p_assert, p_message, ...) \ - do \ - { \ - constexpr std::source_location location = std::source_location::current(); \ - if (!(p_assert)) [[unlikely]] \ - { \ - HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ - BREAK; \ - } \ - } while (false) + ::Bigfoot::AssertCheck((p_assert), \ + [&] \ + { \ + return eastl::string { \ + fmt::format(p_message __VA_OPT__(, ) __VA_ARGS__).c_str()}; \ + }) #define SOFT_ASSERT(HANDLER, p_assert, p_message, ...) \ - do \ - { \ - constexpr std::source_location location = std::source_location::current(); \ - if (!(p_assert)) [[unlikely]] \ - { \ - HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ - BREAK; \ - } \ - } while (false) + ::Bigfoot::AssertCheck((p_assert), \ + [&] \ + { \ + return eastl::string { \ + fmt::format(p_message __VA_OPT__(, ) __VA_ARGS__).c_str()}; \ + }) #define CRITICAL_ASSERT(HANDLER, p_assert, p_message, ...) \ - do \ - { \ - constexpr std::source_location location = std::source_location::current(); \ - if (!(p_assert)) [[unlikely]] \ - { \ - HANDLER::Handle(location, p_message __VA_OPT__(, ) __VA_ARGS__); \ - BREAK; \ - std::abort(); \ - } \ - } while (false) + ::Bigfoot::CriticalAssertCheck((p_assert), \ + [&] \ + { \ + return eastl::string { \ + fmt::format(p_message __VA_OPT__(, ) __VA_ARGS__).c_str()}; \ + }) #else #define ASSERT(HANDLER, p_assert, p_message, ...) diff --git a/Bigfoot/Sources/Utils/Include/Utils/Assert/AssertHandler.hpp b/Bigfoot/Sources/Utils/Include/Utils/Assert/AssertHandler.hpp index 7c21081..e8b4b1d 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Assert/AssertHandler.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Assert/AssertHandler.hpp @@ -11,7 +11,7 @@ #if defined BIGFOOT_NOT_OPTIMIZED -#include +#include #include @@ -32,15 +32,13 @@ class AssertHandler * Handle an assertion. * * \param p_location Location of the assertion. - * \param p_format Format string for the assertion message. - * \param p_args Arguments for the format string. + * \param p_message Message describing the assertion failure. */ - template - static void Handle(const std::source_location& p_location, fmt::format_string p_format, ARGS&&... p_args) + static void Handle(const std::source_location& p_location, const eastl::string& p_message) { BIGFOOT_LOG_FATAL(LOGGER, "Assert: {} (File:{}, Line:{}, Function:{}\n", - fmt::format(p_format, std::forward(p_args)...), + p_message, p_location.file_name(), p_location.line(), p_location.function_name()); diff --git a/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp b/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp index ba8eb39..08d3a10 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp +++ b/Bigfoot/Sources/Utils/Include/Utils/Log/LogMacros.hpp @@ -10,6 +10,15 @@ #include #if defined BIGFOOT_NOT_OPTIMIZED +#define BIGFOOT_FLUSH_LOG \ + do \ + { \ + if (Bigfoot::Singleton::HasInstance()) \ + { \ + Bigfoot::Singleton::GetInstance().Flush(); \ + } \ + } while (false) + #define BIGFOOT_LOG_DEBUG(loggerName, fmt, ...) \ do \ { \ diff --git a/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h b/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h index 9c019b1..fceadb8 100644 --- a/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h +++ b/Bigfoot/Sources/Utils/Include/Utils/TargetMacros.h @@ -15,6 +15,12 @@ #define BIGFOOT_WINDOWS_OR_LINUX(p_windows, p_linux) p_linux #endif +#if defined BIGFOOT_WINDOWS +#define BIGFOOT_ALWAYS_INLINE [[msvc::forceinline]] +#elif defined BIGFOOT_LINUX +#define BIGFOOT_ALWAYS_INLINE [[gnu::always_inline]] inline +#endif + #if defined BIGFOOT_OPTIMIZED #define BIGFOOT_OPTIMIZED_ONLY(...) __VA_ARGS__ #define BIGFOOT_NOT_OPTIMIZED_ONLY(...) diff --git a/Bigfoot/Tests/Engine/EngineTests/main.cpp b/Bigfoot/Tests/Engine/EngineTests/main.cpp index 6645ee3..0a50313 100644 --- a/Bigfoot/Tests/Engine/EngineTests/main.cpp +++ b/Bigfoot/Tests/Engine/EngineTests/main.cpp @@ -13,6 +13,8 @@ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); return RUN_ALL_TESTS(); diff --git a/Bigfoot/Tests/System/SystemTests/main.cpp b/Bigfoot/Tests/System/SystemTests/main.cpp index 6645ee3..0a50313 100644 --- a/Bigfoot/Tests/System/SystemTests/main.cpp +++ b/Bigfoot/Tests/System/SystemTests/main.cpp @@ -13,6 +13,8 @@ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); return RUN_ALL_TESTS(); diff --git a/Bigfoot/Tests/Tools/SasquatchBaker/SasquatchBakerTests/main.cpp b/Bigfoot/Tests/Tools/SasquatchBaker/SasquatchBakerTests/main.cpp index ec88d0c..d8fe0b5 100644 --- a/Bigfoot/Tests/Tools/SasquatchBaker/SasquatchBakerTests/main.cpp +++ b/Bigfoot/Tests/Tools/SasquatchBaker/SasquatchBakerTests/main.cpp @@ -13,6 +13,8 @@ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); return RUN_ALL_TESTS(); diff --git a/Bigfoot/Tests/Utils/Assert/Assert.cpp b/Bigfoot/Tests/Utils/Assert/Assert.cpp new file mode 100644 index 0000000..ad11a53 --- /dev/null +++ b/Bigfoot/Tests/Utils/Assert/Assert.cpp @@ -0,0 +1,33 @@ +/********************************************************************* + * \file Assert.cpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#include + +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +#include + +namespace Bigfoot +{ +using TestAssertHandler = AssertHandler; + +/****************************************************************************************/ + +TEST(AssertDeathTest, Assert_ShouldTerminateTheProcessWhenTheConditionIsFalse) +{ + EXPECT_DEATH({ ASSERT(TestAssertHandler, false, "Something went wrong: {}", 42); }, ""); +} + +/****************************************************************************************/ + +TEST(AssertDeathTest, CriticalAssert_ShouldTerminateTheProcessWhenTheConditionIsFalse) +{ + EXPECT_DEATH({ CRITICAL_ASSERT(TestAssertHandler, false, "Something critical went wrong: {}", 42); }, ""); +} +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Tests/Utils/Assert/AssertHandler.cpp b/Bigfoot/Tests/Utils/Assert/AssertHandler.cpp new file mode 100644 index 0000000..3c19238 --- /dev/null +++ b/Bigfoot/Tests/Utils/Assert/AssertHandler.cpp @@ -0,0 +1,63 @@ +/********************************************************************* + * \file AssertHandler.cpp + * + * \author Romain BOULLARD + * \date September 2026 + *********************************************************************/ +#include + +#include + +#include + +#if defined BIGFOOT_NOT_OPTIMIZED + +#include +#include +#include +#include + +#include +#include +#include + +namespace Bigfoot +{ +class AssertHandlerFixture: public ::testing::Test +{ + protected: + eastl::string ReadFileSinkContent() + { + Singleton::GetInstance().Flush(); + + std::ifstream file {std::string {Log::FILE_SINK_PATH.data()}}; + std::stringstream buffer; + buffer << file.rdbuf(); + return eastl::string {buffer.str().c_str()}; + } +}; + +/****************************************************************************************/ + +TEST_F(AssertHandlerFixture, Handle_ShouldLogAFatalMessageContainingTheGivenMessage) +{ + constexpr std::source_location location = std::source_location::current(); + AssertHandler::Handle(location, + eastl::string {fmt::format("Something went wrong: {}", 42).c_str()}); + + EXPECT_THAT(std::string {ReadFileSinkContent().c_str()}, ::testing::HasSubstr("Something went wrong: 42")); +} + +/****************************************************************************************/ + +TEST_F(AssertHandlerFixture, Handle_ShouldLogAFatalMessageContainingTheSourceLocation) +{ + constexpr std::source_location location = std::source_location::current(); + AssertHandler::Handle(location, "Doesn't matter"); + + const std::string content {ReadFileSinkContent().c_str()}; + EXPECT_THAT(content, ::testing::HasSubstr(location.file_name())); + EXPECT_THAT(content, ::testing::HasSubstr(location.function_name())); +} +} // namespace Bigfoot +#endif diff --git a/Bigfoot/Tests/Utils/UtilsTests/main.cpp b/Bigfoot/Tests/Utils/UtilsTests/main.cpp index 6645ee3..0a50313 100644 --- a/Bigfoot/Tests/Utils/UtilsTests/main.cpp +++ b/Bigfoot/Tests/Utils/UtilsTests/main.cpp @@ -13,6 +13,8 @@ int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); + GTEST_FLAG_SET(death_test_style, "threadsafe"); + BIGFOOT_NOT_OPTIMIZED_ONLY(::Bigfoot::Singleton<::Bigfoot::Log>::Lifetime m_lifetime); return RUN_ALL_TESTS(); diff --git a/CMake/CustomTargets.cmake b/CMake/CustomTargets.cmake index ada8bd5..66807c4 100644 --- a/CMake/CustomTargets.cmake +++ b/CMake/CustomTargets.cmake @@ -3,11 +3,11 @@ add_library(BigfootCompileAndLinkFlags INTERFACE) target_compile_options(BigfootCompileAndLinkFlags INTERFACE $<$:/W4 /WX> $<$:-Wall -Wextra -Wpedantic -Werror> - $<$,$>:-fprofile-instr-generate -fcoverage-mapping> + $<$,$>:-fprofile-instr-generate -fcoverage-mapping -fprofile-continuous> ) target_link_options(BigfootCompileAndLinkFlags INTERFACE - $<$,$>:-fprofile-instr-generate> + $<$,$>:-fprofile-instr-generate -fprofile-continuous> ) target_compile_definitions(BigfootCompileAndLinkFlags INTERFACE