Makes gtest print enums as integers instead of hex dumps (by Zhanyong Wan); improves the hex dump format (by Zhanyong Wan); gets rid of class TestInfoImpl (by Zhanyong Wan); adds exception handling (by Vlad Losev).


git-svn-id: http://googletest.googlecode.com/svn/trunk@453 861a406c-534a-0410-8894-cb66d6ee9925
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4a978a1..316d257 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -142,6 +142,8 @@
 
   cxx_library(gtest_no_exception "${cxx_no_exception}"
     src/gtest-all.cc)
+  cxx_library(gtest_main_no_exception "${cxx_no_exception}"
+    src/gtest-all.cc src/gtest_main.cc)
   cxx_library(gtest_main_no_rtti "${cxx_no_rtti}"
     src/gtest-all.cc src/gtest_main.cc)
 
@@ -180,6 +182,18 @@
   cxx_executable(gtest_break_on_failure_unittest_ test gtest)
   py_test(gtest_break_on_failure_unittest)
 
+  cxx_executable_with_flags(
+    gtest_catch_exceptions_no_ex_test_
+    "${cxx_no_exception}"
+    gtest_main_no_exception
+    test/gtest_catch_exceptions_test_.cc)
+  cxx_executable_with_flags(
+    gtest_catch_exceptions_ex_test_
+    "${cxx_exception}"
+    gtest_main
+    test/gtest_catch_exceptions_test_.cc)
+  py_test(gtest_catch_exceptions_test)
+
   cxx_executable(gtest_color_test_ test gtest)
   py_test(gtest_color_test)
 
diff --git a/include/gtest/gtest-printers.h b/include/gtest/gtest-printers.h
index 0676269..68e7eb1 100644
--- a/include/gtest/gtest-printers.h
+++ b/include/gtest/gtest-printers.h
@@ -115,16 +115,23 @@
                                      size_t count,
                                      ::std::ostream* os);
 
-// TypeWithoutFormatter<T, kIsProto>::PrintValue(value, os) is called
+// For selecting which printer to use when a given type has neither <<
+// nor PrintTo().
+enum TypeKind {
+  kProtobuf,              // a protobuf type
+  kConvertibleToInteger,  // a type implicitly convertible to BiggestInt
+                          // (e.g. a named or unnamed enum type)
+  kOtherType,             // anything else
+};
+
+// TypeWithoutFormatter<T, kTypeKind>::PrintValue(value, os) is called
 // by the universal printer to print a value of type T when neither
-// operator<< nor PrintTo() is defined for type T.  When T is
-// ProtocolMessage, proto2::Message, or a subclass of those, kIsProto
-// will be true and the short debug string of the protocol message
-// value will be printed; otherwise kIsProto will be false and the
-// bytes in the value will be printed.
-template <typename T, bool kIsProto>
+// operator<< nor PrintTo() is defined for T, where kTypeKind is the
+// "kind" of T as defined by enum TypeKind.
+template <typename T, TypeKind kTypeKind>
 class TypeWithoutFormatter {
  public:
+  // This default version is called when kTypeKind is kOtherType.
   static void PrintValue(const T& value, ::std::ostream* os) {
     PrintBytesInObjectTo(reinterpret_cast<const unsigned char*>(&value),
                          sizeof(value), os);
@@ -137,22 +144,39 @@
 const size_t kProtobufOneLinerMaxLength = 50;
 
 template <typename T>
-class TypeWithoutFormatter<T, true> {
+class TypeWithoutFormatter<T, kProtobuf> {
  public:
   static void PrintValue(const T& value, ::std::ostream* os) {
     const ::testing::internal::string short_str = value.ShortDebugString();
     const ::testing::internal::string pretty_str =
         short_str.length() <= kProtobufOneLinerMaxLength ?
         short_str : ("\n" + value.DebugString());
-    ::std::operator<<(*os, "<" + pretty_str + ">");
+    *os << ("<" + pretty_str + ">");
+  }
+};
+
+template <typename T>
+class TypeWithoutFormatter<T, kConvertibleToInteger> {
+ public:
+  // Since T has no << operator or PrintTo() but can be implicitly
+  // converted to BiggestInt, we print it as a BiggestInt.
+  //
+  // Most likely T is an enum type (either named or unnamed), in which
+  // case printing it as an integer is the desired behavior.  In case
+  // T is not an enum, printing it as an integer is the best we can do
+  // given that it has no user-defined printer.
+  static void PrintValue(const T& value, ::std::ostream* os) {
+    const internal::BiggestInt kBigInt = value;
+    *os << kBigInt;
   }
 };
 
 // Prints the given value to the given ostream.  If the value is a
-// protocol message, its short debug string is printed; otherwise the
-// bytes in the value are printed.  This is what
-// UniversalPrinter<T>::Print() does when it knows nothing about type
-// T and T has no << operator.
+// protocol message, its debug string is printed; if it's an enum or
+// of a type implicitly convertible to BiggestInt, it's printed as an
+// integer; otherwise the bytes in the value are printed.  This is
+// what UniversalPrinter<T>::Print() does when it knows nothing about
+// type T and T has neither << operator nor PrintTo().
 //
 // A user can override this behavior for a class type Foo by defining
 // a << operator in the namespace where Foo is defined.
@@ -174,8 +198,10 @@
 template <typename Char, typename CharTraits, typename T>
 ::std::basic_ostream<Char, CharTraits>& operator<<(
     ::std::basic_ostream<Char, CharTraits>& os, const T& x) {
-  TypeWithoutFormatter<T, ::testing::internal::IsAProtocolMessage<T>::value>::
-      PrintValue(x, &os);
+  TypeWithoutFormatter<T,
+      (internal::IsAProtocolMessage<T>::value ? kProtobuf :
+       internal::ImplicitlyConvertible<const T&, internal::BiggestInt>::value ?
+       kConvertibleToInteger : kOtherType)>::PrintValue(x, &os);
   return os;
 }
 
diff --git a/include/gtest/gtest.h b/include/gtest/gtest.h
index af9d9e7..20028a1 100644
--- a/include/gtest/gtest.h
+++ b/include/gtest/gtest.h
@@ -148,7 +148,6 @@
 class NoExecDeathTest;
 class FinalSuccessChecker;
 class GTestFlagSaver;
-class TestInfoImpl;
 class TestResultAccessor;
 class TestEventListenersAccessor;
 class TestEventRepeater;
@@ -341,7 +340,7 @@
 // Test is not copyable.
 class GTEST_API_ Test {
  public:
-  friend class internal::TestInfoImpl;
+  friend class TestInfo;
 
   // Defines types for pointers to functions that set up and tear down
   // a test case.
@@ -418,6 +417,10 @@
   // Sets up, executes, and tears down the test.
   void Run();
 
+  // Deletes self.  We deliberately pick an unusual name for this
+  // internal method to avoid clashing with names used in user TESTs.
+  void DeleteSelf_() { delete this; }
+
   // Uses a GTestFlagSaver to save and restore all Google Test flags.
   const internal::GTestFlagSaver* const gtest_flag_saver_;
 
@@ -532,7 +535,6 @@
   friend class UnitTest;
   friend class internal::DefaultGlobalTestPartResultReporter;
   friend class internal::ExecDeathTest;
-  friend class internal::TestInfoImpl;
   friend class internal::TestResultAccessor;
   friend class internal::UnitTestImpl;
   friend class internal::WindowsDeathTest;
@@ -612,16 +614,16 @@
   ~TestInfo();
 
   // Returns the test case name.
-  const char* test_case_name() const;
+  const char* test_case_name() const { return test_case_name_.c_str(); }
 
   // Returns the test name.
-  const char* name() const;
+  const char* name() const { return name_.c_str(); }
 
   // Returns the test case comment.
-  const char* test_case_comment() const;
+  const char* test_case_comment() const { return test_case_comment_.c_str(); }
 
   // Returns the test comment.
-  const char* comment() const;
+  const char* comment() const { return comment_.c_str(); }
 
   // Returns true if this test should run, that is if the test is not disabled
   // (or it is disabled but the also_run_disabled_tests flag has been specified)
@@ -639,10 +641,10 @@
   //
   // For example, *A*:Foo.* is a filter that matches any string that
   // contains the character 'A' or starts with "Foo.".
-  bool should_run() const;
+  bool should_run() const { return should_run_; }
 
   // Returns the result of the test.
-  const TestResult* result() const;
+  const TestResult* result() const { return &result_; }
 
  private:
 #if GTEST_HAS_DEATH_TEST
@@ -650,7 +652,6 @@
 #endif  // GTEST_HAS_DEATH_TEST
   friend class Test;
   friend class TestCase;
-  friend class internal::TestInfoImpl;
   friend class internal::UnitTestImpl;
   friend TestInfo* internal::MakeAndRegisterTestInfo(
       const char* test_case_name, const char* name,
@@ -660,17 +661,6 @@
       Test::TearDownTestCaseFunc tear_down_tc,
       internal::TestFactoryBase* factory);
 
-  // Returns true if this test matches the user-specified filter.
-  bool matches_filter() const;
-
-  // Increments the number of death tests encountered in this test so
-  // far.
-  int increment_death_test_count();
-
-  // Accessors for the implementation object.
-  internal::TestInfoImpl* impl() { return impl_; }
-  const internal::TestInfoImpl* impl() const { return impl_; }
-
   // Constructs a TestInfo object. The newly constructed instance assumes
   // ownership of the factory object.
   TestInfo(const char* test_case_name, const char* name,
@@ -678,8 +668,36 @@
            internal::TypeId fixture_class_id,
            internal::TestFactoryBase* factory);
 
-  // An opaque implementation object.
-  internal::TestInfoImpl* impl_;
+  // Increments the number of death tests encountered in this test so
+  // far.
+  int increment_death_test_count() {
+    return result_.increment_death_test_count();
+  }
+
+  // Creates the test object, runs it, records its result, and then
+  // deletes it.
+  void Run();
+
+  static void ClearTestResult(TestInfo* test_info) {
+    test_info->result_.Clear();
+  }
+
+  // These fields are immutable properties of the test.
+  const std::string test_case_name_;     // Test case name
+  const std::string name_;               // Test name
+  const std::string test_case_comment_;  // Test case comment
+  const std::string comment_;            // Test comment
+  const internal::TypeId fixture_class_id_;   // ID of the test fixture class
+  bool should_run_;                 // True iff this test should run
+  bool is_disabled_;                // True iff this test is disabled
+  bool matches_filter_;             // True if this test matches the
+                                    // user-specified filter.
+  internal::TestFactoryBase* const factory_;  // The factory that creates
+                                              // the test object
+
+  // This field is mutable and needs to be reset before running the
+  // test for the second time.
+  TestResult result_;
 
   GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfo);
 };
@@ -777,17 +795,33 @@
   // Runs every test in this TestCase.
   void Run();
 
+  // Runs SetUpTestCase() for this TestCase.  This wrapper is needed
+  // for catching exceptions thrown from SetUpTestCase().
+  void RunSetUpTestCase() { (*set_up_tc_)(); }
+
+  // Runs TearDownTestCase() for this TestCase.  This wrapper is
+  // needed for catching exceptions thrown from TearDownTestCase().
+  void RunTearDownTestCase() { (*tear_down_tc_)(); }
+
   // Returns true iff test passed.
-  static bool TestPassed(const TestInfo * test_info);
+  static bool TestPassed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Passed();
+  }
 
   // Returns true iff test failed.
-  static bool TestFailed(const TestInfo * test_info);
+  static bool TestFailed(const TestInfo* test_info) {
+    return test_info->should_run() && test_info->result()->Failed();
+  }
 
   // Returns true iff test is disabled.
-  static bool TestDisabled(const TestInfo * test_info);
+  static bool TestDisabled(const TestInfo* test_info) {
+    return test_info->is_disabled_;
+  }
 
   // Returns true if the given test should run.
-  static bool ShouldRunTest(const TestInfo *test_info);
+  static bool ShouldRunTest(const TestInfo* test_info) {
+    return test_info->should_run();
+  }
 
   // Shuffles the tests in this test case.
   void ShuffleTests(internal::Random* random);
@@ -962,10 +996,10 @@
 
  private:
   friend class TestCase;
+  friend class TestInfo;
   friend class internal::DefaultGlobalTestPartResultReporter;
   friend class internal::NoExecDeathTest;
   friend class internal::TestEventListenersAccessor;
-  friend class internal::TestInfoImpl;
   friend class internal::UnitTestImpl;
 
   // Returns repeater that broadcasts the TestEventListener events to all
diff --git a/src/gtest-internal-inl.h b/src/gtest-internal-inl.h
index c5608c9..d1e0b59 100644
--- a/src/gtest-internal-inl.h
+++ b/src/gtest-internal-inl.h
@@ -340,85 +340,6 @@
   String key_;
 };
 
-class TestInfoImpl {
- public:
-  TestInfoImpl(TestInfo* parent, const char* test_case_name,
-               const char* name, const char* test_case_comment,
-               const char* comment, TypeId fixture_class_id,
-               internal::TestFactoryBase* factory);
-  ~TestInfoImpl();
-
-  // Returns true if this test should run.
-  bool should_run() const { return should_run_; }
-
-  // Sets the should_run member.
-  void set_should_run(bool should) { should_run_ = should; }
-
-  // Returns true if this test is disabled. Disabled tests are not run.
-  bool is_disabled() const { return is_disabled_; }
-
-  // Sets the is_disabled member.
-  void set_is_disabled(bool is) { is_disabled_ = is; }
-
-  // Returns true if this test matches the filter specified by the user.
-  bool matches_filter() const { return matches_filter_; }
-
-  // Sets the matches_filter member.
-  void set_matches_filter(bool matches) { matches_filter_ = matches; }
-
-  // Returns the test case name.
-  const char* test_case_name() const { return test_case_name_.c_str(); }
-
-  // Returns the test name.
-  const char* name() const { return name_.c_str(); }
-
-  // Returns the test case comment.
-  const char* test_case_comment() const { return test_case_comment_.c_str(); }
-
-  // Returns the test comment.
-  const char* comment() const { return comment_.c_str(); }
-
-  // Returns the ID of the test fixture class.
-  TypeId fixture_class_id() const { return fixture_class_id_; }
-
-  // Returns the test result.
-  TestResult* result() { return &result_; }
-  const TestResult* result() const { return &result_; }
-
-  // Creates the test object, runs it, records its result, and then
-  // deletes it.
-  void Run();
-
-  // Clears the test result.
-  void ClearResult() { result_.Clear(); }
-
-  // Clears the test result in the given TestInfo object.
-  static void ClearTestResult(TestInfo * test_info) {
-    test_info->impl()->ClearResult();
-  }
-
- private:
-  // These fields are immutable properties of the test.
-  TestInfo* const parent_;          // The owner of this object
-  const String test_case_name_;     // Test case name
-  const String name_;               // Test name
-  const String test_case_comment_;  // Test case comment
-  const String comment_;            // Test comment
-  const TypeId fixture_class_id_;   // ID of the test fixture class
-  bool should_run_;                 // True iff this test should run
-  bool is_disabled_;                // True iff this test is disabled
-  bool matches_filter_;             // True if this test matches the
-                                    // user-specified filter.
-  internal::TestFactoryBase* const factory_;  // The factory that creates
-                                              // the test object
-
-  // This field is mutable and needs to be reset before running the
-  // test for the second time.
-  TestResult result_;
-
-  GTEST_DISALLOW_COPY_AND_ASSIGN_(TestInfoImpl);
-};
-
 // Class UnitTestOptions.
 //
 // This class contains functions for processing options the user
@@ -747,12 +668,10 @@
   void RegisterParameterizedTests();
 
   // Runs all tests in this UnitTest object, prints the result, and
-  // returns 0 if all tests are successful, or 1 otherwise.  If any
-  // exception is thrown during a test on Windows, this test is
-  // considered to be failed, but the rest of the tests will still be
-  // run.  (We disable exceptions on Linux and Mac OS X, so the issue
-  // doesn't apply there.)
-  int RunAllTests();
+  // returns true if all tests are successful.  If any exception is
+  // thrown during a test, this test is considered to be failed, but
+  // the rest of the tests will still be run.
+  bool RunAllTests();
 
   // Clears the results of all tests, except the ad hoc tests.
   void ClearNonAdHocTestResult() {
diff --git a/src/gtest-printers.cc b/src/gtest-printers.cc
index 1d97b53..07a0d85 100644
--- a/src/gtest-printers.cc
+++ b/src/gtest-printers.cc
@@ -72,9 +72,10 @@
     if (i != 0) {
       // Organizes the bytes into groups of 2 for easy parsing by
       // human.
-      if ((j % 2) == 0) {
-        *os << " ";
-      }
+      if ((j % 2) == 0)
+        *os << ' ';
+      else
+        *os << '-';
     }
     snprintf(text, sizeof(text), "%02X", obj_bytes[j]);
     *os << text;
diff --git a/src/gtest.cc b/src/gtest.cc
index 03799a2..f3768e3 100644
--- a/src/gtest.cc
+++ b/src/gtest.cc
@@ -495,13 +495,26 @@
 // given SEH exception, or EXCEPTION_CONTINUE_SEARCH otherwise.
 // This function is useful as an __except condition.
 int UnitTestOptions::GTestShouldProcessSEH(DWORD exception_code) {
-  // Google Test should handle an exception if:
+  // Google Test should handle a SEH exception if:
   //   1. the user wants it to, AND
-  //   2. this is not a breakpoint exception.
-  return (GTEST_FLAG(catch_exceptions) &&
-          exception_code != EXCEPTION_BREAKPOINT) ?
-      EXCEPTION_EXECUTE_HANDLER :
-      EXCEPTION_CONTINUE_SEARCH;
+  //   2. this is not a breakpoint exception, AND
+  //   3. this is not a C++ exception (VC++ implements them via SEH,
+  //      apparently).
+  //
+  // SEH exception code for C++ exceptions.
+  // (see http://support.microsoft.com/kb/185294 for more information).
+  const DWORD kCxxExceptionCode = 0xe06d7363;
+
+  bool should_handle = true;
+
+  if (!GTEST_FLAG(catch_exceptions))
+    should_handle = false;
+  else if (exception_code == EXCEPTION_BREAKPOINT)
+    should_handle = false;
+  else if (exception_code == kCxxExceptionCode)
+    should_handle = false;
+
+  return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH;
 }
 #endif  // GTEST_OS_WINDOWS
 
@@ -1922,22 +1935,6 @@
 
 }  // namespace internal
 
-#if GTEST_OS_WINDOWS
-// We are on Windows.
-
-// Adds an "exception thrown" fatal failure to the current test.
-static void AddExceptionThrownFailure(DWORD exception_code,
-                                      const char* location) {
-  Message message;
-  message << "Exception thrown with code 0x" << std::setbase(16) <<
-    exception_code << std::setbase(10) << " in " << location << ".";
-
-  internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
-                                           message.GetString());
-}
-
-#endif  // GTEST_OS_WINDOWS
-
 // Google Test requires all tests in the same test case to use the same test
 // fixture class.  This function checks if the current test has the
 // same fixture class as the first test in the current test case.  If
@@ -1948,15 +1945,13 @@
   const TestCase* const test_case = impl->current_test_case();
 
   // Info about the first test in the current test case.
-  const internal::TestInfoImpl* const first_test_info =
-      test_case->test_info_list()[0]->impl();
-  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id();
+  const TestInfo* const first_test_info = test_case->test_info_list()[0];
+  const internal::TypeId first_fixture_id = first_test_info->fixture_class_id_;
   const char* const first_test_name = first_test_info->name();
 
   // Info about the current test.
-  const internal::TestInfoImpl* const this_test_info =
-      impl->current_test_info()->impl();
-  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id();
+  const TestInfo* const this_test_info = impl->current_test_info();
+  const internal::TypeId this_fixture_id = this_test_info->fixture_class_id_;
   const char* const this_test_name = this_test_info->name();
 
   if (this_fixture_id != first_fixture_id) {
@@ -2006,62 +2001,134 @@
   return true;
 }
 
+#if GTEST_HAS_SEH
+
+// Adds an "exception thrown" fatal failure to the current test.  This
+// function returns its result via an output parameter pointer because VC++
+// prohibits creation of objects with destructors on stack in functions
+// using __try (see error C2712).
+static internal::String* FormatSehExceptionMessage(DWORD exception_code,
+                                                   const char* location) {
+  Message message;
+  message << "SEH exception with code 0x" << std::setbase(16) <<
+    exception_code << std::setbase(10) << " thrown in " << location << ".";
+
+  return new internal::String(message.GetString());
+}
+
+#endif  // GTEST_HAS_SEH
+
+#if GTEST_HAS_EXCEPTIONS
+
+// Adds an "exception thrown" fatal failure to the current test.
+static internal::String FormatCxxExceptionMessage(const char* description,
+                                                  const char* location) {
+  Message message;
+  if (description != NULL) {
+    message << "C++ exception with description \"" << description << "\"";
+  } else {
+    message << "Unknown C++ exception";
+  }
+  message << " thrown in " << location << ".";
+
+  return message.GetString();
+}
+
+static internal::String PrintTestPartResultToString(
+    const TestPartResult& test_part_result);
+
+// A failed Google Test assertion will throw an exception of this type when
+// GTEST_FLAG(throw_on_failure) is true (if exceptions are enabled).  We
+// derive it from std::runtime_error, which is for errors presumably
+// detectable only at run time.  Since std::runtime_error inherits from
+// std::exception, many testing frameworks know how to extract and print the
+// message inside it.
+class GoogleTestFailureException : public ::std::runtime_error {
+ public:
+  explicit GoogleTestFailureException(const TestPartResult& failure)
+      : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
+};
+#endif  // GTEST_HAS_EXCEPTIONS
+
+// Runs the given method and handles SEH exceptions it throws, when
+// SEH is supported; returns the 0-value for type Result in case of an
+// SEH exception.  (Microsoft compilers cannot handle SEH and C++
+// exceptions in the same function.  Therefore, we provide a separate
+// wrapper function for handling SEH exceptions.)
+template <class T, typename Result>
+static Result HandleSehExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_SEH
+  __try {
+    return (object->*method)();
+  } __except (internal::UnitTestOptions::GTestShouldProcessSEH(  // NOLINT
+      GetExceptionCode())) {
+    // We create the exception message on the heap because VC++ prohibits
+    // creation of objects with destructors on stack in functions using __try
+    // (see error C2712).
+    internal::String* exception_message = FormatSehExceptionMessage(
+        GetExceptionCode(), location);
+    internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure,
+                                             *exception_message);
+    delete exception_message;
+    return static_cast<Result>(0);
+  }
+#else
+  (void)location;
+  return (object->*method)();
+#endif  // GTEST_HAS_SEH
+}
+
+// Runs the given method and catches and reports C++ and/or SEH-style
+// exceptions, if they are supported; returns the 0-value for type
+// Result in case of an SEH exception.
+template <class T, typename Result>
+static Result HandleExceptionsInMethodIfSupported(
+    T* object, Result (T::*method)(), const char* location) {
+#if GTEST_HAS_EXCEPTIONS
+  try {
+    return HandleSehExceptionsInMethodIfSupported(object, method, location);
+  } catch (const GoogleTestFailureException&) {  // NOLINT
+    // This exception doesn't originate in code under test. It makes no
+    // sense to report it as a test failure.
+    throw;
+  } catch (const std::exception& e) {  // NOLINT
+    internal::ReportFailureInUnknownLocation(
+        TestPartResult::kFatalFailure,
+        FormatCxxExceptionMessage(e.what(), location));
+  } catch (...) {  // NOLINT
+    internal::ReportFailureInUnknownLocation(
+        TestPartResult::kFatalFailure,
+        FormatCxxExceptionMessage(NULL, location));
+  }
+  return static_cast<Result>(0);
+#else
+  return HandleSehExceptionsInMethodIfSupported(object, method, location);
+#endif  // GTEST_HAS_EXCEPTIONS
+}
+
 // Runs the test and updates the test result.
 void Test::Run() {
   if (!HasSameFixtureClass()) return;
 
   internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
-#if GTEST_HAS_SEH
-  // Catch SEH-style exceptions.
   impl->os_stack_trace_getter()->UponLeavingGTest();
-  __try {
-    SetUp();
-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
-      GetExceptionCode())) {
-    AddExceptionThrownFailure(GetExceptionCode(), "SetUp()");
-  }
-
-  // We will run the test only if SetUp() had no fatal failure.
-  if (!HasFatalFailure()) {
-    impl->os_stack_trace_getter()->UponLeavingGTest();
-    __try {
-      TestBody();
-    } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
-        GetExceptionCode())) {
-      AddExceptionThrownFailure(GetExceptionCode(), "the test body");
-    }
-  }
-
-  // However, we want to clean up as much as possible.  Hence we will
-  // always call TearDown(), even if SetUp() or the test body has
-  // failed.
-  impl->os_stack_trace_getter()->UponLeavingGTest();
-  __try {
-    TearDown();
-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
-      GetExceptionCode())) {
-    AddExceptionThrownFailure(GetExceptionCode(), "TearDown()");
-  }
-
-#else  // We are on a compiler or platform that doesn't support SEH.
-  impl->os_stack_trace_getter()->UponLeavingGTest();
-  SetUp();
-
+  HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()");
   // We will run the test only if SetUp() was successful.
   if (!HasFatalFailure()) {
     impl->os_stack_trace_getter()->UponLeavingGTest();
-    TestBody();
+    HandleExceptionsInMethodIfSupported(
+        this, &Test::TestBody, "the test body");
   }
 
   // However, we want to clean up as much as possible.  Hence we will
   // always call TearDown(), even if SetUp() or the test body has
   // failed.
   impl->os_stack_trace_getter()->UponLeavingGTest();
-  TearDown();
-#endif  // GTEST_HAS_SEH
+  HandleExceptionsInMethodIfSupported(
+      this, &Test::TearDown, "TearDown()");
 }
 
-
 // Returns true iff the current test has a fatal failure.
 bool Test::HasFatalFailure() {
   return internal::GetUnitTestImpl()->current_test_result()->HasFatalFailure();
@@ -2076,22 +2143,26 @@
 // class TestInfo
 
 // Constructs a TestInfo object. It assumes ownership of the test factory
-// object via impl_.
+// object.
 TestInfo::TestInfo(const char* a_test_case_name,
                    const char* a_name,
                    const char* a_test_case_comment,
                    const char* a_comment,
                    internal::TypeId fixture_class_id,
-                   internal::TestFactoryBase* factory) {
-  impl_ = new internal::TestInfoImpl(this, a_test_case_name, a_name,
-                                     a_test_case_comment, a_comment,
-                                     fixture_class_id, factory);
-}
+                   internal::TestFactoryBase* factory)
+    : test_case_name_(a_test_case_name),
+      name_(a_name),
+      test_case_comment_(a_test_case_comment),
+      comment_(a_comment),
+      fixture_class_id_(fixture_class_id),
+      should_run_(false),
+      is_disabled_(false),
+      matches_filter_(false),
+      factory_(factory),
+      result_() {}
 
 // Destructs a TestInfo object.
-TestInfo::~TestInfo() {
-  delete impl_;
-}
+TestInfo::~TestInfo() { delete factory_; }
 
 namespace internal {
 
@@ -2147,41 +2218,6 @@
 
 }  // namespace internal
 
-// Returns the test case name.
-const char* TestInfo::test_case_name() const {
-  return impl_->test_case_name();
-}
-
-// Returns the test name.
-const char* TestInfo::name() const {
-  return impl_->name();
-}
-
-// Returns the test case comment.
-const char* TestInfo::test_case_comment() const {
-  return impl_->test_case_comment();
-}
-
-// Returns the test comment.
-const char* TestInfo::comment() const {
-  return impl_->comment();
-}
-
-// Returns true if this test should run.
-bool TestInfo::should_run() const { return impl_->should_run(); }
-
-// Returns true if this test matches the user-specified filter.
-bool TestInfo::matches_filter() const { return impl_->matches_filter(); }
-
-// Returns the result of the test.
-const TestResult* TestInfo::result() const { return impl_->result(); }
-
-// Increments the number of death tests encountered in this test so
-// far.
-int TestInfo::increment_death_test_count() {
-  return impl_->result()->increment_death_test_count();
-}
-
 namespace {
 
 // A predicate that checks the test name of a TestInfo against a known
@@ -2225,70 +2261,54 @@
 #endif
 }
 
+}  // namespace internal
+
 // Creates the test object, runs it, records its result, and then
 // deletes it.
-void TestInfoImpl::Run() {
+void TestInfo::Run() {
   if (!should_run_) return;
 
   // Tells UnitTest where to store test result.
-  UnitTestImpl* const impl = internal::GetUnitTestImpl();
-  impl->set_current_test_info(parent_);
+  internal::UnitTestImpl* const impl = internal::GetUnitTestImpl();
+  impl->set_current_test_info(this);
 
   TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater();
 
   // Notifies the unit test event listeners that a test is about to start.
-  repeater->OnTestStart(*parent_);
+  repeater->OnTestStart(*this);
 
-  const TimeInMillis start = GetTimeInMillis();
+  const TimeInMillis start = internal::GetTimeInMillis();
 
   impl->os_stack_trace_getter()->UponLeavingGTest();
-#if GTEST_HAS_SEH
-  // Catch SEH-style exceptions.
-  Test* test = NULL;
-
-  __try {
-    // Creates the test object.
-    test = factory_->CreateTest();
-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
-      GetExceptionCode())) {
-    AddExceptionThrownFailure(GetExceptionCode(),
-                              "the test fixture's constructor");
-    return;
-  }
-#else  // We are on a compiler or platform that doesn't support SEH.
-
-  // TODO(wan): If test->Run() throws, test won't be deleted.  This is
-  // not a problem now as we don't use exceptions.  If we were to
-  // enable exceptions, we should revise the following to be
-  // exception-safe.
 
   // Creates the test object.
-  Test* test = factory_->CreateTest();
-#endif  // GTEST_HAS_SEH
+  Test* const test = HandleExceptionsInMethodIfSupported(
+      factory_, &internal::TestFactoryBase::CreateTest,
+      "the test fixture's constructor");
 
-  // Runs the test only if the constructor of the test fixture didn't
+  // Runs the test only if the test object was created and its constructor didn't
   // generate a fatal failure.
-  if (!Test::HasFatalFailure()) {
+  if ((test != NULL) && !Test::HasFatalFailure()) {
+    // This doesn't throw as all user code that can throw are wrapped into
+    // exception handling code.
     test->Run();
   }
 
   // Deletes the test object.
   impl->os_stack_trace_getter()->UponLeavingGTest();
-  delete test;
-  test = NULL;
+  HandleExceptionsInMethodIfSupported(
+      test, &Test::DeleteSelf_, "the test fixture's destructor");
 
-  result_.set_elapsed_time(GetTimeInMillis() - start);
+  result_.set_elapsed_time(internal::GetTimeInMillis() - start);
 
   // Notifies the unit test event listener that a test has just finished.
-  repeater->OnTestEnd(*parent_);
+  repeater->OnTestEnd(*this);
 
   // Tells UnitTest to stop associating assertion results to this
   // test.
   impl->set_current_test_info(NULL);
 }
 
-}  // namespace internal
-
 // class TestCase
 
 // Gets the number of successful tests in this test case.
@@ -2371,45 +2391,26 @@
 
   repeater->OnTestCaseStart(*this);
   impl->os_stack_trace_getter()->UponLeavingGTest();
-  set_up_tc_();
+  HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunSetUpTestCase, "SetUpTestCase()");
 
   const internal::TimeInMillis start = internal::GetTimeInMillis();
   for (int i = 0; i < total_test_count(); i++) {
-    GetMutableTestInfo(i)->impl()->Run();
+    GetMutableTestInfo(i)->Run();
   }
   elapsed_time_ = internal::GetTimeInMillis() - start;
 
   impl->os_stack_trace_getter()->UponLeavingGTest();
-  tear_down_tc_();
+  HandleExceptionsInMethodIfSupported(
+      this, &TestCase::RunTearDownTestCase, "TearDownTestCase()");
+
   repeater->OnTestCaseEnd(*this);
   impl->set_current_test_case(NULL);
 }
 
 // Clears the results of all tests in this test case.
 void TestCase::ClearResult() {
-  ForEach(test_info_list_, internal::TestInfoImpl::ClearTestResult);
-}
-
-// Returns true iff test passed.
-bool TestCase::TestPassed(const TestInfo * test_info) {
-  const internal::TestInfoImpl* const impl = test_info->impl();
-  return impl->should_run() && impl->result()->Passed();
-}
-
-// Returns true iff test failed.
-bool TestCase::TestFailed(const TestInfo * test_info) {
-  const internal::TestInfoImpl* const impl = test_info->impl();
-  return impl->should_run() && impl->result()->Failed();
-}
-
-// Returns true iff test is disabled.
-bool TestCase::TestDisabled(const TestInfo * test_info) {
-  return test_info->impl()->is_disabled();
-}
-
-// Returns true if the given test should run.
-bool TestCase::ShouldRunTest(const TestInfo *test_info) {
-  return test_info->impl()->should_run();
+  ForEach(test_info_list_, TestInfo::ClearTestResult);
 }
 
 // Shuffles the tests in this test case.
@@ -3505,19 +3506,6 @@
   return env;
 }
 
-#if GTEST_HAS_EXCEPTIONS
-// A failed Google Test assertion will throw an exception of this type
-// when exceptions are enabled.  We derive it from std::runtime_error,
-// which is for errors presumably detectable only at run time.  Since
-// std::runtime_error inherits from std::exception, many testing
-// frameworks know how to extract and print the message inside it.
-class GoogleTestFailureException : public ::std::runtime_error {
- public:
-  explicit GoogleTestFailureException(const TestPartResult& failure)
-      : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {}
-};
-#endif
-
 // Adds a TestPartResult to the current TestResult object.  All Google Test
 // assertion macros (e.g. ASSERT_TRUE, EXPECT_EQ, etc) eventually call
 // this to report their results.  The user code should use the
@@ -3640,20 +3628,12 @@
           _WRITE_ABORT_MSG | _CALL_REPORTFAULT);  // pop-up window, core dump.
 #endif
   }
-
-  __try {
-    return impl_->RunAllTests();
-  } __except(internal::UnitTestOptions::GTestShouldProcessSEH(
-      GetExceptionCode())) {
-    printf("Exception thrown with code 0x%x.\nFAIL\n", GetExceptionCode());
-    fflush(stdout);
-    return 1;
-  }
-
-#else  // We are on a compiler or platform that doesn't support SEH.
-
-  return impl_->RunAllTests();
 #endif  // GTEST_HAS_SEH
+
+  return HandleExceptionsInMethodIfSupported(
+      impl_,
+      &internal::UnitTestImpl::RunAllTests,
+      "auxiliary test code (environments or event listeners)") ? 0 : 1;
 }
 
 // Returns the working directory when the first TEST() or TEST_F() was
@@ -3890,27 +3870,26 @@
 static void TearDownEnvironment(Environment* env) { env->TearDown(); }
 
 // Runs all tests in this UnitTest object, prints the result, and
-// returns 0 if all tests are successful, or 1 otherwise.  If any
-// exception is thrown during a test on Windows, this test is
-// considered to be failed, but the rest of the tests will still be
-// run.  (We disable exceptions on Linux and Mac OS X, so the issue
-// doesn't apply there.)
+// returns true if all tests are successful.  If any exception is
+// thrown during a test, the test is considered to be failed, but the
+// rest of the tests will still be run.
+//
 // When parameterized tests are enabled, it expands and registers
 // parameterized tests first in RegisterParameterizedTests().
 // All other functions called from RunAllTests() may safely assume that
 // parameterized tests are ready to be counted and run.
-int UnitTestImpl::RunAllTests() {
+bool UnitTestImpl::RunAllTests() {
   // Makes sure InitGoogleTest() was called.
   if (!GTestIsInitialized()) {
     printf("%s",
            "\nThis test program did NOT call ::testing::InitGoogleTest "
            "before calling RUN_ALL_TESTS().  Please fix it.\n");
-    return 1;
+    return false;
   }
 
   // Do not run any test if the --help flag was specified.
   if (g_help_flag)
-    return 0;
+    return true;
 
   // Repeats the call to the post-flag parsing initialization in case the
   // user didn't call InitGoogleTest.
@@ -3942,7 +3921,7 @@
   if (GTEST_FLAG(list_tests)) {
     // This must be called *after* FilterTests() has been called.
     ListTestsMatchingFilter();
-    return 0;
+    return true;
   }
 
   random_seed_ = GTEST_FLAG(shuffle) ?
@@ -4028,8 +4007,7 @@
 
   repeater->OnTestProgramEnd(*parent_);
 
-  // Returns 0 if all tests passed, or 1 other wise.
-  return failed ? 1 : 0;
+  return !failed;
 }
 
 // Reads the GTEST_SHARD_STATUS_FILE environment variable, and creates the file
@@ -4159,12 +4137,12 @@
                                                    kDisableTestFilter) ||
           internal::UnitTestOptions::MatchesFilter(test_name,
                                                    kDisableTestFilter);
-      test_info->impl()->set_is_disabled(is_disabled);
+      test_info->is_disabled_ = is_disabled;
 
       const bool matches_filter =
           internal::UnitTestOptions::FilterMatchesTest(test_case_name,
                                                        test_name);
-      test_info->impl()->set_matches_filter(matches_filter);
+      test_info->matches_filter_ = matches_filter;
 
       const bool is_runnable =
           (GTEST_FLAG(also_run_disabled_tests) || !is_disabled) &&
@@ -4178,7 +4156,7 @@
       num_runnable_tests += is_runnable;
       num_selected_tests += is_selected;
 
-      test_info->impl()->set_should_run(is_selected);
+      test_info->should_run_ = is_selected;
       test_case->set_should_run(test_case->should_run() || is_selected);
     }
   }
@@ -4194,7 +4172,7 @@
     for (size_t j = 0; j < test_case->test_info_list().size(); j++) {
       const TestInfo* const test_info =
           test_case->test_info_list()[j];
-      if (test_info->matches_filter()) {
+      if (test_info->matches_filter_) {
         if (!printed_test_case_name) {
           printed_test_case_name = true;
           printf("%s.\n", test_case->name());
@@ -4234,7 +4212,7 @@
 // the TestResult for the ad hoc test if no test is running.
 TestResult* UnitTestImpl::current_test_result() {
   return current_test_info_ ?
-    current_test_info_->impl()->result() : &ad_hoc_test_result_;
+      &(current_test_info_->result_) : &ad_hoc_test_result_;
 }
 
 // Shuffles all test cases, and the tests within each test case,
@@ -4263,32 +4241,6 @@
   }
 }
 
-// TestInfoImpl constructor. The new instance assumes ownership of the test
-// factory object.
-TestInfoImpl::TestInfoImpl(TestInfo* parent,
-                           const char* a_test_case_name,
-                           const char* a_name,
-                           const char* a_test_case_comment,
-                           const char* a_comment,
-                           TypeId a_fixture_class_id,
-                           internal::TestFactoryBase* factory) :
-    parent_(parent),
-    test_case_name_(String(a_test_case_name)),
-    name_(String(a_name)),
-    test_case_comment_(String(a_test_case_comment)),
-    comment_(String(a_comment)),
-    fixture_class_id_(a_fixture_class_id),
-    should_run_(false),
-    is_disabled_(false),
-    matches_filter_(false),
-    factory_(factory) {
-}
-
-// TestInfoImpl destructor.
-TestInfoImpl::~TestInfoImpl() {
-  delete factory_;
-}
-
 // Returns the current OS stack trace as a String.
 //
 // The maximum number of stack frames to be included is specified by
@@ -4306,8 +4258,8 @@
   return GetUnitTestImpl()->CurrentOsStackTraceExceptTop(skip_count + 1);
 }
 
-// Used by the GTEST_HIDE_UNREACHABLE_CODE_ macro to suppress unreachable
-// code warnings.
+// Used by the GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ macro to
+// suppress unreachable code warnings.
 namespace {
 class ClassUniqueToAlwaysTrue {};
 }
diff --git a/test/gtest-death-test_test.cc b/test/gtest-death-test_test.cc
index ed5b53b..d33cfeb 100644
--- a/test/gtest-death-test_test.cc
+++ b/test/gtest-death-test_test.cc
@@ -614,17 +614,6 @@
     abort();
   }, "");
 }
-
-TEST(PopUpDeathTest, DoesNotShowPopUpOnThrow) {
-  printf("This test should be considered failing if it shows "
-         "any pop-up dialogs.\n");
-  fflush(stdout);
-
-  EXPECT_DEATH({
-    testing::GTEST_FLAG(catch_exceptions) = false;
-    throw 1;
-  }, "");
-}
 #endif  // GTEST_OS_WINDOWS
 
 // Tests that EXPECT_DEBUG_DEATH in debug mode does not abort
diff --git a/test/gtest-printers_test.cc b/test/gtest-printers_test.cc
index 11f6625..5dec871 100644
--- a/test/gtest-printers_test.cc
+++ b/test/gtest-printers_test.cc
@@ -60,6 +60,42 @@
 
 // Some user-defined types for testing the universal value printer.
 
+// An anonymous enum type.
+enum AnonymousEnum {
+  kAE1 = -1,
+  kAE2 = 1
+};
+
+// An enum without a user-defined printer.
+enum EnumWithoutPrinter {
+  kEWP1 = -2,
+  kEWP2 = 42
+};
+
+// An enum with a << operator.
+enum EnumWithStreaming {
+  kEWS1 = 10,
+};
+
+std::ostream& operator<<(std::ostream& os, EnumWithStreaming e) {
+  return os << (e == kEWS1 ? "kEWS1" : "invalid");
+}
+
+// An enum with a PrintTo() function.
+enum EnumWithPrintTo {
+  kEWPT1 = 1,
+};
+
+void PrintTo(EnumWithPrintTo e, std::ostream* os) {
+  *os << (e == kEWPT1 ? "kEWPT1" : "invalid");
+}
+
+// A class implicitly convertible to BiggestInt.
+class BiggestIntConvertible {
+ public:
+  operator ::testing::internal::BiggestInt() const { return 42; }
+};
+
 // A user-defined unprintable class template in the global namespace.
 template <typename T>
 class UnprintableTemplateInGlobal {
@@ -207,6 +243,34 @@
   return ss.str();
 }
 
+// Tests printing various enum types.
+
+TEST(PrintEnumTest, AnonymousEnum) {
+  EXPECT_EQ("-1", Print(kAE1));
+  EXPECT_EQ("1", Print(kAE2));
+}
+
+TEST(PrintEnumTest, EnumWithoutPrinter) {
+  EXPECT_EQ("-2", Print(kEWP1));
+  EXPECT_EQ("42", Print(kEWP2));
+}
+
+TEST(PrintEnumTest, EnumWithStreaming) {
+  EXPECT_EQ("kEWS1", Print(kEWS1));
+  EXPECT_EQ("invalid", Print(static_cast<EnumWithStreaming>(0)));
+}
+
+TEST(PrintEnumTest, EnumWithPrintTo) {
+  EXPECT_EQ("kEWPT1", Print(kEWPT1));
+  EXPECT_EQ("invalid", Print(static_cast<EnumWithPrintTo>(0)));
+}
+
+// Tests printing a class implicitly convertible to BiggestInt.
+
+TEST(PrintClassTest, BiggestIntConvertible) {
+  EXPECT_EQ("42", Print(BiggestIntConvertible()));
+}
+
 // Tests printing various char types.
 
 // char.
@@ -913,7 +977,7 @@
 
 // Unprintable types in a user namespace.
 TEST(PrintUnprintableTypeTest, InUserNamespace) {
-  EXPECT_EQ("16-byte object <EF12 0000 34AB 0000 0000 0000 0000 0000>",
+  EXPECT_EQ("16-byte object <EF-12 00-00 34-AB 00-00 00-00 00-00 00-00 00-00>",
             Print(::foo::UnprintableInFoo()));
 }
 
@@ -925,13 +989,13 @@
 };
 
 TEST(PrintUnpritableTypeTest, BigObject) {
-  EXPECT_EQ("257-byte object <0000 0000 0000 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 ... 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 "
-            "0000 0000 0000 0000 0000 0000 0000 0000 00>",
+  EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 "
+            "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>",
             Print(Big()));
 }
 
@@ -1022,7 +1086,7 @@
 
   const ::foo::UnprintableInFoo x;
   EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object "
-            "<EF12 0000 34AB 0000 0000 0000 0000 0000>",
+            "<EF-12 00-00 34-AB 00-00 00-00 00-00 00-00 00-00>",
             PrintByRef(x));
 }
 
diff --git a/test/gtest_catch_exceptions_test.py b/test/gtest_catch_exceptions_test.py
new file mode 100755
index 0000000..c4d1756
--- /dev/null
+++ b/test/gtest_catch_exceptions_test.py
@@ -0,0 +1,203 @@
+#!/usr/bin/env python
+#
+# Copyright 2010 Google Inc.  All Rights Reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Tests Google Test's exception catching behavior.
+
+This script invokes gtest_catch_exceptions_test_ and
+gtest_catch_exceptions_ex_test_ (programs written with
+Google Test) and verifies their output.
+"""
+
+__author__ = 'vladl@google.com (Vlad Losev)'
+
+import os
+
+import gtest_test_utils
+
+# Constants.
+LIST_TESTS_FLAG = '--gtest_list_tests'
+
+# Path to the gtest_catch_exceptions_ex_test_ binary, compiled with
+# exceptions enabled.
+EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+    'gtest_catch_exceptions_ex_test_')
+
+# Path to the gtest_catch_exceptions_test_ binary, compiled with
+# exceptions disabled.
+EXE_PATH = gtest_test_utils.GetTestExecutablePath(
+    'gtest_catch_exceptions_no_ex_test_')
+
+TEST_LIST = gtest_test_utils.Subprocess([EXE_PATH, LIST_TESTS_FLAG]).output
+
+SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST
+
+if SUPPORTS_SEH_EXCEPTIONS:
+  BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH]).output
+
+EX_BINARY_OUTPUT = gtest_test_utils.Subprocess([EX_EXE_PATH]).output
+
+
+# The tests.
+if SUPPORTS_SEH_EXCEPTIONS:
+  # pylint:disable-msg=C6302
+  class CatchSehExceptionsTest(gtest_test_utils.TestCase):
+    """Tests exception-catching behavior."""
+
+
+    def TestSehExceptions(self, test_output):
+      self.assert_('SEH exception with code 0x2a thrown '
+                   'in the test fixture\'s constructor'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown '
+                   'in the test fixture\'s destructor'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown in SetUp()'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown in TearDown()'
+                   in test_output)
+      self.assert_('SEH exception with code 0x2a thrown in the test body'
+                   in test_output)
+
+    def testCatchesSehExceptionsWithCxxExceptionsEnabled(self):
+      self.TestSehExceptions(EX_BINARY_OUTPUT)
+
+    def testCatchesSehExceptionsWithCxxExceptionsDisabled(self):
+      self.TestSehExceptions(BINARY_OUTPUT)
+
+
+class CatchCxxExceptionsTest(gtest_test_utils.TestCase):
+  """Tests C++ exception-catching behavior.
+
+     Tests in this test case verify that:
+     * C++ exceptions are caught and logged as C++ (not SEH) exceptions
+     * Exception thrown affect the remainder of the test work flow in the
+       expected manner.
+  """
+
+  def testCatchesCxxExceptionsInFixtureConstructor(self):
+    self.assert_('C++ exception with description '
+                 '"Standard C++ exception" thrown '
+                 'in the test fixture\'s constructor'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+                 'This failure belongs in this test only if '
+                 '"CxxExceptionInConstructorTest" (no quotes) '
+                 'appears on the same line as words "called unexpectedly"')
+
+  def testCatchesCxxExceptionsInFixtureDestructor(self):
+    self.assert_('C++ exception with description '
+                 '"Standard C++ exception" thrown '
+                 'in the test fixture\'s destructor'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+
+  def testCatchesCxxExceptionsInSetUpTestCase(self):
+    self.assert_('C++ exception with description "Standard C++ exception"'
+                 ' thrown in SetUpTestCase()'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTestCaseTest constructor '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTestCaseTest destructor '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTestCaseTest test body '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+
+  def testCatchesCxxExceptionsInTearDownTestCase(self):
+    self.assert_('C++ exception with description "Standard C++ exception"'
+                 ' thrown in TearDownTestCase()'
+                 in EX_BINARY_OUTPUT)
+
+  def testCatchesCxxExceptionsInSetUp(self):
+    self.assert_('C++ exception with description "Standard C++ exception"'
+                 ' thrown in SetUp()'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTest destructor '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInSetUpTest::TearDown() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('unexpected' not in EX_BINARY_OUTPUT,
+                 'This failure belongs in this test only if '
+                 '"CxxExceptionInSetUpTest" (no quotes) '
+                 'appears on the same line as words "called unexpectedly"')
+
+  def testCatchesCxxExceptionsInTearDown(self):
+    self.assert_('C++ exception with description "Standard C++ exception"'
+                 ' thrown in TearDown()'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInTearDownTest destructor '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+
+  def testCatchesCxxExceptionsInTestBody(self):
+    self.assert_('C++ exception with description "Standard C++ exception"'
+                 ' thrown in the test body'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInTestBodyTest destructor '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+    self.assert_('CxxExceptionInTestBodyTest::TearDown() '
+                 'called as expected.'
+                 in EX_BINARY_OUTPUT)
+
+  def testCatchesNonStdCxxExceptions(self):
+    self.assert_('Unknown C++ exception thrown in the test body'
+                 in EX_BINARY_OUTPUT)
+
+if __name__ == '__main__':
+  gtest_test_utils.Main()
diff --git a/test/gtest_catch_exceptions_test_.cc b/test/gtest_catch_exceptions_test_.cc
new file mode 100644
index 0000000..8673681
--- /dev/null
+++ b/test/gtest_catch_exceptions_test_.cc
@@ -0,0 +1,299 @@
+// Copyright 2010, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// Author: vladl@google.com (Vlad Losev)
+//
+// Tests for Google Test itself. Tests in this file throw C++ or SEH
+// exceptions, and the output is verified by gtest_catch_exceptions_test.py.
+
+#include <gtest/gtest.h>
+
+#include <stdio.h>  // NOLINT
+
+#if GTEST_HAS_SEH
+#include <windows.h>
+#endif
+
+#if GTEST_HAS_EXCEPTIONS
+#include <stdexcept>
+#endif
+
+using testing::Test;
+using testing::GTEST_FLAG(catch_exceptions);
+
+#if GTEST_HAS_SEH
+
+class SehExceptionInConstructorTest : public Test {
+ public:
+  SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {}
+
+class SehExceptionInDestructorTest : public Test {
+ public:
+  ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {}
+
+class SehExceptionInSetUpTestCaseTest : public Test {
+ public:
+  static void SetUpTestCase() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {}
+
+class SehExceptionInTearDownTestCaseTest : public Test {
+ public:
+  static void TearDownTestCase() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {}
+
+class SehExceptionInSetUpTest : public Test {
+ protected:
+  virtual void SetUp() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {}
+
+class SehExceptionInTearDownTest : public Test {
+ protected:
+  virtual void TearDown() { RaiseException(42, 0, 0, NULL); }
+};
+
+TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {}
+
+TEST(SehExceptionTest, ThrowsSehException) {
+  RaiseException(42, 0, 0, NULL);
+}
+
+#endif  // GTEST_HAS_SEH
+
+#if GTEST_HAS_EXCEPTIONS
+
+class CxxExceptionInConstructorTest : public Test {
+ public:
+  CxxExceptionInConstructorTest() {
+    // Without this macro VC++ complains about unreachable code at the end of
+    // the constructor.
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+        throw std::runtime_error("Standard C++ exception"));
+  }
+
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInConstructorTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInConstructorTest() {
+    ADD_FAILURE() << "CxxExceptionInConstructorTest destructor "
+                  << "called unexpectedly.";
+  }
+
+  virtual void SetUp() {
+    ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() "
+                  << "called unexpectedly.";
+  }
+
+  virtual void TearDown() {
+    ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() "
+                  << "called unexpectedly.";
+  }
+};
+
+TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor) {
+  ADD_FAILURE() << "CxxExceptionInConstructorTest test body "
+                << "called unexpectedly.";
+}
+
+class CxxExceptionInDestructorTest : public Test {
+ public:
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInDestructorTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInDestructorTest() {
+    GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(
+        throw std::runtime_error("Standard C++ exception"));
+  }
+};
+
+TEST_F(CxxExceptionInDestructorTest, ThrowsExceptionInDestructor) {}
+
+class CxxExceptionInSetUpTestCaseTest : public Test {
+ public:
+  CxxExceptionInSetUpTestCaseTest() {
+    printf("%s",
+           "CxxExceptionInSetUpTestCaseTest constructor "
+           "called as expected.\n");
+  }
+
+  static void SetUpTestCase() {
+    throw std::runtime_error("Standard C++ exception");
+  }
+
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInSetUpTestCaseTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInSetUpTestCaseTest() {
+    printf("%s",
+           "CxxExceptionInSetUpTestCaseTest destructor "
+           "called as expected.\n");
+  }
+
+  virtual void SetUp() {
+    printf("%s",
+           "CxxExceptionInSetUpTestCaseTest::SetUp() "
+           "called as expected.\n");
+  }
+
+  virtual void TearDown() {
+    printf("%s",
+           "CxxExceptionInSetUpTestCaseTest::TearDown() "
+           "called as expected.\n");
+  }
+};
+
+TEST_F(CxxExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {
+  printf("%s",
+         "CxxExceptionInSetUpTestCaseTest test body "
+         "called as expected.\n");
+}
+
+class CxxExceptionInTearDownTestCaseTest : public Test {
+ public:
+  static void TearDownTestCase() {
+    throw std::runtime_error("Standard C++ exception");
+  }
+};
+
+TEST_F(CxxExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {}
+
+class CxxExceptionInSetUpTest : public Test {
+ public:
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInSetUpTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInSetUpTest() {
+    printf("%s",
+           "CxxExceptionInSetUpTest destructor "
+           "called as expected.\n");
+  }
+
+  virtual void SetUp() { throw std::runtime_error("Standard C++ exception"); }
+
+  virtual void TearDown() {
+    printf("%s",
+           "CxxExceptionInSetUpTest::TearDown() "
+           "called as expected.\n");
+  }
+};
+
+TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp) {
+  ADD_FAILURE() << "CxxExceptionInSetUpTest test body "
+                << "called unexpectedly.";
+}
+
+class CxxExceptionInTearDownTest : public Test {
+ public:
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInTearDownTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInTearDownTest() {
+    printf("%s",
+           "CxxExceptionInTearDownTest destructor "
+           "called as expected.\n");
+  }
+
+  virtual void TearDown() {
+    throw std::runtime_error("Standard C++ exception");
+  }
+};
+
+TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {}
+
+class CxxExceptionInTestBodyTest : public Test {
+ public:
+  static void TearDownTestCase() {
+    printf("%s",
+           "CxxExceptionInTestBodyTest::TearDownTestCase() "
+           "called as expected.\n");
+  }
+
+ protected:
+  ~CxxExceptionInTestBodyTest() {
+    printf("%s",
+           "CxxExceptionInTestBodyTest destructor "
+           "called as expected.\n");
+  }
+
+  virtual void TearDown() {
+    printf("%s",
+           "CxxExceptionInTestBodyTest::TearDown() "
+           "called as expected.\n");
+  }
+};
+
+TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException) {
+  throw std::runtime_error("Standard C++ exception");
+}
+
+TEST(CxxExceptionTest, ThrowsNonStdCxxException) {
+  throw "C-string";
+}
+
+#endif  // GTEST_HAS_EXCEPTIONS
+
+int main(int argc, char** argv) {
+#if GTEST_HAS_SEH
+  // Tells Google Test to catch SEH-style exceptions on Windows.
+  GTEST_FLAG(catch_exceptions) = true;
+#endif
+  testing::InitGoogleTest(&argc, argv);
+  return RUN_ALL_TESTS();
+}
diff --git a/test/gtest_output_test_.cc b/test/gtest_output_test_.cc
index 454e1ba..fc80fac 100644
--- a/test/gtest_output_test_.cc
+++ b/test/gtest_output_test_.cc
@@ -445,137 +445,6 @@
   ADD_FAILURE_AT("foo.cc", 42) << "Expected failure in foo.cc";
 }
 
-#if GTEST_OS_WINDOWS
-
-// This group of tests verifies that Google Test handles SEH and C++
-// exceptions correctly.
-
-// A function that throws an SEH exception.
-static void ThrowSEH() {
-  int* p = NULL;
-  *p = 0;  // Raises an access violation.
-}
-
-// Tests exceptions thrown in the test fixture constructor.
-class ExceptionInFixtureCtorTest : public testing::Test {
- protected:
-  ExceptionInFixtureCtorTest() {
-    printf("(expecting a failure on thrown exception "
-           "in the test fixture's constructor)\n");
-
-    ThrowSEH();
-  }
-
-  virtual ~ExceptionInFixtureCtorTest() {
-    Deinit();
-  }
-
-  virtual void SetUp() {
-    FAIL() << "UNEXPECTED failure in SetUp().  "
-           << "We should never get here, as the test fixture c'tor threw.";
-  }
-
-  virtual void TearDown() {
-    FAIL() << "UNEXPECTED failure in TearDown().  "
-           << "We should never get here, as the test fixture c'tor threw.";
-  }
- private:
-  void Deinit() {
-    FAIL() << "UNEXPECTED failure in the d'tor.  "
-           << "We should never get here, as the test fixture c'tor threw.";
-  }
-};
-
-TEST_F(ExceptionInFixtureCtorTest, ExceptionInFixtureCtor) {
-  FAIL() << "UNEXPECTED failure in the test function.  "
-         << "We should never get here, as the test fixture c'tor threw.";
-}
-
-// Tests exceptions thrown in SetUp().
-class ExceptionInSetUpTest : public testing::Test {
- protected:
-  virtual ~ExceptionInSetUpTest() {
-    Deinit();
-  }
-
-  virtual void SetUp() {
-    printf("(expecting 3 failures)\n");
-
-    ThrowSEH();
-  }
-
-  virtual void TearDown() {
-    FAIL() << "Expected failure #2, in TearDown().";
-  }
- private:
-  void Deinit() {
-    FAIL() << "Expected failure #3, in the test fixture d'tor.";
-  }
-};
-
-TEST_F(ExceptionInSetUpTest, ExceptionInSetUp) {
-  FAIL() << "UNEXPECTED failure in the test function.  "
-         << "We should never get here, as SetUp() threw.";
-}
-
-// Tests that TearDown() and the test fixture d'tor are always called,
-// even when the test function throws an exception.
-class ExceptionInTestFunctionTest : public testing::Test {
- protected:
-  virtual ~ExceptionInTestFunctionTest() {
-    Deinit();
-  }
-
-  virtual void TearDown() {
-    FAIL() << "Expected failure #2, in TearDown().";
-  }
- private:
-  void Deinit() {
-    FAIL() << "Expected failure #3, in the test fixture d'tor.";
-  }
-};
-
-// Tests that the test fixture d'tor is always called, even when the
-// test function throws an SEH exception.
-TEST_F(ExceptionInTestFunctionTest, SEH) {
-  printf("(expecting 3 failures)\n");
-
-  ThrowSEH();
-}
-
-#if GTEST_HAS_EXCEPTIONS
-
-// Tests that the test fixture d'tor is always called, even when the
-// test function throws a C++ exception.  We do this only when
-// GTEST_HAS_EXCEPTIONS is non-zero, i.e. C++ exceptions are enabled.
-TEST_F(ExceptionInTestFunctionTest, CppException) {
-  throw 1;
-}
-
-// Tests exceptions thrown in TearDown().
-class ExceptionInTearDownTest : public testing::Test {
- protected:
-  virtual ~ExceptionInTearDownTest() {
-    Deinit();
-  }
-
-  virtual void TearDown() {
-    throw 1;
-  }
- private:
-  void Deinit() {
-    FAIL() << "Expected failure #2, in the test fixture d'tor.";
-  }
-};
-
-TEST_F(ExceptionInTearDownTest, ExceptionInTearDown) {
-  printf("(expecting 2 failures)\n");
-}
-
-#endif  // GTEST_HAS_EXCEPTIONS
-
-#endif  // GTEST_OS_WINDOWS
-
 #if GTEST_IS_THREADSAFE
 
 // A unary function that may die.
diff --git a/test/gtest_output_test_golden_win.txt b/test/gtest_output_test_golden_win.txt
index 135f39e..8251c23 100644
--- a/test/gtest_output_test_golden_win.txt
+++ b/test/gtest_output_test_golden_win.txt
@@ -5,7 +5,7 @@
 Expected: true
 gtest_output_test_.cc:#: error: Value of: 3
 Expected: 2
-[==========] Running 63 tests from 29 test cases.
+[==========] Running 58 tests from 25 test cases.
 [----------] Global test environment set-up.
 FooEnvironment::SetUp() called.
 BarEnvironment::SetUp() called.
@@ -178,42 +178,6 @@
 foo.cc(42): error: Failed
 Expected failure in foo.cc
 [  FAILED  ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber
-[----------] 1 test from ExceptionInFixtureCtorTest
-[ RUN      ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor
-(expecting a failure on thrown exception in the test fixture's constructor)
-unknown file: error: Exception thrown with code 0xc0000005 in the test fixture's constructor.
-[----------] 1 test from ExceptionInSetUpTest
-[ RUN      ] ExceptionInSetUpTest.ExceptionInSetUp
-(expecting 3 failures)
-unknown file: error: Exception thrown with code 0xc0000005 in SetUp().
-gtest_output_test_.cc:#: error: Failed
-Expected failure #2, in TearDown().
-gtest_output_test_.cc:#: error: Failed
-Expected failure #3, in the test fixture d'tor.
-[  FAILED  ] ExceptionInSetUpTest.ExceptionInSetUp
-[----------] 2 tests from ExceptionInTestFunctionTest
-[ RUN      ] ExceptionInTestFunctionTest.SEH
-(expecting 3 failures)
-unknown file: error: Exception thrown with code 0xc0000005 in the test body.
-gtest_output_test_.cc:#: error: Failed
-Expected failure #2, in TearDown().
-gtest_output_test_.cc:#: error: Failed
-Expected failure #3, in the test fixture d'tor.
-[  FAILED  ] ExceptionInTestFunctionTest.SEH
-[ RUN      ] ExceptionInTestFunctionTest.CppException
-unknown file: error: Exception thrown with code 0xe06d7363 in the test body.
-gtest_output_test_.cc:#: error: Failed
-Expected failure #2, in TearDown().
-gtest_output_test_.cc:#: error: Failed
-Expected failure #3, in the test fixture d'tor.
-[  FAILED  ] ExceptionInTestFunctionTest.CppException
-[----------] 1 test from ExceptionInTearDownTest
-[ RUN      ] ExceptionInTearDownTest.ExceptionInTearDown
-(expecting 2 failures)
-unknown file: error: Exception thrown with code 0xe06d7363 in TearDown().
-gtest_output_test_.cc:#: error: Failed
-Expected failure #2, in the test fixture d'tor.
-[  FAILED  ] ExceptionInTearDownTest.ExceptionInTearDown
 [----------] 4 tests from MixedUpTestCaseTest
 [ RUN      ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
 [       OK ] MixedUpTestCaseTest.FirstTestFromNamespaceFoo
@@ -497,9 +461,9 @@
 FooEnvironment::TearDown() called.
 gtest_output_test_.cc:#: error: Failed
 Expected fatal failure.
-[==========] 63 tests from 29 test cases ran.
+[==========] 58 tests from 25 test cases ran.
 [  PASSED  ] 21 tests.
-[  FAILED  ] 42 tests, listed below:
+[  FAILED  ] 37 tests, listed below:
 [  FAILED  ] FatalFailureTest.FatalFailureInSubroutine
 [  FAILED  ] FatalFailureTest.FatalFailureInNestedSubroutine
 [  FAILED  ] FatalFailureTest.NonfatalFailureInSubroutine
@@ -514,11 +478,6 @@
 [  FAILED  ] NonFatalFailureInSetUpTest.FailureInSetUp
 [  FAILED  ] FatalFailureInSetUpTest.FailureInSetUp
 [  FAILED  ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber
-[  FAILED  ] ExceptionInFixtureCtorTest.ExceptionInFixtureCtor
-[  FAILED  ] ExceptionInSetUpTest.ExceptionInSetUp
-[  FAILED  ] ExceptionInTestFunctionTest.SEH
-[  FAILED  ] ExceptionInTestFunctionTest.CppException
-[  FAILED  ] ExceptionInTearDownTest.ExceptionInTearDown
 [  FAILED  ] MixedUpTestCaseTest.ThisShouldFail
 [  FAILED  ] MixedUpTestCaseTest.ThisShouldFailToo
 [  FAILED  ] MixedUpTestCaseWithSameTestNameTest.TheSecondTestWithThisNameShouldFail
@@ -543,7 +502,7 @@
 [  FAILED  ] ExpectFailureTest.ExpectNonFatalFailureOnAllThreads
 [  FAILED  ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2
 
-42 FAILED TESTS
+37 FAILED TESTS
   YOU HAVE 1 DISABLED TEST
 
 Note: Google Test filter = FatalFailureTest.*:LoggingTest.*
diff --git a/test/gtest_unittest.cc b/test/gtest_unittest.cc
index 910d4e2..9b95b13 100644
--- a/test/gtest_unittest.cc
+++ b/test/gtest_unittest.cc
@@ -3767,6 +3767,17 @@
     "Value of: y\n  Actual: -1\nExpected: x\nWhich is: 5");
 }
 
+enum NamedEnum {
+  kE1 = 0,
+  kE2 = 1,
+};
+
+TEST(AssertionTest, NamedEnum) {
+  EXPECT_EQ(kE1, kE1);
+  EXPECT_LT(kE1, kE2);
+  EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0");
+  EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Actual: 1");
+}
 
 // The version of gcc used in XCode 2.2 has a bug and doesn't allow
 // anonymous enums in assertions.  Therefore the following test is not
@@ -3776,7 +3787,7 @@
 
 // Tests using assertions with anonymous enums.
 enum {
-  CASE_A = -1,
+  kCaseA = -1,
 #if GTEST_OS_LINUX
   // We want to test the case where the size of the anonymous enum is
   // larger than sizeof(int), to make sure our implementation of the
@@ -3784,37 +3795,44 @@
   // (incorrectly) doesn't allow an enum value to exceed the range of
   // an int, so this has to be conditionally compiled.
   //
-  // On Linux, CASE_B and CASE_A have the same value when truncated to
+  // On Linux, kCaseB and kCaseA have the same value when truncated to
   // int size.  We want to test whether this will confuse the
   // assertions.
-  CASE_B = testing::internal::kMaxBiggestInt,
+  kCaseB = testing::internal::kMaxBiggestInt,
 #else
-  CASE_B = INT_MAX,
+  kCaseB = INT_MAX,
 #endif  // GTEST_OS_LINUX
+  kCaseC = 42,
 };
 
 TEST(AssertionTest, AnonymousEnum) {
 #if GTEST_OS_LINUX
-  EXPECT_EQ(static_cast<int>(CASE_A), static_cast<int>(CASE_B));
+  EXPECT_EQ(static_cast<int>(kCaseA), static_cast<int>(kCaseB));
 #endif  // GTEST_OS_LINUX
 
-  EXPECT_EQ(CASE_A, CASE_A);
-  EXPECT_NE(CASE_A, CASE_B);
-  EXPECT_LT(CASE_A, CASE_B);
-  EXPECT_LE(CASE_A, CASE_B);
-  EXPECT_GT(CASE_B, CASE_A);
-  EXPECT_GE(CASE_A, CASE_A);
-  EXPECT_NONFATAL_FAILURE(EXPECT_GE(CASE_A, CASE_B),
-                          "(CASE_A) >= (CASE_B)");
+  EXPECT_EQ(kCaseA, kCaseA);
+  EXPECT_NE(kCaseA, kCaseB);
+  EXPECT_LT(kCaseA, kCaseB);
+  EXPECT_LE(kCaseA, kCaseB);
+  EXPECT_GT(kCaseB, kCaseA);
+  EXPECT_GE(kCaseA, kCaseA);
+  EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB),
+                          "(kCaseA) >= (kCaseB)");
+  EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC),
+                          "-1 vs 42");
 
-  ASSERT_EQ(CASE_A, CASE_A);
-  ASSERT_NE(CASE_A, CASE_B);
-  ASSERT_LT(CASE_A, CASE_B);
-  ASSERT_LE(CASE_A, CASE_B);
-  ASSERT_GT(CASE_B, CASE_A);
-  ASSERT_GE(CASE_A, CASE_A);
-  EXPECT_FATAL_FAILURE(ASSERT_EQ(CASE_A, CASE_B),
-                       "Value of: CASE_B");
+  ASSERT_EQ(kCaseA, kCaseA);
+  ASSERT_NE(kCaseA, kCaseB);
+  ASSERT_LT(kCaseA, kCaseB);
+  ASSERT_LE(kCaseA, kCaseB);
+  ASSERT_GT(kCaseB, kCaseA);
+  ASSERT_GE(kCaseA, kCaseA);
+  EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB),
+                       "Value of: kCaseB");
+  EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC),
+                       "Actual: 42");
+  EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC),
+                       "Which is: -1");
 }
 
 #endif  // !GTEST_OS_MAC && !defined(__SUNPRO_CC)