int assert_report(hash_t context, const char* condition, size_t cond_length, const char* file, size_t file_length, unsigned int line, const char* msg, size_t msg_length) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %.*s\nFile/line: %.*s : %d\n%.*s%.*s\n%.*s\n"; #if BUILD_ENABLE_ASSERT string_t tracestr = { _assert_stacktrace_buffer, sizeof(_assert_stacktrace_buffer) }; string_t contextstr = { _assert_context_buffer, sizeof(_assert_context_buffer) }; string_t messagestr = { _assert_message_buffer, sizeof(_assert_message_buffer) }; #endif if (!condition || !cond_length) { condition = nocondition; cond_length = sizeof(nocondition); } if (!file || !file_length) { file = nofile; file_length = sizeof(nofile); } if (!msg || !msg_length) { msg = nomsg; msg_length = sizeof(nomsg); } if (_assert_handler && (_assert_handler != assert_report)) return (*_assert_handler)(context, condition, cond_length, file, file_length, line, msg, msg_length); #if BUILD_ENABLE_ASSERT contextstr = error_context_buffer(STRING_ARGS(contextstr)); if (foundation_is_initialized()) { size_t num_frames = stacktrace_capture(_assert_stacktrace, ASSERT_STACKTRACE_MAX_DEPTH, ASSERT_STACKTRACE_SKIP_FRAMES); if (num_frames) tracestr = stacktrace_resolve(STRING_ARGS(tracestr), _assert_stacktrace, num_frames, 0U); else tracestr = string_copy(STRING_ARGS(tracestr), STRING_CONST("<no stacktrace>")); } else { tracestr = string_copy(STRING_ARGS(tracestr), STRING_CONST("<no stacktrace - not initialized>")); } messagestr = string_format(STRING_ARGS(messagestr), assert_format, sizeof(assert_format) - 1, (int)cond_length, condition, (int)file_length, file, line, STRING_FORMAT(contextstr), (int)msg_length, msg, STRING_FORMAT(tracestr)); log_errorf(context, ERROR_ASSERT, STRING_CONST("%.*s"), STRING_FORMAT(messagestr)); system_message_box(STRING_CONST("Assert Failure"), STRING_ARGS(messagestr), false); #else log_errorf(context, ERROR_ASSERT, assert_format, sizeof(assert_format) - 1, (int)cond_length, condition, (int)file_length, file, line, 0, "", (int)msg_length, msg, 0, ""); #endif return 1; }
int assert_report( uint64_t context, const char* condition, const char* file, int line, const char* msg ) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %s\nFile/line: %s : %d\n%s%s\n%s\n"; if( !condition ) condition = nocondition; if( !file ) file = nofile; if( !msg ) msg = nomsg; if( _assert_handler && ( _assert_handler != assert_report ) ) return (*_assert_handler)( context, condition, file, line, msg ); #if BUILD_ENABLE_ASSERT _assert_context_buffer[0] = 0; error_context_buffer( _assert_context_buffer, ASSERT_BUFFER_SIZE ); _assert_stacktrace_buffer[0] = 0; if( foundation_is_initialized() ) { unsigned int num_frames = stacktrace_capture( _assert_stacktrace, ASSERT_STACKTRACE_MAX_DEPTH, ASSERT_STACKTRACE_SKIP_FRAMES ); if( num_frames ) { //TODO: Resolve directly into buffer to avoid memory allocations in assert handler char* trace = stacktrace_resolve( _assert_stacktrace, num_frames, 0U ); string_copy( _assert_stacktrace_buffer, trace, ASSERT_BUFFER_SIZE ); string_deallocate( trace ); } } else { string_copy( _assert_stacktrace_buffer, "<no stacktrace - not initialized>", ASSERT_BUFFER_SIZE ); } snprintf( _assert_box_buffer, (size_t)ASSERT_BUFFER_SIZE, assert_format, condition, file, line, _assert_context_buffer, msg, _assert_stacktrace_buffer ); log_errorf( context, ERROR_ASSERT, "%s", _assert_box_buffer ); system_message_box( "Assert Failure", _assert_box_buffer, false ); #else log_errorf( context, ERROR_ASSERT, assert_format, condition, file, line, "", msg, "" ); #endif return 1; }
int assert_report( const char* condition, const char* file, int line, const char* msg ) { static const char nocondition[] = "<Static fail>"; static const char nofile[] = "<No file>"; static const char nomsg[] = "<No message>"; static const char assert_format[] = "****** ASSERT FAILED ******\nCondition: %s\nFile/line: %s : %d\n%s%s\n%s\n"; int ret; if( !condition ) condition = nocondition; if( !file ) file = nofile; if( !msg ) msg = nomsg; if( _assert_handler && ( _assert_handler != assert_report ) ) return (*_assert_handler)( condition, file, line, msg ); _assert_context_buffer[0] = 0; error_context_buffer( _assert_context_buffer, ASSERT_BUFFER_SIZE ); _assert_stacktrace_buffer[0] = 0; if( foundation_is_initialized() ) { if( stacktrace_capture( _assert_stacktrace, 128, 1 ) > 0 ) { //TODO: Resolve directly into buffer to avoid memory allocations in assert handler char* trace = stacktrace_resolve( _assert_stacktrace, 128, 0 ); string_copy( _assert_stacktrace_buffer, trace, ASSERT_BUFFER_SIZE ); string_deallocate( trace ); } } else { string_copy( _assert_stacktrace_buffer, "<no stacktrace - not initialized>", ASSERT_BUFFER_SIZE ); } ret = snprintf( _assert_box_buffer, (size_t)ASSERT_BUFFER_SIZE, assert_format, condition, file, line, _assert_context_buffer, msg, _assert_stacktrace_buffer ); if( ( ret < 0 ) || ( ret >= ASSERT_BUFFER_SIZE ) ) _assert_box_buffer[ASSERT_BUFFER_SIZE-1] = 0; log_errorf( 0, ERROR_ASSERT, "%s", _assert_box_buffer ); system_message_box( "Assert Failure", _assert_box_buffer, false ); return 1; }
DECLARE_TEST(exception, error) { error_handler_fn handler; int ret; error(); EXPECT_EQ(error(), ERROR_NONE); error_report(ERRORLEVEL_ERROR, ERROR_NONE); EXPECT_EQ(error(), ERROR_NONE); error_report(ERRORLEVEL_ERROR, ERROR_EXCEPTION); EXPECT_EQ(error(), ERROR_EXCEPTION); handler = error_handler(); error_set_handler(_error_handler_test); ret = error_report(ERRORLEVEL_WARNING, ERROR_INVALID_VALUE); EXPECT_EQ(error(), ERROR_INVALID_VALUE); EXPECT_EQ(ret, 2); EXPECT_EQ(_error_level_test, ERRORLEVEL_WARNING); EXPECT_EQ(_error_test, ERROR_INVALID_VALUE); EXPECT_EQ(error_handler(), _error_handler_test); error_set_handler(handler); { #if BUILD_ENABLE_ERROR_CONTEXT const char context_data[] = "another message"; #endif char context_buffer[512]; string_t contextstr; error_context_clear(); error_context_push(STRING_CONST("test context"), STRING_CONST("some message")); error_context_push(STRING_CONST("foo bar"), 0, 0); error_context_pop(); error_context_pop(); error_context_pop(); error_context_push(STRING_CONST("test context"), STRING_CONST(context_data)); #if BUILD_ENABLE_ERROR_CONTEXT EXPECT_NE(error_context(), 0); EXPECT_EQ(error_context()->depth, 1); EXPECT_CONSTSTRINGEQ(error_context()->frame[0].name, string_const(STRING_CONST("test context"))); EXPECT_EQ(error_context()->frame[0].data.str, context_data); EXPECT_EQ(error_context()->frame[0].data.length, sizeof(context_data) - 1); #endif contextstr = error_context_buffer(context_buffer, 512); #if BUILD_ENABLE_ERROR_CONTEXT EXPECT_NE_MSGFORMAT(string_find_string(STRING_ARGS(contextstr), STRING_CONST("test context"), 0), STRING_NPOS, "context name 'test context' not found in buffer: %s", context_buffer); EXPECT_NE_MSGFORMAT(string_find_string(STRING_ARGS(contextstr), STRING_CONST(context_data), 0), STRING_NPOS, "context data '%s' not found in buffer: %s", context_data, context_buffer); #else EXPECT_EQ(contextstr.length, 0); #endif error_context_clear(); contextstr = error_context_buffer(context_buffer, 512); #if BUILD_ENABLE_ERROR_CONTEXT EXPECT_STRINGEQ(contextstr, string_empty()); #endif } return 0; }