[RFA] Make test names unique in python.exp and guile.exp

Message ID 20200623205159.23461-1-philippe.waroquiers@skynet.be
State New
Headers show
Series
  • [RFA] Make test names unique in python.exp and guile.exp
Related show

Commit Message

Jose E. Marchesi via Gdb-patches June 23, 2020, 8:51 p.m.
Note that gdb_test_multiline and gdb_py_test_multiple are using
the "input line" as the test name, and so when there is a duplicated
input line (such as a line containing "end"), we have duplicated test
names => as gdb_test_multiline and gdb_py_test_multiple are identical,
as indicated in FIXME, move this to gdb.exp, and make the test name unique
by adding the inputnr to the pass message for each input.

YYYY-MM-DD  Philippe Waroquiers  <philippe.waroquiers@skynet.be>

	* lib/gdb.exp (gdb_test_multiline): New, moved from gdb-guile.exp,
	have a seq nr in each pass message.
        * lib/gdb-guile.exp (gdb_test_multiline): Move to gdb.exp.
	* lib/gdb-python.exp (gdb_py_test_multiple): Remove.
	* gdb.python/python.exp: Make test names unique,
	 use gdb_test_multiline instead of gdb_py_test_multiple.
	* gdb.guile/guile.exp: Make test names unique.
---
 gdb/testsuite/gdb.python/python.exp | 50 ++++++++++++++---------------
 gdb/testsuite/lib/gdb-guile.exp     | 20 ------------
 gdb/testsuite/lib/gdb-python.exp    | 19 -----------
 gdb/testsuite/lib/gdb.exp           | 22 +++++++++++++
 4 files changed, 47 insertions(+), 64 deletions(-)

-- 
2.20.1

Comments

Simon Marchi June 23, 2020, 9:32 p.m. | #1
On 2020-06-23 4:51 p.m., Philippe Waroquiers via Gdb-patches wrote:
> Note that gdb_test_multiline and gdb_py_test_multiple are using

> the "input line" as the test name, and so when there is a duplicated

> input line (such as a line containing "end"), we have duplicated test

> names => as gdb_test_multiline and gdb_py_test_multiple are identical,

> as indicated in FIXME, move this to gdb.exp, and make the test name unique

> by adding the inputnr to the pass message for each input.

> 

> YYYY-MM-DD  Philippe Waroquiers  <philippe.waroquiers@skynet.be>

> 

> 	* lib/gdb.exp (gdb_test_multiline): New, moved from gdb-guile.exp,

> 	have a seq nr in each pass message.

>         * lib/gdb-guile.exp (gdb_test_multiline): Move to gdb.exp.

> 	* lib/gdb-python.exp (gdb_py_test_multiple): Remove.

> 	* gdb.python/python.exp: Make test names unique,

> 	 use gdb_test_multiline instead of gdb_py_test_multiple.

> 	* gdb.guile/guile.exp: Make test names unique.

> ---

>  gdb/testsuite/gdb.python/python.exp | 50 ++++++++++++++---------------

>  gdb/testsuite/lib/gdb-guile.exp     | 20 ------------

>  gdb/testsuite/lib/gdb-python.exp    | 19 -----------

>  gdb/testsuite/lib/gdb.exp           | 22 +++++++++++++

>  4 files changed, 47 insertions(+), 64 deletions(-)

> 

> diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp

> index a751787b26..8efecd8655 100644

> --- a/gdb/testsuite/gdb.python/python.exp

> +++ b/gdb/testsuite/gdb.python/python.exp

> @@ -46,7 +46,7 @@ gdb_test_multiple "python print (23)" "verify python support" {

>  	  "source source2.py when python disabled"

>  

>        # Verify multi-line python commands cause an error.

> -      gdb_py_test_multiple "multi-line python command" \

> +      gdb_test_multiline "multi-line python command" \

>  	  "python" "" \

>  	  "print (23)" "" \

>  	  "end" "not supported.*"

> @@ -56,7 +56,7 @@ gdb_test_multiple "python print (23)" "verify python support" {

>      -re "$gdb_prompt $"	{}

>  }

>  

> -gdb_py_test_multiple "multi-line python command" \

> +gdb_test_multiline "multi-line python command" \

>    "python" "" \

>    "print (23)" "" \

>    "end" "23"

> @@ -77,15 +77,15 @@ with_test_prefix "python interactive help" {

>      }

>  }

