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.meow-7.2.2
parent
c6ccdb5b50
commit
10ab4adc86
|
|
@ -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<>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* @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());
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue