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
|
/**
* @file catch_and_store_what_in.h
* @author Nat Goodspeed
* @date 2012-02-15
* @brief catch_what() template function, CATCH_AND_STORE_WHAT_IN() macro
*
* $LicenseInfo:firstyear=2012&license=viewerlgpl$
* Copyright (c) 2012, Linden Research, Inc.
* $/LicenseInfo$
*/
#if ! defined(LL_CATCH_AND_STORE_WHAT_IN_H)
#define LL_CATCH_AND_STORE_WHAT_IN_H
/**
* In the brave new world of lambdas, we can use a nicer C++ idiom for testing
* exceptions than CATCH_AND_STORE_WHAT_IN() below, e.g.:
*
* @code
* std::string threw = catch_what<std::runtime_error>(
* [](){ throw std::runtime_error("badness"); });
* ensure_equals(threw, "badness");
* @endcode
*/
template <typename EXCEPTION, typename FUNC>
std::string catch_what(FUNC func)
{
try
{
func();
return {};
}
catch (const EXCEPTION& err)
{
return err.what();
}
}
/**
* Idiom useful for test programs: catch an expected exception, store its
* what() string in a specified std::string variable. From there the caller
* can do things like:
* @code
* ensure("expected exception not thrown", ! string.empty());
* @endcode
* or
* @code
* ensure_contains("exception doesn't mention blah", string, "blah");
* @endcode
* etc.
*
* The trouble is that when linking to a dynamic libllcommon.so on Linux, we
* generally fail to catch the specific exception. Oddly, we can catch it as
* std::runtime_error and validate its typeid().name(), so we do -- but that's
* a lot of boilerplate per test. Encapsulate with this macro. Usage:
*
* @code
* std::string threw;
* try
* {
* some_call_that_should_throw_Foo();
* }
* CATCH_AND_STORE_WHAT_IN(threw, Foo)
* ensure("some_call_that_should_throw_Foo() didn't throw", ! threw.empty());
* @endcode
*/
#define CATCH_AND_STORE_WHAT_IN(THREW, EXCEPTION) \
catch (const EXCEPTION& ex) \
{ \
(THREW) = ex.what(); \
} \
CATCH_MISSED_LINUX_EXCEPTION(THREW, EXCEPTION)
#ifndef LL_LINUX
#define CATCH_MISSED_LINUX_EXCEPTION(THREW, EXCEPTION) \
/* only needed on Linux */
#else // LL_LINUX
#define CATCH_MISSED_LINUX_EXCEPTION(THREW, EXCEPTION) \
catch (const std::runtime_error& ex) \
{ \
/* This clause is needed on Linux, on the viewer side, because */ \
/* the exception isn't caught by catch (const EXCEPTION&). */ \
/* But if the expected exception was thrown, allow the test to */ \
/* succeed anyway. Not sure how else to handle this odd case. */ \
if (std::string(typeid(ex).name()) == typeid(EXCEPTION).name()) \
{ \
/* std::cerr << "Caught " << typeid(ex).name() */ \
/* << " with Linux workaround" << std::endl; */ \
(THREW) = ex.what(); \
/*std::cout << ex.what() << std::endl;*/ \
} \
else \
{ \
/* We don't even recognize this exception. Let it propagate */ \
/* out to TUT to fail the test. */ \
throw; \
} \
} \
catch (...) \
{ \
std::cerr << "Failed to catch expected exception " \
<< #EXCEPTION << "!" << std::endl; \
/* This indicates a problem in the test that should be addressed. */ \
throw; \
}
#endif // LL_LINUX
#endif /* ! defined(LL_CATCH_AND_STORE_WHAT_IN_H) */
|