Mercurial > ecos
comparison host/infra/hosttest.exp @ 76:435cced73e2f ecos-v1_3_1-release
eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
| author | jlarmour |
|---|---|
| date | Tue, 28 Mar 2000 14:10:45 +0000 |
| parents | |
| children | f58bc1b2c2bc |
comparison
equal
deleted
inserted
replaced
| 75:41bf073c0c32 | 76:435cced73e2f |
|---|---|
| 1 #=============================================================================== | |
| 2 # | |
| 3 # hosttest.exp | |
| 4 # | |
| 5 # Support for host-side testing | |
| 6 # | |
| 7 #=============================================================================== | |
| 8 ######COPYRIGHTBEGIN#### | |
| 9 # | |
| 10 # ---------------------------------------------------------------------------- | |
| 11 # Copyright (C) 1998, 1999, 2000 Red Hat, Inc. | |
| 12 # | |
| 13 # This file is part of the eCos host tools. | |
| 14 # | |
| 15 # This program is free software; you can redistribute it and/or modify it | |
| 16 # under the terms of the GNU General Public License as published by the Free | |
| 17 # Software Foundation; either version 2 of the License, or (at your option) | |
| 18 # any later version. | |
| 19 # | |
| 20 # This program is distributed in the hope that it will be useful, but WITHOUT | |
| 21 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| 22 # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
| 23 # more details. | |
| 24 # | |
| 25 # You should have received a copy of the GNU General Public License along with | |
| 26 # this program; if not, write to the Free Software Foundation, Inc., | |
| 27 # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
| 28 # | |
| 29 # ---------------------------------------------------------------------------- | |
| 30 # | |
| 31 ######COPYRIGHTEND#### | |
| 32 #=============================================================================== | |
| 33 ######DESCRIPTIONBEGIN#### | |
| 34 # | |
| 35 # Author(s): bartv | |
| 36 # Contributors: bartv | |
| 37 # Date: 1998-11-25 | |
| 38 # Note: Arguably this should be a loadable package | |
| 39 # | |
| 40 #####DESCRIPTIONEND#### | |
| 41 #=============================================================================== | |
| 42 # | |
| 43 | |
| 44 # ---------------------------------------------------------------------------- | |
| 45 # This script gets loaded by host-side DejaGnu test harnesses to provide | |
| 46 # various utilities for testing eCos host applications. It lives in the | |
| 47 # host-side infrastructure directory and gets installed in | |
| 48 # $(PREFIX)/share/dejagnu. | |
| 49 # | |
| 50 # The script can assume that a number of globals from the site.exp | |
| 51 # file have been read in. These include: | |
| 52 # tool - name of the tool (i.e. the package) | |
| 53 # srcdir - location of the source directory | |
| 54 # objdir - location of the build tree | |
| 55 # host_alias - config triplet | |
| 56 # host_triplet - ditto | |
| 57 # | |
| 58 # The generated Makefile has some additional information that is useful. | |
| 59 # CC - name of the C compiler that is used | |
| 60 # CXX - name of the C++ compiler | |
| 61 # prefix - where everything gets installed | |
| 62 # OBJEXT - either o or obj | |
| 63 # EXEEXT - either nothing or .exe | |
| 64 # VERSION - the version number | |
| 65 # CFLAGS - flags to use when compiling C code | |
| 66 # CXXFLAGS - flags to use when compiling C++ code | |
| 67 # | |
| 68 # hosttest_initialize | |
| 69 # Perform any initialization steps that are needed. Currently this | |
| 70 # means reading in the Makefile from the top-level of the build tree | |
| 71 # and figuring out the values of CC, CXX, and anything else that is | |
| 72 # useful. Any errors should be reported via perror and then the | |
| 73 # script should exit. | |
| 74 # | |
| 75 # There is an optional argument, a list of additional variables which | |
| 76 # should be present in the makefile and whose values are desired. | |
| 77 | |
| 78 proc hosttest_initialize { { pkg_vars {} } } { | |
| 79 | |
| 80 # First check that this script is actually running inside DejaGnu | |
| 81 if { [info exists ::objdir] == 0 } { | |
| 82 puts "Variable ::objdir is not defined, is this script really running inside DejaGnu?" | |
| 83 exit 1 | |
| 84 } | |
| 85 | |
| 86 # The information is stored in an array hosttest_data. Make sure this | |
| 87 # array exists. | |
| 88 array set ::hosttest_data {} | |
| 89 | |
| 90 # Now clear out any entries in the array | |
| 91 foreach entry [array names ::hosttest_data] { | |
| 92 unset ::hosttest_data($entry) | |
| 93 } | |
| 94 | |
| 95 # Now read in the build tree's Makefile (and not the testsuite's Makefile) | |
| 96 set filename [file join $::objdir .. Makefile] | |
| 97 if { [file exists $filename] == 0 } { | |
| 98 perror "Initialization error: the build tree's Makefile $filename does not exist." | |
| 99 exit 1 | |
| 100 } | |
| 101 set status [ catch { | |
| 102 set fd [open $filename r] | |
| 103 set contents [read $fd] | |
| 104 close $fd | |
| 105 } message] | |
| 106 if { $status != 0 } { | |
| 107 perror "Error reading $filename.\n$message" | |
| 108 exit 1 | |
| 109 } | |
| 110 | |
| 111 # The data is available. Search it for each of the variables of | |
| 112 # interest. Some variables are optional and are given default | |
| 113 # values. | |
| 114 set ::hosttest_data(CFLAGS) "" | |
| 115 set ::hosttest_data(CXXFLAGS) "" | |
| 116 | |
| 117 set lines [split $contents "\n"] | |
| 118 | |
| 119 foreach var [concat { CC CXX prefix OBJEXT EXEEXT VERSION CFLAGS CXXFLAGS } $pkg_vars] { | |
| 120 | |
| 121 set pattern "^$var\[ \t\]*:?=\[ \t\]* (.*)\$" | |
| 122 set dummy "" | |
| 123 set match "" | |
| 124 | |
| 125 foreach line $lines { | |
| 126 if { [regexp -- $pattern $line dummy match] == 1 } { | |
| 127 set ::hosttest_data($var) $match | |
| 128 break | |
| 129 } | |
| 130 } | |
| 131 if { [info exists ::hosttest_data($var)] == 0 } { | |
| 132 perror "Variable $var is not defined in $filename" | |
| 133 exit 1 | |
| 134 } | |
| 135 } | |
| 136 | |
| 137 # If compiling with VC++ remove any cygwin-isms from the prefix | |
| 138 if { [string match "cl*" $::hosttest_data(CC)] } { | |
| 139 set status [catch "exec cygpath -w $::hosttest_data(prefix)" message] | |
| 140 if { $status == 0 } { | |
| 141 regsub -all -- {\\} $message {/} ::hosttest_data(prefix) | |
| 142 } else { | |
| 143 perror "Converting cygwin pathname $::hosttest_data(prefix)\n$message" | |
| 144 exit 1 | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 | |
| 150 # ---------------------------------------------------------------------------- | |
| 151 # hosttest_extract_version | |
| 152 # Assuming there has been a call to initialize, the required information | |
| 153 # should be available in the hosttest_data array. The initialize | |
| 154 # function should have aborted if the data is not available. | |
| 155 | |
| 156 proc hosttest_extract_version { } { | |
| 157 | |
| 158 if { [info exists ::hosttest_data(VERSION)] == 0 } { | |
| 159 error "No version information - host testing has not been properly initialized." | |
| 160 } | |
| 161 | |
| 162 if { [info exists ::objdir] == 0 } { | |
| 163 error "Variable ::objdir is not defined, is this script really running inside DejaGnu?" | |
| 164 } | |
| 165 return $::hosttest_data(VERSION) | |
| 166 } | |
| 167 | |
| 168 # ---------------------------------------------------------------------------- | |
| 169 # hosttest_compile | |
| 170 # compile and link one or more source files. The arguments are: | |
| 171 # 1) the name of the test case | |
| 172 # 2) a list of one or more source files that need to be compiled. | |
| 173 # Both .c and .cxx files are supported, and the appropriate | |
| 174 # compiler will be used. If this list is empty then the | |
| 175 # code will look for a .c or a .cxx file which matches the | |
| 176 # name of the test executable. Source files are assumed to | |
| 177 # be relative to $::srcdir/$::subdir | |
| 178 # 3) a list (possibly empty) of directories that should be in the | |
| 179 # include path. The build tree's directory is automatically in | |
| 180 # the path, as is $(PREFIX)/include. Note that the build tree | |
| 181 # is actually one level above objdir, on the assumption that | |
| 182 # objdir is the testsuite subdirectory of the real objdir. | |
| 183 # 4) ditto for library search paths. | |
| 184 # 5) and a list of additional libraries that should be linked. | |
| 185 # | |
| 186 # Currently it is not possible to pass compiler flags since those | |
| 187 # might need translating between gcc and VC++. This may have to be | |
| 188 # resolved. | |
| 189 # | |
| 190 # Currently linking is not done via libtool. This may have to change. | |
| 191 # | |
| 192 # The various object files and the executable are placed in a directory | |
| 193 # testcase in the build tree, to avoid the risk of name clashes. This | |
| 194 # directory must not exist yet. There is a separate routine hosttest_clean | |
| 195 # which simply expunges the entire testcase directory. | |
| 196 # | |
| 197 # The output of a succesful compile or built is reported using | |
| 198 # verbose at level 2. Unsuccesful compiles or builts are reported using | |
| 199 # level 1. | |
| 200 | |
| 201 proc hosttest_compile { name sources incdirs libdirs libs } { | |
| 202 | |
| 203 # Make sure that the testcase directory does not yet exist, then | |
| 204 # create it. This guarantees a clean system and reasonable access | |
| 205 # permissions. Each testcase invocation should involve a call to | |
| 206 # the clean function. | |
| 207 set dirname [file join $::objdir "testcase"] | |
| 208 if { [file exists $dirname] != 0 } { | |
| 209 # An empty directory is ok. | |
| 210 if { [llength [glob -nocomplain -- [file join $dirname "*"]]] != 0 } { | |
| 211 error "hosttest_compile: $dirname already exists" | |
| 212 } | |
| 213 } | |
| 214 | |
| 215 set status [catch { file mkdir $dirname } message] | |
| 216 if { $status != 0 } { | |
| 217 error "hosttest_compile: unable to create directory $dirname" | |
| 218 } | |
| 219 | |
| 220 # The only argument that must be valid is the test name. | |
| 221 if { $name == "" } { | |
| 222 error "hosttest_compile: invalid test case name" | |
| 223 } | |
| 224 | |
| 225 # If the list of sources is empty then look for a suitable | |
| 226 # file in the appropriate directory. | |
| 227 if { [llength $sources] == 0 } { | |
| 228 set filename [file join $::srcdir $::subdir "${name}.c"] | |
| 229 if { [file exists $filename] && [file isfile $filename] } { | |
| 230 lappend sources [file tail $filename] | |
| 231 } else { | |
| 232 set filename [file join $::srcdir $::subdir "${name}.cxx"] | |
| 233 if { [file exists $filename] && [file isfile $filename] } { | |
| 234 lappend sources [file tail $filename] | |
| 235 } else { | |
| 236 error "hosttest_compile: no sources listed and unable to find ${name}.c or ${name}.cxx" | |
| 237 } | |
| 238 } | |
| 239 } | |
| 240 | |
| 241 # For each source file, generate a compile command line and try to execute | |
| 242 # it. The command line takes the form: | |
| 243 # (CC|CXX) -c (CFLAGS|CXXFLAGS) (INCDIRS) -o xxx yyy | |
| 244 # | |
| 245 # It is also useful to produce a list of the object files that need to | |
| 246 # linked later on, and to work out which tool should be invoked for | |
| 247 # linking. | |
| 248 set object_files {} | |
| 249 set has_cxx_files 0 | |
| 250 | |
| 251 foreach source $sources { | |
| 252 set commandline "" | |
| 253 if { [file extension $source] == ".c" } { | |
| 254 append commandline "$::hosttest_data(CC) -c $::hosttest_data(CFLAGS) " | |
| 255 } elseif { [file extension $source] == ".cxx" } { | |
| 256 set has_cxx_files 1 | |
| 257 append commandline "$::hosttest_data(CXX) -c $::hosttest_data(CXXFLAGS) " | |
| 258 } else { | |
| 259 error "hosttest_compile: files of type [file extension $source] ($source) are not yet supported." | |
| 260 } | |
| 261 | |
| 262 # Include path: start with the source tree. Then the build tree. | |
| 263 # Then any additional directories specified explicitly by the | |
| 264 # testcase. Finish off with the prefix. Note that header files | |
| 265 # in the prefix directory may be out of date, depending on whether | |
| 266 # or not there has been an install recently. | |
| 267 append commandline "-I[file join [pwd] [file dirname $::srcdir]] " | |
| 268 append commandline "-I[file join [pwd] [file dirname $::objdir]] " | |
| 269 foreach dir $incdirs { | |
| 270 append commandline "-I[file join [pwd] $dir] " | |
| 271 } | |
| 272 append commandline "-I[file join [pwd] $::hosttest_data(prefix) include] " | |
| 273 | |
| 274 # The output file must go into the testcase directory and have the right suffix | |
| 275 set objfile "[file root [file tail $source]].$::hosttest_data(OBJEXT)" | |
| 276 lappend object_files $objfile | |
| 277 if { [string match "cl*" $::hosttest_data(CC)] } { | |
| 278 append commandline "-Fo[file join $::objdir testcase $objfile] " | |
| 279 } else { | |
| 280 append commandline "-o [file join $::objdir testcase $objfile] " | |
| 281 } | |
| 282 | |
| 283 # Finally provide the source file. | |
| 284 append commandline "[file join $::srcdir $::subdir $source]" | |
| 285 verbose -log -- $commandline | |
| 286 | |
| 287 # Time to invoke the compiler. | |
| 288 set status [catch { set result [eval exec -keepnewline -- $commandline] } message] | |
| 289 if { $status == 0 } { | |
| 290 # The compile succeeded and the output is in result. Report the | |
| 291 # output. | |
| 292 verbose -log -- $result | |
| 293 } else { | |
| 294 # The compile failed and the output is in message. | |
| 295 verbose -log -- $message | |
| 296 error "hosttest_compile: failed to compile $source" | |
| 297 } | |
| 298 } | |
| 299 | |
| 300 # At this stage all the source files have been compiled, a list of | |
| 301 # object files has been constructed, and it is known whether or | |
| 302 # not any of the sources were c++. Time to construct a new command | |
| 303 # line. | |
| 304 set commandline "" | |
| 305 if { $has_cxx_files == 0 } { | |
| 306 append commandline "$::hosttest_data(CC) $::hosttest_data(CFLAGS) " | |
| 307 } else { | |
| 308 append commandline "$::hosttest_data(CXX) $::hosttest_data(CXXFLAGS) " | |
| 309 } | |
| 310 set exename [file join $::objdir "testcase" "$name$::hosttest_data(EXEEXT)"] | |
| 311 | |
| 312 # List all of the object files | |
| 313 foreach obj $object_files { | |
| 314 append commandline "[file join $::objdir "testcase" $obj] " | |
| 315 } | |
| 316 | |
| 317 # Now take care of libraries and search paths. This requires different | |
| 318 # code for gcc and VC++. | |
| 319 | |
| 320 if { [string match "cl*" $::hosttest_data(CC)] } { | |
| 321 append commandline "-Fe$exename " | |
| 322 | |
| 323 foreach lib $libs { | |
| 324 append commandline "${lib}.lib " | |
| 325 } | |
| 326 append commandline "-link " | |
| 327 append commandline "-libpath=[file join [pwd] [file dirname $::objdir]] " | |
| 328 foreach dir $libdirs { | |
| 329 append commandline "-libpath=[file join [pwd] $dir] " | |
| 330 } | |
| 331 append commandline "-libpath=[file join [pwd] $::hosttest_data(prefix) lib] " | |
| 332 } else { | |
| 333 append commandline "-o $exename " | |
| 334 append commandline "-L[file join [pwd] [file dirname $::objdir]] " | |
| 335 foreach dir $libdirs { | |
| 336 append commandline "-L[file join [pwd] $dir] " | |
| 337 } | |
| 338 append commandline "-L[file join [pwd] $::hosttest_data(prefix) lib] " | |
| 339 foreach lib $libs { | |
| 340 append commandline "-l$lib " | |
| 341 } | |
| 342 } | |
| 343 | |
| 344 # We have a command line, go for it. | |
| 345 verbose -log -- $commandline | |
| 346 set status [catch { set result [eval exec -keepnewline -- $commandline] } message] | |
| 347 if { $status == 0 } { | |
| 348 # The link has succeeded, we have an executable. | |
| 349 verbose -log -- $result | |
| 350 } else { | |
| 351 # The link failed and the output is in message. | |
| 352 # Report things are per compilation failures | |
| 353 verbose -log -- $message | |
| 354 error "hosttest_compile: failed to link $exename" | |
| 355 } | |
| 356 | |
| 357 # There should be a test executable. | |
| 358 } | |
| 359 | |
| 360 # ---------------------------------------------------------------------------- | |
| 361 # hosttest_clean | |
| 362 # Clean up a testcase directory. | |
| 363 | |
| 364 proc hosttest_clean { } { | |
| 365 | |
| 366 set dirname [file join $::objdir "testcase"] | |
| 367 if { [file exists $dirname] == 0 } { | |
| 368 | |
| 369 # Something must have gone seriously wrong during the build phase, | |
| 370 # there is nothing there. | |
| 371 return | |
| 372 } | |
| 373 | |
| 374 if { [file isdirectory $dirname] == 0 } { | |
| 375 error "hosttest_clean: $dirname should be a directory" | |
| 376 } | |
| 377 | |
| 378 foreach entry [glob -nocomplain -- [file join $dirname "*"]] { | |
| 379 set filename [file join $dirname $entry] | |
| 380 if { [file isfile $filename] == 0 } { | |
| 381 error "hosttest_clean: $filename is not a file" | |
| 382 } | |
| 383 set status [catch { file delete -force -- $filename } message] | |
| 384 if { $status != 0 } { | |
| 385 error "hosttest_clean: unable to delete $filename, $message" | |
| 386 } | |
| 387 } | |
| 388 set status [catch { file delete -force -- $dirname } message] | |
| 389 if { $status != 0 } { | |
| 390 error "hosttest_clean: unable to delete directory $dirname, $message" | |
| 391 } | |
| 392 } | |
| 393 | |
| 394 # ---------------------------------------------------------------------------- | |
| 395 # Run a test executable, returning the status code and the output. | |
| 396 # The results are returned in variables. It is assumed that some test cases | |
| 397 # will fail, so raising an exception is appropriate only if something | |
| 398 # has gone wrong at the test harness level. The argument list | |
| 399 # should be the name of the test case (from which the executable file name | |
| 400 # can be derived) and a list of arguments. | |
| 401 | |
| 402 proc hosttest_run { result_arg output_arg test args } { | |
| 403 | |
| 404 upvar $result_arg result | |
| 405 upvar $output_arg output | |
| 406 | |
| 407 # Figure out the filename corresponding to the test and make | |
| 408 # sure it exists. | |
| 409 set filename [file join $::objdir "testcase" $test] | |
| 410 append filename $::hosttest_data(EXEEXT) | |
| 411 if { ([file exists $filename] == 0) || ([file isfile $filename] == 0) } { | |
| 412 error "hosttest_run: testcase file $filename does not exist" | |
| 413 } | |
| 414 | |
| 415 # There is no need to worry about interacting with the program, | |
| 416 # just exec it. It is a good idea to do this in the testcase directory, | |
| 417 # so that any core dumps get cleaned up as well. | |
| 418 set current_dir [pwd] | |
| 419 set status [ catch { cd [file join $::objdir "testcase"] } message ] | |
| 420 if { $status != 0 } { | |
| 421 error "unable to change directory to [file join $::objdir testcase]\n$message" | |
| 422 } | |
| 423 | |
| 424 verbose -log -- $filename $args | |
| 425 set status [ catch { set result [eval exec -keepnewline -- $filename $args] } output] | |
| 426 if { $status == 0 } { | |
| 427 # The command has succeeded. The exit code is 0 and the output | |
| 428 # was returned by the exec. | |
| 429 set output $result | |
| 430 set result 0 | |
| 431 } else { | |
| 432 # The command has failed. The exit code is 1 and the output is | |
| 433 # already in the right place. | |
| 434 verbose -log -- $output | |
| 435 set result 1 | |
| 436 } | |
| 437 set status [catch { cd $current_dir } message] | |
| 438 if { $status != 0 } { | |
| 439 error "unable to change directory back to $current_dir" | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 # ---------------------------------------------------------------------------- | |
| 444 # Given some test output, look through it for pass and fail messages. | |
| 445 # These should result in appropriate DejaGnu pass and fail calls. | |
| 446 # In addition, if the program exited with a non-zero status code but | |
| 447 # did not report any failures then a special failure is reported. | |
| 448 | |
| 449 proc hosttest_handle_output { name result output } { | |
| 450 | |
| 451 set passes 0 | |
| 452 set fails 0 | |
| 453 | |
| 454 foreach line [split $output "\n"] { | |
| 455 | |
| 456 # The output should be of one of the following forms: | |
| 457 # PASS:<message> | |
| 458 # FAIL:<message> Line: xx File: xx | |
| 459 # Whatever | |
| 460 # | |
| 461 # PASS and FAIL messages will be reported via DejaGnu pass and fail | |
| 462 # calls. Everything else gets passed to verbose, so the user gets | |
| 463 # to choose how much information gets reported. | |
| 464 | |
| 465 set dummy "" | |
| 466 set match1 "" | |
| 467 set match2 "" | |
| 468 | |
| 469 if { [regexp -- {^PASS:<(.*)>.*$} $line dummy match1] == 1 } { | |
| 470 pass $match1 | |
| 471 incr passes | |
| 472 } elseif { [regexp -- {^FAIL:<(.*)>(.*)$} $line dummy match1 match2] == 1 } { | |
| 473 fail "$match1 $match2" | |
| 474 incr fails | |
| 475 } else { | |
| 476 verbose $line | |
| 477 } | |
| 478 } | |
| 479 | |
| 480 if { ($result != 0) && ($fails == 0) } { | |
| 481 fail "program terminated with non-zero exit code but did not report any failures" | |
| 482 } elseif { ($passes == 0) && ($fails == 0) } { | |
| 483 unresolved "test case $name did not report any passes or failures" | |
| 484 } | |
| 485 } | |
| 486 | |
| 487 # ---------------------------------------------------------------------------- | |
| 488 # hosttest_run_test_with_filter | |
| 489 # This routines combines the compile, run and clean operations, | |
| 490 # plus it invokes a supplied callback to filter the output. The | |
| 491 # callback is passed three arguments: the test name, the exit code, | |
| 492 # and all of the program output. | |
| 493 | |
| 494 proc hosttest_run_test_with_filter { name filter sources incdirs libdirs libs args } { | |
| 495 | |
| 496 set result 0 | |
| 497 set output "" | |
| 498 | |
| 499 set status [ catch { hosttest_compile $name $sources $incdirs $libdirs $libs } message] | |
| 500 if { $status != 0 } { | |
| 501 fail "unable to compile test case $name, $message" | |
| 502 hosttest_clean | |
| 503 return | |
| 504 } | |
| 505 set status [ catch { hosttest_run result output $name $args } message] | |
| 506 if { $status != 0 } { | |
| 507 fail "unable to run test case $name, $message" | |
| 508 hosttest_clean | |
| 509 return | |
| 510 } | |
| 511 set status [ catch { $filter $name $result $output } message] | |
| 512 if { $status != 0 } { | |
| 513 fail "unable to parse output from test case $name" | |
| 514 hosttest_clean | |
| 515 return | |
| 516 } | |
| 517 | |
| 518 hosttest_clean | |
| 519 } | |
| 520 | |
| 521 # ---------------------------------------------------------------------------- | |
| 522 # hosttest_run_simple_test | |
| 523 # This routine combines the compile, run, output, and clean operations. | |
| 524 # The arguments are the same as for compilation, plus an additional | |
| 525 # list for run-time parameters to the test case. | |
| 526 | |
| 527 proc hosttest_run_simple_test { name sources incdirs libdirs libs args } { | |
| 528 | |
| 529 | |
| 530 set result 0 | |
| 531 set output "" | |
| 532 | |
| 533 set status [ catch { hosttest_compile $name $sources $incdirs $libdirs $libs } message] | |
| 534 if { $status != 0 } { | |
| 535 fail "unable to compile test case $name, $message" | |
| 536 hosttest_clean | |
| 537 return | |
| 538 } | |
| 539 set status [ catch { hosttest_run result output $name $args } message] | |
| 540 if { $status != 0 } { | |
| 541 fail "unable to run test case $name, $message" | |
| 542 hosttest_clean | |
| 543 return | |
| 544 } | |
| 545 set status [ catch { hosttest_handle_output $name $result $output } message] | |
| 546 if { $status != 0 } { | |
| 547 fail "unable to parse output from test case $name" | |
| 548 hosttest_clean | |
| 549 return | |
| 550 } | |
| 551 | |
| 552 hosttest_clean | |
| 553 } | |
| 554 | |
| 555 # ---------------------------------------------------------------------------- | |
| 556 # Filename translation. A particular file has been created and must now | |
| 557 # be accessed from Tcl. | |
| 558 # | |
| 559 # Under Unix everything just works. | |
| 560 # | |
| 561 # Under Windows, well there is cygwin and there is the Windows world. | |
| 562 # A file may have come from either. cygtclsh80 and hence DejaGnu is not | |
| 563 # fully integrated with cygwin, for example it does not know about | |
| 564 # cygwin mount points. There are also complications because of | |
| 565 # volume-relative filenames. | |
| 566 # | |
| 567 # The code here tries a number of different ways of finding a file which | |
| 568 # matches the name. It is possible that the result is not actually what | |
| 569 # was intended, but hopefully this case will never arise. | |
| 570 | |
| 571 proc hosttest_translate_existing_filename { name } { | |
| 572 | |
| 573 if { $::tcl_platform(platform) == "unix" } { | |
| 574 # The file should exist. It is worth checking just in case. | |
| 575 if { [file exists $name] == 0 } { | |
| 576 return "" | |
| 577 } else { | |
| 578 return $name | |
| 579 } | |
| 580 } | |
| 581 | |
| 582 if { $::tcl_platform(platform) != "windows" } { | |
| 583 perror "The testing framework does not know about platform $::tcl_platform(platform)" | |
| 584 return "" | |
| 585 } | |
| 586 | |
| 587 # Always get rid of any backslashes, they just cause trouble | |
| 588 regsub -all -- {\\} $name {/} name | |
| 589 | |
| 590 # If the name is already valid, great. | |
| 591 if { [file exists $name] } { | |
| 592 return $name | |
| 593 } | |
| 594 | |
| 595 # OK, try to use cygwin's cygpath utility to convert it. | |
| 596 set status [catch "exec cygpath -w $name" message] | |
| 597 if { $status == 0 } { | |
| 598 set cygwin_name "" | |
| 599 regsub -all -- {\\} $message {/} cygwin_name | |
| 600 if { [file exists $cygwin_name] } { | |
| 601 return $cygwin_name | |
| 602 } | |
| 603 } | |
| 604 | |
| 605 # Is the name volumerelative? If so work out the current volume | |
| 606 # from the current directory and prepend this. | |
| 607 if { [file pathtype $name] == "volumerelative" } { | |
| 608 append fullname [string range [pwd] 0 1] $name | |
| 609 if { [file exists $fullname] } { | |
| 610 return $fullname | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 # There are other possibilities, e.g. d:xxx indicating a file | |
| 615 # relative to the current directory on drive d:. For now such | |
| 616 # Lovecraftian abominations are ignored. | |
| 617 return "" | |
| 618 } | |
| 619 | |
| 620 # ---------------------------------------------------------------------------- | |
| 621 # Support for assertion dumps. The infrastructure allows other subsystems | |
| 622 # to add their own callbacks which get invoked during a panic and which | |
| 623 # can write additional output to the dump file. For example it would be | |
| 624 # possible to output full details of the current configuration. These | |
| 625 # routines make it easier to write test cases for such callbacks. | |
| 626 # | |
| 627 # hosttest_assert_check(result output) | |
| 628 # Make sure that the test case really triggered an assertion. | |
| 629 # | |
| 630 # hosttest_assert_read_dump(output) | |
| 631 # Identify the temporary file used for the dump, read it in, delete | |
| 632 # it (no point in leaving such temporaries lying around when running | |
| 633 # testcases) and return the contents of the file. | |
| 634 # | |
| 635 # hosttest_assert_extract_callback(dump title) | |
| 636 # Given a dump output as returned by read_dump, look for a section | |
| 637 # generated by a callback with the given title. Return the contents | |
| 638 # of the callback. | |
| 639 | |
| 640 proc hosttest_assert_check { result output } { | |
| 641 | |
| 642 if { $result == 0 } { | |
| 643 return 0 | |
| 644 } | |
| 645 | |
| 646 foreach line [split $output "\n"] { | |
| 647 if { [string match "Assertion failure*" $line] } { | |
| 648 return 1 | |
| 649 } | |
| 650 } | |
| 651 return 0 | |
| 652 } | |
| 653 | |
| 654 # This routine assumes that assert_check has already been called. | |
| 655 proc hosttest_assert_read_dump { output } { | |
| 656 | |
| 657 foreach line [split $output "\n"] { | |
| 658 set dummy "" | |
| 659 set match "" | |
| 660 | |
| 661 if { [regexp -nocase -- {^writing additional output to (.*)$} $line dummy match] } { | |
| 662 | |
| 663 # The filename is in match, but it may not be directly accessible. | |
| 664 set filename [hosttest_translate_existing_filename $match] | |
| 665 if { $filename == "" } { | |
| 666 return "" | |
| 667 } | |
| 668 set status [ catch { | |
| 669 set fd [open $filename r] | |
| 670 set data [read $fd] | |
| 671 close $fd | |
| 672 file delete $filename | |
| 673 } message] | |
| 674 if { $status != 0 } { | |
| 675 unresolved "Unable to process assertion dump file $filename" | |
| 676 unresolved "File $filename may have to be deleted manually" | |
| 677 return "" | |
| 678 } | |
| 679 return $data | |
| 680 } | |
| 681 } | |
| 682 return "" | |
| 683 } | |
| 684 | |
| 685 # Look for the appropriate markers. Also clean up blank lines | |
| 686 # at the start and end. | |
| 687 proc hosttest_assert_extract_callback { dump title } { | |
| 688 | |
| 689 set lines [split $dump "\n"] | |
| 690 set result "" | |
| 691 | |
| 692 while { [llength $lines] > 0 } { | |
| 693 set line [lindex $lines 0] | |
| 694 set lines [lreplace $lines 0 0] | |
| 695 | |
| 696 if { [regexp -nocase -- "^\# \{\{\{.*${title}.*\$" $line] } { | |
| 697 | |
| 698 # Skip any blank lines at the start | |
| 699 while { [llength $lines] > 0 } { | |
| 700 set line [lindex $lines 0] | |
| 701 if { [regexp -- {^ *$} $line] == 0} { | |
| 702 break | |
| 703 } | |
| 704 set lines [lreplace $lines 0 0] | |
| 705 } | |
| 706 | |
| 707 # Now add any lines until the close marker. | |
| 708 # Nested folds are not supported yet. | |
| 709 while { [llength $lines] > 0 } { | |
| 710 set line [lindex $lines 0] | |
| 711 set lines [lreplace $lines 0 0] | |
| 712 if { [regexp -nocase -- {^\# \}\}\}.*$} $line] } { | |
| 713 break | |
| 714 } | |
| 715 append result $line "\n" | |
| 716 } | |
| 717 | |
| 718 return $result | |
| 719 } | |
| 720 } | |
| 721 | |
| 722 return "" | |
| 723 } | |
| 724 | |
| 725 | |
| 726 | |
| 727 |