>  

> -gdb_py_test_multiple "show python command" \

> +gdb_test_multiline "show python command" \

>    "define zzq" "Type commands for definition of .* just \"end\"\\.*" \

>    "python" "" \

>    "print (23)" "" \

> -  "end" "" \

> +  "                     end" "" \


This change is not needed anymore then?

>    "end" "" \

>    "show user zzq" "User command \"zzq\":.*  python.*print \\(23\\).*  end"

>  

> -gdb_py_test_multiple "indented multi-line python command" \

> +gdb_test_multiline "indented multi-line python command" \

>    "python" "" \

>    "def foo ():" "" \

>    "  print ('hello, world!')" "" \

> @@ -124,7 +124,7 @@ gdb_test "python gdb.execute('echo 2\\necho 3\\\\n\\n')" "23" \

>  gdb_test " " "23" "gdb.execute does not affect repeat history"

>  

>  # Test post_event.

> -gdb_py_test_multiple "post event insertion" \

> +gdb_test_multiline "post event insertion" \

>    "python" "" \

>    "someVal = 0" "" \

>    "class Foo(object):" "" \

> @@ -194,7 +194,7 @@ gdb_test "python print (a)" ".*aliases -- User-defined aliases of other commands

>  gdb_py_test_silent_cmd "python nothread = gdb.selected_thread()" "Attempt to aquire thread with no inferior" 1

>  gdb_test "python print (nothread == None)" "True" "ensure that no threads are returned"

>  

> -gdb_py_test_multiple "register atexit function" \

> +gdb_test_multiline "register atexit function" \

>      "python" "" \

>      "import atexit" "" \

>      "def printit(arg):" "" \

> @@ -229,10 +229,10 @@ runto $lineno

>  gdb_test "python gdb.decode_line(\"main.c:43\")" \

>      "gdb.error: No source file named main.c.*" "test decode_line no source named main"

>  

> -gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "test decode_line current location" 1

> -gdb_test "python print (len(symtab))" "2" "test decode_line current location"

> -gdb_test "python print (symtab\[0\])" "None" "test decode_line expression parse"

> -gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line current location"

> +gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "test decode_line current location =" 1

> +gdb_test "python print (len(symtab))" "2" "test decode_line current location len"

> +gdb_test "python print (symtab\[0\])" "None" "test decode_line expression parse None"

> +gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line current location len 1"


I think it would make sense to use with_test_prefix here, instead of repeating
test decode_line current location.  And the test name should be at least a bit
descriptive of what we test.  This is what I would write:

with_test_prefix "test decode_line current location" {
    gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "decode current line" 1
    gdb_test "python print (len(symtab))" "2" "length of result"
    gdb_test "python print (symtab\[0\])" "None" "no unparsed text"
    gdb_test "python print (len(symtab\[1\]))" "1" "length of result locations"
}

That could apply to other cases below in this file as well.

> diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp

> index 7b243f5fff..12886c43f1 100644

> --- a/gdb/testsuite/lib/gdb.exp

> +++ b/gdb/testsuite/lib/gdb.exp

> @@ -1236,6 +1236,28 @@ proc gdb_test_multiple { command message args } {

>      return $result

>  }

>  

> +# Usage: gdb_test_multiline NAME INPUT RESULT {INPUT RESULT} ...

> +# Run a test named NAME, consisting of multiple lines of input.

> +# After each input line INPUT, search for result line RESULT.

> +# Succeed if all results are seen; fail otherwise.

> +

