Enable MSVC assert report box [Abort|Retry|Ignore] if a debugger is present (#5279)
[platform/upstream/flatbuffers.git] / tests / test_assert.cpp
1 #include "test_assert.h"
2
3 #include <assert.h>
4
5 #ifdef _MSC_VER
6 #  include <crtdbg.h>
7 #  include <windows.h>
8 #endif
9
10 int testing_fails = 0;
11 static TestFailEventListener fail_listener_ = nullptr;
12
13 void TestFail(const char *expval, const char *val, const char *exp,
14               const char *file, int line, const char *func) {
15   TEST_OUTPUT_LINE("VALUE: \"%s\"", expval);
16   TEST_OUTPUT_LINE("EXPECTED: \"%s\"", val);
17   TEST_OUTPUT_LINE("TEST FAILED: %s:%d, %s in %s", file, line, exp,
18                    func ? func : "");
19   testing_fails++;
20
21   // Notify, emulate 'gtest::OnTestPartResult' event handler.
22   if (fail_listener_) (*fail_listener_)(expval, val, exp, file, line, func);
23
24   assert(0);  // ignored in Release if NDEBUG defined
25 }
26
27 void TestEqStr(const char *expval, const char *val, const char *exp,
28                const char *file, int line) {
29   if (strcmp(expval, val) != 0) { TestFail(expval, val, exp, file, line); }
30 }
31
32 #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING) && defined(_MSC_VER) && \
33     defined(_DEBUG)
34 #define FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC
35 #endif
36
37 void InitTestEngine(TestFailEventListener listener) {
38   testing_fails = 0;
39   // Disable stdout buffering to prevent information lost on assertion or core
40   // dump.
41   setvbuf(stdout, NULL, _IONBF, 0);
42   setvbuf(stderr, NULL, _IONBF, 0);
43
44   // clang-format off
45
46   #ifdef _MSC_VER
47     // By default, send all reports to STDOUT to prevent CI hangs.
48     // Enable assert report box [Abort|Retry|Ignore] if a debugger is present.
49     const int dbg_mode = (_CRTDBG_MODE_FILE | _CRTDBG_MODE_DEBUG) |
50                          (IsDebuggerPresent() ? _CRTDBG_MODE_WNDW : 0);
51     (void)dbg_mode; // release mode fix
52     // CrtDebug reports to _CRT_WARN channel.
53     _CrtSetReportMode(_CRT_WARN, dbg_mode);
54     _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
55     // The assert from <assert.h> reports to _CRT_ERROR channel
56     _CrtSetReportMode(_CRT_ERROR, dbg_mode);
57     _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
58     // Internal CRT assert channel?
59     _CrtSetReportMode(_CRT_ASSERT, dbg_mode);
60     _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
61   #endif
62
63   #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC)
64     // For more thorough checking:
65     // _CRTDBG_DELAY_FREE_MEM_DF | _CRTDBG_CHECK_ALWAYS_DF
66     auto flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
67     _CrtSetDbgFlag(flags | _CRTDBG_ALLOC_MEM_DF);
68   #endif
69   // clang-format on
70
71   fail_listener_ = listener;
72 }
73
74 int CloseTestEngine(bool force_report) {
75   if (!testing_fails || force_report) {
76   #if defined(FLATBUFFERS_MEMORY_LEAK_TRACKING_MSVC)
77       auto flags = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
78       flags &= ~_CRTDBG_DELAY_FREE_MEM_DF;
79       flags |= _CRTDBG_LEAK_CHECK_DF;
80       _CrtSetDbgFlag(flags);
81   #endif
82   }
83   return (0 != testing_fails);
84 }