Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
C
cpython
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
cpython
Commits
3fe33043
Commit
3fe33043
authored
Mar 18, 2018
by
xdegaye
Committed by
Mariatta
Mar 18, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
bpo-19417: Add test_bdb.py (GH-5217)
parent
f64aae46
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
1153 additions
and
1 deletion
+1153
-1
Lib/test/test_bdb.py
Lib/test/test_bdb.py
+1151
-0
Lib/test/test_sundry.py
Lib/test/test_sundry.py
+1
-1
Misc/NEWS.d/next/Tests/2018-01-08-13-33-47.bpo-19417.2asoXy.rst
...EWS.d/next/Tests/2018-01-08-13-33-47.bpo-19417.2asoXy.rst
+1
-0
No files found.
Lib/test/test_bdb.py
0 → 100644
View file @
3fe33043
""" Test the bdb module.
A test defines a list of tuples that may be seen as paired tuples, each
pair being defined by 'expect_tuple, set_tuple' as follows:
([event, [lineno[, co_name[, eargs]]]]), (set_type, [sargs])
* 'expect_tuple' describes the expected current state of the Bdb instance.
It may be the empty tuple and no check is done in that case.
* 'set_tuple' defines the set_*() method to be invoked when the Bdb
instance reaches this state.
Example of an 'expect_tuple, set_tuple' pair:
('line', 2, 'tfunc_main'), ('step', )
Definitions of the members of the 'expect_tuple':
event:
Name of the trace event. The set methods that do not give back
control to the tracer [1] do not trigger a tracer event and in
that case the next 'event' may be 'None' by convention, its value
is not checked.
[1] Methods that trigger a trace event are set_step(), set_next(),
set_return(), set_until() and set_continue().
lineno:
Line number. Line numbers are relative to the start of the
function when tracing a function in the test_bdb module (i.e. this
module).
co_name:
Name of the function being currently traced.
eargs:
A tuple:
* On an 'exception' event the tuple holds a class object, the
current exception must be an instance of this class.
* On a 'line' event, the tuple holds a dictionary and a list. The
dictionary maps each breakpoint number that has been hit on this
line to its hits count. The list holds the list of breakpoint
number temporaries that are being deleted.
Definitions of the members of the 'set_tuple':
set_type:
The type of the set method to be invoked. This may
be the type of one of the Bdb set methods: 'step', 'next',
'until', 'return', 'continue', 'break', 'quit', or the type of one
of the set methods added by test_bdb.Bdb: 'ignore', 'enable',
'disable', 'clear', 'up', 'down'.
sargs:
The arguments of the set method if any, packed in a tuple.
"""
import
bdb
as
_bdb
import
sys
import
os
import
unittest
import
textwrap
import
importlib
import
linecache
from
contextlib
import
contextmanager
from
itertools
import
islice
,
repeat
import
test.support
class
BdbException
(
Exception
):
pass
class
BdbError
(
BdbException
):
"""Error raised by the Bdb instance."""
class
BdbSyntaxError
(
BdbException
):
"""Syntax error in the test case."""
class
BdbNotExpectedError
(
BdbException
):
"""Unexpected result."""
# When 'dry_run' is set to true, expect tuples are ignored and the actual
# state of the tracer is printed after running each set_*() method of the test
# case. The full list of breakpoints and their attributes is also printed
# after each 'line' event where a breakpoint has been hit.
dry_run
=
0
def
reset_Breakpoint
():
_bdb
.
Breakpoint
.
next
=
1
_bdb
.
Breakpoint
.
bplist
=
{}
_bdb
.
Breakpoint
.
bpbynumber
=
[
None
]
def
info_breakpoints
():
bp_list
=
[
bp
for
bp
in
_bdb
.
Breakpoint
.
bpbynumber
if
bp
]
if
not
bp_list
:
return
''
header_added
=
False
for
bp
in
bp_list
:
if
not
header_added
:
info
=
'BpNum Temp Enb Hits Ignore Where
\
n
'
header_added
=
True
disp
=
'yes '
if
bp
.
temporary
else
'no '
enab
=
'yes'
if
bp
.
enabled
else
'no '
info
+=
(
'%-5d %s %s %-4d %-6d at %s:%d'
%
(
bp
.
number
,
disp
,
enab
,
bp
.
hits
,
bp
.
ignore
,
os
.
path
.
basename
(
bp
.
file
),
bp
.
line
))
if
bp
.
cond
:
info
+=
'
\
n
\
t
stop only if %s'
%
(
bp
.
cond
,)
info
+=
'
\
n
'
return
info
class
Bdb
(
_bdb
.
Bdb
):
"""Extend Bdb to enhance test coverage."""
def
trace_dispatch
(
self
,
frame
,
event
,
arg
):
self
.
currentbp
=
None
return
super
().
trace_dispatch
(
frame
,
event
,
arg
)
def
set_break
(
self
,
filename
,
lineno
,
temporary
=
False
,
cond
=
None
,
funcname
=
None
):
if
isinstance
(
funcname
,
str
):
if
filename
==
__file__
:
globals_
=
globals
()
else
:
module
=
importlib
.
import_module
(
filename
[:
-
3
])
globals_
=
module
.
__dict__
func
=
eval
(
funcname
,
globals_
)
code
=
func
.
__code__
filename
=
code
.
co_filename
lineno
=
code
.
co_firstlineno
funcname
=
code
.
co_name
res
=
super
().
set_break
(
filename
,
lineno
,
temporary
=
temporary
,
cond
=
cond
,
funcname
=
funcname
)
if
isinstance
(
res
,
str
):
raise
BdbError
(
res
)
return
res
def
get_stack
(
self
,
f
,
t
):
self
.
stack
,
self
.
index
=
super
().
get_stack
(
f
,
t
)
self
.
frame
=
self
.
stack
[
self
.
index
][
0
]
return
self
.
stack
,
self
.
index
def
set_ignore
(
self
,
bpnum
):
"""Increment the ignore count of Breakpoint number 'bpnum'."""
bp
=
self
.
get_bpbynumber
(
bpnum
)
bp
.
ignore
+=
1
def
set_enable
(
self
,
bpnum
):
bp
=
self
.
get_bpbynumber
(
bpnum
)
bp
.
enabled
=
True
def
set_disable
(
self
,
bpnum
):
bp
=
self
.
get_bpbynumber
(
bpnum
)
bp
.
enabled
=
False
def
set_clear
(
self
,
fname
,
lineno
):
err
=
self
.
clear_break
(
fname
,
lineno
)
if
err
:
raise
BdbError
(
err
)
def
set_up
(
self
):
"""Move up in the frame stack."""
if
not
self
.
index
:
raise
BdbError
(
'Oldest frame'
)
self
.
index
-=
1
self
.
frame
=
self
.
stack
[
self
.
index
][
0
]
def
set_down
(
self
):
"""Move down in the frame stack."""
if
self
.
index
+
1
==
len
(
self
.
stack
):
raise
BdbError
(
'Newest frame'
)
self
.
index
+=
1
self
.
frame
=
self
.
stack
[
self
.
index
][
0
]
class
Tracer
(
Bdb
):
"""A tracer for testing the bdb module."""
def
__init__
(
self
,
expect_set
,
skip
=
None
,
dry_run
=
False
,
test_case
=
None
):
super
().
__init__
(
skip
=
skip
)
self
.
expect_set
=
expect_set
self
.
dry_run
=
dry_run
self
.
header
=
(
'Dry-run results for %s:'
%
test_case
if
test_case
is
not
None
else
None
)
self
.
init_test
()
def
init_test
(
self
):
self
.
cur_except
=
None
self
.
expect_set_no
=
0
self
.
breakpoint_hits
=
None
self
.
expected_list
=
list
(
islice
(
self
.
expect_set
,
0
,
None
,
2
))
self
.
set_list
=
list
(
islice
(
self
.
expect_set
,
1
,
None
,
2
))
def
trace_dispatch
(
self
,
frame
,
event
,
arg
):
# On an 'exception' event, call_exc_trace() in Python/ceval.c discards
# a BdbException raised by the Tracer instance, so we raise it on the
# next trace_dispatch() call that occurs unless the set_quit() or
# set_continue() method has been invoked on the 'exception' event.
if
self
.
cur_except
is
not
None
:
raise
self
.
cur_except
if
event
==
'exception'
:
try
:
res
=
super
().
trace_dispatch
(
frame
,
event
,
arg
)
return
res
except
BdbException
as
e
:
self
.
cur_except
=
e
return
self
.
trace_dispatch
else
:
return
super
().
trace_dispatch
(
frame
,
event
,
arg
)
def
user_call
(
self
,
frame
,
argument_list
):
# Adopt the same behavior as pdb and, as a side effect, skip also the
# first 'call' event when the Tracer is started with Tracer.runcall()
# which may be possibly considered as a bug.
if
not
self
.
stop_here
(
frame
):
return
self
.
process_event
(
'call'
,
frame
,
argument_list
)
self
.
next_set_method
()
def
user_line
(
self
,
frame
):
self
.
process_event
(
'line'
,
frame
)
if
self
.
dry_run
and
self
.
breakpoint_hits
:
info
=
info_breakpoints
().
strip
(
'
\
n
'
)
# Indent each line.
for
line
in
info
.
split
(
'
\
n
'
):
print
(
' '
+
line
)
self
.
delete_temporaries
()
self
.
breakpoint_hits
=
None
self
.
next_set_method
()
def
user_return
(
self
,
frame
,
return_value
):
self
.
process_event
(
'return'
,
frame
,
return_value
)
self
.
next_set_method
()
def
user_exception
(
self
,
frame
,
exc_info
):
self
.
exc_info
=
exc_info
self
.
process_event
(
'exception'
,
frame
)
self
.
next_set_method
()
def
do_clear
(
self
,
arg
):
# The temporary breakpoints are deleted in user_line().
bp_list
=
[
self
.
currentbp
]
self
.
breakpoint_hits
=
(
bp_list
,
bp_list
)
def
delete_temporaries
(
self
):
if
self
.
breakpoint_hits
:
for
n
in
self
.
breakpoint_hits
[
1
]:
self
.
clear_bpbynumber
(
n
)
def
pop_next
(
self
):
self
.
expect_set_no
+=
1
try
:
self
.
expect
=
self
.
expected_list
.
pop
(
0
)
except
IndexError
:
raise
BdbNotExpectedError
(
'expect_set list exhausted, cannot pop item %d'
%
self
.
expect_set_no
)
self
.
set_tuple
=
self
.
set_list
.
pop
(
0
)
def
process_event
(
self
,
event
,
frame
,
*
args
):
# Call get_stack() to enable walking the stack with set_up() and
# set_down().
tb
=
None
if
event
==
'exception'
:
tb
=
self
.
exc_info
[
2
]
self
.
get_stack
(
frame
,
tb
)
# A breakpoint has been hit and it is not a temporary.
if
self
.
currentbp
is
not
None
and
not
self
.
breakpoint_hits
:
bp_list
=
[
self
.
currentbp
]
self
.
breakpoint_hits
=
(
bp_list
,
[])
# Pop next event.
self
.
event
=
event
self
.
pop_next
()
if
self
.
dry_run
:
self
.
print_state
(
self
.
header
)
return
# Validate the expected results.
if
self
.
expect
:
self
.
check_equal
(
self
.
expect
[
0
],
event
,
'Wrong event type'
)
self
.
check_lno_name
()
if
event
in
(
'call'
,
'return'
):
self
.
check_expect_max_size
(
3
)
elif
len
(
self
.
expect
)
>
3
:
if
event
==
'line'
:
bps
,
temporaries
=
self
.
expect
[
3
]
bpnums
=
sorted
(
bps
.
keys
())
if
not
self
.
breakpoint_hits
:
self
.
raise_not_expected
(
'No breakpoints hit at expect_set item %d'
%
self
.
expect_set_no
)
self
.
check_equal
(
bpnums
,
self
.
breakpoint_hits
[
0
],
'Breakpoint numbers do not match'
)
self
.
check_equal
([
bps
[
n
]
for
n
in
bpnums
],
[
self
.
get_bpbynumber
(
n
).
hits
for
n
in
self
.
breakpoint_hits
[
0
]],
'Wrong breakpoint hit count'
)
self
.
check_equal
(
sorted
(
temporaries
),
self
.
breakpoint_hits
[
1
],
'Wrong temporary breakpoints'
)
elif
event
==
'exception'
:
if
not
isinstance
(
self
.
exc_info
[
1
],
self
.
expect
[
3
]):
self
.
raise_not_expected
(
"Wrong exception at expect_set item %d, got '%s'"
%
(
self
.
expect_set_no
,
self
.
exc_info
))
def
check_equal
(
self
,
expected
,
result
,
msg
):
if
expected
==
result
:
return
self
.
raise_not_expected
(
"%s at expect_set item %d, got '%s'"
%
(
msg
,
self
.
expect_set_no
,
result
))
def
check_lno_name
(
self
):
"""Check the line number and function co_name."""
s
=
len
(
self
.
expect
)
if
s
>
1
:
lineno
=
self
.
lno_abs2rel
()
self
.
check_equal
(
self
.
expect
[
1
],
lineno
,
'Wrong line number'
)
if
s
>
2
:
self
.
check_equal
(
self
.
expect
[
2
],
self
.
frame
.
f_code
.
co_name
,
'Wrong function name'
)
def
check_expect_max_size
(
self
,
size
):
if
len
(
self
.
expect
)
>
size
:
raise
BdbSyntaxError
(
'Invalid size of the %s expect tuple: %s'
%
(
self
.
event
,
self
.
expect
))
def
lno_abs2rel
(
self
):
fname
=
self
.
canonic
(
self
.
frame
.
f_code
.
co_filename
)
lineno
=
self
.
frame
.
f_lineno
return
((
lineno
-
self
.
frame
.
f_code
.
co_firstlineno
+
1
)
if
fname
==
self
.
canonic
(
__file__
)
else
lineno
)
def
lno_rel2abs
(
self
,
fname
,
lineno
):
return
(
self
.
frame
.
f_code
.
co_firstlineno
+
lineno
-
1
if
(
lineno
and
self
.
canonic
(
fname
)
==
self
.
canonic
(
__file__
))
else
lineno
)
def
get_state
(
self
):
lineno
=
self
.
lno_abs2rel
()
co_name
=
self
.
frame
.
f_code
.
co_name
state
=
"('%s', %d, '%s'"
%
(
self
.
event
,
lineno
,
co_name
)
if
self
.
breakpoint_hits
:
bps
=
'{'
for
n
in
self
.
breakpoint_hits
[
0
]:
if
bps
!=
'{'
:
bps
+=
', '
bps
+=
'%s: %s'
%
(
n
,
self
.
get_bpbynumber
(
n
).
hits
)
bps
+=
'}'
bps
=
'('
+
bps
+
', '
+
str
(
self
.
breakpoint_hits
[
1
])
+
')'
state
+=
', '
+
bps
elif
self
.
event
==
'exception'
:
state
+=
', '
+
self
.
exc_info
[
0
].
__name__
state
+=
'), '
return
state
.
ljust
(
32
)
+
str
(
self
.
set_tuple
)
+
','
def
print_state
(
self
,
header
=
None
):
if
header
is
not
None
and
self
.
expect_set_no
==
1
:
print
()
print
(
header
)
print
(
'%d: %s'
%
(
self
.
expect_set_no
,
self
.
get_state
()))
def
raise_not_expected
(
self
,
msg
):
msg
+=
'
\
n
'
msg
+=
' Expected: %s
\
n
'
%
str
(
self
.
expect
)
msg
+=
' Got: '
+
self
.
get_state
()
raise
BdbNotExpectedError
(
msg
)
def
next_set_method
(
self
):
set_type
=
self
.
set_tuple
[
0
]
args
=
self
.
set_tuple
[
1
]
if
len
(
self
.
set_tuple
)
==
2
else
None
set_method
=
getattr
(
self
,
'set_'
+
set_type
)
# The following set methods give back control to the tracer.
if
set_type
in
(
'step'
,
'continue'
,
'quit'
):
set_method
()
return
elif
set_type
in
(
'next'
,
'return'
):
set_method
(
self
.
frame
)
return
elif
set_type
==
'until'
:
lineno
=
None
if
args
:
lineno
=
self
.
lno_rel2abs
(
self
.
frame
.
f_code
.
co_filename
,
args
[
0
])
set_method
(
self
.
frame
,
lineno
)
return
# The following set methods do not give back control to the tracer and
# next_set_method() is called recursively.
if
(
args
and
set_type
in
(
'break'
,
'clear'
,
'ignore'
,
'enable'
,
'disable'
))
or
set_type
in
(
'up'
,
'down'
):
if
set_type
in
(
'break'
,
'clear'
):
fname
,
lineno
,
*
remain
=
args
lineno
=
self
.
lno_rel2abs
(
fname
,
lineno
)
args
=
[
fname
,
lineno
]
args
.
extend
(
remain
)
set_method
(
*
args
)
elif
set_type
in
(
'ignore'
,
'enable'
,
'disable'
):
set_method
(
*
args
)
elif
set_type
in
(
'up'
,
'down'
):
set_method
()
# Process the next expect_set item.
# It is not expected that a test may reach the recursion limit.
self
.
event
=
None
self
.
pop_next
()
if
self
.
dry_run
:
self
.
print_state
()
else
:
if
self
.
expect
:
self
.
check_lno_name
()
self
.
check_expect_max_size
(
3
)
self
.
next_set_method
()
else
:
raise
BdbSyntaxError
(
'"%s" is an invalid set_tuple'
%
self
.
set_tuple
)
class
TracerRun
():
"""Provide a context for running a Tracer instance with a test case."""
def
__init__
(
self
,
test_case
,
skip
=
None
):
self
.
test_case
=
test_case
self
.
dry_run
=
test_case
.
dry_run
self
.
tracer
=
Tracer
(
test_case
.
expect_set
,
skip
=
skip
,
dry_run
=
self
.
dry_run
,
test_case
=
test_case
.
id
())
def
__enter__
(
self
):
# test_pdb does not reset Breakpoint class attributes on exit :-(
reset_Breakpoint
()
return
self
.
tracer
def
__exit__
(
self
,
type_
=
None
,
value
=
None
,
traceback
=
None
):
reset_Breakpoint
()
sys
.
settrace
(
None
)
not_empty
=
''
if
self
.
tracer
.
set_list
:
not_empty
+=
'All paired tuples have not been processed, '
not_empty
+=
(
'the last one was number %d'
%
self
.
tracer
.
expect_set_no
)
# Make a BdbNotExpectedError a unittest failure.
if
type_
is
not
None
and
issubclass
(
BdbNotExpectedError
,
type_
):
if
isinstance
(
value
,
BaseException
)
and
value
.
args
:
err_msg
=
value
.
args
[
0
]
if
not_empty
:
err_msg
+=
'
\
n
'
+
not_empty
if
self
.
dry_run
:
print
(
err_msg
)
return
True
else
:
self
.
test_case
.
fail
(
err_msg
)
else
:
assert
False
,
'BdbNotExpectedError with empty args'
if
not_empty
:
if
self
.
dry_run
:
print
(
not_empty
)
else
:
self
.
test_case
.
fail
(
not_empty
)
def
run_test
(
modules
,
set_list
,
skip
=
None
):
"""Run a test and print the dry-run results.
'modules': A dictionary mapping module names to their source code as a
string. The dictionary MUST include one module named
'test_module' with a main() function.
'set_list': A list of set_type tuples to be run on the module.
For example, running the following script outputs the following results:
***************************** SCRIPT ********************************
from test.test_bdb import run_test, break_in_func
code = '''
def func():
lno = 3
def main():
func()
lno = 7
'''
set_list = [
break_in_func('func', 'test_module.py'),
('continue', ),
('step', ),
('step', ),
('step', ),
('quit', ),
]
modules = { 'test_module': code }
run_test(modules, set_list)
**************************** results ********************************
1: ('line', 2, 'tfunc_import'), ('next',),
2: ('line', 3, 'tfunc_import'), ('step',),
3: ('call', 5, 'main'), ('break', ('test_module.py', None, False, None, 'func')),
4: ('None', 5, 'main'), ('continue',),
5: ('line', 3, 'func', ({1: 1}, [])), ('step',),
BpNum Temp Enb Hits Ignore Where
1 no yes 1 0 at test_module.py:2
6: ('return', 3, 'func'), ('step',),
7: ('line', 7, 'main'), ('step',),
8: ('return', 7, 'main'), ('quit',),
*************************************************************************
"""
def
gen
(
a
,
b
):
try
:
while
1
:
x
=
next
(
a
)
y
=
next
(
b
)
yield
x
yield
y
except
StopIteration
:
return
# Step over the import statement in tfunc_import using 'next' and step
# into main() in test_module.
sl
=
[(
'next'
,
),
(
'step'
,
)]
sl
.
extend
(
set_list
)
test
=
BaseTestCase
()
test
.
dry_run
=
True
test
.
id
=
lambda
:
None
test
.
expect_set
=
list
(
gen
(
repeat
(()),
iter
(
sl
)))
with
create_modules
(
modules
):
sys
.
path
.
append
(
os
.
getcwd
())
with
TracerRun
(
test
,
skip
=
skip
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
@
contextmanager
def
create_modules
(
modules
):
with
test
.
support
.
temp_cwd
():
try
:
for
m
in
modules
:
fname
=
m
+
'.py'
with
open
(
fname
,
'w'
)
as
f
:
f
.
write
(
textwrap
.
dedent
(
modules
[
m
]))
linecache
.
checkcache
(
fname
)
importlib
.
invalidate_caches
()
yield
finally
:
for
m
in
modules
:
test
.
support
.
forget
(
m
)
def
break_in_func
(
funcname
,
fname
=
__file__
,
temporary
=
False
,
cond
=
None
):
return
'break'
,
(
fname
,
None
,
temporary
,
cond
,
funcname
)
TEST_MODULE
=
'test_module'
TEST_MODULE_FNAME
=
TEST_MODULE
+
'.py'
def
tfunc_import
():
import
test_module
test_module
.
main
()
def
tfunc_main
():
lno
=
2
tfunc_first
()
tfunc_second
()
lno
=
5
lno
=
6
lno
=
7
def
tfunc_first
():
lno
=
2
lno
=
3
lno
=
4
def
tfunc_second
():
lno
=
2
class
BaseTestCase
(
unittest
.
TestCase
):
"""Base class for all tests."""
dry_run
=
dry_run
def
fail
(
self
,
msg
=
None
):
# Override fail() to use 'raise from None' to avoid repetition of the
# error message and traceback.
raise
self
.
failureException
(
msg
)
from
None
class
StateTestCase
(
BaseTestCase
):
"""Test the step, next, return, until and quit 'set_' methods."""
def
test_step
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'step'
,
),
(
'line'
,
2
,
'tfunc_first'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_step_next_on_last_statement
(
self
):
for
set_type
in
(
'step'
,
'next'
):
with
self
.
subTest
(
set_type
=
set_type
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'break'
,
(
__file__
,
3
)),
(
'None'
,
1
,
'tfunc_first'
),
(
'continue'
,
),
(
'line'
,
3
,
'tfunc_first'
,
({
1
:
1
},
[])),
(
set_type
,
),
(
'line'
,
4
,
'tfunc_first'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_next
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'next'
,
),
(
'line'
,
4
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_second'
),
(
'step'
,
),
(
'line'
,
2
,
'tfunc_second'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_next_over_import
(
self
):
code
=
"""
def main():
lno = 3
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'next'
,
),
(
'line'
,
3
,
'tfunc_import'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_next_on_plain_statement
(
self
):
# Check that set_next() is equivalent to set_step() on a plain
# statement.
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'next'
,
),
(
'line'
,
2
,
'tfunc_first'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_next_in_caller_frame
(
self
):
# Check that set_next() in the caller frame causes the tracer
# to stop next in the caller frame.
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'up'
,
),
(
'None'
,
3
,
'tfunc_main'
),
(
'next'
,
),
(
'line'
,
4
,
'tfunc_main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_return
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'step'
,
),
(
'line'
,
2
,
'tfunc_first'
),
(
'return'
,
),
(
'return'
,
4
,
'tfunc_first'
),
(
'step'
,
),
(
'line'
,
4
,
'tfunc_main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_return_in_caller_frame
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'up'
,
),
(
'None'
,
3
,
'tfunc_main'
),
(
'return'
,
),
(
'return'
,
7
,
'tfunc_main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_until
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'step'
,
),
(
'line'
,
2
,
'tfunc_first'
),
(
'until'
,
(
4
,
)),
(
'line'
,
4
,
'tfunc_first'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_until_with_too_large_count
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
break_in_func
(
'tfunc_first'
),
(
'None'
,
2
,
'tfunc_main'
),
(
'continue'
,
),
(
'line'
,
2
,
'tfunc_first'
,
({
1
:
1
},
[])),
(
'until'
,
(
9999
,
)),
(
'return'
,
4
,
'tfunc_first'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_until_in_caller_frame
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'up'
,
),
(
'None'
,
3
,
'tfunc_main'
),
(
'until'
,
(
6
,
)),
(
'line'
,
6
,
'tfunc_main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
def
test_skip
(
self
):
# Check that tracing is skipped over the import statement in
# 'tfunc_import()'.
code
=
"""
def main():
lno = 3
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_import'
),
(
'quit'
,
),
]
skip
=
(
'importlib*'
,
TEST_MODULE
)
with
TracerRun
(
self
,
skip
=
skip
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_down
(
self
):
# Check that set_down() raises BdbError at the newest frame.
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'down'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
self
.
assertRaises
(
BdbError
,
tracer
.
runcall
,
tfunc_main
)
def
test_up
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_main'
),
(
'step'
,
),
(
'line'
,
3
,
'tfunc_main'
),
(
'step'
,
),
(
'call'
,
1
,
'tfunc_first'
),
(
'up'
,
),
(
'None'
,
3
,
'tfunc_main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_main
)
class
BreakpointTestCase
(
BaseTestCase
):
"""Test the breakpoint set method."""
def
test_bp_on_non_existent_module
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'break'
,
(
'/non/existent/module.py'
,
1
))
]
with
TracerRun
(
self
)
as
tracer
:
self
.
assertRaises
(
BdbError
,
tracer
.
runcall
,
tfunc_import
)
def
test_bp_after_last_statement
(
self
):
code
=
"""
def main():
lno = 3
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'break'
,
(
TEST_MODULE_FNAME
,
4
))
]
with
TracerRun
(
self
)
as
tracer
:
self
.
assertRaises
(
BdbError
,
tracer
.
runcall
,
tfunc_import
)
def
test_temporary_bp
(
self
):
code
=
"""
def func():
lno = 3
def main():
for i in range(2):
func()
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
,
True
),
(
'None'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
,
True
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
1
},
[
1
])),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
2
:
1
},
[
2
])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_disabled_temporary_bp
(
self
):
code
=
"""
def func():
lno = 3
def main():
for i in range(3):
func()
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
,
True
),
(
'None'
,
2
,
'tfunc_import'
),
(
'disable'
,
(
2
,
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
1
},
[])),
(
'enable'
,
(
2
,
)),
(
'None'
,
3
,
'func'
),
(
'disable'
,
(
1
,
)),
(
'None'
,
3
,
'func'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
2
:
1
},
[
2
])),
(
'enable'
,
(
1
,
)),
(
'None'
,
3
,
'func'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
2
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_bp_condition
(
self
):
code
=
"""
def func(a):
lno = 3
def main():
for i in range(3):
func(i)
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
,
False
,
'a == 2'
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
3
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_bp_exception_on_condition_evaluation
(
self
):
code
=
"""
def func(a):
lno = 3
def main():
func(0)
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
,
False
,
'1 / 0'
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
1
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_bp_ignore_count
(
self
):
code
=
"""
def func():
lno = 3
def main():
for i in range(2):
func()
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'ignore'
,
(
1
,
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
2
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_ignore_count_on_disabled_bp
(
self
):
code
=
"""
def func():
lno = 3
def main():
for i in range(3):
func()
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'ignore'
,
(
1
,
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'disable'
,
(
1
,
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
2
:
1
},
[])),
(
'enable'
,
(
1
,
)),
(
'None'
,
3
,
'func'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
2
:
2
},
[])),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
2
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_clear_two_bp_on_same_line
(
self
):
code
=
"""
def func():
lno = 3
lno = 4
def main():
for i in range(3):
func()
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'break'
,
(
TEST_MODULE_FNAME
,
3
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'break'
,
(
TEST_MODULE_FNAME
,
3
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'break'
,
(
TEST_MODULE_FNAME
,
4
)),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
1
},
[])),
(
'continue'
,
),
(
'line'
,
4
,
'func'
,
({
3
:
1
},
[])),
(
'clear'
,
(
TEST_MODULE_FNAME
,
3
)),
(
'None'
,
4
,
'func'
),
(
'continue'
,
),
(
'line'
,
4
,
'func'
,
({
3
:
2
},
[])),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_clear_at_no_bp
(
self
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
(
'clear'
,
(
__file__
,
1
))
]
with
TracerRun
(
self
)
as
tracer
:
self
.
assertRaises
(
BdbError
,
tracer
.
runcall
,
tfunc_import
)
class
RunTestCase
(
BaseTestCase
):
"""Test run, runeval and set_trace."""
def
test_run_step
(
self
):
# Check that the bdb 'run' method stops at the first line event.
code
=
"""
lno = 2
"""
self
.
expect_set
=
[
(
'line'
,
2
,
'<module>'
),
(
'step'
,
),
(
'return'
,
2
,
'<module>'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
run
(
compile
(
textwrap
.
dedent
(
code
),
'<string>'
,
'exec'
))
def
test_runeval_step
(
self
):
# Test bdb 'runeval'.
code
=
"""
def main():
lno = 3
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
1
,
'<module>'
),
(
'step'
,
),
(
'call'
,
2
,
'main'
),
(
'step'
,
),
(
'line'
,
3
,
'main'
),
(
'step'
,
),
(
'return'
,
3
,
'main'
),
(
'step'
,
),
(
'return'
,
1
,
'<module>'
),
(
'quit'
,
),
]
import
test_module
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runeval
(
'test_module.main()'
,
globals
(),
locals
())
class
IssuesTestCase
(
BaseTestCase
):
"""Test fixed bdb issues."""
def
test_step_at_return_with_no_trace_in_caller
(
self
):
# Issue #13183.
# Check that the tracer does step into the caller frame when the
# trace function is not set in that frame.
code_1
=
"""
from test_module_2 import func
def main():
func()
lno = 5
"""
code_2
=
"""
def func():
lno = 3
"""
modules
=
{
TEST_MODULE
:
code_1
,
'test_module_2'
:
code_2
,
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'func'
,
'test_module_2.py'
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'func'
,
({
1
:
1
},
[])),
(
'step'
,
),
(
'return'
,
3
,
'func'
),
(
'step'
,
),
(
'line'
,
5
,
'main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_next_until_return_in_generator
(
self
):
# Issue #16596.
# Check that set_next(), set_until() and set_return() do not treat the
# `yield` and `yield from` statements as if they were returns and stop
# instead in the current frame.
code
=
"""
def test_gen():
yield 0
lno = 4
return 123
def main():
it = test_gen()
next(it)
next(it)
lno = 11
"""
modules
=
{
TEST_MODULE
:
code
}
for
set_type
in
(
'next'
,
'until'
,
'return'
):
with
self
.
subTest
(
set_type
=
set_type
):
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'test_gen'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'test_gen'
,
({
1
:
1
},
[])),
(
set_type
,
),
]
if
set_type
==
'return'
:
self
.
expect_set
.
extend
(
[(
'exception'
,
10
,
'main'
,
StopIteration
),
(
'step'
,),
(
'return'
,
10
,
'main'
),
(
'quit'
,
),
]
)
else
:
self
.
expect_set
.
extend
(
[(
'line'
,
4
,
'test_gen'
),
(
'quit'
,
),]
)
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_next_command_in_generator_for_loop
(
self
):
# Issue #16596.
code
=
"""
def test_gen():
yield 0
lno = 4
yield 1
return 123
def main():
for i in test_gen():
lno = 10
lno = 11
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'test_gen'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'test_gen'
,
({
1
:
1
},
[])),
(
'next'
,
),
(
'line'
,
4
,
'test_gen'
),
(
'next'
,
),
(
'line'
,
5
,
'test_gen'
),
(
'next'
,
),
(
'line'
,
6
,
'test_gen'
),
(
'next'
,
),
(
'exception'
,
9
,
'main'
,
StopIteration
),
(
'step'
,
),
(
'line'
,
11
,
'main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_next_command_in_generator_with_subiterator
(
self
):
# Issue #16596.
code
=
"""
def test_subgen():
yield 0
return 123
def test_gen():
x = yield from test_subgen()
return 456
def main():
for i in test_gen():
lno = 12
lno = 13
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'test_gen'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
7
,
'test_gen'
,
({
1
:
1
},
[])),
(
'next'
,
),
(
'line'
,
8
,
'test_gen'
),
(
'next'
,
),
(
'exception'
,
11
,
'main'
,
StopIteration
),
(
'step'
,
),
(
'line'
,
13
,
'main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_return_command_in_generator_with_subiterator
(
self
):
# Issue #16596.
code
=
"""
def test_subgen():
yield 0
return 123
def test_gen():
x = yield from test_subgen()
return 456
def main():
for i in test_gen():
lno = 12
lno = 13
"""
modules
=
{
TEST_MODULE
:
code
}
with
create_modules
(
modules
):
self
.
expect_set
=
[
(
'line'
,
2
,
'tfunc_import'
),
break_in_func
(
'test_subgen'
,
TEST_MODULE_FNAME
),
(
'None'
,
2
,
'tfunc_import'
),
(
'continue'
,
),
(
'line'
,
3
,
'test_subgen'
,
({
1
:
1
},
[])),
(
'return'
,
),
(
'exception'
,
7
,
'test_gen'
,
StopIteration
),
(
'return'
,
),
(
'exception'
,
11
,
'main'
,
StopIteration
),
(
'step'
,
),
(
'line'
,
13
,
'main'
),
(
'quit'
,
),
]
with
TracerRun
(
self
)
as
tracer
:
tracer
.
runcall
(
tfunc_import
)
def
test_main
():
test
.
support
.
run_unittest
(
StateTestCase
,
RunTestCase
,
BreakpointTestCase
,
IssuesTestCase
,
)
if
__name__
==
"__main__"
:
test_main
()
Lib/test/test_sundry.py
View file @
3fe33043
...
@@ -6,7 +6,7 @@ import unittest
...
@@ -6,7 +6,7 @@ import unittest
class
TestUntestedModules
(
unittest
.
TestCase
):
class
TestUntestedModules
(
unittest
.
TestCase
):
def
test_untested_modules_can_be_imported
(
self
):
def
test_untested_modules_can_be_imported
(
self
):
untested
=
(
'
bdb'
,
'
encodings'
,
'formatter'
,
'tabnanny'
)
untested
=
(
'encodings'
,
'formatter'
,
'tabnanny'
)
with
support
.
check_warnings
(
quiet
=
True
):
with
support
.
check_warnings
(
quiet
=
True
):
for
name
in
untested
:
for
name
in
untested
:
try
:
try
:
...
...
Misc/NEWS.d/next/Tests/2018-01-08-13-33-47.bpo-19417.2asoXy.rst
0 → 100644
View file @
3fe33043
Add test_bdb.py.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment