// Copyright Epic Games, Inc. All Rights Reserved. #include #if ZEN_PLATFORM_WINDOWS # include #endif #if ZEN_PLATFORM_LINUX # include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace zen::assert { void ExecAssertFmt(const char* Filename, int LineNumber, const char* FunctionName, std::string_view Format, fmt::format_args Args) { fmt::basic_memory_buffer Message; fmt::vformat_to(fmt::appender(Message), Format, Args); Message.push_back('\0'); AssertImpl::ExecAssert(Filename, LineNumber, FunctionName, Message.data()); } } // namespace zen::assert namespace zen { void refcount_forcelink(); AssertImpl AssertImpl::DefaultAssertImpl; AssertImpl* AssertImpl::CurrentAssertImpl = &AssertImpl::DefaultAssertImpl; ////////////////////////////////////////////////////////////////////////// bool IsDebuggerPresent() { #if ZEN_PLATFORM_WINDOWS return ::IsDebuggerPresent(); #else return false; #endif } std::optional InteractiveSessionFlag; void SetIsInteractiveSession(bool Value) { InteractiveSessionFlag = Value; } bool IsInteractiveSession() { if (!InteractiveSessionFlag.has_value()) { #if ZEN_PLATFORM_WINDOWS DWORD dwSessionId = 0; if (ProcessIdToSessionId(GetCurrentProcessId(), &dwSessionId)) { InteractiveSessionFlag = (dwSessionId != 0); } else { InteractiveSessionFlag = false; } #else // TODO: figure out what actually makes sense here InteractiveSessionFlag = true; #endif } return InteractiveSessionFlag.value(); } ////////////////////////////////////////////////////////////////////////// static int s_ApplicationExitCode = 0; static bool s_ApplicationExitRequested; bool IsApplicationExitRequested() { return s_ApplicationExitRequested; } void RequestApplicationExit(int ExitCode) { s_ApplicationExitCode = ExitCode; s_ApplicationExitRequested = true; } int ApplicationExitCode() { return s_ApplicationExitCode; } #if ZEN_WITH_TESTS void zencore_forcelinktests() { zen::blake3_forcelink(); zen::compositebuffer_forcelink(); zen::compress_forcelink(); zen::crypto_forcelink(); zen::filesystem_forcelink(); zen::jobqueue_forcelink(); zen::intmath_forcelink(); zen::iobuffer_forcelink(); zen::logging_forcelink(); zen::memory_forcelink(); zen::mpscqueue_forcelink(); zen::process_forcelink(); zen::refcount_forcelink(); zen::sha1_forcelink(); zen::stats_forcelink(); zen::stream_forcelink(); zen::string_forcelink(); zen::thread_forcelink(); zen::timer_forcelink(); zen::uid_forcelink(); zen::uson_forcelink(); zen::usonbuilder_forcelink(); zen::usonpackage_forcelink(); zen::workthreadpool_forcelink(); } } // namespace zen # include namespace zen { TEST_SUITE_BEGIN("core.assert"); TEST_CASE("Assert.Default") { bool A = true; bool B = false; CHECK_THROWS_WITH(ZEN_ASSERT(A == B), "A == B"); } TEST_CASE("Assert.Format") { bool A = true; bool B = false; CHECK_THROWS_WITH(ZEN_ASSERT_FORMAT(A == B, "{} == {}", A, B), "assert(A == B) failed: true == false"); } TEST_CASE("Assert.Custom") { struct MyAssertImpl : AssertImpl { ZEN_FORCENOINLINE ZEN_DEBUG_SECTION MyAssertImpl() : PrevAssertImpl(CurrentAssertImpl) { CurrentAssertImpl = this; } virtual ZEN_FORCENOINLINE ZEN_DEBUG_SECTION ~MyAssertImpl() { CurrentAssertImpl = PrevAssertImpl; } virtual void ZEN_FORCENOINLINE ZEN_DEBUG_SECTION OnAssert(const char* Filename, int LineNumber, const char* FunctionName, const char* Msg) { AssertFileName = Filename; Line = LineNumber; FuncName = FunctionName; Message = Msg; } AssertImpl* PrevAssertImpl; const char* AssertFileName = nullptr; int Line = -1; const char* FuncName = nullptr; const char* Message = nullptr; }; MyAssertImpl MyAssert; bool A = true; bool B = false; CHECK_THROWS_WITH(ZEN_ASSERT(A == B), "A == B"); CHECK(MyAssert.AssertFileName != nullptr); CHECK(MyAssert.Line != -1); CHECK(MyAssert.FuncName != nullptr); CHECK(strcmp(MyAssert.Message, "A == B") == 0); } TEST_SUITE_END(); #endif } // namespace zen