111 lines
4.2 KiB
C++
111 lines
4.2 KiB
C++
/**
|
|
* @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) */
|