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
141 lines (118 loc) · 3.48 KB
/
custom_error.cpp
File metadata and controls
141 lines (118 loc) · 3.48 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
134
135
136
137
138
139
140
141
#include "pch.h"
using namespace winrt;
using namespace Windows::Foundation;
namespace
{
// Some custom exception type unknown to C++/WinRT
struct CustomError
{
};
struct Sample : implements<Sample, IStringable>
{
hstring ToString()
{
// Throw custom exception inside C++/WinRT projection
throw CustomError();
}
};
// Global handler to translate custom exception
int32_t __stdcall handler(void* address) noexcept
{
REQUIRE(address);
try
{
throw;
}
catch (CustomError)
{
return 0x80000018; // E_ILLEGAL_DELEGATE_ASSIGNMENT
}
REQUIRE(false);
return 0;
}
// Global handler to translate custom exception to message
hstring __stdcall message_handler(void* address)
{
REQUIRE(address);
try
{
throw;
}
catch (CustomError)
{
return L"a custom error";
}
REQUIRE(false);
return {};
}
static bool s_loggerCalled = false;
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;
}
}
TEST_CASE("custom_error")
{
// Set up global handler
REQUIRE(!winrt_to_hresult_handler);
winrt_to_hresult_handler = handler;
// Validate that handler translated exception
REQUIRE_THROWS_AS(make<Sample>().ToString(), hresult_illegal_delegate_assignment);
// Remove global handler
winrt_to_hresult_handler = nullptr;
}
TEST_CASE("custom_error_logger")
{
// Set up global handler
REQUIRE(!s_loggerCalled);
REQUIRE(!winrt_throw_hresult_handler);
winrt_throw_hresult_handler = logger;
// Validate that handler translated exception
REQUIRE_THROWS_AS(check_hresult(0x80000018), hresult_illegal_delegate_assignment);
REQUIRE(s_loggerCalled);
#ifndef __cpp_lib_source_location
// In C++17 these fields cannot be filled in so they are expected to be empty.
REQUIRE(s_loggerArgs.lineNumber == 0);
REQUIRE(s_loggerArgs.fileName == nullptr);
REQUIRE(s_loggerArgs.functionName == nullptr);
#else
// GCC/Clang can only compile these tests in C++20 mode. If source_location
// is available these fields will be filled in. Don't do any checks here
// because these are already tested in `test_cpp20/custom_error.cpp`.
#endif
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;
}
TEST_CASE("custom_error_message")
{
// Set up global handler
REQUIRE(!winrt_to_message_handler);
winrt_to_message_handler = message_handler;
try
{
throw CustomError();
}
catch (...)
{
REQUIRE(to_message() == L"a custom error");
}
// Remove global handler
winrt_to_message_handler = nullptr;
}