blob: 3105f6c378193ef3c0f0f6add296d87f700b4499 [file] [log] [blame]
Tim Petersc7b6bed2002-07-17 00:34:26 +00001import sys
Skip Montanaro599bd5e2004-11-04 04:31:30 +00002import unittest
Guido van Rossum34d19282007-08-09 01:03:29 +00003import io
Fred Drakec19425d2000-06-28 15:07:31 +00004import atexit
Marcel Plch776407f2017-12-20 11:17:58 +01005import os
Benjamin Petersonee8712c2008-05-20 21:35:26 +00006from test import support
Antoine Pitroufc5db952017-12-13 02:29:07 +01007from test.support import script_helper
Fred Drakec19425d2000-06-28 15:07:31 +00008
Collin Winter670e6922007-03-21 02:57:17 +00009### helpers
10def h1():
11 print("h1")
12
13def h2():
14 print("h2")
15
16def h3():
17 print("h3")
18
19def h4(*args, **kwargs):
20 print("h4", args, kwargs)
21
22def raise1():
23 raise TypeError
24
25def raise2():
26 raise SystemError
27
Serhiy Storchaka3fd54d42017-06-12 08:25:04 +030028def exit():
29 raise SystemExit
30
Antoine Pitrou2d350fd2013-08-01 20:56:12 +020031
32class GeneralTest(unittest.TestCase):
33
Collin Winter670e6922007-03-21 02:57:17 +000034 def setUp(self):
Victor Stinner457ab062011-01-05 23:47:00 +000035 self.save_stdout = sys.stdout
36 self.save_stderr = sys.stderr
Guido van Rossum34d19282007-08-09 01:03:29 +000037 self.stream = io.StringIO()
Collin Winter670e6922007-03-21 02:57:17 +000038 sys.stdout = sys.stderr = self.stream
39 atexit._clear()
Guido van Rossumd8faa362007-04-27 19:54:29 +000040
Collin Winter670e6922007-03-21 02:57:17 +000041 def tearDown(self):
Benjamin Petersonf10a79a2008-10-11 00:49:57 +000042 sys.stdout = self.save_stdout
43 sys.stderr = self.save_stderr
Collin Winter670e6922007-03-21 02:57:17 +000044 atexit._clear()
45
Skip Montanaro599bd5e2004-11-04 04:31:30 +000046 def test_args(self):
47 # be sure args are handled properly
Collin Winter670e6922007-03-21 02:57:17 +000048 atexit.register(h1)
49 atexit.register(h4)
50 atexit.register(h4, 4, kw="abc")
51 atexit._run_exitfuncs()
52
53 self.assertEqual(self.stream.getvalue(),
54 "h4 (4,) {'kw': 'abc'}\nh4 () {}\nh1\n")
Fred Drakec19425d2000-06-28 15:07:31 +000055
Benjamin Petersonb8401c72008-09-23 03:14:49 +000056 def test_badargs(self):
57 atexit.register(lambda: 1, 0, 0, (x for x in (1,2)), 0, 0)
58 self.assertRaises(TypeError, atexit._run_exitfuncs)
59
Skip Montanaro599bd5e2004-11-04 04:31:30 +000060 def test_order(self):
61 # be sure handlers are executed in reverse order
Collin Winter670e6922007-03-21 02:57:17 +000062 atexit.register(h1)
63 atexit.register(h2)
64 atexit.register(h3)
65 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +000066
Collin Winter670e6922007-03-21 02:57:17 +000067 self.assertEqual(self.stream.getvalue(), "h3\nh2\nh1\n")
Fred Drakec19425d2000-06-28 15:07:31 +000068
Skip Montanaro599bd5e2004-11-04 04:31:30 +000069 def test_raise(self):
70 # be sure raises are handled properly
Collin Winter670e6922007-03-21 02:57:17 +000071 atexit.register(raise1)
72 atexit.register(raise2)
Guido van Rossumd8faa362007-04-27 19:54:29 +000073
Collin Winter670e6922007-03-21 02:57:17 +000074 self.assertRaises(TypeError, atexit._run_exitfuncs)
Guido van Rossumd8faa362007-04-27 19:54:29 +000075
Victor Stinner358e11d2011-01-05 03:54:25 +000076 def test_raise_unnormalized(self):
77 # Issue #10756: Make sure that an unnormalized exception is
78 # handled properly
79 atexit.register(lambda: 1 / 0)
80
81 self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
82 self.assertIn("ZeroDivisionError", self.stream.getvalue())
83
Serhiy Storchaka3fd54d42017-06-12 08:25:04 +030084 def test_exit(self):
85 # be sure a SystemExit is handled properly
86 atexit.register(exit)
87
88 self.assertRaises(SystemExit, atexit._run_exitfuncs)
89 self.assertEqual(self.stream.getvalue(), '')
90
Antoine Pitrou24201d42013-10-13 21:53:13 +020091 def test_print_tracebacks(self):
92 # Issue #18776: the tracebacks should be printed when errors occur.
93 def f():
94 1/0 # one
95 def g():
96 1/0 # two
97 def h():
98 1/0 # three
99 atexit.register(f)
100 atexit.register(g)
101 atexit.register(h)
102
103 self.assertRaises(ZeroDivisionError, atexit._run_exitfuncs)
104 stderr = self.stream.getvalue()
105 self.assertEqual(stderr.count("ZeroDivisionError"), 3)
106 self.assertIn("# one", stderr)
107 self.assertIn("# two", stderr)
108 self.assertIn("# three", stderr)
109
Collin Winter670e6922007-03-21 02:57:17 +0000110 def test_stress(self):
111 a = [0]
112 def inc():
113 a[0] += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000114
Collin Winter670e6922007-03-21 02:57:17 +0000115 for i in range(128):
116 atexit.register(inc)
117 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000118
Collin Winter670e6922007-03-21 02:57:17 +0000119 self.assertEqual(a[0], 128)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000120
Collin Winter670e6922007-03-21 02:57:17 +0000121 def test_clear(self):
122 a = [0]
123 def inc():
124 a[0] += 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000125
Collin Winter670e6922007-03-21 02:57:17 +0000126 atexit.register(inc)
127 atexit._clear()
128 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000129
Collin Winter670e6922007-03-21 02:57:17 +0000130 self.assertEqual(a[0], 0)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000131
Collin Winter670e6922007-03-21 02:57:17 +0000132 def test_unregister(self):
133 a = [0]
134 def inc():
135 a[0] += 1
136 def dec():
137 a[0] -= 1
Guido van Rossumd8faa362007-04-27 19:54:29 +0000138
139 for i in range(4):
Collin Winter670e6922007-03-21 02:57:17 +0000140 atexit.register(inc)
141 atexit.register(dec)
142 atexit.unregister(inc)
143 atexit._run_exitfuncs()
Guido van Rossumd8faa362007-04-27 19:54:29 +0000144
Collin Winter670e6922007-03-21 02:57:17 +0000145 self.assertEqual(a[0], -1)
Guido van Rossumd8faa362007-04-27 19:54:29 +0000146
Collin Winter670e6922007-03-21 02:57:17 +0000147 def test_bound_methods(self):
148 l = []
149 atexit.register(l.append, 5)
150 atexit._run_exitfuncs()
151 self.assertEqual(l, [5])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000152
Collin Winter670e6922007-03-21 02:57:17 +0000153 atexit.unregister(l.append)
154 atexit._run_exitfuncs()
155 self.assertEqual(l, [5])
Guido van Rossumd8faa362007-04-27 19:54:29 +0000156
Antoine Pitroufc5db952017-12-13 02:29:07 +0100157 def test_shutdown(self):
158 # Actually test the shutdown mechanism in a subprocess
159 code = """if 1:
160 import atexit
161
162 def f(msg):
163 print(msg)
164
165 atexit.register(f, "one")
166 atexit.register(f, "two")
167 """
168 res = script_helper.assert_python_ok("-c", code)
169 self.assertEqual(res.out.decode().splitlines(), ["two", "one"])
170 self.assertFalse(res.err)
171
Tim Peters012b69c2002-07-16 19:30:59 +0000172
Serhiy Storchaka24c738a2017-03-19 20:20:10 +0200173@support.cpython_only
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200174class SubinterpreterTest(unittest.TestCase):
175
176 def test_callbacks_leak(self):
177 # This test shows a leak in refleak mode if atexit doesn't
178 # take care to free callbacks in its per-subinterpreter module
179 # state.
180 n = atexit._ncallbacks()
181 code = r"""if 1:
182 import atexit
183 def f():
184 pass
185 atexit.register(f)
186 del atexit
187 """
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100188 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200189 self.assertEqual(ret, 0)
190 self.assertEqual(atexit._ncallbacks(), n)
191
192 def test_callbacks_leak_refcycle(self):
193 # Similar to the above, but with a refcycle through the atexit
194 # module.
195 n = atexit._ncallbacks()
196 code = r"""if 1:
197 import atexit
198 def f():
199 pass
200 atexit.register(f)
201 atexit.__atexit = atexit
202 """
Victor Stinnered3b0bc2013-11-23 12:27:24 +0100203 ret = support.run_in_subinterp(code)
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200204 self.assertEqual(ret, 0)
205 self.assertEqual(atexit._ncallbacks(), n)
206
Marcel Plch776407f2017-12-20 11:17:58 +0100207 def test_callback_on_subinterpreter_teardown(self):
208 # This tests if a callback is called on
209 # subinterpreter teardown.
210 expected = b"The test has passed!"
211 r, w = os.pipe()
212
213 code = r"""if 1:
214 import os
215 import atexit
216 def callback():
217 os.write({:d}, b"The test has passed!")
218 atexit.register(callback)
219 """.format(w)
220 ret = support.run_in_subinterp(code)
221 os.close(w)
222 self.assertEqual(os.read(r, len(expected)), expected)
223 os.close(r)
224
Antoine Pitrou2d350fd2013-08-01 20:56:12 +0200225
Skip Montanaro599bd5e2004-11-04 04:31:30 +0000226if __name__ == "__main__":
Zachary Ware38c707e2015-04-13 15:00:43 -0500227 unittest.main()