From 10ab4adc86207f86df30ab23d8858c23e7f550ea Mon Sep 17 00:00:00 2001
From: Nat Goodspeed <nat@lindenlab.com>
Date: Wed, 15 Feb 2012 13:44:43 -0500
Subject: [PATCH] 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.

---
 indra/llcommon/tests/llprocess_test.cpp    |  6 +-
 indra/llmessage/tests/llsdmessage_test.cpp | 36 +--------
 indra/test/catch_and_store_what_in.h       | 86 ++++++++++++++++++++++
 indra/test/llevents_tut.cpp                | 69 ++---------------
 4 files changed, 98 insertions(+), 99 deletions(-)
 create mode 100644 indra/test/catch_and_store_what_in.h

diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index 06f9f3827f8..a901c577d68 100644
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -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)
 
diff --git a/indra/llmessage/tests/llsdmessage_test.cpp b/indra/llmessage/tests/llsdmessage_test.cpp
index 0f2c0693031..6871ac0d527 100644
--- a/indra/llmessage/tests/llsdmessage_test.cpp
+++ b/indra/llmessage/tests/llsdmessage_test.cpp
@@ -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<>
diff --git a/indra/test/catch_and_store_what_in.h b/indra/test/catch_and_store_what_in.h
new file mode 100644
index 00000000000..59f8cc00858
--- /dev/null
+++ b/indra/test/catch_and_store_what_in.h
@@ -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) */
diff --git a/indra/test/llevents_tut.cpp b/indra/test/llevents_tut.cpp
index 4699bb18271..ca4c74099ff 100644
--- a/indra/test/llevents_tut.cpp
+++ b/indra/test/llevents_tut.cpp
@@ -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());
 }
-- 
GitLab