Testsuite: add dg-{begin|end}-multiline-output commands
authorDavid Malcolm <dmalcolm@redhat.com>
Fri, 9 Oct 2015 13:55:23 +0000 (13:55 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Fri, 9 Oct 2015 13:55:23 +0000 (13:55 +0000)
This patch adds an easy way to write tests for expected multiline
output.  For example we can test carets and underlines for
a particular diagnostic with:

/* { dg-begin-multiline-output "" }
 typedef struct _GMutex GMutex;
                ^~~~~~~
   { dg-end-multiline-output "" } */

multiline.exp is used by prune.exp; hence we need to load it before
prune.exp via *load_gcc_lib* for the testsuites of the various
non-"gcc" support libraries (e.g. boehm-gc).

gcc/testsuite/ChangeLog:
* lib/multiline.exp: New file.
* lib/prune.exp: Load multiline.exp.
(prune_gcc_output): Call into multiline.exp to handle any
multiline output directives.
* lib/libgo.exp: Load multiline.exp before prune.exp, using
load_gcc_lib.

boehm-gc/ChangeLog:
* testsuite/lib/boehm-gc.exp: Load multiline.exp before
prune.exp, using load_gcc_lib.

libatomic/ChangeLog:
* testsuite/lib/libatomic.exp: Load multiline.exp before
prune.exp, using load_gcc_lib.

libgomp/ChangeLog:
* testsuite/lib/libgomp.exp: Load multiline.exp before prune.exp,
using load_gcc_lib.

libitm/ChangeLog:
* testsuite/lib/libitm.exp: Load multiline.exp before prune.exp,
using load_gcc_lib.

libvtv/ChangeLog:
* testsuite/lib/libvtv.exp: Load multiline.exp before prune.exp,
using load_gcc_lib.

From-SVN: r228655

14 files changed:
boehm-gc/ChangeLog
boehm-gc/testsuite/lib/boehm-gc.exp
gcc/testsuite/ChangeLog
gcc/testsuite/lib/multiline.exp [new file with mode: 0644]
gcc/testsuite/lib/prune.exp
libatomic/ChangeLog
libatomic/testsuite/lib/libatomic.exp
libgo/testsuite/lib/libgo.exp
libgomp/ChangeLog
libgomp/testsuite/lib/libgomp.exp
libitm/ChangeLog
libitm/testsuite/lib/libitm.exp
libvtv/ChangeLog
libvtv/testsuite/lib/libvtv.exp

index e610484ad1e0c43b9122e91066c6bb90f3899fe4..365038e4bfe26bd46c2a04a7b0bd7f3348359998 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/lib/boehm-gc.exp: Load multiline.exp before
+       prune.exp, using load_gcc_lib.
+
 2015-08-27  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * os_dep.c [GC_SOLARIS_THREADS] (GC_dirty_init): Use
index bafe7bb34e8acc2a4d657e310743eb873b24c3f4..d162035b63b2a7a6e80374def2d2fed7cf8689d1 100644 (file)
@@ -31,6 +31,7 @@ load_gcc_lib target-utils.exp
 # For ${tool}_exit.
 load_gcc_lib gcc-defs.exp
 # For prune_gcc_output.
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 
 set dg-do-what-default run
index cca7bdf7c9711ff78f53959a817fe280ec72215a..09da4fdce10cd6c9c11ec6b06cf8a987f19d711a 100644 (file)
@@ -1,3 +1,12 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * lib/multiline.exp: New file.
+       * lib/prune.exp: Load multiline.exp.
+       (prune_gcc_output): Call into multiline.exp to handle any
+       multiline output directives.
+       * lib/libgo.exp: Load multiline.exp before prune.exp, using
+       load_gcc_lib.
+
 2015-10-09  Martin Jambor  <mjambor@suse.cz>
 
        tree-optimization/67794
diff --git a/gcc/testsuite/lib/multiline.exp b/gcc/testsuite/lib/multiline.exp
new file mode 100644 (file)
index 0000000..eb72143
--- /dev/null
@@ -0,0 +1,241 @@
+#   Copyright (C) 2015 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+# Testing of multiline output
+
+# We have pre-existing testcases like this:
+#   |typedef struct _GMutex GMutex; // { dg-message "previously declared here"}
+# (using "|" here to indicate the start of a line),
+# generating output like this:
+#   |gcc/testsuite/g++.dg/diagnostic/wrong-tag-1.C:4:16: note: 'struct _GMutex' was previously declared here
+# where the location of the dg-message determines the expected line at
+# which the error should be reported.
+#
+# To handle rich error-reporting, we want to be able to verify that we
+# get output like this:
+#   |gcc/testsuite/g++.dg/diagnostic/wrong-tag-1.C:4:16: note: 'struct _GMutex' was previously declared here
+#   | typedef struct _GMutex GMutex; // { dg-message "previously declared here"}
+#   |                ^~~~~~~
+# where the compiler's first line of output is as before, but in
+# which it then echoes the source lines, adding annotations.
+#
+# We want to be able to write testcases that verify that the
+# emitted source-and-annotations are sane.
+#
+# A complication here is that the source lines contain comments
+# containing DejaGnu directives (such as the "dg-message" above).
+#
+# We punt this somewhat by only matching the beginnings of lines.
+# so that we can write e.g.
+#   |/* { dg-begin-multiline-output "" }
+#   | typedef struct _GMutex GMutex;
+#   |                ^~~~~~~
+#   |   { dg-end-multiline-output "" } */
+# to have the testsuite verify the expected output.
+
+############################################################################
+# Global variables.  Although global, these are intended to only be used from
+# within multiline.exp.
+############################################################################
+
+# The line number of the last dg-begin-multiline-output directive.
+set _multiline_last_beginning_line -1
+
+# A list of lists of strings.
+set _multiline_expected_outputs []
+
+############################################################################
+# Exported functions.
+############################################################################
+
+# Mark the beginning of an expected multiline output
+# All lines between this and the next dg-end-multiline-output are
+# expected to be seen.
+
+proc dg-begin-multiline-output { args } {
+    global _multiline_last_beginning_line
+    verbose "dg-begin-multiline-output: args: $args" 3
+    set line [expr [lindex $args 0] + 1]
+    set _multiline_last_beginning_line $line
+}
+
+# Mark the end of an expected multiline output
+# All lines up to here since the last dg-begin-multiline-output are
+# expected to be seen.
+
+proc dg-end-multiline-output { args } {
+    global _multiline_last_beginning_line
+    verbose "dg-end-multiline-output: args: $args" 3
+    set line [expr [lindex $args 0] - 1]
+    verbose "multiline output lines: $_multiline_last_beginning_line-$line" 3
+
+    upvar 1 prog prog
+    verbose "prog: $prog" 3
+    # "prog" now contains the filename
+    # Load it and split it into lines
+
+    set lines [_get_lines $prog $_multiline_last_beginning_line $line]
+    set _multiline_last_beginning_line -1
+
+    verbose "lines: $lines" 3
+    global _multiline_expected_outputs
+    lappend _multiline_expected_outputs $lines
+    verbose "within dg-end-multiline-output: _multiline_expected_outputs: $_multiline_expected_outputs" 3
+}
+
+# Hook to be called by prune.exp's prune_gcc_output to
+# look for the expected multiline outputs, pruning them,
+# reporting PASS for those that are found, and FAIL for
+# those that weren't found.
+#
+# It returns a pruned version of its output.
+#
+# It also clears the list of expected multiline outputs.
+
+proc handle-multiline-outputs { text } {
+    global _multiline_expected_outputs
+    set index 0
+    foreach multiline $_multiline_expected_outputs {
+       verbose "  multiline: $multiline" 4
+       set rexp [_build_multiline_regex $multiline $index]
+       verbose "rexp: ${rexp}" 4
+       # Escape newlines in $rexp so that we can print them in
+       # pass/fail results.
+       set escaped_regex [string map {"\n" "\\n"} $rexp]
+       verbose "escaped_regex: ${escaped_regex}" 4
+
+       # Use "regsub" to attempt to prune the pattern from $text
+       if {[regsub -line $rexp $text "" text]} {
+           # Success; the multiline pattern was pruned.
+           pass "expected multiline pattern $index was found: \"$escaped_regex\""
+       } else {
+           fail "expected multiline pattern $index not found: \"$escaped_regex\""
+       }
+
+       set index [expr $index + 1]
+    }
+
+    # Clear the list of expected multiline outputs
+    set _multiline_expected_outputs []
+
+    return $text
+}
+
+############################################################################
+# Internal functions
+############################################################################
+
+# Load FILENAME and extract the lines from FIRST_LINE
+# to LAST_LINE (inclusive) as a list of strings.
+
+proc _get_lines { filename first_line last_line } {
+    verbose "_get_lines" 3
+    verbose "  filename: $filename" 3
+    verbose "  first_line: $first_line" 3
+    verbose "  last_line: $last_line" 3
+
+    set fp [open $filename r]
+    set file_data [read $fp]
+    close $fp
+    set data [split $file_data "\n"]
+    set linenum 1
+    set lines []
+    foreach line $data {
+       verbose "line $linenum: $line" 4
+       if { $linenum >= $first_line && $linenum <= $last_line } {
+           lappend lines $line
+       }
+       set linenum [expr $linenum + 1]
+    }
+
+    return $lines
+}
+
+# Convert $multiline from a list of strings to a multiline regex
+# We need to support matching arbitrary followup text on each line,
+# to deal with comments containing containing DejaGnu directives.
+
+proc _build_multiline_regex { multiline index } {
+    verbose "_build_multiline_regex: $multiline $index" 4
+
+    set rexp ""
+    foreach line $multiline {
+       verbose "  line: $line" 4
+
+       # We need to escape "^" and other regexp metacharacters.
+       set line [string map {"^" "\\^"
+                             "(" "\\("
+                             ")" "\\)"
+                             "[" "\\["
+                             "]" "\\]"
+                             "." "\\."
+                             "\\" "\\\\"
+                             "?" "\\?"
+                             "+" "\\+"
+                             "*" "\\*"
+                             "|" "\\|"} $line]
+
+       append rexp $line
+       if {[string match "*^" $line] || [string match "*~" $line]} {
+           # Assume a line containing a caret/range.  This must be
+           # an exact match.
+       } elseif {[string match "*\\|" $line]} {
+           # Assume a source line with a right-margin.  Support
+           # arbitrary text in place of any whitespace before the
+           # right-margin, to deal with comments containing containing
+           # DejaGnu directives.
+
+           # Remove final "\|":
+           set rexp [string range $rexp 0 [expr [string length $rexp] - 3]]
+
+           # Trim off trailing whitespace:
+           set old_length [string length $rexp]
+           set rexp [string trimright $rexp]
+           set new_length [string length $rexp]
+
+           # Replace the trimmed whitespace with "." chars to match anything:
+           set ws [string repeat "." [expr $old_length - $new_length]]
+           set rexp "${rexp}${ws}"
+
+           # Add back the trailing '\|':
+           set rexp "${rexp}\\|"
+       } else {
+           # Assume that we have a quoted source line.
+           # Support arbitrary followup text on each line,
+           # to deal with comments containing containing DejaGnu
+           # directives.
+           append rexp ".*"
+       }
+       append rexp "\n"
+    }
+
+    # dg.exp's dg-test trims leading whitespace from the output
+    # in this line:
+    #   set comp_output [string trimleft $comp_output]
+    # so we can't rely on the exact leading whitespace for the
+    # first line in the *first* multiline regex.
+    #
+    # Trim leading whitespace from the regexp, replacing it with
+    # a "\s*", to match zero or more whitespace characters.
+    if { $index == 0 } {
+       set rexp [string trimleft $rexp]
+       set rexp "\\s*$rexp"
+    }
+
+    verbose "rexp: $rexp" 4
+
+    return $rexp
+}
index 8e4c203206346d418da86ec181dabe004113ff27..fa10043f6b203000862d6bb4c883956eed1a55dc 100644 (file)
@@ -16,6 +16,8 @@
 
 # Prune messages from gcc that aren't useful.
 
+load_lib multiline.exp
+
 if ![info exists TEST_ALWAYS_FLAGS] {
     set TEST_ALWAYS_FLAGS ""
 }
@@ -68,6 +70,9 @@ proc prune_gcc_output { text } {
     # Ignore harmless warnings from Xcode 4.0.
     regsub -all "(^|\n)\[^\n\]*ld: warning: could not create compact unwind for\[^\n\]*" $text "" text
 
+    # Call into multiline.exp to handle any multiline output directives.
+    set text [handle-multiline-outputs $text]
+
     #send_user "After:$text\n"
 
     return $text
index b187ea177bd450491ede1c7cdc655f24fd00a01e..9ca15c2cc653b903ab70bef3978ffbb59f644ef9 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/lib/libatomic.exp: Load multiline.exp before
+       prune.exp, using load_gcc_lib.
+
 2015-07-14  John Marino  <gnugcc@marino.st>
 
        * configure.tgt: Add *-*-dragonfly to supported targets.
index 0491c188ad4076d8516c7231e6c68307d15579ab..cafab5432b7512e4015a9f6c1ff5ce43805e327a 100644 (file)
@@ -37,6 +37,7 @@ load_gcc_lib scandump.exp
 load_gcc_lib scanrtl.exp
 load_gcc_lib scantree.exp
 load_gcc_lib scanipa.exp
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp
index 7031f635eb1c31a79e9ec25eb4c15a05c92cfd23..1b0f26a68845169d27ba962a09235bd601f8029c 100644 (file)
@@ -39,6 +39,7 @@ proc load_gcc_lib { filename } {
     set loaded_libs($filename) ""
 }
 
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp
index 191f21fd4e025a049b8d96e4ef42bdfd22c94ab6..7440b3e7ba6ccd0ccde54798d6344d19e0ba09d5 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/lib/libgomp.exp: Load multiline.exp before prune.exp,
+       using load_gcc_lib.
+
 2015-10-02  Thomas Schwinge  <thomas@codesourcery.com>
 
        * oacc-ptx.h: Remove file, moving its content into...
index f04b163fafcef3d0d14545f22bf4bd0ad3f30145..1040c29e0ebabaf489e9b1d954cca9673b066a6e 100644 (file)
@@ -14,6 +14,7 @@ load_lib dg.exp
 # loaded until ${tool}_target_compile is defined since it uses that
 # to determine default LTO options.
 
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp
index 6285c85fd44aff37722e6e04c00c2898102f9aaa..2ed540d440a656f06b8f6fa0f41e7e27d03c2e65 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/lib/libitm.exp: Load multiline.exp before prune.exp,
+       using load_gcc_lib.
+
 2015-08-20  Gleb Fotengauer-Malinovskiy  <glebfm@altlinux.org>  (tiny change)
 
        PR libitm/61164
index 1361d56bc6e5148cb079068e894d74835c00884b..041629687f66ff21fd1c860585667cc8a50e80b5 100644 (file)
@@ -28,6 +28,7 @@ load_lib dg.exp
 # loaded until ${tool}_target_compile is defined since it uses that
 # to determine default LTO options.
 
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp
index 529f5afc8202cc6aea5f26a32aaff99265d7951c..6284e134ab2efc660ad01422b0cfda6429d1d287 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-09  David Malcolm  <dmalcolm@redhat.com>
+
+       * testsuite/lib/libvtv.exp: Load multiline.exp before prune.exp,
+       using load_gcc_lib.
+
 2015-08-27  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        Update copyrights.
index aefcbd26ef4fab5b9e4ec03ec7e1d2ddaa45c891..edf5fddbad28271f4f211e54a98a05da7fe836f5 100644 (file)
@@ -28,6 +28,7 @@ load_lib dg.exp
 # loaded until ${tool}_target_compile is defined since it uses that
 # to determine default LTO options.
 
+load_gcc_lib multiline.exp
 load_gcc_lib prune.exp
 load_gcc_lib target-libpath.exp
 load_gcc_lib wrapper.exp