Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes14kdownloads
util_test.py374 linesDownload Raw Back to test
1import re
2import sys
3import datetime
4import textwrap
5import unittest
6
7import tornado
8from tornado.escape import utf8
9from tornado.util import (
10    raise_exc_info,
11    Configurable,
12    exec_in,
13    ArgReplacer,
14    timedelta_to_seconds,
15    import_object,
16    re_unescape,
17)
18
19from typing import cast, Dict, Any
20
21
22class RaiseExcInfoTest(unittest.TestCase):
23    def test_two_arg_exception(self):
24        # This test would fail on python 3 if raise_exc_info were simply
25        # a three-argument raise statement, because TwoArgException
26        # doesn't have a "copy constructor"
27        class TwoArgException(Exception):
28            def __init__(self, a, b):
29                super().__init__()
30                self.a, self.b = a, b
31
32        try:
33            raise TwoArgException(1, 2)
34        except TwoArgException:
35            exc_info = sys.exc_info()
36        try:
37            raise_exc_info(exc_info)
38            self.fail("didn't get expected exception")
39        except TwoArgException as e:
40            self.assertIs(e, exc_info[1])
41
42
43class TestConfigurable(Configurable):
44    @classmethod
45    def configurable_base(cls):
46        return TestConfigurable
47
48    @classmethod
49    def configurable_default(cls):
50        return TestConfig1
51
52
53class TestConfig1(TestConfigurable):
54    def initialize(self, pos_arg=None, a=None):
55        self.a = a
56        self.pos_arg = pos_arg
57
58
59class TestConfig2(TestConfigurable):
60    def initialize(self, pos_arg=None, b=None):
61        self.b = b
62        self.pos_arg = pos_arg
63
64
65class TestConfig3(TestConfigurable):
66    # TestConfig3 is a configuration option that is itself configurable.
67    @classmethod
68    def configurable_base(cls):
69        return TestConfig3
70
71    @classmethod
72    def configurable_default(cls):
73        return TestConfig3A
74
75
76class TestConfig3A(TestConfig3):
77    def initialize(self, a=None):
78        self.a = a
79
80
81class TestConfig3B(TestConfig3):
82    def initialize(self, b=None):
83        self.b = b
84
85
86class ConfigurableTest(unittest.TestCase):
87    def setUp(self):
88        self.saved = TestConfigurable._save_configuration()
89        self.saved3 = TestConfig3._save_configuration()
90
91    def tearDown(self):
92        TestConfigurable._restore_configuration(self.saved)
93        TestConfig3._restore_configuration(self.saved3)
94
95    def checkSubclasses(self):
96        # no matter how the class is configured, it should always be
97        # possible to instantiate the subclasses directly
98        self.assertIsInstance(TestConfig1(), TestConfig1)
99        self.assertIsInstance(TestConfig2(), TestConfig2)
100
101        obj = TestConfig1(a=1)
102        self.assertEqual(obj.a, 1)
103        obj2 = TestConfig2(b=2)
104        self.assertEqual(obj2.b, 2)
105
106    def test_default(self):
107        # In these tests we combine a typing.cast to satisfy mypy with
108        # a runtime type-assertion. Without the cast, mypy would only
109        # let us access attributes of the base class.
110        obj = cast(TestConfig1, TestConfigurable())
111        self.assertIsInstance(obj, TestConfig1)
112        self.assertIsNone(obj.a)
113
114        obj = cast(TestConfig1, TestConfigurable(a=1))
115        self.assertIsInstance(obj, TestConfig1)
116        self.assertEqual(obj.a, 1)
117
118        self.checkSubclasses()
119
120    def test_config_class(self):
121        TestConfigurable.configure(TestConfig2)
122        obj = cast(TestConfig2, TestConfigurable())
123        self.assertIsInstance(obj, TestConfig2)
124        self.assertIsNone(obj.b)
125
126        obj = cast(TestConfig2, TestConfigurable(b=2))
127        self.assertIsInstance(obj, TestConfig2)
128        self.assertEqual(obj.b, 2)
129
130        self.checkSubclasses()
131
132    def test_config_str(self):
133        TestConfigurable.configure("tornado.test.util_test.TestConfig2")
134        obj = cast(TestConfig2, TestConfigurable())
135        self.assertIsInstance(obj, TestConfig2)
136        self.assertIsNone(obj.b)
137
138        obj = cast(TestConfig2, TestConfigurable(b=2))
139        self.assertIsInstance(obj, TestConfig2)
140        self.assertEqual(obj.b, 2)
141
142        self.checkSubclasses()
143
144    def test_config_args(self):
145        TestConfigurable.configure(None, a=3)
146        obj = cast(TestConfig1, TestConfigurable())
147        self.assertIsInstance(obj, TestConfig1)
148        self.assertEqual(obj.a, 3)
149
150        obj = cast(TestConfig1, TestConfigurable(42, a=4))
151        self.assertIsInstance(obj, TestConfig1)
152        self.assertEqual(obj.a, 4)
153        self.assertEqual(obj.pos_arg, 42)
154
155        self.checkSubclasses()
156        # args bound in configure don't apply when using the subclass directly
157        obj = TestConfig1()
158        self.assertIsNone(obj.a)
159
160    def test_config_class_args(self):
161        TestConfigurable.configure(TestConfig2, b=5)
162        obj = cast(TestConfig2, TestConfigurable())
163        self.assertIsInstance(obj, TestConfig2)
164        self.assertEqual(obj.b, 5)
165
166        obj = cast(TestConfig2, TestConfigurable(42, b=6))
167        self.assertIsInstance(obj, TestConfig2)
168        self.assertEqual(obj.b, 6)
169        self.assertEqual(obj.pos_arg, 42)
170
171        self.checkSubclasses()
172        # args bound in configure don't apply when using the subclass directly
173        obj = TestConfig2()
174        self.assertIsNone(obj.b)
175
176    def test_config_multi_level(self):
177        TestConfigurable.configure(TestConfig3, a=1)
178        obj = cast(TestConfig3A, TestConfigurable())
179        self.assertIsInstance(obj, TestConfig3A)
180        self.assertEqual(obj.a, 1)
181
182        TestConfigurable.configure(TestConfig3)
183        TestConfig3.configure(TestConfig3B, b=2)
184        obj2 = cast(TestConfig3B, TestConfigurable())
185        self.assertIsInstance(obj2, TestConfig3B)
186        self.assertEqual(obj2.b, 2)
187
188    def test_config_inner_level(self):
189        # The inner level can be used even when the outer level
190        # doesn't point to it.
191        obj = TestConfig3()
192        self.assertIsInstance(obj, TestConfig3A)
193
194        TestConfig3.configure(TestConfig3B)
195        obj = TestConfig3()
196        self.assertIsInstance(obj, TestConfig3B)
197
198        # Configuring the base doesn't configure the inner.
199        obj2 = TestConfigurable()
200        self.assertIsInstance(obj2, TestConfig1)
201        TestConfigurable.configure(TestConfig2)
202
203        obj3 = TestConfigurable()
204        self.assertIsInstance(obj3, TestConfig2)
205
206        obj = TestConfig3()
207        self.assertIsInstance(obj, TestConfig3B)
208
209
210class UnicodeLiteralTest(unittest.TestCase):
211    def test_unicode_escapes(self):
212        self.assertEqual(utf8("\u00e9"), b"\xc3\xa9")
213
214
215class ExecInTest(unittest.TestCase):
216    def test_no_inherit_future(self):
217        # Two files: the first has "from __future__ import annotations", and it executes the second
218        # which doesn't. The second file should not be affected by the first's __future__ imports.
219        #
220        # The annotations future became available in python 3.7 but has been replaced by PEP 649, so
221        # it should remain supported but off-by-default for the foreseeable future.
222        code1 = textwrap.dedent(
223            """
224            from __future__ import annotations
225            from tornado.util import exec_in
226
227            exec_in(code2, globals())
228            """
229        )
230
231        code2 = textwrap.dedent(
232            """
233            def f(x: int) -> int:
234                return x + 1
235            output[0] = f.__annotations__
236            """
237        )
238
239        # Make a mutable container to pass the result back to the caller
240        output = [None]
241        exec_in(code1, dict(code2=code2, output=output))
242        # If the annotations future were in effect, these would be strings instead of the int type
243        # object.
244        self.assertEqual(output[0], {"x": int, "return": int})
245
246
247class ArgReplacerTest(unittest.TestCase):
248    def setUp(self):
249        def function(x, y, callback=None, z=None):
250            pass
251
252        self.replacer = ArgReplacer(function, "callback")
253
254    def test_omitted(self):
255        args = (1, 2)
256        kwargs: Dict[str, Any] = dict()
257        self.assertIsNone(self.replacer.get_old_value(args, kwargs))
258        self.assertEqual(
259            self.replacer.replace("new", args, kwargs),
260            (None, (1, 2), dict(callback="new")),
261        )
262
263    def test_position(self):
264        args = (1, 2, "old", 3)
265        kwargs: Dict[str, Any] = dict()
266        self.assertEqual(self.replacer.get_old_value(args, kwargs), "old")
267        self.assertEqual(
268            self.replacer.replace("new", args, kwargs),
269            ("old", [1, 2, "new", 3], dict()),
270        )
271
272    def test_keyword(self):
273        args = (1,)
274        kwargs = dict(y=2, callback="old", z=3)
275        self.assertEqual(self.replacer.get_old_value(args, kwargs), "old")
276        self.assertEqual(
277            self.replacer.replace("new", args, kwargs),
278            ("old", (1,), dict(y=2, callback="new", z=3)),
279        )
280
281
282class TimedeltaToSecondsTest(unittest.TestCase):
283    def test_timedelta_to_seconds(self):
284        time_delta = datetime.timedelta(hours=1)
285        self.assertEqual(timedelta_to_seconds(time_delta), 3600.0)
286
287
288class ImportObjectTest(unittest.TestCase):
289    def test_import_member(self):
290        self.assertIs(import_object("tornado.escape.utf8"), utf8)
291
292    def test_import_member_unicode(self):
293        self.assertIs(import_object("tornado.escape.utf8"), utf8)
294
295    def test_import_module(self):
296        self.assertIs(import_object("tornado.escape"), tornado.escape)
297
298    def test_import_module_unicode(self):
299        # The internal implementation of __import__ differs depending on
300        # whether the thing being imported is a module or not.
301        # This variant requires a byte string in python 2.
302        self.assertIs(import_object("tornado.escape"), tornado.escape)
303
304
305class ReUnescapeTest(unittest.TestCase):
306    def test_re_unescape(self):
307        test_strings = ("/favicon.ico", "index.html", "Hello, World!", "!$@#%;")
308        for string in test_strings:
309            self.assertEqual(string, re_unescape(re.escape(string)))
310
311    def test_re_unescape_raises_error_on_invalid_input(self):
312        with self.assertRaises(ValueError):
313            re_unescape("\\d")
314        with self.assertRaises(ValueError):
315            re_unescape("\\b")
316        with self.assertRaises(ValueError):
317            re_unescape("\\Z")
318
319
320class VersionInfoTest(unittest.TestCase):
321    def assert_version_info_compatible(self, version, version_info):
322        # We map our version identifier string (a subset of
323        # https://packaging.python.org/en/latest/specifications/version-specifiers/#public-version-identifiers)
324        # to a 4-tuple of integers for easy comparisons. The last component is
325        # 0 for a final release, negative for a pre-release, and would be positive for a
326        # post-release if we did any of those. This test is not a promise that these are the
327        # only formats we will ever use, but it does catch accidents like
328        # https://github.com/tornadoweb/tornado/issues/3406.
329        major = minor = patch = "0"
330        is_pre = False
331        if m := re.fullmatch(r"(\d+)\.(\d+)\.(\d+)", version):
332            # Regular 3-component version number
333            major, minor, patch = m.groups()
334        elif m := re.fullmatch(r"(\d+)\.(\d+)", version):
335            # Two-component version number, equivalent to major.minor.0
336            major, minor = m.groups()
337        elif m := re.fullmatch(r"(\d+)\.(\d+)\.(\d+)(?:\.dev|a|b|rc)\d+", version):
338            # Pre-release 3-component version number.
339            major, minor, patch = m.groups()
340            is_pre = True
341        elif m := re.fullmatch(r"(\d+)\.(\d+)(?:\.dev|a|b|rc)\d+", version):
342            # Pre-release 2-component version number.
343            major, minor = m.groups()
344            is_pre = True
345        else:
346            self.fail(f"Unrecognized version format: {version}")
347
348        self.assertEqual(version_info[:3], (int(major), int(minor), int(patch)))
349        if is_pre:
350            self.assertLess(int(version_info[3]), 0)
351        else:
352            self.assertEqual(int(version_info[3]), 0)
353
354    def test_version_info_compatible(self):
355        self.assert_version_info_compatible("6.5.0", (6, 5, 0, 0))
356        self.assert_version_info_compatible("6.5", (6, 5, 0, 0))
357        self.assert_version_info_compatible("6.5.1", (6, 5, 1, 0))
358        self.assert_version_info_compatible("6.6.dev1", (6, 6, 0, -100))
359        self.assert_version_info_compatible("6.6a1", (6, 6, 0, -100))
360        self.assert_version_info_compatible("6.6b1", (6, 6, 0, -100))
361        self.assert_version_info_compatible("6.6rc1", (6, 6, 0, -100))
362        self.assertRaises(
363            AssertionError, self.assert_version_info_compatible, "6.5.0", (6, 5, 0, 1)
364        )
365        self.assertRaises(
366            AssertionError, self.assert_version_info_compatible, "6.5.0", (6, 4, 0, 0)
367        )
368        self.assertRaises(
369            AssertionError, self.assert_version_info_compatible, "6.5.1", (6, 5, 0, 1)
370        )
371
372    def test_current_version(self):
373        self.assert_version_info_compatible(tornado.version, tornado.version_info)
374 
codekingpro/portable-devtools · Team Ai