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
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>]'
25
assert debug_repr([1, "test"]) == (
26
'[<span class="number">1</span>,'
27
' <span class="string">'test'</span>]'
29
assert debug_repr([None]) == '[<span class="object">None</span>]'
31
def test_string_repr(self):
32
assert debug_repr("") == '<span class="string">''</span>'
33
assert debug_repr("foo") == '<span class="string">'foo'</span>'
34
assert debug_repr("s" * 80) == (
35
f'<span class="string">'{"s" * 69}'
36
f'<span class="extended">{"s" * 11}'</span></span>'
38
assert debug_repr("<" * 80) == (
39
f'<span class="string">'{"<" * 69}'
40
f'<span class="extended">{"<" * 11}'</span></span>'
43
def test_string_subclass_repr(self):
47
assert debug_repr(Test("foo")) == (
48
'<span class="module">test_debug.</span>'
49
'Test(<span class="string">'foo'</span>)'
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>]'
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">'foo''
71
'</span></span>: <span class="value"><span class="number">42'
72
"</span></span></span>}"
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>}"
107
assert debug_repr((1, "zwei", "drei")) == (
108
'(<span class="number">1</span>, <span class="string">''
109
'zwei'</span>, <span class="string">'drei'</span>)'
112
def test_custom_repr(self):
117
assert debug_repr(Foo()) == '<span class="object"><Foo 42></span>'
119
def test_list_subclass_repr(self):
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>])'
128
def test_regex_repr(self):
130
debug_repr(re.compile(r"foo\d"))
131
== "re.compile(<span class=\"string regex\">r'foo\\d'</span>)"
135
assert debug_repr(re.compile("foo\\d")) == (
136
"re.compile(<span class=\"string regex\">r'foo\\d'</span>)"
139
def test_set_repr(self):
141
debug_repr(frozenset("x"))
142
== 'frozenset([<span class="string">'x'</span>])'
144
assert debug_repr(set("x")) == (
145
'set([<span class="string">'x'</span>])'
148
def test_recursive_repr(self):
151
assert debug_repr(a) == '[<span class="number">1</span>, [...]]'
153
def test_broken_repr(self):
156
raise Exception("broken!")
158
assert debug_repr(Foo()) == (
159
'<span class="brokenrepr"><broken repr (Exception: '
160
"broken!)></span>"
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)
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)
186
out = drg.dump_object({"x": 42, "y": 23, 23: 11})
187
assert not re.search("Contents of", out)
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)
194
def test_debug_dump(self):
196
sys.stdout = HTMLStringO()
199
x = sys.stdout.reset()
201
y = sys.stdout.reset()
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
209
assert "<th>old" in y
211
def test_debug_help(self):
213
sys.stdout = HTMLStringO()
216
x = sys.stdout.reset()
220
assert "Help on list object" in x
221
assert "__delitem__" in x
223
def test_exc_divider_found_on_chained_exception(self):
227
raise ValueError("inner")
232
raise KeyError("outer")
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
243
def test_get_machine_id():
244
rv = get_machine_id()
245
assert isinstance(rv, bytes)
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)
257
assert b"The debugger caught an exception in your WSGI application" in r.data
259
assert r.json["PATH_INFO"] == "/"
262
def test_console_closure_variables(monkeypatch):
264
monkeypatch.setattr(sys, "displayhook", console._displayhook)
265
c = console.Console()
267
c.eval("x = lambda: y")
269
assert ret == ">>> x()\n5\n"
272
@pytest.mark.timeout(2)
273
def test_chained_exception_cycle():
279
except TypeError as e:
281
e.__context__.__context__ = error = e
284
tb = DebugTraceback(error)
285
assert len(tb.all_tracebacks) == 2
288
def test_exception_without_traceback():
290
raise Exception("msg1")
291
except Exception as e:
293
e.__context__ = Exception("msg2")