Implement specification of MI tests as comments
in C and C++ sources. * lib/mi-support.exp (mi_autotest_data): New variable. (mi_autotest_source): New variable. (count_newlines, mi_prepare_inline_tests) (mi_get_inline_test, mi_continue_to_line) (mi_run_inline_test, mi_tbreak) (mi_send_resuming_command, mi_wait_for_stop): New functions. * gdb.mi/mi-var-cp.exp: Move most content to the C file. Run inline tests. * gdb.mi/mi-var-cp.cc: Define tests here.
This commit is contained in:
parent
a028a6f534
commit
2d0720d988
4 changed files with 295 additions and 47 deletions
|
@ -1,3 +1,17 @@
|
||||||
|
2007-01-04 Vladimir Prus <vladimir@codesourcery.com>
|
||||||
|
|
||||||
|
Implement specification of MI tests as comments
|
||||||
|
in C and C++ sources.
|
||||||
|
* lib/mi-support.exp (mi_autotest_data): New variable.
|
||||||
|
(mi_autotest_source): New variable.
|
||||||
|
(count_newlines, mi_prepare_inline_tests)
|
||||||
|
(mi_get_inline_test, mi_continue_to_line)
|
||||||
|
(mi_run_inline_test, mi_tbreak)
|
||||||
|
(mi_send_resuming_command, mi_wait_for_stop): New functions.
|
||||||
|
* gdb.mi/mi-var-cp.exp: Move most content to the C file.
|
||||||
|
Run inline tests.
|
||||||
|
* gdb.mi/mi-var-cp.cc: Define tests here.
|
||||||
|
|
||||||
2007-01-04 Daniel Jacobowitz <dan@codesourcery.com>
|
2007-01-04 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* configure.ac (build_warnings): Use -Wall and
|
* configure.ac (build_warnings): Use -Wall and
|
||||||
|
|
|
@ -17,10 +17,22 @@
|
||||||
|
|
||||||
void reference_update_tests ()
|
void reference_update_tests ()
|
||||||
{
|
{
|
||||||
|
/*: BEGIN: reference_update :*/
|
||||||
int x = 167;
|
int x = 167;
|
||||||
|
/*: mi_create_varobj "RX" "rx" "create varobj for rx" :*/
|
||||||
int& rx = x;
|
int& rx = x;
|
||||||
|
/*: mi_varobj_update RX {RX} "update RX (1)"
|
||||||
|
mi_check_varobj_value RX 167 "check RX: expect 167"
|
||||||
|
:*/
|
||||||
x = 567;
|
x = 567;
|
||||||
|
/*: mi_varobj_update RX {RX} "update RX (2)"
|
||||||
|
mi_check_varobj_value RX 567 "check RX: expect 567"
|
||||||
|
:*/
|
||||||
x = 567;
|
x = 567;
|
||||||
|
/*: mi_varobj_update RX {} "update RX (3)"
|
||||||
|
:*/
|
||||||
|
|
||||||
|
/*: END: reference_update :*/
|
||||||
}
|
}
|
||||||
|
|
||||||
struct S { int i; int j; };
|
struct S { int i; int j; };
|
||||||
|
@ -28,7 +40,26 @@ struct S2 : S {};
|
||||||
|
|
||||||
int base_in_reference_test (S2& s2)
|
int base_in_reference_test (S2& s2)
|
||||||
{
|
{
|
||||||
|
/*: BEGIN: base_in_reference :*/
|
||||||
return s2.i;
|
return s2.i;
|
||||||
|
/*:
|
||||||
|
mi_create_varobj "S2" "s2" "create varobj for s2"
|
||||||
|
mi_list_varobj_children "S2" {
|
||||||
|
{"S2.S" "S" "1" "S"}
|
||||||
|
} "list children of s2"
|
||||||
|
mi_list_varobj_children "S2.S" {
|
||||||
|
{"S2.S.public" "public" "2"}
|
||||||
|
} "list children of s2.s"
|
||||||
|
mi_list_varobj_children "S2.S.public" {
|
||||||
|
{"S2.S.public.i" "i" "0" "int"}
|
||||||
|
{"S2.S.public.j" "j" "0" "int"}
|
||||||
|
} "list children of s2.s.public"
|
||||||
|
|
||||||
|
mi_check_varobj_value "S2.S.public.i" "67" "check S2.S.public.i"
|
||||||
|
mi_check_varobj_value "S2.S.public.j" "89" "check S2.S.public.j"
|
||||||
|
|
||||||
|
:*/
|
||||||
|
/*: END: base_in_reference :*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void base_in_reference_test_main ()
|
void base_in_reference_test_main ()
|
||||||
|
|
|
@ -39,53 +39,10 @@ if {[gdb_compile $srcdir/$subdir/$srcfile $binfile executable {debug c++}] != ""
|
||||||
|
|
||||||
mi_gdb_load ${binfile}
|
mi_gdb_load ${binfile}
|
||||||
|
|
||||||
# Test that children of classes are properly reported
|
mi_prepare_inline_tests $srcfile
|
||||||
|
|
||||||
mi_runto reference_update_tests
|
|
||||||
|
|
||||||
mi_create_varobj "RX" "rx" "create varobj for rx"
|
|
||||||
|
|
||||||
set x_assignment [gdb_get_line_number "x = 567;"]
|
|
||||||
mi_next_to "reference_update_tests" {} ".*${srcfile}" [expr $x_assignment-1] \
|
|
||||||
"step to x assignment"
|
|
||||||
mi_next_to "reference_update_tests" {} ".*${srcfile}" [expr $x_assignment] \
|
|
||||||
"step to x assignment"
|
|
||||||
|
|
||||||
mi_varobj_update RX {RX} "update RX (1)"
|
|
||||||
|
|
||||||
mi_check_varobj_value RX 167 "check RX: expect 167"
|
|
||||||
|
|
||||||
# Execute the first 'x = 567' line.
|
|
||||||
mi_next_to "reference_update_tests" {} ".*${srcfile}" [expr $x_assignment+1] \
|
|
||||||
"step to x assignment"
|
|
||||||
|
|
||||||
mi_varobj_update RX {RX} "update RX (2)"
|
|
||||||
mi_check_varobj_value RX 567 "check RX: expect 567"
|
|
||||||
|
|
||||||
# Execute the second 'x = 567' line.
|
|
||||||
mi_next_to "reference_update_tests" {} ".*${srcfile}" [expr $x_assignment+2] \
|
|
||||||
"step to x assignment"
|
|
||||||
|
|
||||||
mi_varobj_update RX {} "update RX (3)"
|
|
||||||
|
|
||||||
mi_runto base_in_reference_test
|
|
||||||
|
|
||||||
mi_create_varobj "S2" "s2" "create varobj for s2"
|
|
||||||
|
|
||||||
mi_list_varobj_children "S2" {{"S2.S" "S" "1" "S"}} "list children of s2"
|
|
||||||
|
|
||||||
mi_list_varobj_children "S2.S" {{"S2.S.public" "public" "2"}} \
|
|
||||||
"list children of s2.s"
|
|
||||||
|
|
||||||
mi_list_varobj_children "S2.S.public"\
|
|
||||||
{
|
|
||||||
{"S2.S.public.i" "i" "0" "int"}
|
|
||||||
{"S2.S.public.j" "j" "0" "int"}
|
|
||||||
} "list children of s2.s.public"
|
|
||||||
|
|
||||||
mi_check_varobj_value "S2.S.public.i" "67" "check S2.S.public.i"
|
|
||||||
mi_check_varobj_value "S2.S.public.j" "89" "check S2.S.public.j"
|
|
||||||
|
|
||||||
|
mi_run_inline_test reference_update
|
||||||
|
mi_run_inline_test base_in_reference
|
||||||
|
|
||||||
mi_gdb_exit
|
mi_gdb_exit
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -822,7 +822,7 @@ proc mi_run_cmd {args} {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# NOTE: Shortly after this there will be a ``000*stopping,...(gdb)''
|
# NOTE: Shortly after this there will be a ``000*stopped,...(gdb)''
|
||||||
}
|
}
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -1086,3 +1086,249 @@ proc mi_list_varobj_children { varname children testname } {
|
||||||
|
|
||||||
mi_gdb_test "-var-list-children $varname" $expected $testname
|
mi_gdb_test "-var-list-children $varname" $expected $testname
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# A list of two-element lists. First element of each list is
|
||||||
|
# a Tcl statement, and the second element is the line
|
||||||
|
# number of source C file where the statement originates.
|
||||||
|
set mi_autotest_data ""
|
||||||
|
# The name of the source file for autotesting.
|
||||||
|
set mi_autotest_source ""
|
||||||
|
|
||||||
|
proc count_newlines { string } {
|
||||||
|
return [regexp -all "\n" $string]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Prepares for running inline tests in FILENAME.
|
||||||
|
# See comments for mi_run_inline_test for detailed
|
||||||
|
# explanation of the idea and syntax.
|
||||||
|
proc mi_prepare_inline_tests { filename } {
|
||||||
|
|
||||||
|
global srcdir
|
||||||
|
global subdir
|
||||||
|
global mi_autotest_source
|
||||||
|
global mi_autotest_data
|
||||||
|
|
||||||
|
set mi_autotest_data {}
|
||||||
|
|
||||||
|
set mi_autotest_source $filename
|
||||||
|
|
||||||
|
if { ! [regexp "^/" "$filename"] } then {
|
||||||
|
set filename "$srcdir/$subdir/$filename"
|
||||||
|
}
|
||||||
|
|
||||||
|
set chan [open $filename]
|
||||||
|
set content [read $chan]
|
||||||
|
set line_number 1
|
||||||
|
while {1} {
|
||||||
|
set start [string first "/*:" $content]
|
||||||
|
if {$start != -1} {
|
||||||
|
set end [string first ":*/" $content]
|
||||||
|
if {$end == -1} {
|
||||||
|
error "Unterminated special comment in $filename"
|
||||||
|
}
|
||||||
|
|
||||||
|
set prefix [string range $content 0 $start]
|
||||||
|
set prefix_newlines [count_newlines $prefix]
|
||||||
|
|
||||||
|
set line_number [expr $line_number+$prefix_newlines]
|
||||||
|
set comment_line $line_number
|
||||||
|
|
||||||
|
set comment [string range $content [expr $start+3] [expr $end-1]]
|
||||||
|
|
||||||
|
set comment_newlines [count_newlines $comment]
|
||||||
|
set line_number [expr $line_number+$comment_newlines]
|
||||||
|
|
||||||
|
set comment [string trim $comment]
|
||||||
|
set content [string range $content [expr $end+3] \
|
||||||
|
[string length $content]]
|
||||||
|
lappend mi_autotest_data [list $comment $comment_line]
|
||||||
|
} else {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $chan
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper to mi_run_inline_test below.
|
||||||
|
# Return the list of all (statement,line_number) lists
|
||||||
|
# that comprise TESTCASE. The begin and end markers
|
||||||
|
# are not included.
|
||||||
|
proc mi_get_inline_test {testcase} {
|
||||||
|
|
||||||
|
global mi_gdb_prompt
|
||||||
|
global mi_autotest_data
|
||||||
|
global mi_autotest_source
|
||||||
|
|
||||||
|
set result {}
|
||||||
|
|
||||||
|
set seen_begin 0
|
||||||
|
set seen_end 0
|
||||||
|
foreach l $mi_autotest_data {
|
||||||
|
|
||||||
|
set comment [lindex $l 0]
|
||||||
|
|
||||||
|
if {$comment == "BEGIN: $testcase"} {
|
||||||
|
set seen_begin 1
|
||||||
|
} elseif {$comment == "END: $testcase"} {
|
||||||
|
set seen_end 1
|
||||||
|
break
|
||||||
|
} elseif {$seen_begin==1} {
|
||||||
|
lappend result $l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$seen_begin == 0} {
|
||||||
|
error "Autotest $testcase not found"
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$seen_begin == 1 && $seen_end == 0} {
|
||||||
|
error "Missing end marker for test $testcase"
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result
|
||||||
|
}
|
||||||
|
|
||||||
|
# Sets temporary breakpoint at LOCATION.
|
||||||
|
proc mi_tbreak {location} {
|
||||||
|
|
||||||
|
global mi_gdb_prompt
|
||||||
|
|
||||||
|
mi_gdb_test "-break-insert -t $location" \
|
||||||
|
{\^done,bkpt=.*} \
|
||||||
|
"run to $location (set breakpoint)"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send COMMAND that must be a command that resumes
|
||||||
|
# the inferiour (run/continue/next/etc) and consumes
|
||||||
|
# the "^running" output from it.
|
||||||
|
proc mi_send_resuming_command {command test} {
|
||||||
|
|
||||||
|
global mi_gdb_prompt
|
||||||
|
|
||||||
|
send_gdb "220-$command\n"
|
||||||
|
gdb_expect {
|
||||||
|
-re "220\\^running\r\n${mi_gdb_prompt}" {
|
||||||
|
}
|
||||||
|
timeout {
|
||||||
|
fail $test
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Helper to mi_run_inline_test below.
|
||||||
|
# Sets a temporary breakpoint at LOCATION and runs
|
||||||
|
# the program using COMMAND. When the program is stopped
|
||||||
|
# returns the line at which it. Returns -1 if line cannot
|
||||||
|
# be determined.
|
||||||
|
# Does not check that the line is the same as requested.
|
||||||
|
# The caller can check itself if required.
|
||||||
|
proc mi_continue_to_line {location command} {
|
||||||
|
|
||||||
|
mi_tbreak $location
|
||||||
|
mi_send_resuming_command "exec-continue" "run to $location (exec-continue)"
|
||||||
|
return [mi_wait_for_stop]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Wait until gdb prints the current line.
|
||||||
|
proc mi_wait_for_stop {test} {
|
||||||
|
|
||||||
|
global mi_gdb_prompt
|
||||||
|
|
||||||
|
gdb_expect {
|
||||||
|
-re ".*line=\"(.*)\".*\r\n$mi_gdb_prompt$" {
|
||||||
|
return $expect_out(1,string)
|
||||||
|
}
|
||||||
|
-re ".*$mi_gdb_prompt$" {
|
||||||
|
fail "wait for stop ($test)"
|
||||||
|
}
|
||||||
|
timeout {
|
||||||
|
fail "wait for stop ($test)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Run a MI test embedded in comments in a C file.
|
||||||
|
# The C file should contain special comments in the following
|
||||||
|
# three forms:
|
||||||
|
#
|
||||||
|
# /*: BEGIN: testname :*/
|
||||||
|
# /*: <Tcl statements> :*/
|
||||||
|
# /*: END: testname :*/
|
||||||
|
#
|
||||||
|
# This procedure find the begin and end marker for the requested
|
||||||
|
# test. Then, a temporary breakpoint is set at the begin
|
||||||
|
# marker and the program is run (from start).
|
||||||
|
#
|
||||||
|
# After that, for each special comment between the begin and end
|
||||||
|
# marker, the Tcl statements are executed. It is assumed that
|
||||||
|
# for each comment, the immediately preceding line is executable
|
||||||
|
# C statement. Then, gdb will be single-stepped until that
|
||||||
|
# preceding C statement is executed, and after that the
|
||||||
|
# Tcl statements in the comment will be executed.
|
||||||
|
#
|
||||||
|
# For example:
|
||||||
|
#
|
||||||
|
# /*: BEGIN: assignment-test :*/
|
||||||
|
# v = 10;
|
||||||
|
# /*: <Tcl code to check that 'v' is indeed 10 :*/
|
||||||
|
# /*: END: assignment-test :*/
|
||||||
|
#
|
||||||
|
# The mi_prepare_inline_tests function should be called before
|
||||||
|
# calling this function. A given C file can contain several
|
||||||
|
# inline tests. The names of the tests must be unique within one
|
||||||
|
# C file.
|
||||||
|
#
|
||||||
|
proc mi_run_inline_test { testcase } {
|
||||||
|
|
||||||
|
global mi_gdb_prompt
|
||||||
|
global hex
|
||||||
|
global decimal
|
||||||
|
global fullname_syntax
|
||||||
|
global mi_autotest_source
|
||||||
|
|
||||||
|
set commands [mi_get_inline_test $testcase]
|
||||||
|
|
||||||
|
set first 1
|
||||||
|
set line_now 1
|
||||||
|
|
||||||
|
foreach c $commands {
|
||||||
|
set statements [lindex $c 0]
|
||||||
|
set line [lindex $c 1]
|
||||||
|
set line [expr $line-1]
|
||||||
|
|
||||||
|
# We want gdb to be stopped at the expression immediately
|
||||||
|
# before the comment. If this is the first comment, the
|
||||||
|
# program is either not started yet or is in some random place,
|
||||||
|
# so we run it. For further comments, we might be already
|
||||||
|
# standing at the right line. If not continue till the
|
||||||
|
# right line.
|
||||||
|
|
||||||
|
if {$first==1} {
|
||||||
|
# Start the program afresh.
|
||||||
|
mi_tbreak "$mi_autotest_source:$line"
|
||||||
|
mi_run_cmd
|
||||||
|
set line_now [mi_wait_for_stop "$testcase: step to $line"]
|
||||||
|
set first 0
|
||||||
|
} elseif {$line_now!=$line} {
|
||||||
|
set line_now [mi_continue_to_line "$mi_autotest_source:$line"]
|
||||||
|
}
|
||||||
|
|
||||||
|
if {$line_now!=$line} {
|
||||||
|
fail "$testcase: go to line $line"
|
||||||
|
}
|
||||||
|
|
||||||
|
# We're not at the statement right above the comment.
|
||||||
|
# Execute that statement so that the comment can test
|
||||||
|
# the state after the statement is executed.
|
||||||
|
|
||||||
|
# Single-step past the line.
|
||||||
|
mi_send_resuming_command "exec-next" "$testcase: step over $line"
|
||||||
|
set line_now [mi_wait_for_stop "$testcase: step over $line"]
|
||||||
|
|
||||||
|
# We probably want to use 'uplevel' so that statements
|
||||||
|
# have direct access to global variables that the
|
||||||
|
# main 'exp' file has set up. But it's not yet clear,
|
||||||
|
# will need more experience to be sure.
|
||||||
|
eval $statements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue