On Tue, 18 Mar 2025, Jakub Jelinek wrote: > Hi! > > The COBOL tests has many tests which just dump emit lots of output > to stdout and want to compare it against expected output. > We have the dg-output directive, but if one needs more than dozens > of lines in the output, adding hundreds of dg-output directives to > each source uses too much memory and is harder to maintain. > > The following patch offers an alternative, dg-output-file > directive where one can supply a text file with expected output > (no regexp matching in that case, just exact output, except that it > handles different line ending styles (for the expected file > using tcl gets, for the actual output skips over \n, \r\n or \r). > And a newline at the end of the whole output is optional (in the actual > output, because I think some boards get it eaten). > > Tested on x86_64-linux and i686-linux, ok for trunk?
LGTM. Thanks, Richard. > Also tested with addition or subtraction of some characters from the > expected output files and saw FAILs with appropriate messages. > > 2025-03-18 Jakub Jelinek <ja...@redhat.com> > > * doc/sourcebuild.texi (dg-output-file): Document. > > * lib/gcc-dg.exp (${tool}-load): If output-file is set, compare > combined output against content of the [lindex ${output-file} 1] > file. > (dg-output-file): New directive. > * lib/dg-test-cleanup.exp (cleanup-after-saved-dg-test): Clear > output-file variable. > * gcc.dg/dg-output-file-1.c: New test. > * gcc.dg/dg-output-file-1-lp64.txt: New test. > * gcc.dg/dg-output-file-1-ilp32.txt: New test. > > --- gcc/doc/sourcebuild.texi.jj 2025-03-11 09:18:21.750133577 +0100 > +++ gcc/doc/sourcebuild.texi 2025-03-18 14:41:59.253345259 +0100 > @@ -1315,6 +1315,10 @@ Prune messages matching @var{regexp} fro > @item @{ dg-output @var{regexp} [@{ target/xfail @var{selector} @}] @} > This DejaGnu directive compares @var{regexp} to the combined output > that the test executable writes to @file{stdout} and @file{stderr}. > + > +@item @{ dg-output-file @var{file} [@{ target/xfail @var{selector} @}] @} > +Compares the content of @var{file} against the combined output that the > +test executable writes to @file{stdout} and @file{stderr}. > @end table > > @subsubsection Specify environment variables for a test > --- gcc/testsuite/lib/gcc-dg.exp.jj 2025-03-13 14:05:09.707017142 +0100 > +++ gcc/testsuite/lib/gcc-dg.exp 2025-03-18 14:37:32.476088575 +0100 > @@ -473,6 +473,7 @@ if { [info procs ${tool}_load] != [list] > global tool > global shouldfail > global set_target_env_var > + global output-file > > set saved_target_env_var [list] > if { [info exists set_target_env_var] \ > @@ -497,6 +498,75 @@ if { [info procs ${tool}_load] != [list] > } > > set result [list [lindex $result 0] [prune_file_path [lindex $result > 1]]] > + if { [info exists output-file] && [lindex $result 0] eq "pass" } { > + if { [lindex ${output-file} 0] eq "F" } { > + setup_xfail "*-*-*" > + } > + set output [lindex $result 1] > + set idx 0 > + set linenum 1 > + set outfile [open [lindex ${output-file} 1]] > + set do_fail 0 > + set name [file tail [lindex ${output-file} 1]] > + verbose "output-file args is $args program is $program" 1 > + while { [gets $outfile line] >= 0 } { > + if { $linenum != 1 } { > + set c [string index $output $idx] > + if { $c eq "\n" } { > + set idx [expr $idx + 1] > + } elseif { $c eq "\r" } { > + set idx [expr $idx + 1] > + set c [string index $output $idx] > + if { $c eq "\n" } { > + set idx [expr $idx + 1] > + } > + } else { > + set do_fail 1 > + fail "$name output file test" > + send_log "Unexpected character $c on line [expr > $linenum - 1] where new-line expected\n" > + verbose "Failed test for output line [expr $linenum - > 1]" 3 > + break > + } > + } > + set len [string length $line] > + set output_line [string range $output $idx [expr $idx + $len - > 1]] > + if { $line ne $output_line } { > + set do_fail 1 > + fail "$name output file test" > + send_log "Output line $linenum was:\n$output_line\nShould > match (from [lindex ${output-file} 1]):\n$line\n" > + verbose "Failed test for output line $linenum $line" 3 > + break > + } > + set idx [expr $idx + $len] > + incr linenum > + } > + close $outfile > + if { $do_fail == 0 } { > + set c [string index $output $idx] > + if { $c eq "\n" } { > + set idx [expr $idx + 1] > + } elseif { $c eq "\r" } { > + set idx [expr $idx + 1] > + set c [string index $output $idx] > + if { $c eq "\n" } { > + set idx [expr $idx + 1] > + } > + } else { > + incr linenum -1 > + } > + set c [string index $output $idx] > + if { $c ne "" } { > + fail "$name output file test" > + send_log "Unexpected character $c on line $linenum where > and of output expected\n" > + verbose "Failed test for output line $linenum" 3 > + break > + } else { > + pass "$name output file test" > + verbose "Passed test for output file [lindex ${output-file} > 1]" 3 > + } > + } > + unset output > + } > return $result > } > } > @@ -575,6 +645,35 @@ proc restore-compiler-env-var { } { > } > } > > +# Indicate expected program output in a file. > +# > +proc dg-output-file { args } { > + global output-file > + global srcdir subdir > + > + if { [llength $args] > 3 } { > + error "[lindex $args 0]: too many arguments" > + } > + > + # Allow target dependent output. > + > + if { ![info exists output-file] } { > + set output-file "P" > + } > + set expected [lindex ${output-file} 0] > + if { [llength $args] >= 3 } { > + switch -- [dg-process-target [lindex $args 2]] { > + "N" { return } > + "S" { } > + "F" { set expected "F" } > + # Don't override a previous xfail. > + "P" { } > + } > + } > + > + set output-file [list $expected $srcdir/$subdir/[lindex $args 1]] > +} > + > # Utility routines. > > # > --- gcc/testsuite/lib/dg-test-cleanup.exp.jj 2025-01-02 11:47:41.684062215 > +0100 > +++ gcc/testsuite/lib/dg-test-cleanup.exp 2025-03-18 12:05:55.714299937 > +0100 > @@ -45,6 +45,7 @@ if { [info procs saved-dg-test] == [list > global multiline_expected_outputs > global freeform_regexps > global save_linenr_varnames > + global output-file > > set additional_files "" > set additional_sources "" > @@ -70,6 +71,9 @@ if { [info procs saved-dg-test] == [list > if [info exists testname_with_flags] { > unset testname_with_flags > } > + if [info exists output-file] { > + unset output-file > + } > set nn_line_numbers_enabled 0 > set multiline_expected_outputs [] > set freeform_regexps [] > --- gcc/testsuite/gcc.dg/dg-output-file-1.c.jj 2025-03-18 > 12:30:38.355563473 +0100 > +++ gcc/testsuite/gcc.dg/dg-output-file-1.c 2025-03-18 12:48:26.306636698 > +0100 > @@ -0,0 +1,13 @@ > +/* { dg-do run { target { lp64 || ilp32 } } } */ > +/* { dg-options "-O2" } */ > +/* { dg-output-file "dg-output-file-1-lp64.txt" { target lp64 } } */ > +/* { dg-output-file "dg-output-file-1-ilp32.txt" { target ilp32 } } */ > + > +int > +main () > +{ > + __builtin_printf ("This is a test output for %s target\n" > + "to verify\n" > + "dg-output-file directive\n", > + __SIZEOF_LONG__ * __CHAR_BIT__ == 64 ? "lp64" : "ilp32"); > +} > --- gcc/testsuite/gcc.dg/dg-output-file-1-lp64.txt.jj 2025-03-18 > 12:31:08.514141366 +0100 > +++ gcc/testsuite/gcc.dg/dg-output-file-1-lp64.txt 2025-03-18 > 12:32:12.080251677 +0100 > @@ -0,0 +1,3 @@ > +This is a test output for lp64 target > +to verify > +dg-output-file directive > --- gcc/testsuite/gcc.dg/dg-output-file-1-ilp32.txt.jj 2025-03-18 > 12:31:38.841716894 +0100 > +++ gcc/testsuite/gcc.dg/dg-output-file-1-ilp32.txt 2025-03-18 > 14:37:50.289838618 +0100 > @@ -0,0 +1,3 @@ > +This is a test output for ilp32 target > +to verify > +dg-output-file directive > > Jakub > > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstrasse 146, 90461 Nuernberg, Germany; GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)