1 # Copyright (C) 1992-2019, 2020 Free Software Foundation, Inc.
3 # This file is part of DejaGnu.
5 # DejaGnu is free software: you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # the Free Software Foundation, either version 3 of the License, or
8 # (at your option) any later version.
10 # DejaGnu is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with DejaGnu. If not, see <http://www.gnu.org/licenses/>.
18 # This file was originally written by Rob Savoye <rob@welcomehome.org>.
20 ## Internal infrastructure
22 namespace eval ::dejagnu::group {
27 proc ::dejagnu::group::check_name { name } {
28 return [string is graph -strict $name]
31 proc ::dejagnu::group::current {} {
33 return [join $names "/"]
36 proc ::dejagnu::group::push { name file } {
42 proc ::dejagnu::group::pop { name file } {
46 if { $file ne [lindex $files end]
47 || $name ne [lindex $names end] } {
48 error "expected to close group {$name} from {$file}\n\
49 actually found group {[lindex $names end]}\
50 from {[lindex $files end]}"
52 set names [lreplace $names end end]
53 set files [lreplace $files end end]
56 proc ::dejagnu::group::pop_to_file { file } {
60 while { $file ne [lindex $files end] } {
61 perror "closing forgotten group {[::dejagnu::group::current]}\
62 from {[lindex $files end]}" 0
63 set names [lreplace $names end end]
64 set files [lreplace $files end end]
65 if { [llength $names] < 1 } {
66 error "no more groups while unwinding to file $file"
71 ## General code; not yet sorted under headings
73 # These variables are local to this file.
74 # This or more warnings and a test fails.
75 set warning_threshold 3
76 # This or more errors and a test fails.
77 set perror_threshold 1
79 proc mail_file { file to subject } {
80 if {[file readable $file]} {
81 catch "exec mail -s \"$subject\" $to < $file"
85 # Insert DTD for xml format checking.
88 xml_output "<!DOCTYPE testsuite \[
89 <!-- testsuite.dtd -->
90 <!ELEMENT testsuite (test | summary)+>
91 <!ELEMENT test (input, output, result, name, prms_id )>
92 <!ELEMENT input (#PCDATA)>
93 <!ELEMENT output (#PCDATA)>
94 <!ELEMENT result (#PCDATA)>
95 <!ELEMENT name (#PCDATA)>
96 <!ELEMENT prms_id (#PCDATA)>
97 <!ELEMENT summary (result, description, total)>
98 <!ELEMENT description (#PCDATA)>
99 <!ELEMENT total (#PCDATA)>
103 # Open the output logs.
115 catch "file delete -force -- $outdir/$tool.sum"
116 set sum_file [open [file join $outdir $tool.sum] w]
118 catch "file delete -force -- $outdir/$tool.xml"
119 set xml_file [open [file join $outdir $tool.xml] w]
120 xml_output "<?xml version=\"1.1\"?>"
122 xml_output "<testsuite>"
124 catch "file delete -force -- $outdir/$tool.log"
125 log_file -a $outdir/$tool.log
126 verbose "Opening log files in $outdir"
127 if { $tool eq "testrun" } {
130 fconfigure $sum_file -buffering line
133 # Close the output logs.
135 proc close_logs { } {
141 xml_output "</testsuite>"
142 catch "close $xml_file"
145 catch "close $sum_file"
148 # Check build host triplet for PATTERN.
149 # With no arguments it returns the triplet string.
151 proc isbuild { { pattern "" } } {
155 if {![info exists build_triplet]} {
156 set build_triplet $host_triplet
158 if {$pattern eq ""} {
159 return $build_triplet
161 verbose "Checking pattern \"$pattern\" with $build_triplet" 2
163 if {[string match $pattern $build_triplet]} {
170 # Is $board remote? Return a non-zero value if so.
172 proc isremote { board } {
173 verbose "calling isremote $board" 3
174 return [is_remote $board]
177 # Legacy library proc for isremote.
179 proc is_remote { board } {
183 verbose "calling is_remote $board" 3
184 # Remove any target variant specifications from the name.
185 set board [lindex [split $board "/"] 0]
187 # Map the host or build back into their short form.
188 if { [board_info build name] eq $board } {
190 } elseif { [board_info host name] eq $board } {
194 # We're on the "build". The check for the empty string is just for
195 # paranoia's sake--we shouldn't ever get one. "unix" is a magic
196 # string that should really go away someday.
197 if { $board eq "build" || $board eq "unix" || $board eq "" } {
198 verbose "board is $board, not remote" 3
202 if { $board eq "host" } {
203 if { [info exists host_board] && $host_board ne "" } {
204 verbose "board is $board, is remote" 3
207 verbose "board is $board, host is local" 3
212 if { $board eq "target" } {
213 global current_target_name
215 if {[info exists current_target_name]} {
216 # This shouldn't happen, but we'll be paranoid anyway.
217 if { $current_target_name ne "target" } {
218 return [is_remote $current_target_name]
223 if {[board_info $board exists isremote]} {
224 verbose "board is $board, isremote is [board_info $board isremote]" 3
225 return [board_info $board isremote]
230 # If this is a Canadian (3 way) cross. This means the tools are
231 # being built with a cross compiler for another host.
237 if {![info exists build_triplet]} {
238 set build_triplet $host_triplet
240 verbose "Checking $host_triplet against $build_triplet" 2
241 if { $build_triplet eq $host_triplet } {
247 # Check host triplet for PATTERN.
248 # With no arguments it returns the triplet string.
250 proc ishost { { pattern "" } } {
253 if {$pattern eq ""} {
256 verbose "Checking pattern \"$pattern\" with $host_triplet" 2
258 if {[string match $pattern $host_triplet]} {
265 # Check target triplet for pattern.
267 # With no arguments it returns the triplet string.
268 # Returns 1 if the target looked for, or 0 if not.
270 proc istarget { { args "" } } {
271 global target_triplet
273 # if no arg, return the config string
275 if {[info exists target_triplet]} {
276 return $target_triplet
278 perror "No target configuration names found."
282 set triplet [lindex $args 0]
284 # now check against the canonical name
285 if {[info exists target_triplet]} {
286 verbose "Checking \"$triplet\" against \"$target_triplet\"" 2
287 if {[string match $triplet $target_triplet]} {
296 # Check to see if we're running the tests in a native environment
297 # Returns 1 if running native, 0 if on a target.
300 global target_triplet
303 return [string equal $build_triplet $target_triplet]
306 # unknown -- called by expect if a proc is called that doesn't exist
308 # Rename unknown to tcl_unknown so that we can wrap tcl_unknown.
309 # This allows Tcl package autoloading to work in the modern age.
311 rename ::unknown ::tcl_unknown
312 proc unknown { args } {
317 set code [catch {uplevel 1 ::tcl_unknown $args} msg]
319 set ret_cmd [list return -code $code]
321 # If the command now exists, then it was autoloaded. We are here,
322 # therefore invoking the autoloaded command raised an error.
323 # Silently propagate errors from autoloaded procedures, but
324 # complain noisily about undefined commands.
325 set have_it_now [llength [info commands [lindex $args 0]]]
327 if { ! $have_it_now } {
328 clone_output "ERROR: (DejaGnu) proc \"$args\" does not exist."
332 if { [info exists errorCode] } {
333 lappend ret_cmd -errorcode $errorCode
334 if { ! $have_it_now } {
335 send_error "The error code is $errorCode\n"
338 if { [info exists errorInfo] } {
339 # omitting errorInfo from the propagated error makes this proc
340 # invisible with the backtrace pointing directly to the problem
341 if { ! $have_it_now } {
342 send_error "The info on the error is:\n$errorInfo\n"
350 # Propagate return value.
355 # Print output to stdout (or stderr) and to log file
357 # If the --all flag (-a) option was used then all messages go the the screen.
358 # Without this, all messages that start with a keyword are written only to the
359 # detail log file. All messages that go to the screen will also appear in the
360 # detail log. This should only be used by the framework itself using pass,
361 # fail, xpass, xfail, kpass, kfail, warning, perror, note, untested, unresolved,
362 # or unsupported procedures.
364 proc clone_output { message } {
368 if { $sum_file ne "" } {
369 puts $sum_file $message
372 regsub "^\[ \t\]*(\[^ \t\]+).*$" $message "\\1" firstword
373 switch -glob -- $firstword {
381 send_user -- "$message\n"
384 send_log -- "$message\n"
390 send_error -- "$message\n"
394 send_user -- "$message\n"
400 # Reset a few counters.
403 global test_names test_counts
404 global warncnt errcnt
406 # other miscellaneous variables
415 foreach x $test_names {
416 set test_counts($x,count) 0
419 # Variables local to this file.
420 global warning_threshold perror_threshold
421 set warning_threshold 3
422 set perror_threshold 1
425 proc log_and_exit {} {
427 global tool mail_logs outdir mailing_list
430 # extract version number
431 if {[info procs ${tool}_version] ne ""} {
432 if {[catch ${tool}_version output]} {
433 warning "${tool}_version failed:\n$output"
436 if {[llength $::dejagnu::error::list] > 0} {
437 # print errors again at end of output
438 foreach { cell } $::dejagnu::error::list {
439 clone_output "ERROR: [string repeat - 43]"
440 clone_output "ERROR: in testcase [lindex $cell 0]"
441 clone_output "ERROR: [lindex $cell 1]"
442 clone_output "ERROR: tcl error code [lindex $cell 2]"
443 clone_output "ERROR: \
444 tcl error info:\n[lindex $cell 3]\n[string repeat - 50]"
448 verbose -log "runtest completed at [timestamp -format %c]"
453 mail_file $outdir/$tool.sum $mailing_list "Dejagnu Summary Log"
460 # Emit an XML tag, but escape XML special characters in the body.
461 proc xml_tag { tag body } {
462 set escapes { < < > > & & \" " ' ' }
463 for {set i 1} {$i < 32} {incr i} {
464 if {[lsearch [list 9 10 13] $i] >= 0} {
465 # skip valid XML whitespace chars
468 # Append non-printable character
469 lappend escapes [format %c $i]
470 # .. and then the corresponding XML escape
471 lappend escapes &#x[format %x $i]\;
473 return <$tag>[string map $escapes $body]</$tag>
476 proc xml_output { message } {
478 if { $xml_file ne "" } {
479 puts $xml_file $message
483 # Print summary of all pass/fail counts.
485 proc log_summary { args } {
494 global current_target_name
497 if { [llength $args] == 0 } {
500 set which [lindex $args 0]
503 if { [llength $args] == 0 } {
504 clone_output "\n\t\t=== $tool Summary for $current_target_name ===\n"
506 clone_output "\n\t\t=== $tool Summary ===\n"
509 foreach x { PASS FAIL XPASS XFAIL KPASS KFAIL UNRESOLVED UNTESTED UNSUPPORTED } {
510 set val $test_counts($x,$which)
512 set mess "# of $test_counts($x,name)"
514 xml_output " <summary>"
515 xml_output " [xml_tag result $x]"
516 xml_output " [xml_tag description $mess]"
517 xml_output " [xml_tag total $val]"
518 xml_output " </summary>"
520 if { [string length $mess] < 24 } {
523 clone_output "$mess\t$val"
528 # Setup a flag to control whether a failure is expected or not
530 # Multiple target triplet patterns can be specified for targets
531 # for which the test fails. A bug report ID can be specified,
532 # which is a string without '-'.
534 proc setup_xfail { args } {
539 set argc [ llength $args ]
540 for { set i 0 } { $i < $argc } { incr i } {
541 set sub_arg [ lindex $args $i ]
542 # is a prms number. we assume this is a string with no '-' characters
543 if {[regexp "^\[^\-\]+$" $sub_arg]} {
544 set xfail_prms $sub_arg
547 if {[istarget $sub_arg]} {
554 # Setup a flag to control whether it is a known failure.
556 # A bug report ID _MUST_ be specified, and is the first argument.
557 # It still must be a string without '-' so we can be sure someone
558 # did not just forget it and we end-up using a target triple as
561 # Multiple target triplet patterns can be specified for targets
562 # for which the test is known to fail.
564 proc setup_kfail { args } {
569 set argc [ llength $args ]
570 for { set i 0 } { $i < $argc } { incr i } {
571 set sub_arg [ lindex $args $i ]
572 # is a prms number. we assume this is a string with no '-' characters
573 if {[regexp "^\[^\-\]+$" $sub_arg]} {
574 set kfail_prms $sub_arg
577 if {[istarget $sub_arg]} {
583 if {$kfail_prms == 0} {
584 perror "Attempt to set a kfail without specifying bug tracking id"
588 # Check to see if a conditional xfail is triggered.
589 # message {targets} {include} {exclude}
591 proc check_conditional_xfail { args } {
592 global compiler_flags
594 set all_args [lindex $args 0]
596 set message [lindex $all_args 0]
598 set target_list [lindex $all_args 1]
599 verbose "Limited to targets: $target_list" 3
601 # get the list of flags to look for
602 set includes [lindex $all_args 2]
603 verbose "Will search for options $includes" 3
605 # get the list of flags to exclude
606 if { [llength $all_args] > 3 } {
607 set excludes [lindex $all_args 3]
608 verbose "Will exclude for options $excludes" 3
613 # loop through all the targets, checking the options for each one
614 verbose "Compiler flags are: $compiler_flags" 2
618 foreach targ $target_list {
619 if {[istarget $targ]} {
620 # look through the compiler options for flags we want to see
621 # this is really messy cause each set of options to look for
622 # may also be a list. We also want to find each element of the
623 # list, regardless of order to make sure they're found.
624 # So we look for lists in side of lists, and make sure all
625 # the elements match before we decide this is legit.
626 # Se we 'incl_hit' to 1 before the loop so that if the 'includes'
627 # list is empty, this test will report a hit. (This can be
628 # useful if a target will always fail unless certain flags,
629 # specified in the 'excludes' list, are used.)
631 for { set i 0 } { $i < [llength $includes] } { incr i } {
633 set opt [lindex $includes $i]
634 verbose "Looking for $opt to include in the compiler flags" 2
636 if {[string match "* $j *" $compiler_flags]} {
637 verbose "Found $j to include in the compiler flags" 2
641 # if the number of hits we get is the same as the number of
642 # specified options, then we got a match
643 if {$incl_hit == [llength $opt]} {
649 # look through the compiler options for flags we don't
651 for { set i 0 } { $i < [llength $excludes] } { incr i } {
653 set opt [lindex $excludes $i]
654 verbose "Looking for $opt to exclude in the compiler flags" 2
656 if {[string match "* $j *" $compiler_flags]} {
657 verbose "Found $j to exclude in the compiler flags" 2
661 # if the number of hits we get is the same as the number of
662 # specified options, then we got a match
663 if {$excl_hit == [llength $opt]} {
670 # if we got a match for what to include, but didn't find any reasons
671 # to exclude this, then we got a match! So return one to turn this into
672 # an expected failure.
673 if {$incl_hit && ! $excl_hit } {
674 verbose "This is a conditional match" 2
677 verbose "This is not a conditional match" 2
685 # Clear the xfail flag for a particular target.
687 proc clear_xfail { args } {
691 set argc [ llength $args ]
692 for { set i 0 } { $i < $argc } { incr i } {
693 set sub_arg [ lindex $args $i ]
694 switch -glob -- $sub_arg {
695 "*-*-*" { # is a configuration triplet
696 if {[istarget $sub_arg]} {
706 # Clear the kfail flag for a particular target.
708 proc clear_kfail { args } {
712 set argc [ llength $args ]
713 for { set i 0 } { $i < $argc } { incr i } {
714 set sub_arg [ lindex $args $i ]
715 switch -glob -- $sub_arg {
716 "*-*-*" { # is a configuration triplet
717 if {[istarget $sub_arg]} {
727 # Record that a test has passed or failed (perhaps unexpectedly).
728 # This is an internal procedure, only used in this file.
730 proc record_test { type message args } {
733 global prms_id bug_id
734 global xfail_flag xfail_prms
735 global kfail_flag kfail_prms
736 global errcnt warncnt
737 global warning_threshold perror_threshold
740 if { [llength $args] > 0 } {
741 set count [lindex $args 0]
745 if {[info exists pf_prefix]} {
746 set message [concat $pf_prefix " " $message]
749 # If we have too many warnings or errors,
750 # the output of the test can't be considered correct.
751 if { $warning_threshold > 0 && $warncnt >= $warning_threshold
752 || $perror_threshold > 0 && $errcnt >= $perror_threshold } {
753 verbose "Error/Warning threshold exceeded: \
754 $errcnt $warncnt (max. $perror_threshold $warning_threshold)"
763 if {[info exists errorInfo]} {
768 if { [catch { set rio [split $expect_out(buffer) "\n"] } result]} {
769 #do nothing - leave as { "" "" }
773 set output "expect_out(buffer)"
775 xml_output " [xml_tag input [string trimright [lindex $rio 0]]]"
776 xml_output " [xml_tag output [string trimright [lindex $rio 1]]]"
777 xml_output " [xml_tag result $type]"
778 xml_output " [xml_tag name $message]"
779 xml_output " [xml_tag prms_id $prms_id]"
780 xml_output " </test>"
786 set message [concat $message "\t(PRMS $prms_id)"]
792 set message [concat $message "\t(PRMS $prms_id)"]
797 if { $xfail_prms != 0 } {
798 set message [concat $message "\t(PRMS $xfail_prms)"]
802 if { $xfail_prms != 0 } {
803 set message [concat $message "\t(PRMS $xfail_prms)"]
808 if { $kfail_prms != 0 } {
809 set message [concat $message "\t(PRMS $kfail_prms)"]
813 if { $kfail_prms != 0 } {
814 set message [concat $message "\t(PRMS: $kfail_prms)"]
818 # The only reason we look at the xfail/kfail stuff is to pick up
820 if { $kfail_flag && $kfail_prms != 0 } {
821 set message [concat $message "\t(PRMS $kfail_prms)"]
822 } elseif { $xfail_flag && $xfail_prms != 0 } {
823 set message [concat $message "\t(PRMS $xfail_prms)"]
824 } elseif { $prms_id } {
825 set message [concat $message "\t(PRMS $prms_id)"]
830 # The only reason we look at the xfail/kfail stuff is to pick up
832 if { $kfail_flag && $kfail_prms != 0 } {
833 set message [concat $message "\t(PRMS $kfail_prms)"]
834 } elseif { $xfail_flag && $xfail_prms != 0 } {
835 set message [concat $message "\t(PRMS $xfail_prms)"]
836 } elseif { $prms_id } {
837 set message [concat $message "\t(PRMS $prms_id)"]
841 # The only reason we look at the xfail/kfail stuff is to pick up
843 if { $kfail_flag && $kfail_prms != 0 } {
844 set message [concat $message "\t(PRMS $kfail_prms)"]
845 } elseif { $xfail_flag && $xfail_prms != 0 } {
846 set message [concat $message "\t(PRMS $xfail_prms)"]
847 } elseif { $prms_id } {
848 set message [concat $message "\t(PRMS $prms_id)"]
852 perror "record_test called with bad type `$type'"
859 set message [concat $message "\t(BUG $bug_id)"]
862 global multipass_name
863 if { $multipass_name ne "" } {
864 set message [format "%s: %s: %s" $type $multipass_name $message]
866 set message "$type: $message"
868 clone_output $message
870 # If a command name exists in the $local_record_procs associative
871 # array for this type of result, then invoke it.
873 set lowcase_type [string tolower $type]
874 global local_record_procs
875 if {[info exists local_record_procs($lowcase_type)]} {
876 $local_record_procs($lowcase_type) $message
879 # Reset these so they're ready for the next test case. We don't reset
880 # prms_id or bug_id here. There may be multiple tests for them. Instead
881 # they are reset in the main loop after each test. It is also the
882 # testsuite driver's responsibility to reset them after each testcase.
891 # Record that a test has passed.
893 proc pass { message } {
894 global xfail_flag kfail_flag compiler_conditional_xfail_data
896 # if we have a conditional xfail setup, then see if our compiler flags match
897 if {[ info exists compiler_conditional_xfail_data ]} {
898 if {[check_conditional_xfail $compiler_conditional_xfail_data]} {
901 unset compiler_conditional_xfail_data
905 record_test KPASS $message
906 } elseif { $xfail_flag } {
907 record_test XPASS $message
909 record_test PASS $message
913 # Record that a test has failed.
915 proc fail { message } {
916 global xfail_flag kfail_flag compiler_conditional_xfail_data
918 # if we have a conditional xfail setup, then see if our compiler flags match
919 if {[ info exists compiler_conditional_xfail_data ]} {
920 if {[check_conditional_xfail $compiler_conditional_xfail_data]} {
923 unset compiler_conditional_xfail_data
927 record_test KFAIL $message
928 } elseif { $xfail_flag } {
929 record_test XFAIL $message
931 record_test FAIL $message
935 # Record that a test that was expected to fail has passed unexpectedly.
937 proc xpass { message } {
938 record_test XPASS $message
941 # Record that a test that was expected to fail did indeed fail.
943 proc xfail { message } {
944 record_test XFAIL $message
947 # Record that a test for a known bug has passed unexpectedly.
949 proc kpass { bugid message } {
950 global kfail_flag kfail_prms
952 set kfail_prms $bugid
953 record_test KPASS $message
956 # Record that a test has failed due to a known bug.
958 proc kfail { bugid message } {
959 global kfail_flag kfail_prms
961 set kfail_prms $bugid
962 record_test KFAIL $message
965 # Set warning threshold.
967 proc set_warning_threshold { threshold } {
968 global warning_threshold
969 set warning_threshold $threshold
972 # Get warning threshold.
974 proc get_warning_threshold { } {
975 global warning_threshold
976 return $warning_threshold
979 # Prints warning messages.
980 # These are warnings from the framework, not from the tools being
981 # tested. It takes a string, and an optional number and returns
984 proc warning { args } {
987 if { [llength $args] > 1 } {
988 set warncnt [lindex $args 1]
992 set message [lindex $args 0]
994 clone_output "WARNING: $message"
997 if {[info exists errorInfo]} {
1002 # Prints error messages.
1003 # These are errors from the framework, not from the tools being
1004 # tested. It takes a string, and an optional number and returns
1007 proc perror { args } {
1010 if { [llength $args] > 1 } {
1011 set errcnt [lindex $args 1]
1015 set message [lindex $args 0]
1017 clone_output "ERROR: $message"
1020 if {[info exists errorInfo]} {
1025 # Prints informational messages.
1027 # These are messages from the framework, not from the tools being
1028 # tested. This means that it is currently illegal to call this proc
1029 # outside of dejagnu proper.
1031 proc note { message } {
1032 clone_output "NOTE: $message"
1035 # untested -- mark the test case as untested.
1037 proc untested { message } {
1038 record_test UNTESTED $message
1041 # Mark the test case as unresolved.
1043 proc unresolved { message } {
1044 record_test UNRESOLVED $message
1047 # Mark the test case as unsupported.
1048 # Usually this is used for a test that is missing OS support.
1050 proc unsupported { message } {
1051 record_test UNSUPPORTED $message
1054 # Set up the values in the test_counts array (name and initial
1057 proc init_testcounts { } {
1058 global test_counts test_names
1059 set test_counts(TOTAL,name) "testcases run"
1060 set test_counts(PASS,name) "expected passes"
1061 set test_counts(FAIL,name) "unexpected failures"
1062 set test_counts(XFAIL,name) "expected failures"
1063 set test_counts(XPASS,name) "unexpected successes"
1064 set test_counts(KFAIL,name) "known failures"
1065 set test_counts(KPASS,name) "unknown successes"
1066 set test_counts(WARNING,name) "warnings"
1067 set test_counts(ERROR,name) "errors"
1068 set test_counts(UNSUPPORTED,name) "unsupported tests"
1069 set test_counts(UNRESOLVED,name) "unresolved testcases"
1070 set test_counts(UNTESTED,name) "untested testcases"
1073 foreach i [lsort [array names test_counts]] {
1074 regsub ",.*$" $i "" i
1078 set test_counts($i,total) 0
1079 lappend test_names $i
1084 # Increment NAME in the test_counts array; the amount to increment can
1085 # be is optional (defaults to 1).
1087 proc incr_count { name args } {
1090 if { [llength $args] == 0 } {
1093 set count [lindex $args 0]
1095 if {[info exists test_counts($name,count)]} {
1096 incr test_counts($name,count) $count
1097 incr test_counts($name,total) $count
1099 perror "$name doesn't exist in incr_count"
1103 ## API implementations and multiplex calls
1105 # Return or provide information about the current testsuite. (multiplex)
1107 proc testsuite { subcommand args } {
1108 if { $subcommand eq "file" } {
1109 testsuite_file $args
1110 } elseif { $subcommand eq "can" } {
1113 error "unknown \"testsuite\" command: testsuite $subcommand $args"
1116 namespace eval ::dejagnu {}
1120 proc testsuite_can { argv } {
1121 verbose "entering testsuite can $argv" 3
1123 if { [lindex $argv 0] eq "call" } {
1124 set call [lrange $argv 1 end]
1125 set result [info exists ::dejagnu::apilist($call)]
1127 error "unknown feature test: testsuite can $argv"
1130 verbose "leaving testsuite can: $result" 3
1133 array set ::dejagnu::apilist { {testsuite can call} 1 }
1135 # Return a full file name in or near the testsuite
1137 proc testsuite_file { argv } {
1138 global testsuitedir testbuilddir testdir
1139 verbose "entering testsuite file $argv" 3
1140 set argc [llength $argv]
1141 set dir_must_exist true
1142 set basedir $testsuitedir
1143 for { set argi 0 } { $argi < $argc } { incr argi } {
1144 set arg [lindex $argv $argi]
1145 if { $arg eq "--" } { # explicit end of arguments
1147 } elseif { $arg eq "-object" } {
1148 set basedir $testbuilddir
1149 } elseif { $arg eq "-source" } {
1150 set basedir $testsuitedir
1151 } elseif { $arg eq "-top" } {
1153 } elseif { $arg eq "-test" } {
1154 set dirtail $testdir
1155 } elseif { $arg eq "-hypothetical" } {
1156 set dir_must_exist false
1157 } elseif { [string match "-*" $arg] } {
1158 error "testsuite file: unrecognized flag [lindex $argv $argi]"
1159 } else { # implicit end of arguments
1163 if { [lindex $argv $argi] eq "--" } { incr argi }
1164 if { ![info exists dirtail] } {
1165 error "testsuite file requires one of -top|-test\n\
1166 but was given: $argv"
1168 if { $dirtail ne "" } {
1169 set dirtail [relative_filename $testsuitedir $dirtail]
1171 set result [eval [list file join $basedir $dirtail] [lrange $argv $argi end]]
1173 verbose "implying: [file dirname $result]" 3
1174 if { $dir_must_exist && ![file isdirectory [file dirname $result]] } {
1175 if { $basedir eq $testbuilddir } {
1176 file mkdir [file dirname $result]
1177 verbose "making directory" 3
1179 error "directory '[file dirname $result]' does not exist"
1183 verbose "leaving testsuite file: $result" 3
1186 array set ::dejagnu::apilist { {testsuite file} 1 }
1188 # Return or provide information about the current dynamic state. (multiplex)
1190 proc testcase { subcommand args } {
1191 if { $subcommand eq "group" } {
1192 testcase_group $args
1194 error "unknown \"testcase\" command: testcase $subcommand $args"
1198 # Indicate group boundaries or return current group
1200 proc testcase_group { argv } {
1201 verbose "entering testcase group $argv" 3
1202 set argc [llength $argv]
1205 set result [::dejagnu::group::current]
1207 set what [lindex $argv 0]
1208 set name [lindex $argv 1]
1210 if { $what eq "begin" } {
1211 if { ![::dejagnu::group::check_name $name] } {
1212 error "group name '$name' is not valid"
1214 ::dejagnu::group::push $name [uplevel 2 info script]
1216 } elseif { $what eq "end" } {
1217 if { ![::dejagnu::group::check_name $name] } {
1218 error "group name '$name' is not valid"
1220 ::dejagnu::group::pop $name [uplevel 2 info script]
1222 } elseif { $what eq "eval" } {
1223 if { ![::dejagnu::group::check_name $name] } {
1224 error "group name '$name' is not valid"
1226 ::dejagnu::group::push $name [uplevel 2 info script]
1227 set result [uplevel 2 [lindex $argv 2]]
1228 ::dejagnu::group::pop $name [uplevel 2 info script]
1230 error "unknown group operation: testcase group $argv"
1234 verbose "leaving testcase group: $result" 3
1237 array set ::dejagnu::apilist {
1239 {testcase group begin} 1 {testcase group end} 1
1240 {testcase group eval} 1