> +proc gdb_test_multiline { name args } {

> +    global gdb_prompt

> +    set inputnr 0

> +    foreach {input result} $args {

> +	set inputnr [expr ${inputnr} + 1]


You can use `incr inputnr`

> +	if {[gdb_test_multiple $input "$name - $input" {

> +	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {

> +		pass "$name - $input (input nr $inputnr)"


The test name passed as the second argument of `gdb_test_multiple` and the test
name passed to `pass` should match.  This is why the special variable $gdb_test_name
was added, to avoid potential mismatches.  You can use "pass $gdb_test_name" inside
the gdb_test_multiple body.

Simon
Jose E. Marchesi via Gdb-patches June 23, 2020, 9:43 p.m. | #2
On 6/23/20 10:32 PM, Simon Marchi wrote:
> On 2020-06-23 4:51 p.m., Philippe Waroquiers via Gdb-patches wrote:

>> +	if {[gdb_test_multiple $input "$name - $input" {

>> +	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {

>> +		pass "$name - $input (input nr $inputnr)"

> 

> The test name passed as the second argument of `gdb_test_multiple` and the test

> name passed to `pass` should match.  This is why the special variable $gdb_test_name

> was added, to avoid potential mismatches.  You can use "pass $gdb_test_name" inside

> the gdb_test_multiple body.


Text within the "(xxx)" at the end is considered informational, not
part of the test name, though.  That's why we avoid trailing parens
in general.  So in this case they do match.  Just like these match:

 PASS: foo
 FAIL: foo (timeout)

Still a good idea to write:

 pass "$gdb_test_name (input nr $inputnr)"

though.

There were other cases in the patch that didn't match though.  Like:

>  gdb_test_multiple "python gdb.prompt_hook = prompt" "set the hook" {

>      -re "\[\r\n\]$newprompt $" {

> -	pass "set hook"

> +	pass "set hook prompt"

>      }

>  }


Here this can result in either:

 FAIL: set the hook
 PASS: set hook prompt

Pedro Alves
Simon Marchi June 23, 2020, 9:56 p.m. | #3
On 2020-06-23 5:43 p.m., Pedro Alves wrote:
> On 6/23/20 10:32 PM, Simon Marchi wrote:

>> On 2020-06-23 4:51 p.m., Philippe Waroquiers via Gdb-patches wrote:

>>> +	if {[gdb_test_multiple $input "$name - $input" {

>>> +	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {

>>> +		pass "$name - $input (input nr $inputnr)"

>>

>> The test name passed as the second argument of `gdb_test_multiple` and the test

>> name passed to `pass` should match.  This is why the special variable $gdb_test_name

>> was added, to avoid potential mismatches.  You can use "pass $gdb_test_name" inside

>> the gdb_test_multiple body.

> 

> Text within the "(xxx)" at the end is considered informational, not

> part of the test name, though.  That's why we avoid trailing parens

> in general.  So in this case they do match.  Just like these match:

> 

>  PASS: foo

>  FAIL: foo (timeout)

> 

> Still a good idea to write:

> 

>  pass "$gdb_test_name (input nr $inputnr)"

> 

> though.


But here we want to use $inputnr to really differentiate the names of
the tests, because $input is a command to execute.  So if two commands to
execute are "end", we would end up with

  PASS: something - end (input nr 0)
  PASS: something - end (input nr 1)

which would be wrongfully considered as the same test.  So I think we need
inputnr to be part of the test name, not in parenthesis.  Maybe

  $name: input $inputnr: $input

?

Simon
Jose E. Marchesi via Gdb-patches June 24, 2020, 11:28 a.m. | #4
On 6/23/20 10:56 PM, Simon Marchi wrote:
> On 2020-06-23 5:43 p.m., Pedro Alves wrote:

>> On 6/23/20 10:32 PM, Simon Marchi wrote:

>>> On 2020-06-23 4:51 p.m., Philippe Waroquiers via Gdb-patches wrote:

>>>> +	if {[gdb_test_multiple $input "$name - $input" {

>>>> +	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {

>>>> +		pass "$name - $input (input nr $inputnr)"

>>>

>>> The test name passed as the second argument of `gdb_test_multiple` and the test

>>> name passed to `pass` should match.  This is why the special variable $gdb_test_name

>>> was added, to avoid potential mismatches.  You can use "pass $gdb_test_name" inside

>>> the gdb_test_multiple body.

>>

>> Text within the "(xxx)" at the end is considered informational, not

>> part of the test name, though.  That's why we avoid trailing parens

>> in general.  So in this case they do match.  Just like these match:

>>

>>  PASS: foo

>>  FAIL: foo (timeout)

>>

>> Still a good idea to write:

>>

>>  pass "$gdb_test_name (input nr $inputnr)"

>>

>> though.

> 

> But here we want to use $inputnr to really differentiate the names of

> the tests, because $input is a command to execute.  So if two commands to

> execute are "end", we would end up with

> 

>   PASS: something - end (input nr 0)

>   PASS: something - end (input nr 1)

> 

> which would be wrongfully considered as the same test.  So I think we need

> inputnr to be part of the test name, not in parenthesis.  Maybe

> 

>   $name: input $inputnr: $input

Hmm, yeah.  I didn't realize that command issues a PASS for each of the
the lines.  That looks good to me.

Thanks,
Pedro Alves

Patch

diff --git a/gdb/testsuite/gdb.python/python.exp b/gdb/testsuite/gdb.python/python.exp
index a751787b26..8efecd8655 100644
--- a/gdb/testsuite/gdb.python/python.exp
+++ b/gdb/testsuite/gdb.python/python.exp
@@ -46,7 +46,7 @@  gdb_test_multiple "python print (23)" "verify python support" {
 	  "source source2.py when python disabled"
 
       # Verify multi-line python commands cause an error.
-      gdb_py_test_multiple "multi-line python command" \
+      gdb_test_multiline "multi-line python command" \
 	  "python" "" \
 	  "print (23)" "" \
 	  "end" "not supported.*"
@@ -56,7 +56,7 @@  gdb_test_multiple "python print (23)" "verify python support" {
     -re "$gdb_prompt $"	{}
 }
 
-gdb_py_test_multiple "multi-line python command" \
+gdb_test_multiline "multi-line python command" \
   "python" "" \
   "print (23)" "" \
   "end" "23"
@@ -77,15 +77,15 @@  with_test_prefix "python interactive help" {
     }
 }
 
-gdb_py_test_multiple "show python command" \
+gdb_test_multiline "show python command" \
   "define zzq" "Type commands for definition of .* just \"end\"\\.*" \
   "python" "" \
   "print (23)" "" \
-  "end" "" \
+  "                     end" "" \
   "end" "" \
   "show user zzq" "User command \"zzq\":.*  python.*print \\(23\\).*  end"
 
-gdb_py_test_multiple "indented multi-line python command" \
+gdb_test_multiline "indented multi-line python command" \
   "python" "" \
   "def foo ():" "" \
   "  print ('hello, world!')" "" \
@@ -124,7 +124,7 @@  gdb_test "python gdb.execute('echo 2\\necho 3\\\\n\\n')" "23" \
 gdb_test " " "23" "gdb.execute does not affect repeat history"
 
 # Test post_event.
-gdb_py_test_multiple "post event insertion" \
+gdb_test_multiline "post event insertion" \
   "python" "" \
   "someVal = 0" "" \
   "class Foo(object):" "" \
@@ -194,7 +194,7 @@  gdb_test "python print (a)" ".*aliases -- User-defined aliases of other commands
 gdb_py_test_silent_cmd "python nothread = gdb.selected_thread()" "Attempt to aquire thread with no inferior" 1
 gdb_test "python print (nothread == None)" "True" "ensure that no threads are returned"
 
-gdb_py_test_multiple "register atexit function" \
+gdb_test_multiline "register atexit function" \
     "python" "" \
     "import atexit" "" \
     "def printit(arg):" "" \
@@ -229,10 +229,10 @@  runto $lineno
 gdb_test "python gdb.decode_line(\"main.c:43\")" \
     "gdb.error: No source file named main.c.*" "test decode_line no source named main"
 
-gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "test decode_line current location" 1
-gdb_test "python print (len(symtab))" "2" "test decode_line current location"
-gdb_test "python print (symtab\[0\])" "None" "test decode_line expression parse"
-gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line current location"
+gdb_py_test_silent_cmd "python symtab = gdb.decode_line()" "test decode_line current location =" 1
+gdb_test "python print (len(symtab))" "2" "test decode_line current location len"
+gdb_test "python print (symtab\[0\])" "None" "test decode_line expression parse None"
+gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line current location len 1"
 
 # Test that decode_line with an empty string argument does not crash.
 gdb_py_test_silent_cmd "python symtab2 = gdb.decode_line('')" \
@@ -246,18 +246,18 @@  if { [is_remote host] } {
 gdb_test "python print (symtab\[1\]\[0\].symtab)" ".*${python_c}" "test decode_line current location filename"
 gdb_test "python print (symtab\[1\]\[0\].line)" "$lineno" "test decode_line current location line number"
 
-gdb_py_test_silent_cmd "python symtab = gdb.decode_line(\"python.c:26 if foo\")" "test decode_line python.c:26" 1
-gdb_test "python print (len(symtab))" "2" "test decode_line python.c:26 length"
+gdb_py_test_silent_cmd "python symtab = gdb.decode_line(\"python.c:26 if foo\")" "test decode_line python.c:26 decode" 1
+gdb_test "python print (len(symtab))" "2" "test decode_line python.c:26 length 2"
 gdb_test "python print (symtab\[0\])" "if foo" "test decode_line expression parse"
-gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line python.c:26 length"
+gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line python.c:26 length 1"
 gdb_test "python print (symtab\[1\]\[0\].symtab)" ".*${python_c}" "test decode_line python.c:26 filename"
 gdb_test "python print (symtab\[1\]\[0\].line)" "26" "test decode_line python.c:26 line number"
 
 gdb_test "python gdb.decode_line(\"randomfunc\")" \
     "gdb.error: Function \"randomfunc\" not defined.*" "test decode_line randomfunc"
 gdb_py_test_silent_cmd "python symtab = gdb.decode_line(\"func1\")" "test decode_line func1()" 1
-gdb_test "python print (len(symtab))" "2" "test decode_line func1 length"
-gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line func1 length"
+gdb_test "python print (len(symtab))" "2" "test decode_line func1 length 2"
+gdb_test "python print (len(symtab\[1\]))" "1" "test decode_line func1 length 1"
 
 if { [is_remote host] } {
     set python_1_c [string_to_regexp "python-1.c"]
@@ -308,7 +308,7 @@  gdb_py_test_silent_cmd "set python print-stack full" \
 
 # Test prompt substituion
 
-gdb_py_test_multiple "prompt substitution" \
+gdb_test_multiline "prompt substitution" \
   "python" "" \
   "someCounter = 0" "" \
   "def prompt(current):" "" \
@@ -319,7 +319,7 @@  gdb_py_test_multiple "prompt substitution" \
   "   return \"py prompt \" + str (someCounter) + \" \"" "" \
   "end" ""
 
-gdb_py_test_multiple "prompt substitution readline" \
+gdb_test_multiline "prompt substitution readline" \
   "python" "" \
   "pCounter = 0" "" \
   "def program_prompt(current):" "" \
@@ -336,7 +336,7 @@  set testfake "testfake"
 
 gdb_test_multiple "python gdb.prompt_hook = prompt" "set the hook" {
     -re "\[\r\n\]$newprompt $" {
-	pass "set hook"
+	pass "set hook prompt"
     }
 }
 
@@ -395,7 +395,7 @@  gdb_test_multiple "end" "end programming" {
     }
 }
 
-gdb_py_test_multiple "prompt substitution readline" \
+gdb_test_multiline "prompt substitution readline import" \
   "python" "" \
   "import gdb.command.prompt" "" \
   "end" ""
@@ -449,7 +449,7 @@  gdb_test "show python print-stack" \
 gdb_py_test_silent_cmd "set python print-stack message" \
     "Test print-stack set setting to message" 1
 
-gdb_py_test_multiple "prompt substitution readline" \
+gdb_test_multiline "prompt substitution readline error_prompt" \
   "python" "" \
   "pCounter = 0" "" \
   "def error_prompt(current):" "" \
@@ -458,24 +458,24 @@  gdb_py_test_multiple "prompt substitution readline" \
 
 gdb_test_multiple "python gdb.prompt_hook = error_prompt" "set the hook" {
     -re "Python Exception (exceptions.RuntimeError|<(type 'exceptions.|class ')RuntimeError'>) Python exception called.*$gdb_prompt $" {
-	pass "set hook"
+	pass "set hook error_prompt"
     }
 }
 
 gdb_py_test_silent_cmd "python gdb.prompt_hook = None" \
-    "set the hook to default" 1
+    "set the hook to default 1" 1
 
 gdb_py_test_silent_cmd "set python print-stack full" \
     "set print-stack full for prompt error test" 1
 
 gdb_test_multiple "python gdb.prompt_hook = error_prompt" "set the hook" {
     -re "Traceback.*File.*line.*RuntimeError.*Python exception called.*$gdb_prompt $" {
-	pass "set hook"
+	pass "set hook error_prompt traceback"
     }
 }
 
 gdb_py_test_silent_cmd "python gdb.prompt_hook = None" \
-    "set the hook to default" 1
+    "set the hook to default 2" 1
 
 # Start with a fresh gdb.
 clean_restart ${testfile}
diff --git a/gdb/testsuite/lib/gdb-guile.exp b/gdb/testsuite/lib/gdb-guile.exp
index bda994b74c..ab6277b45a 100644
--- a/gdb/testsuite/lib/gdb-guile.exp
+++ b/gdb/testsuite/lib/gdb-guile.exp
@@ -54,26 +54,6 @@  proc gdb_scm_test_silent_cmd { cmd name {report_pass 1} } {
     }
 }
 
-# Usage: gdb_test_multiline NAME INPUT RESULT {INPUT RESULT} ...
-# Run a test named NAME, consisting of multiple lines of input.
-# After each input line INPUT, search for result line RESULT.
-# Succeed if all results are seen; fail otherwise.
-# FIXME: Move to gdb.exp and remove Python's gdb_py_test_multiple.
-
-proc gdb_test_multiline { name args } {
-    global gdb_prompt
-    foreach {input result} $args {
-	if {[gdb_test_multiple $input "$name - $input" {
-	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
-		pass "$name - $input"
-	    }
-	}]} {
-	    return 1
-	}
-    }
-    return 0
-}
-
 # Load Scheme file FILE_NAME.
 # TEST_NAME can be used to specify the name of the test,
 # otherwise a standard test name is provided.
diff --git a/gdb/testsuite/lib/gdb-python.exp b/gdb/testsuite/lib/gdb-python.exp
index 2408f2e221..b41032feb2 100644
--- a/gdb/testsuite/lib/gdb-python.exp
+++ b/gdb/testsuite/lib/gdb-python.exp
@@ -27,25 +27,6 @@  proc gdb_py_test_silent_cmd { cmd name report_pass } {
     }
 }
 
-# Usage: gdb_py_test_multiple NAME INPUT RESULT {INPUT RESULT}...
-# Run a test named NAME, consisting of multiple lines of input.
-# After each input line INPUT, search for result line RESULT.
-# Succeed if all results are seen; fail otherwise.
-
-proc gdb_py_test_multiple { name args } {
-    global gdb_prompt
-    foreach {input result} $args {
-	if {[gdb_test_multiple $input "$name - $input" {
-	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
-		pass "$name - $input"
-	    }
-	}]} {
-	    return 1
-	}
-    }
-    return 0
-}
-
 # Return the result of python expression EXPR.  DEFAULT is returned if
 # there's an error.  TEST is the test message to use.  It can be
 # omitted, in which case a test message is built from EXP.  This is
diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp
index 7b243f5fff..12886c43f1 100644
--- a/gdb/testsuite/lib/gdb.exp
+++ b/gdb/testsuite/lib/gdb.exp
@@ -1236,6 +1236,28 @@  proc gdb_test_multiple { command message args } {
     return $result
 }
 
+# Usage: gdb_test_multiline NAME INPUT RESULT {INPUT RESULT} ...
+# Run a test named NAME, consisting of multiple lines of input.
+# After each input line INPUT, search for result line RESULT.
+# Succeed if all results are seen; fail otherwise.
+
+proc gdb_test_multiline { name args } {
+    global gdb_prompt
+    set inputnr 0
+    foreach {input result} $args {
+	set inputnr [expr ${inputnr} + 1]
+	if {[gdb_test_multiple $input "$name - $input" {
+	    -re "\[\r\n\]*($result)\[\r\n\]+($gdb_prompt | *>)$" {
+		pass "$name - $input (input nr $inputnr)"
+	    }
+	}]} {
+	    return 1
+	}
+    }
+    return 0
+}
+
+
 # gdb_test COMMAND PATTERN MESSAGE QUESTION RESPONSE
 # Send a command to gdb; test the result.
 #