675 lines
14 KiB
Python
Executable File
675 lines
14 KiB
Python
Executable File
#!/usr/bin/python
|
|
|
|
# Copyright 2016 Steven Watanabe
|
|
# Distributed under the Boost Software License, Version 1.0.
|
|
# (See accompanying file LICENSE.txt or https://www.bfgroup.xyz/b2/LICENSE.txt)
|
|
|
|
# Test for the debugger
|
|
|
|
import BoostBuild
|
|
import TestCmd
|
|
import re
|
|
|
|
def split_stdin_stdout(text):
|
|
"""stdin is all text after the prompt up to and including
|
|
the next newline. Everything else is stdout. stdout
|
|
may contain regular expressions enclosed in {{}}."""
|
|
prompt = re.escape('(b2db) ')
|
|
pattern = re.compile('(?<=%s)(.*\n)' % prompt)
|
|
text = text.replace("{{bjam}}", "{{.*}}b2{{(?:\\.exe)?}}")
|
|
stdin = ''.join(re.findall(pattern, text))
|
|
stdout = re.sub(pattern, '', text)
|
|
outside_pattern = re.compile(r'(?:\A|(?<=\}\}))(?:[^\{]|(?:\{(?!\{)))*(?:(?=\{\{)|\Z)')
|
|
|
|
def escape_line(line):
|
|
line = re.sub(outside_pattern, lambda m: re.escape(m.group(0)), line)
|
|
return re.sub(r'\{\{|\}\}', '', line)
|
|
|
|
stdout = '\n'.join([escape_line(line) for line in stdout.split('\n')])
|
|
return (stdin,stdout)
|
|
|
|
def run(tester, io):
|
|
(input,output) = split_stdin_stdout(io)
|
|
tester.run_build_system(stdin=input, stdout=output, match=TestCmd.match_re)
|
|
|
|
def make_tester():
|
|
return BoostBuild.Tester(["-dconsole"], pass_toolset=False, pass_d0=False,
|
|
use_test_config=False, ignore_toolset_requirements=False, match=TestCmd.match_re)
|
|
|
|
def test_run():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
UPDATE ;
|
|
""")
|
|
|
|
run(t, """\
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Child {{\d+}} exited with status 0
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
def test_exit_status():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
EXIT : 1 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
|
|
Child {{\d+}} exited with status 1
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_step():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule g ( )
|
|
{
|
|
a = 1 ;
|
|
b = 2 ;
|
|
}
|
|
rule f ( )
|
|
{
|
|
g ;
|
|
c = 3 ;
|
|
}
|
|
f ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( ) at test.jam:8
|
|
8 g ;
|
|
(b2db) step
|
|
3 a = 1 ;
|
|
(b2db) step
|
|
4 b = 2 ;
|
|
(b2db) step
|
|
9 c = 3 ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
# Note: step doesn't need to worry about breakpoints,
|
|
# as it always stops at the next line executed.
|
|
|
|
def test_next():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule g ( )
|
|
{
|
|
a = 1 ;
|
|
}
|
|
rule f ( )
|
|
{
|
|
g ;
|
|
b = 2 ;
|
|
c = 3 ;
|
|
}
|
|
rule h ( )
|
|
{
|
|
f ;
|
|
g ;
|
|
}
|
|
h ;
|
|
d = 4 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( ) at test.jam:7
|
|
7 g ;
|
|
(b2db) next
|
|
8 b = 2 ;
|
|
(b2db) next
|
|
9 c = 3 ;
|
|
(b2db) next
|
|
14 g ;
|
|
(b2db) next
|
|
17 d = 4 ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_next_breakpoint():
|
|
"""next should stop if it encounters a breakpoint.
|
|
If the normal end point happens to be a breakpoint,
|
|
then it should be reported as normal stepping."""
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( recurse ? )
|
|
{
|
|
if $(recurse) { f ; }
|
|
a = 1 ;
|
|
}
|
|
rule g ( )
|
|
{
|
|
b = 2 ;
|
|
}
|
|
f true ;
|
|
g ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) break g
|
|
Breakpoint 2 set at g
|
|
(b2db) break test.jam:4
|
|
Breakpoint 3 set at test.jam:4
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( true ) at test.jam:3
|
|
3 if $(recurse) { f ; }
|
|
(b2db) next
|
|
Breakpoint 1, f ( ) at test.jam:3
|
|
3 if $(recurse) { f ; }
|
|
(b2db) next
|
|
4 a = 1 ;
|
|
(b2db) next
|
|
4 a = 1 ;
|
|
(b2db) next
|
|
11 g ;
|
|
(b2db) next
|
|
Breakpoint 2, g ( ) at test.jam:8
|
|
8 b = 2 ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_finish():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( )
|
|
{
|
|
a = 1 ;
|
|
}
|
|
rule g ( )
|
|
{
|
|
f ;
|
|
b = 2 ;
|
|
i ;
|
|
}
|
|
rule h ( )
|
|
{
|
|
g ;
|
|
i ;
|
|
}
|
|
rule i ( )
|
|
{
|
|
c = 3 ;
|
|
}
|
|
h ;
|
|
d = 4 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( ) at test.jam:3
|
|
3 a = 1 ;
|
|
(b2db) finish
|
|
8 b = 2 ;
|
|
(b2db) finish
|
|
14 i ;
|
|
(b2db) finish
|
|
21 d = 4 ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_finish_breakpoints():
|
|
"""finish should stop when it reaches a breakpoint."""
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( recurse * )
|
|
{
|
|
if $(recurse)
|
|
{
|
|
a = [ f $(recurse[2-]) ] ;
|
|
}
|
|
}
|
|
rule g ( list * )
|
|
{
|
|
for local v in $(list)
|
|
{
|
|
x = $(v) ;
|
|
}
|
|
}
|
|
f 1 2 ;
|
|
g 1 2 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break test.jam:5
|
|
Breakpoint 1 set at test.jam:5
|
|
(b2db) break test.jam:12
|
|
Breakpoint 2 set at test.jam:12
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( 1 2 ) at test.jam:5
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) finish
|
|
Breakpoint 1, f ( 2 ) at test.jam:5
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) finish
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) finish
|
|
16 g 1 2 ;
|
|
(b2db) finish
|
|
Breakpoint 2, g ( 1 2 ) at test.jam:12
|
|
12 x = $(v) ;
|
|
(b2db) finish
|
|
Breakpoint 2, g ( 1 2 ) at test.jam:12
|
|
12 x = $(v) ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_continue_breakpoints():
|
|
"""continue should stop when it reaches a breakpoint"""
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( recurse * )
|
|
{
|
|
if $(recurse)
|
|
{
|
|
a = [ f $(recurse[2-]) ] ;
|
|
}
|
|
}
|
|
rule g ( list * )
|
|
{
|
|
for local v in $(list)
|
|
{
|
|
x = $(v) ;
|
|
}
|
|
}
|
|
f 1 2 ;
|
|
g 1 2 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break test.jam:5
|
|
Breakpoint 1 set at test.jam:5
|
|
(b2db) break test.jam:12
|
|
Breakpoint 2 set at test.jam:12
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( 1 2 ) at test.jam:5
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) continue
|
|
Breakpoint 1, f ( 2 ) at test.jam:5
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) continue
|
|
Breakpoint 1, f ( 1 2 ) at test.jam:5
|
|
5 a = [ f $(recurse[2-]) ] ;
|
|
(b2db) continue
|
|
Breakpoint 2, g ( 1 2 ) at test.jam:12
|
|
12 x = $(v) ;
|
|
(b2db) continue
|
|
Breakpoint 2, g ( 1 2 ) at test.jam:12
|
|
12 x = $(v) ;
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_breakpoints():
|
|
"""Tests the interaction between the following commands:
|
|
break, clear, delete, disable, enable"""
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( )
|
|
{
|
|
a = 1 ;
|
|
}
|
|
rule g ( )
|
|
{
|
|
b = 2 ;
|
|
}
|
|
rule h ( )
|
|
{
|
|
c = 3 ;
|
|
d = 4 ;
|
|
}
|
|
f ;
|
|
g ;
|
|
h ;
|
|
UPDATE ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( ) at test.jam:3
|
|
3 a = 1 ;
|
|
(b2db) kill
|
|
(b2db) break g
|
|
Breakpoint 2 set at g
|
|
(b2db) disable 1
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 2, g ( ) at test.jam:7
|
|
7 b = 2 ;
|
|
(b2db) kill
|
|
(b2db) enable 1
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( ) at test.jam:3
|
|
3 a = 1 ;
|
|
(b2db) kill
|
|
(b2db) delete 1
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 2, g ( ) at test.jam:7
|
|
7 b = 2 ;
|
|
(b2db) kill
|
|
(b2db) break test.jam:12
|
|
Breakpoint 3 set at test.jam:12
|
|
(b2db) clear g
|
|
Deleted breakpoint 2
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 3, h ( ) at test.jam:12
|
|
12 d = 4 ;
|
|
(b2db) kill
|
|
(b2db) clear test.jam:12
|
|
Deleted breakpoint 3
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Child {{\d+}} exited with status 0
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_breakpoints_running():
|
|
"""Tests that breakpoints can be added and modified
|
|
while the program is running."""
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( )
|
|
{
|
|
a = 1 ;
|
|
}
|
|
rule g ( )
|
|
{
|
|
b = 2 ;
|
|
}
|
|
rule h ( )
|
|
{
|
|
c = 3 ;
|
|
d = 4 ;
|
|
}
|
|
f ;
|
|
g ;
|
|
h ;
|
|
UPDATE ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break test.jam:14
|
|
Breakpoint 1 set at test.jam:14
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) break f
|
|
Breakpoint 2 set at f
|
|
(b2db) continue
|
|
Breakpoint 2, f ( ) at test.jam:3
|
|
3 a = 1 ;
|
|
(b2db) kill
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) break g
|
|
Breakpoint 3 set at g
|
|
(b2db) disable 2
|
|
(b2db) continue
|
|
Breakpoint 3, g ( ) at test.jam:7
|
|
7 b = 2 ;
|
|
(b2db) kill
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) enable 2
|
|
(b2db) continue
|
|
Breakpoint 2, f ( ) at test.jam:3
|
|
3 a = 1 ;
|
|
(b2db) kill
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) delete 2
|
|
(b2db) continue
|
|
Breakpoint 3, g ( ) at test.jam:7
|
|
7 b = 2 ;
|
|
(b2db) kill
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) break test.jam:12
|
|
Breakpoint 4 set at test.jam:12
|
|
(b2db) clear g
|
|
Deleted breakpoint 3
|
|
(b2db) continue
|
|
Breakpoint 4, h ( ) at test.jam:12
|
|
12 d = 4 ;
|
|
(b2db) kill
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:14
|
|
14 f ;
|
|
(b2db) clear test.jam:12
|
|
Deleted breakpoint 4
|
|
(b2db) continue
|
|
Child {{\d+}} exited with status 0
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_backtrace():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( x * : y * : z * )
|
|
{
|
|
return $(x) ;
|
|
}
|
|
rule g ( x * : y * : z * )
|
|
{
|
|
return [ f $(x) : $(y) : $(z) ] ;
|
|
}
|
|
g 1 : 2 : 3 ;
|
|
""")
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( 1 : 2 : 3 ) at test.jam:3
|
|
3 return $(x) ;
|
|
(b2db) backtrace
|
|
#0 in f ( 1 : 2 : 3 ) at test.jam:3
|
|
#1 in g ( 1 : 2 : 3 ) at test.jam:7
|
|
#2 in module scope at test.jam:9
|
|
(b2db) quit
|
|
""")
|
|
t.cleanup()
|
|
|
|
def test_print():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
rule f ( args * )
|
|
{
|
|
return $(args) ;
|
|
}
|
|
f x ;
|
|
f x y ;
|
|
""")
|
|
|
|
run(t, """\
|
|
(b2db) break f
|
|
Breakpoint 1 set at f
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, f ( x ) at test.jam:3
|
|
3 return $(args) ;
|
|
(b2db) print $(args)
|
|
x
|
|
(b2db) continue
|
|
Breakpoint 1, f ( x y ) at test.jam:3
|
|
3 return $(args) ;
|
|
(b2db) print $(args)
|
|
x y
|
|
(b2db) disable 1
|
|
(b2db) print [ f z ]
|
|
z
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
def test_run_running():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
UPDATE ;
|
|
""")
|
|
|
|
run(t, """\
|
|
(b2db) break test.jam:1
|
|
Breakpoint 1 set at test.jam:1
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:1
|
|
1 UPDATE ;
|
|
(b2db) run -ftest.jam
|
|
Child {{\d+}} exited with status 0
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:1
|
|
1 UPDATE ;
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
def test_error_not_running():
|
|
t = make_tester()
|
|
run(t, """\
|
|
(b2db) continue
|
|
The program is not being run.
|
|
(b2db) step
|
|
The program is not being run.
|
|
(b2db) next
|
|
The program is not being run.
|
|
(b2db) finish
|
|
The program is not being run.
|
|
(b2db) kill
|
|
The program is not being run.
|
|
(b2db) backtrace
|
|
The program is not being run.
|
|
(b2db) print 1
|
|
The program is not being run.
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
def test_bad_arguments():
|
|
t = make_tester()
|
|
t.write("test.jam", """\
|
|
UPDATE ;
|
|
""")
|
|
|
|
run(t, """\
|
|
(b2db) break test.jam:1
|
|
Breakpoint 1 set at test.jam:1
|
|
(b2db) run -ftest.jam
|
|
Starting program: {{bjam}} -ftest.jam
|
|
Breakpoint 1, module scope at test.jam:1
|
|
1 UPDATE ;
|
|
(b2db) continue 1
|
|
Too many arguments to continue.
|
|
(b2db) step 1
|
|
Too many arguments to step.
|
|
(b2db) next 1
|
|
Too many arguments to next.
|
|
(b2db) finish 1
|
|
Too many arguments to finish.
|
|
(b2db) break
|
|
Missing argument to break.
|
|
(b2db) break x y
|
|
Too many arguments to break.
|
|
(b2db) disable
|
|
Missing argument to disable.
|
|
(b2db) disable 1 2
|
|
Too many arguments to disable.
|
|
(b2db) disable x
|
|
Invalid breakpoint number x.
|
|
(b2db) disable 2
|
|
Unknown breakpoint 2.
|
|
(b2db) enable
|
|
Missing argument to enable.
|
|
(b2db) enable 1 2
|
|
Too many arguments to enable.
|
|
(b2db) enable x
|
|
Invalid breakpoint number x.
|
|
(b2db) enable 2
|
|
Unknown breakpoint 2.
|
|
(b2db) delete
|
|
Missing argument to delete.
|
|
(b2db) delete 1 2
|
|
Too many arguments to delete.
|
|
(b2db) delete x
|
|
Invalid breakpoint number x.
|
|
(b2db) delete 2
|
|
Unknown breakpoint 2.
|
|
(b2db) clear
|
|
Missing argument to clear.
|
|
(b2db) clear test.jam:1 test.jam:1
|
|
Too many arguments to clear.
|
|
(b2db) clear test.jam:2
|
|
No breakpoint at test.jam:2.
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
def test_unknown_command():
|
|
t = make_tester()
|
|
run(t, """\
|
|
(b2db) xyzzy
|
|
Unknown command: xyzzy
|
|
(b2db) gnusto rezrov
|
|
Unknown command: gnusto
|
|
(b2db) quit
|
|
""")
|
|
|
|
t.cleanup()
|
|
|
|
test_run()
|
|
test_exit_status()
|
|
test_step()
|
|
test_next()
|
|
test_next_breakpoint()
|
|
test_finish()
|
|
test_finish_breakpoints()
|
|
test_continue_breakpoints()
|
|
test_breakpoints()
|
|
test_breakpoints_running()
|
|
test_backtrace()
|
|
test_print()
|
|
test_run_running()
|
|
test_error_not_running()
|
|
test_bad_arguments()
|
|
test_unknown_command()
|