werkzeug

Форк
0
/
test_debug.py 
294 строки · 10.7 Кб
1
import re
2
import sys
3

4
import pytest
5

6
from werkzeug.debug import console
7
from werkzeug.debug import DebuggedApplication
8
from werkzeug.debug import DebugTraceback
9
from werkzeug.debug import get_machine_id
10
from werkzeug.debug.console import HTMLStringO
11
from werkzeug.debug.repr import debug_repr
12
from werkzeug.debug.repr import DebugReprGenerator
13
from werkzeug.debug.repr import dump
14
from werkzeug.debug.repr import helper
15
from werkzeug.test import Client
16
from werkzeug.wrappers import Request
17

18

19
class TestDebugRepr:
20
    def test_basic_repr(self):
21
        assert debug_repr([]) == "[]"
22
        assert debug_repr([1, 2]) == (
23
            '[<span class="number">1</span>, <span class="number">2</span>]'
24
        )
25
        assert debug_repr([1, "test"]) == (
26
            '[<span class="number">1</span>,'
27
            ' <span class="string">&#39;test&#39;</span>]'
28
        )
29
        assert debug_repr([None]) == '[<span class="object">None</span>]'
30

31
    def test_string_repr(self):
32
        assert debug_repr("") == '<span class="string">&#39;&#39;</span>'
33
        assert debug_repr("foo") == '<span class="string">&#39;foo&#39;</span>'
34
        assert debug_repr("s" * 80) == (
35
            f'<span class="string">&#39;{"s" * 69}'
36
            f'<span class="extended">{"s" * 11}&#39;</span></span>'
37
        )
38
        assert debug_repr("<" * 80) == (
39
            f'<span class="string">&#39;{"&lt;" * 69}'
40
            f'<span class="extended">{"&lt;" * 11}&#39;</span></span>'
41
        )
42

43
    def test_string_subclass_repr(self):
44
        class Test(str):
45
            pass
46

47
        assert debug_repr(Test("foo")) == (
48
            '<span class="module">test_debug.</span>'
49
            'Test(<span class="string">&#39;foo&#39;</span>)'
50
        )
51

52
    def test_sequence_repr(self):
53
        assert debug_repr(list(range(20))) == (
54
            '[<span class="number">0</span>, <span class="number">1</span>, '
55
            '<span class="number">2</span>, <span class="number">3</span>, '
56
            '<span class="number">4</span>, <span class="number">5</span>, '
57
            '<span class="number">6</span>, <span class="number">7</span>, '
58
            '<span class="extended"><span class="number">8</span>, '
59
            '<span class="number">9</span>, <span class="number">10</span>, '
60
            '<span class="number">11</span>, <span class="number">12</span>, '
61
            '<span class="number">13</span>, <span class="number">14</span>, '
62
            '<span class="number">15</span>, <span class="number">16</span>, '
63
            '<span class="number">17</span>, <span class="number">18</span>, '
64
            '<span class="number">19</span></span>]'
65
        )
66

67
    def test_mapping_repr(self):
68
        assert debug_repr({}) == "{}"
69
        assert debug_repr({"foo": 42}) == (
70
            '{<span class="pair"><span class="key"><span class="string">&#39;foo&#39;'
71
            '</span></span>: <span class="value"><span class="number">42'
72
            "</span></span></span>}"
73
        )
74
        assert debug_repr(dict(zip(range(10), [None] * 10))) == (
75
            '{<span class="pair"><span class="key"><span class="number">0'
76
            '</span></span>: <span class="value"><span class="object">None'
77
            "</span></span></span>, "
78
            '<span class="pair"><span class="key"><span class="number">1'
79
            '</span></span>: <span class="value"><span class="object">None'
80
            "</span></span></span>, "
81
            '<span class="pair"><span class="key"><span class="number">2'
82
            '</span></span>: <span class="value"><span class="object">None'
83
            "</span></span></span>, "
84
            '<span class="pair"><span class="key"><span class="number">3'
85
            '</span></span>: <span class="value"><span class="object">None'
86
            "</span></span></span>, "
87
            '<span class="extended">'
88
            '<span class="pair"><span class="key"><span class="number">4'
89
            '</span></span>: <span class="value"><span class="object">None'
90
            "</span></span></span>, "
91
            '<span class="pair"><span class="key"><span class="number">5'
92
            '</span></span>: <span class="value"><span class="object">None'
93
            "</span></span></span>, "
94
            '<span class="pair"><span class="key"><span class="number">6'
95
            '</span></span>: <span class="value"><span class="object">None'
96
            "</span></span></span>, "
97
            '<span class="pair"><span class="key"><span class="number">7'
98
            '</span></span>: <span class="value"><span class="object">None'
99
            "</span></span></span>, "
100
            '<span class="pair"><span class="key"><span class="number">8'
101
            '</span></span>: <span class="value"><span class="object">None'
102
            "</span></span></span>, "
103
            '<span class="pair"><span class="key"><span class="number">9'
104
            '</span></span>: <span class="value"><span class="object">None'
105
            "</span></span></span></span>}"
106
        )
107
        assert debug_repr((1, "zwei", "drei")) == (
108
            '(<span class="number">1</span>, <span class="string">&#39;'
109
            'zwei&#39;</span>, <span class="string">&#39;drei&#39;</span>)'
110
        )
111

112
    def test_custom_repr(self):
113
        class Foo:
114
            def __repr__(self):
115
                return "<Foo 42>"
116

117
        assert debug_repr(Foo()) == '<span class="object">&lt;Foo 42&gt;</span>'
118

119
    def test_list_subclass_repr(self):
120
        class MyList(list):
121
            pass
122

123
        assert debug_repr(MyList([1, 2])) == (
124
            '<span class="module">test_debug.</span>MyList(['
125
            '<span class="number">1</span>, <span class="number">2</span>])'
126
        )
127

128
    def test_regex_repr(self):
129
        assert (
130
            debug_repr(re.compile(r"foo\d"))
131
            == "re.compile(<span class=\"string regex\">r'foo\\d'</span>)"
132
        )
133
        # No ur'' in Py3
134
        # https://bugs.python.org/issue15096
135
        assert debug_repr(re.compile("foo\\d")) == (
136
            "re.compile(<span class=\"string regex\">r'foo\\d'</span>)"
137
        )
138

139
    def test_set_repr(self):
140
        assert (
141
            debug_repr(frozenset("x"))
142
            == 'frozenset([<span class="string">&#39;x&#39;</span>])'
143
        )
144
        assert debug_repr(set("x")) == (
145
            'set([<span class="string">&#39;x&#39;</span>])'
146
        )
147

148
    def test_recursive_repr(self):
149
        a = [1]
150
        a.append(a)
151
        assert debug_repr(a) == '[<span class="number">1</span>, [...]]'
152

153
    def test_broken_repr(self):
154
        class Foo:
155
            def __repr__(self):
156
                raise Exception("broken!")
157

158
        assert debug_repr(Foo()) == (
159
            '<span class="brokenrepr">&lt;broken repr (Exception: '
160
            "broken!)&gt;</span>"
161
        )
162

163

164
class Foo:
165
    x = 42
166
    y = 23
167

168
    def __init__(self):
169
        self.z = 15
170

171

172
class TestDebugHelpers:
173
    def test_object_dumping(self):
174
        drg = DebugReprGenerator()
175
        out = drg.dump_object(Foo())
176
        assert re.search("Details for test_debug.Foo object at", out)
177
        assert re.search('<th>x.*<span class="number">42</span>', out, flags=re.DOTALL)
178
        assert re.search('<th>y.*<span class="number">23</span>', out, flags=re.DOTALL)
179
        assert re.search('<th>z.*<span class="number">15</span>', out, flags=re.DOTALL)
180

181
        out = drg.dump_object({"x": 42, "y": 23})
182
        assert re.search("Contents of", out)
183
        assert re.search('<th>x.*<span class="number">42</span>', out, flags=re.DOTALL)
184
        assert re.search('<th>y.*<span class="number">23</span>', out, flags=re.DOTALL)
185

186
        out = drg.dump_object({"x": 42, "y": 23, 23: 11})
187
        assert not re.search("Contents of", out)
188

189
        out = drg.dump_locals({"x": 42, "y": 23})
190
        assert re.search("Local variables in frame", out)
191
        assert re.search('<th>x.*<span class="number">42</span>', out, flags=re.DOTALL)
192
        assert re.search('<th>y.*<span class="number">23</span>', out, flags=re.DOTALL)
193

194
    def test_debug_dump(self):
195
        old = sys.stdout
196
        sys.stdout = HTMLStringO()
197
        try:
198
            dump([1, 2, 3])
199
            x = sys.stdout.reset()
200
            dump()
201
            y = sys.stdout.reset()
202
        finally:
203
            sys.stdout = old
204

205
        assert "Details for list object at" in x
206
        assert '<span class="number">1</span>' in x
207
        assert "Local variables in frame" in y
208
        assert "<th>x" in y
209
        assert "<th>old" in y
210

211
    def test_debug_help(self):
212
        old = sys.stdout
213
        sys.stdout = HTMLStringO()
214
        try:
215
            helper([1, 2, 3])
216
            x = sys.stdout.reset()
217
        finally:
218
            sys.stdout = old
219

220
        assert "Help on list object" in x
221
        assert "__delitem__" in x
222

223
    def test_exc_divider_found_on_chained_exception(self):
224
        @Request.application
225
        def app(request):
226
            def do_something():
227
                raise ValueError("inner")
228

229
            try:
230
                do_something()
231
            except ValueError:
232
                raise KeyError("outer")  # noqa: B904
233

234
        debugged = DebuggedApplication(app)
235
        client = Client(debugged)
236
        response = client.get("/")
237
        data = response.get_data(as_text=True)
238
        assert 'raise ValueError("inner")' in data
239
        assert '<div class="exc-divider">' in data
240
        assert 'raise KeyError("outer")' in data
241

242

243
def test_get_machine_id():
244
    rv = get_machine_id()
245
    assert isinstance(rv, bytes)
246

247

248
@pytest.mark.filterwarnings("ignore::pytest.PytestUnraisableExceptionWarning")
249
@pytest.mark.parametrize("crash", (True, False))
250
@pytest.mark.dev_server
251
def test_basic(dev_server, crash):
252
    c = dev_server(use_debugger=True)
253
    r = c.request("/crash" if crash else "")
254
    assert r.status == (500 if crash else 200)
255

256
    if crash:
257
        assert b"The debugger caught an exception in your WSGI application" in r.data
258
    else:
259
        assert r.json["PATH_INFO"] == "/"
260

261

262
def test_console_closure_variables(monkeypatch):
263
    # restore the original display hook
264
    monkeypatch.setattr(sys, "displayhook", console._displayhook)
265
    c = console.Console()
266
    c.eval("y = 5")
267
    c.eval("x = lambda: y")
268
    ret = c.eval("x()")
269
    assert ret == ">>> x()\n5\n"
270

271

272
@pytest.mark.timeout(2)
273
def test_chained_exception_cycle():
274
    try:
275
        try:
276
            raise ValueError()
277
        except ValueError:
278
            raise TypeError()  # noqa: B904
279
    except TypeError as e:
280
        # create a cycle and make it available outside the except block
281
        e.__context__.__context__ = error = e
282

283
    # if cycles aren't broken, this will time out
284
    tb = DebugTraceback(error)
285
    assert len(tb.all_tracebacks) == 2
286

287

288
def test_exception_without_traceback():
289
    try:
290
        raise Exception("msg1")
291
    except Exception as e:
292
        # filter_hidden_frames should skip this since it has no traceback
293
        e.__context__ = Exception("msg2")
294
        DebugTraceback(e)
295

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.