Skip to content
Snippets Groups Projects
Commit 10ab4adc authored by Nat Goodspeed's avatar Nat Goodspeed
Browse files

Fix llprocess_test.cpp's exception catching for Linux.

In the course of re-enabling the indra/test tests last year, Log generalized a
workaround I'd introduced in llsdmessage_test.cpp. In Linux viewer land, a
test program trying to catch an expected exception can't seem to catch it by
its specific class (across the libllcommon.so boundary), but must instead
catch std::runtime_error and validate the typeid().name() string. Log added a
macro for this idiom in llevents_tut.cpp. Generalize that macro further for
normal-case processing as well, move it to a header file of its own and use it
in all known places -- plus the new exception-catching tests in
llprocess_test.cpp.
parent c6ccdb5b
No related branches found
No related tags found
No related merge requests found
......@@ -31,6 +31,7 @@
#include "../test/lltut.h"
#include "../test/manageapr.h"
#include "../test/namedtempfile.h"
#include "../test/catch_and_store_what_in.h"
#include "stringize.h"
#include "llsdutil.h"
#include "llevents.h"
......@@ -952,10 +953,7 @@ namespace tut
{ \
CODE; \
} \
catch (const EXCEPTION& e) \
{ \
(THREW) = e.what(); \
} \
CATCH_AND_STORE_WHAT_IN(THREW, EXCEPTION) \
ensure("failed to throw " #EXCEPTION ": " #CODE, ! (THREW).empty()); \
} while (0)
......
......@@ -42,6 +42,7 @@
// external library headers
// other Linden headers
#include "../test/lltut.h"
#include "../test/catch_and_store_what_in.h"
#include "llsdserialize.h"
#include "llevents.h"
#include "stringize.h"
......@@ -72,43 +73,14 @@ namespace tut
template<> template<>
void llsdmessage_object::test<1>()
{
bool threw = false;
std::string threw;
// This should fail...
try
{
LLSDMessage localListener;
}
catch (const LLEventPump::DupPumpName&)
{
threw = true;
}
catch (const std::runtime_error& ex)
{
// This clause is because on Linux, on the viewer side, for this
// one test program (though not others!), the
// LLEventPump::DupPumpName exception isn't caught by the clause
// above. Warn the user...
std::cerr << "Failed to catch " << typeid(ex).name() << std::endl;
// 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(LLEventPump::DupPumpName).name())
{
threw = true;
}
else
{
// We don't even recognize this exception. Let it propagate
// out to TUT to fail the test.
throw;
}
}
catch (...)
{
std::cerr << "Utterly failed to catch expected exception!" << std::endl;
// This case is full of fail. We HAVE to address it.
throw;
}
ensure("second LLSDMessage should throw", threw);
CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName)
ensure("second LLSDMessage should throw", ! threw.empty());
}
template<> template<>
......
/**
* @file catch_and_store_what_in.h
* @author Nat Goodspeed
* @date 2012-02-15
* @brief 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
/**
* 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) */
......@@ -49,46 +49,12 @@
#include <boost/assign/list_of.hpp>
// other Linden headers
#include "lltut.h"
#include "catch_and_store_what_in.h"
#include "stringize.h"
#include "tests/listener.h"
using boost::assign::list_of;
#ifdef LL_LINUX
#define CATCH_MISSED_LINUX_EXCEPTION(exception, threw) \
catch (const std::runtime_error& ex) \
{ \
/* This clause is needed on Linux, on the viewer side, because the */ \
/* exception isn't caught by the clause above. Warn the user... */ \
std::cerr << "Failed to catch " << typeid(ex).name() << std::endl; \
/* But if the expected exception was thrown, allow the test to */ \
/* succeed anyway. Not sure how else to handle this odd case. */ \
/* This approach is also used in llsdmessage_test.cpp. */ \
if (std::string(typeid(ex).name()) == typeid(exception).name()) \
{ \
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 << "Utterly failed to catch expected exception " << #exception << "!" << \
std::endl; \
/* This indicates a problem in the test that should be addressed. */ \
throw; \
}
#else // LL_LINUX
#define CATCH_MISSED_LINUX_EXCEPTION(exception, threw) \
/* Not needed on other platforms */
#endif // LL_LINUX
template<typename T>
T make(const T& value)
{
......@@ -178,11 +144,7 @@ void events_object::test<1>()
per_frame.listen(listener0.getName(), // note bug, dup name
boost::bind(&Listener::call, boost::ref(listener1), _1));
}
catch (const LLEventPump::DupListenerName& e)
{
threw = e.what();
}
CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::DupListenerName, threw)
CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupListenerName)
ensure_equals(threw,
std::string("DupListenerName: "
"Attempt to register duplicate listener name '") +
......@@ -388,12 +350,7 @@ void events_object::test<7>()
// after "Mary" and "checked" -- whoops!
make<NameList>(list_of("Mary")("checked")));
}
catch (const LLEventPump::Cycle& e)
{
threw = e.what();
// std::cout << "Caught: " << e.what() << '\n';
}
CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::Cycle, threw)
CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::Cycle)
// Obviously the specific wording of the exception text can
// change; go ahead and change the test to match.
// Establish that it contains:
......@@ -426,12 +383,7 @@ void events_object::test<7>()
make<NameList>(list_of("shoelaces")),
make<NameList>(list_of("yellow")));
}
catch (const LLEventPump::OrderChange& e)
{
threw = e.what();
// std::cout << "Caught: " << e.what() << '\n';
}
CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::OrderChange, threw)
CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::OrderChange)
// Same remarks about the specific wording of the exception. Just
// ensure that it contains enough information to clarify the
// problem and what must be done to resolve it.
......@@ -459,12 +411,7 @@ void events_object::test<8>()
// then another with a duplicate name.
LLEventStream bob2("bob");
}
catch (const LLEventPump::DupPumpName& e)
{
threw = e.what();
// std::cout << "Caught: " << e.what() << '\n';
}
CATCH_MISSED_LINUX_EXCEPTION(LLEventPump::DupPumpName, threw)
CATCH_AND_STORE_WHAT_IN(threw, LLEventPump::DupPumpName)
ensure("Caught DupPumpName", !threw.empty());
} // delete first 'bob'
LLEventStream bob("bob"); // should work, previous one unregistered
......@@ -505,11 +452,7 @@ void events_object::test<9>()
LLListenerOrPumpName empty;
empty(17);
}
catch (const LLListenerOrPumpName::Empty& e)
{
threw = e.what();
}
CATCH_MISSED_LINUX_EXCEPTION(LLListenerOrPumpName::Empty, threw)
CATCH_AND_STORE_WHAT_IN(threw, LLListenerOrPumpName::Empty)
ensure("threw Empty", !threw.empty());
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment