bpo-37069: tests use catch_unraisable_exception() (GH-13762)

Modify test_coroutines, test_cprofile, test_generators, test_raise,
test_ssl and test_yield_from to use
support.catch_unraisable_exception() rather than
support.captured_stderr().

test_thread: remove test_save_exception_state_on_error() which is now
updated. test_unraisable_exception() checks that sys.unraisablehook()
is called to handle _thread.start_new_thread() exception.

test_cprofile now rely on unittest for test discovery: replace
support.run_unittest() with unittest.main().
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
index b406b1c..208b5c2 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -2032,11 +2032,17 @@
     def test_fatal_coro_warning(self):
         # Issue 27811
         async def func(): pass
-        with warnings.catch_warnings(), support.captured_stderr() as stderr:
+        with warnings.catch_warnings(), \
+             support.catch_unraisable_exception() as cm:
             warnings.filterwarnings("error")
-            func()
+            coro = func()
+            # only store repr() to avoid keeping the coroutine alive
+            coro_repr = repr(coro)
+            coro = None
             support.gc_collect()
-        self.assertIn("was never awaited", stderr.getvalue())
+
+            self.assertIn("was never awaited", str(cm.unraisable.exc_value))
+            self.assertEqual(repr(cm.unraisable.object), coro_repr)
 
     def test_for_assign_raising_stop_async_iteration(self):
         class BadTarget:
diff --git a/Lib/test/test_cprofile.py b/Lib/test/test_cprofile.py
index efcf6bc..5c70037 100644
--- a/Lib/test/test_cprofile.py
+++ b/Lib/test/test_cprofile.py
@@ -1,13 +1,13 @@
 """Test suite for the cProfile module."""
 
 import sys
-from test.support import run_unittest, TESTFN, unlink
 import unittest
 
 # rip off all interesting stuff from test_profile
 import cProfile
 from test.test_profile import ProfileTest, regenerate_expected_output
 from test.support.script_helper import assert_python_failure, assert_python_ok
+from test import support
 
 
 class CProfileTest(ProfileTest):
@@ -18,24 +18,18 @@
     def get_expected_output(self):
         return _ProfileOutput
 
-    # Issue 3895.
     def test_bad_counter_during_dealloc(self):
+        # bpo-3895
         import _lsprof
-        # Must use a file as StringIO doesn't trigger the bug.
-        orig_stderr = sys.stderr
-        try:
-            with open(TESTFN, 'w') as file:
-                sys.stderr = file
-                try:
-                    obj = _lsprof.Profiler(lambda: int)
-                    obj.enable()
-                    obj = _lsprof.Profiler(1)
-                    obj.disable()
-                    obj.clear()
-                finally:
-                    sys.stderr = orig_stderr
-        finally:
-            unlink(TESTFN)
+
+        with support.catch_unraisable_exception() as cm:
+            obj = _lsprof.Profiler(lambda: int)
+            obj.enable()
+            obj = _lsprof.Profiler(1)
+            obj.disable()
+            obj.clear()
+
+            self.assertEqual(cm.unraisable.exc_type, TypeError)
 
     def test_profile_enable_disable(self):
         prof = self.profilerclass()
@@ -70,12 +64,10 @@
         self.assertGreater(rc, 0)
         self.assertIn(b"option -s: invalid choice: 'demo'", err)
 
-def test_main():
-    run_unittest(CProfileTest, TestCommandLine)
 
 def main():
     if '-r' not in sys.argv:
-        test_main()
+        unittest.main()
     else:
         regenerate_expected_output(__file__, CProfileTest)
 
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index 7f1472f..a34e4ec 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -2051,15 +2051,17 @@
 
 Our ill-behaved code should be invoked during GC:
 
->>> import sys, io
->>> old, sys.stderr = sys.stderr, io.StringIO()
->>> g = f()
->>> next(g)
->>> del g
->>> "RuntimeError: generator ignored GeneratorExit" in sys.stderr.getvalue()
+>>> with support.catch_unraisable_exception() as cm:
+...     g = f()
+...     next(g)
+...     del g
+...
+...     cm.unraisable.exc_type == RuntimeError
+...     "generator ignored GeneratorExit" in str(cm.unraisable.exc_value)
+...     cm.unraisable.exc_traceback is not None
 True
->>> sys.stderr = old
-
+True
+True
 
 And errors thrown during closing should propagate:
 
diff --git a/Lib/test/test_raise.py b/Lib/test/test_raise.py
index c1ef154..57da0e1 100644
--- a/Lib/test/test_raise.py
+++ b/Lib/test/test_raise.py
@@ -459,9 +459,12 @@
                 self.assertNotEqual(e.__context__, None)
                 self.assertIsInstance(e.__context__, AttributeError)
 
-        with support.captured_output("stderr"):
+        with support.catch_unraisable_exception() as cm:
             f()
 
+            self.assertEqual(ZeroDivisionError, cm.unraisable.exc_type)
+
+
 class TestRemovedFunctionality(unittest.TestCase):
     def test_tuples(self):
         try:
diff --git a/Lib/test/test_ssl.py b/Lib/test/test_ssl.py
index f368906..a72d791 100644
--- a/Lib/test/test_ssl.py
+++ b/Lib/test/test_ssl.py
@@ -4051,13 +4051,15 @@
             1/0
         server_context.set_servername_callback(cb_raising)
 
-        with self.assertRaises(ssl.SSLError) as cm, \
-             support.captured_stderr() as stderr:
-            stats = server_params_test(client_context, server_context,
-                                       chatty=False,
-                                       sni_name='supermessage')
-        self.assertEqual(cm.exception.reason, 'SSLV3_ALERT_HANDSHAKE_FAILURE')
-        self.assertIn("ZeroDivisionError", stderr.getvalue())
+        with support.catch_unraisable_exception() as catch:
+            with self.assertRaises(ssl.SSLError) as cm:
+                stats = server_params_test(client_context, server_context,
+                                           chatty=False,
+                                           sni_name='supermessage')
+
+            self.assertEqual(cm.exception.reason,
+                             'SSLV3_ALERT_HANDSHAKE_FAILURE')
+            self.assertEqual(catch.unraisable.exc_type, ZeroDivisionError)
 
     @needs_sni
     def test_sni_callback_wrong_return_type(self):
@@ -4069,13 +4071,15 @@
             return "foo"
         server_context.set_servername_callback(cb_wrong_return_type)
 
-        with self.assertRaises(ssl.SSLError) as cm, \
-             support.captured_stderr() as stderr:
-            stats = server_params_test(client_context, server_context,
-                                       chatty=False,
-                                       sni_name='supermessage')
-        self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
-        self.assertIn("TypeError", stderr.getvalue())
+        with support.catch_unraisable_exception() as catch:
+            with self.assertRaises(ssl.SSLError) as cm:
+                stats = server_params_test(client_context, server_context,
+                                           chatty=False,
+                                           sni_name='supermessage')
+
+
+            self.assertEqual(cm.exception.reason, 'TLSV1_ALERT_INTERNAL_ERROR')
+            self.assertEqual(catch.unraisable.exc_type, TypeError)
 
     def test_shared_ciphers(self):
         client_context, server_context, hostname = testing_context()
diff --git a/Lib/test/test_thread.py b/Lib/test/test_thread.py
index f946f7b..9f4801f 100644
--- a/Lib/test/test_thread.py
+++ b/Lib/test/test_thread.py
@@ -133,27 +133,6 @@
                 time.sleep(POLL_SLEEP)
             self.assertEqual(thread._count(), orig)
 
-    def test_save_exception_state_on_error(self):
-        # See issue #14474
-        def task():
-            started.release()
-            raise SyntaxError
-        def mywrite(self, *args):
-            try:
-                raise ValueError
-            except ValueError:
-                pass
-            real_write(self, *args)
-        started = thread.allocate_lock()
-        with support.captured_output("stderr") as stderr:
-            real_write = stderr.write
-            stderr.write = mywrite
-            started.acquire()
-            with support.wait_threads_exit():
-                thread.start_new_thread(task, ())
-                started.acquire()
-        self.assertIn("Traceback", stderr.getvalue())
-
     def test_unraisable_exception(self):
         def task():
             started.release()
diff --git a/Lib/test/test_yield_from.py b/Lib/test/test_yield_from.py
index ce21c3d..4735ef4 100644
--- a/Lib/test/test_yield_from.py
+++ b/Lib/test/test_yield_from.py
@@ -11,6 +11,7 @@
 import inspect
 
 from test.support import captured_stderr, disable_gc, gc_collect
+from test import support
 
 class TestPEP380Operation(unittest.TestCase):
     """
@@ -562,11 +563,12 @@
             self.assertEqual(next(gi), 1)
             gi.throw(AttributeError)
 
-        with captured_stderr() as output:
+        with support.catch_unraisable_exception() as cm:
             gi = g()
             self.assertEqual(next(gi), 1)
             gi.close()
-        self.assertIn('ZeroDivisionError', output.getvalue())
+
+            self.assertEqual(ZeroDivisionError, cm.unraisable.exc_type)
 
     def test_exception_in_initial_next_call(self):
         """