codekingpro/portable-devtools
114k
1import sys
2
3import greenlet
4from . import _test_extension
5from . import TestCase
6from .leakcheck import ignores_leakcheck
7
8# pylint:disable=c-extension-no-member
9
10class CAPITests(TestCase):
11 def test_switch(self):
12 self.assertEqual(
13 50, _test_extension.test_switch(greenlet.greenlet(lambda: 50)))
14
15 def test_switch_kwargs(self):
16 def adder(x, y):
17 return x * y
18 g = greenlet.greenlet(adder)
19 self.assertEqual(6, _test_extension.test_switch_kwargs(g, x=3, y=2))
20
21 with self.assertRaisesRegex(TypeError, "argument 1 must be greenlet"):
22 _test_extension.test_switch_kwargs("not a greenlet")
23
24 def test_setparent(self):
25 # pylint:disable=disallowed-name
26 def foo():
27 def bar():
28 greenlet.getcurrent().parent.switch()
29
30 # This final switch should go back to the main greenlet, since
31 # the test_setparent() function in the C extension should have
32 # reparented this greenlet.
33 greenlet.getcurrent().parent.switch()
34 raise AssertionError("Should never have reached this code")
35 child = greenlet.greenlet(bar)
36 child.switch()
37 greenlet.getcurrent().parent.switch(child)
38 greenlet.getcurrent().parent.throw(
39 AssertionError("Should never reach this code"))
40 foo_child = greenlet.greenlet(foo).switch()
41 self.assertEqual(None, _test_extension.test_setparent(foo_child))
42
43 def test_getcurrent(self):
44 _test_extension.test_getcurrent()
45
46 def test_new_greenlet(self):
47 self.assertEqual(-15, _test_extension.test_new_greenlet(lambda: -15))
48
49 def test_raise_greenlet_dead(self):
50 self.assertRaises(
51 greenlet.GreenletExit, _test_extension.test_raise_dead_greenlet)
52
53 def test_raise_greenlet_error(self):
54 self.assertRaises(
55 greenlet.error, _test_extension.test_raise_greenlet_error)
56
57 def test_throw(self):
58 seen = []
59
60 def foo(): # pylint:disable=disallowed-name
61 try:
62 greenlet.getcurrent().parent.switch()
63 except ValueError:
64 seen.append(sys.exc_info()[1])
65 except greenlet.GreenletExit:
66 raise AssertionError
67 g = greenlet.greenlet(foo)
68 g.switch()
69 _test_extension.test_throw(g)
70 self.assertEqual(len(seen), 1)
71 self.assertTrue(
72 isinstance(seen[0], ValueError),
73 "ValueError was not raised in foo()")
74 self.assertEqual(
75 str(seen[0]),
76 'take that sucka!',
77 "message doesn't match")
78
79 def test_non_traceback_param(self):
80 with self.assertRaises(TypeError) as exc:
81 _test_extension.test_throw_exact(
82 greenlet.getcurrent(),
83 Exception,
84 Exception(),
85 self
86 )
87 self.assertEqual(str(exc.exception),
88 "throw() third argument must be a traceback object")
89
90 def test_instance_of_wrong_type(self):
91 with self.assertRaises(TypeError) as exc:
92 _test_extension.test_throw_exact(
93 greenlet.getcurrent(),
94 Exception(),
95 BaseException(),
96 None,
97 )
98
99 self.assertEqual(str(exc.exception),
100 "instance exception may not have a separate value")
101
102 def test_not_throwable(self):
103 with self.assertRaises(TypeError) as exc:
104 _test_extension.test_throw_exact(
105 greenlet.getcurrent(),
106 "abc",
107 None,
108 None,
109 )
110 self.assertEqual(str(exc.exception),
111 "exceptions must be classes, or instances, not str")
112
113 @ignores_leakcheck
114 def test_leaks(self):
115 from . import PY314
116 iters = 100
117 if PY314:
118 expected_refs = [1] * iters
119 else:
120 expected_refs = [2] * iters
121 for name, caller in (
122 ("test_switch",
123 lambda: _test_extension.test_switch(greenlet.greenlet(object))),
124 ("test_switch_kwargs",
125 lambda: _test_extension.test_switch_kwargs(greenlet.greenlet(object))),
126 ("test_new_greenlet",
127 lambda: _test_extension.test_new_greenlet(object)),
128 ):
129 with self.subTest(name):
130 results = [caller() for _ in range(iters)]
131 refs = [
132 sys.getrefcount(i) - 1 # ignore ref in ``i``
133 for i
134 in results
135 ]
136 self.assertEqual(refs, expected_refs)
137
138
139if __name__ == '__main__':
140 import unittest
141 unittest.main()
142 