forked from microsoft/cppwinrt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcustom_error.cpp
More file actions
133 lines (118 loc) · 4.61 KB
/
custom_error.cpp
File metadata and controls
133 lines (118 loc) · 4.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include "pch.h"
using namespace winrt;
using namespace Windows::Foundation;
namespace
{
static bool s_loggerCalled = false;
void FailOnLine15()
{
// Validate that handler translated exception
#line 15 // Force next line to be reported as line number 15
REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment);
}
static struct {
uint32_t lineNumber;
char const* fileName;
char const* functionName;
void* returnAddress;
winrt::hresult result;
} s_loggerArgs{};
void __stdcall logger(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
{
s_loggerArgs = {
.lineNumber = lineNumber,
.fileName = fileName,
.functionName = functionName,
.returnAddress = returnAddress,
.result = result,
};
s_loggerCalled = true;
}
}
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
// <source_location> not available in libc++ before LLVM 16
TEST_CASE("custom_error_logger_on_throw", "[!shouldfail]")
#else
TEST_CASE("custom_error_logger_on_throw")
#endif
{
// Set up global handler
REQUIRE(!s_loggerCalled);
REQUIRE(!winrt_throw_hresult_handler);
winrt_throw_hresult_handler = logger;
FailOnLine15();
REQUIRE(s_loggerCalled);
// In C++20 these fields should be filled in by std::source_location
REQUIRE(s_loggerArgs.lineNumber == 15);
const auto fileNameSv = std::string_view(s_loggerArgs.fileName);
REQUIRE(!fileNameSv.empty());
REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos);
#ifdef _DEBUG
const auto functionNameSv = std::string_view(s_loggerArgs.functionName);
REQUIRE(!functionNameSv.empty());
// Every compiler has a slightly different naming approach for this function, and even the same
// compiler can change its mind over time. Instead of matching the entire function name just
// match against the part we care about.
REQUIRE((functionNameSv.find("FailOnLine15") != std::string_view::npos));
#else
REQUIRE(s_loggerArgs.functionName == nullptr);
#endif // _DEBUG
REQUIRE(s_loggerArgs.returnAddress);
REQUIRE(s_loggerArgs.result == static_cast<int32_t>(0x80000018)); // E_ILLEGAL_DELEGATE_ASSIGNMENT)
// Remove global handler
winrt_throw_hresult_handler = nullptr;
s_loggerCalled = false;
}
template<typename... Args>
void HresultOnLine80(Args... args)
{
// Validate that handler translated on creating an HRESULT
#line 80 // Force next line to be reported as line number 80
winrt::hresult_canceled(std::forward<Args>(args)...);
}
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 170000
// <source_location> not available in libc++ before LLVM 16
TEST_CASE("custom_error_logger_on_originate", "[!shouldfail]")
#else
TEST_CASE("custom_error_logger_on_originate")
#endif
{
// Set up global handler
REQUIRE(!s_loggerCalled);
REQUIRE(!winrt_throw_hresult_handler);
winrt_throw_hresult_handler = logger;
HresultOnLine80();
REQUIRE(s_loggerCalled);
// In C++20 these fields should be filled in by std::source_location
REQUIRE(s_loggerArgs.lineNumber == 80);
const auto fileNameSv = std::string_view(s_loggerArgs.fileName);
REQUIRE(!fileNameSv.empty());
REQUIRE(fileNameSv.find("custom_error.cpp") != std::string::npos);
#ifdef _DEBUG
const auto functionNameSv = std::string_view(s_loggerArgs.functionName);
REQUIRE(!functionNameSv.empty());
// Every compiler has a slightly different naming approach for this function, and even the same
// compiler can change its mind over time. Instead of matching the entire function name just
// match against the part we care about.
REQUIRE((functionNameSv.find("HresultOnLine80") != std::string_view::npos));
#else
REQUIRE(s_loggerArgs.functionName == nullptr);
#endif // _DEBUG
REQUIRE(s_loggerArgs.returnAddress);
REQUIRE(s_loggerArgs.result == HRESULT_FROM_WIN32(ERROR_CANCELLED)); // E_ILLEGAL_DELEGATE_ASSIGNMENT)
s_loggerCalled = false;
s_loggerArgs.lineNumber = 0;
// verify HRESULT with a custom message
HresultOnLine80(L"with custom message");
REQUIRE(s_loggerCalled);
REQUIRE(s_loggerArgs.lineNumber == 80);
s_loggerCalled = false;
s_loggerArgs.lineNumber = 0;
// verify that no_originate does _not_ call the logger.
HresultOnLine80(winrt::hresult_error::no_originate);
REQUIRE(!s_loggerCalled);
REQUIRE(s_loggerArgs.lineNumber == 0);
// Remove global handler
winrt_throw_hresult_handler = nullptr;
s_loggerCalled = false;
}