summaryrefslogtreecommitdiffstats
path: root/library/tcltest/tcltest.tcl
diff options
context:
space:
mode:
Diffstat (limited to 'library/tcltest/tcltest.tcl')
-rw-r--r--library/tcltest/tcltest.tcl356
1 files changed, 195 insertions, 161 deletions
diff --git a/library/tcltest/tcltest.tcl b/library/tcltest/tcltest.tcl
index edda144..0a7e50d 100644
--- a/library/tcltest/tcltest.tcl
+++ b/library/tcltest/tcltest.tcl
@@ -15,7 +15,7 @@
# Copyright (c) 2000 by Ajuba Solutions
# All rights reserved.
#
-# RCS: @(#) $Id: tcltest.tcl,v 1.52 2002/06/05 01:12:38 dgp Exp $
+# RCS: @(#) $Id: tcltest.tcl,v 1.53 2002/06/06 18:44:43 dgp Exp $
# create the "tcltest" namespace for all testing variables and
# procedures
@@ -131,9 +131,14 @@ namespace eval tcltest {
# predefined constraints (see the explanation for the
# InitConstraints proc for more details).
ArrayDefault testConstraints {}
+ Default ConstraintsSpecifiedByCommandLineArgument {}
+
+ # Kept only for compatibility
Default constraintsSpecified {}
+ trace variable constraintsSpecified r {set ::tcltest::constraintsSpecified \
+ [array names ::tcltest::testConstraints] ;# }
- # Don't run only the constrained tests by default
+ # Don't run only the "-constraint" specified tests by default
Default limitConstraints false
# A test application has to know how to load the tested commands
@@ -434,7 +439,7 @@ namespace eval tcltest {
foreach var {
match skip matchFiles skipFiles matchDirectories
skipDirectories preserveCore debug loadScript singleProcess
- mainThread
+ mainThread ConstraintsSpecifiedByCommandLineArgument
} {
proc $var { {new ""} } [subst -nocommands {
variable $var
@@ -667,25 +672,29 @@ proc tcltest::errorFile { {filename ""} } {
# content of tcltest::testConstraints($constraint)
#
# Side effects:
-# appends the constraint name to tcltest::constraintsSpecified
+# none
proc tcltest::testConstraint {constraint {value ""}} {
variable testConstraints
- variable constraintsSpecified
DebugPuts 3 "entering testConstraint $constraint $value"
if {[llength [info level 0]] == 2} {
return $testConstraints($constraint)
}
- lappend constraintsSpecified $constraint
+ # Check for boolean values
+ if {[catch {expr {$value && $value}} msg]} {
+ return -code error $msg
+ }
set testConstraints($constraint) $value
}
# tcltest::limitConstraints --
#
-# sets the limited constraints to tcltest::limitConstraints
+# sets/gets flag indicating whether tests run are limited only
+# to those matching constraints specified by the -constraints
+# command line option.
#
# Arguments:
-# list of constraint names
+# new boolean value for the flag
#
# Results:
# content of tcltest::limitConstraints
@@ -693,17 +702,22 @@ proc tcltest::testConstraint {constraint {value ""}} {
# Side effects:
# None.
-proc tcltest::limitConstraints { {constraintList ""} } {
- variable constraintsSpecified
+proc tcltest::limitConstraints { {value ""} } {
variable testConstraints
variable limitConstraints
- DebugPuts 3 "entering limitConstraints $constraintList"
+ DebugPuts 3 "entering limitConstraints $value"
if {[llength [info level 0]] == 1} {
return $limitConstraints
}
- set limitConstraints $constraintList
+ # Check for boolean values
+ if {[catch {expr {$value && $value}} msg]} {
+ return -code error $msg
+ }
+ set limitConstraints $value
+ if {!$limitConstraints} {return $limitConstraints}
foreach elt [array names testConstraints] {
- if {[lsearch -exact $constraintsSpecified $elt] == -1} {
+ if {[lsearch -exact [ConstraintsSpecifiedByCommandLineArgument] $elt]
+ == -1} {
testConstraint $elt 0
}
}
@@ -951,10 +965,6 @@ proc tcltest::PrintError {errorMsg} {
return
}
-if {[llength [info commands tcltest::initConstraintsHook]] == 0} {
- proc tcltest::initConstraintsHook {} {}
-}
-
# tcltest::SafeFetch --
#
# The following trace procedure makes it so that we can safely
@@ -981,16 +991,44 @@ proc tcltest::SafeFetch {n1 n2 op} {
DebugPuts 3 "entering SafeFetch $n1 $n2 $op"
if {[string equal {} $n2]} {return}
if {![info exists testConstraints($n2)]} {
- testConstraint $n2 0
+ if {[catch {testConstraint $n2 [eval [ConstraintInitializer $n2]]}]} {
+ testConstraint $n2 0
+ }
}
}
+# tcltest::ConstraintInitializer --
+#
+# Get or set a script that when evaluated in the tcltest namespace
+# will return a boolean value with which to initialize the
+# associated constraint.
+#
+# Arguments:
+# constraint - name of the constraint initialized by the script
+# script - the initializer script
+#
+# Results
+# boolean value of the constraint - enabled or disabled
+#
+# Side effects:
+# Constraint is initialized for future reference by [test]
+proc tcltest::ConstraintInitializer {constraint {script ""}} {
+ variable ConstraintInitializer
+ DebugPuts 3 "entering ConstraintInitializer $constraint $script"
+ if {[llength [info level 0]] == 2} {
+ return $ConstraintInitializer($constraint)
+ }
+ # Check for boolean values
+ if {![info complete $script]} {
+ return -code error "ConstraintInitializer must be complete script"
+ }
+ set ConstraintInitializer($constraint) $script
+}
+
# tcltest::InitConstraints --
#
-# Check constraint information that will determine which tests to run.
-# To do this, create an array testConstraints. Each element has a value
-# of 0 or 1. If the element is "true" then tests with that constraint
-# will be run, otherwise tests with that constraint will be skipped.
+# Call all registered constraint initializers to force initialization
+# of all known constraints.
# See the tcltest man page for the list of built-in constraints defined
# in this procedure.
#
@@ -1006,118 +1044,109 @@ proc tcltest::SafeFetch {n1 n2 op} {
#
proc tcltest::InitConstraints {} {
- global tcl_platform tcl_interactive tk_version
- variable testConstraints
-
- # Safely refer to non-existent members of the testConstraints array
- # without causing an error.
- trace variable testConstraints r [namespace code SafeFetch]
-
+ variable ConstraintInitializer
initConstraintsHook
+ foreach constraint [array names ConstraintInitializer] {
+ testConstraint $constraint
+ }
+}
- testConstraint singleTestInterp [singleProcess]
+proc tcltest::DefineConstraintInitializers {} {
+ ConstraintInitializer singleTestInterp {singleProcess}
# All the 'pc' constraints are here for backward compatibility and
# are not documented. They have been replaced with equivalent 'win'
# constraints.
- testConstraint unixOnly [string equal $tcl_platform(platform) unix]
- testConstraint macOnly \
- [string equal $tcl_platform(platform) macintosh]
- testConstraint pcOnly [string equal $tcl_platform(platform) windows]
- testConstraint winOnly \
- [string equal $tcl_platform(platform) windows]
-
- testConstraint unix [testConstraint unixOnly]
- testConstraint mac [testConstraint macOnly]
- testConstraint pc [testConstraint pcOnly]
- testConstraint win [testConstraint winOnly]
-
- testConstraint unixOrPc \
- [expr {[testConstraint unix] || [testConstraint pc]}]
- testConstraint macOrPc \
- [expr {[testConstraint mac] || [testConstraint pc]}]
- testConstraint unixOrWin \
- [expr {[testConstraint unix] || [testConstraint win]}]
- testConstraint macOrWin \
- [expr {[testConstraint mac] || [testConstraint win]}]
- testConstraint macOrUnix \
- [expr {[testConstraint mac] || [testConstraint unix]}]
-
- testConstraint nt [string equal $tcl_platform(os) "Windows NT"]
- testConstraint 95 [string equal $tcl_platform(os) "Windows 95"]
- testConstraint 98 [string equal $tcl_platform(os) "Windows 98"]
+ ConstraintInitializer unixOnly \
+ {string equal $::tcl_platform(platform) unix}
+ ConstraintInitializer macOnly \
+ {string equal $::tcl_platform(platform) macintosh}
+ ConstraintInitializer pcOnly \
+ {string equal $::tcl_platform(platform) windows}
+ ConstraintInitializer winOnly \
+ {string equal $::tcl_platform(platform) windows}
+
+ ConstraintInitializer unix {testConstraint unixOnly}
+ ConstraintInitializer mac {testConstraint macOnly}
+ ConstraintInitializer pc {testConstraint pcOnly}
+ ConstraintInitializer win {testConstraint winOnly}
+
+ ConstraintInitializer unixOrPc \
+ {expr {[testConstraint unix] || [testConstraint pc]}}
+ ConstraintInitializer macOrPc \
+ {expr {[testConstraint mac] || [testConstraint pc]}}
+ ConstraintInitializer unixOrWin \
+ {expr {[testConstraint unix] || [testConstraint win]}}
+ ConstraintInitializer macOrWin \
+ {expr {[testConstraint mac] || [testConstraint win]}}
+ ConstraintInitializer macOrUnix \
+ {expr {[testConstraint mac] || [testConstraint unix]}}
+
+ ConstraintInitializer nt {string equal $tcl_platform(os) "Windows NT"}
+ ConstraintInitializer 95 {string equal $tcl_platform(os) "Windows 95"}
+ ConstraintInitializer 98 {string equal $tcl_platform(os) "Windows 98"}
# The following Constraints switches are used to mark tests that
# should work, but have been temporarily disabled on certain
# platforms because they don't and we haven't gotten around to
# fixing the underlying problem.
- testConstraint tempNotPc [expr {![testConstraint pc]}]
- testConstraint tempNotWin [expr {![testConstraint win]}]
- testConstraint tempNotMac [expr {![testConstraint mac]}]
- testConstraint tempNotUnix [expr {![testConstraint unix]}]
+ ConstraintInitializer tempNotPc {expr {![testConstraint pc]}}
+ ConstraintInitializer tempNotWin {expr {![testConstraint win]}}
+ ConstraintInitializer tempNotMac {expr {![testConstraint mac]}}
+ ConstraintInitializer tempNotUnix {expr {![testConstraint unix]}}
# The following Constraints switches are used to mark tests that
# crash on certain platforms, so that they can be reactivated again
# when the underlying problem is fixed.
- testConstraint pcCrash [expr {![testConstraint pc]}]
- testConstraint winCrash [expr {![testConstraint win]}]
- testConstraint macCrash [expr {![testConstraint mac]}]
- testConstraint unixCrash [expr {![testConstraint unix]}]
+ ConstraintInitializer pcCrash {expr {![testConstraint pc]}}
+ ConstraintInitializer winCrash {expr {![testConstraint win]}}
+ ConstraintInitializer macCrash {expr {![testConstraint mac]}}
+ ConstraintInitializer unixCrash {expr {![testConstraint unix]}}
# Skip empty tests
- testConstraint emptyTest 0
+ ConstraintInitializer emptyTest {format 0}
# By default, tests that expose known bugs are skipped.
- testConstraint knownBug 0
+ ConstraintInitializer knownBug {format 0}
# By default, non-portable tests are skipped.
- testConstraint nonPortable 0
+ ConstraintInitializer nonPortable {format 0}
# Some tests require user interaction.
- testConstraint userInteraction 0
+ ConstraintInitializer userInteraction {format 0}
# Some tests must be skipped if the interpreter is not in
# interactive mode
- if {[info exists tcl_interactive]} {
- testConstraint interactive $tcl_interactive
- } else {
- testConstraint interactive 0
- }
+ ConstraintInitializer interactive \
+ {expr {[info exists ::tcl_interactive] && $::tcl_interactive}}
# Some tests can only be run if the installation came from a CD
# image instead of a web image. Some tests must be skipped if you
# are running as root on Unix. Other tests can only be run if you
# are running as root on Unix.
- testConstraint root 0
- testConstraint notRoot 1
- if {[string equal unix $tcl_platform(platform)]
- && ([string equal root $tcl_platform(user)]
- || [string equal "" $tcl_platform(user)])} {
- testConstraint root 1
- testConstraint notRoot 0
- }
+ ConstraintInitializer root {expr \
+ {[string equal unix $::tcl_platform(platform)]
+ && ([string equal root $::tcl_platform(user)]
+ || [string equal "" $::tcl_platform(user)])}}
+ ConstraintInitializer notRoot {expr {![testConstraint root]}}
# Set nonBlockFiles constraint: 1 means this platform supports
# setting files into nonblocking mode.
- if {[catch {set f [open defs r]}]} {
- testConstraint nonBlockFiles 1
- } else {
- if {[catch {fconfigure $f -blocking off}] == 0} {
- testConstraint nonBlockFiles 1
- } else {
- testConstraint nonBlockFiles 0
- }
- close $f
+ ConstraintInitializer nonBlockFiles {
+ set code [expr {[catch {set f [open defs r]}]
+ || [catch {fconfigure $f -blocking off}]}]
+ catch {close $f}
+ set code
}
# Set asyncPipeClose constraint: 1 means this platform supports
@@ -1127,94 +1156,82 @@ proc tcltest::InitConstraints {} {
# potential problem with select is apparently interfering.
# (Mark Diekhans).
- testConstraint asyncPipeClose 1
- if {[string equal unix $tcl_platform(platform)] && ([catch {
- exec uname -X | fgrep {Release = 3.2v}}] == 0)} {
- testConstraint asyncPipeClose 0
- }
+ ConstraintInitializer asyncPipeClose {expr {
+ !([string equal unix $::tcl_platform(platform)]
+ && ([catch {exec uname -X | fgrep {Release = 3.2v}}] == 0))}}
# Test to see if we have a broken version of sprintf with respect
# to the "e" format of floating-point numbers.
- testConstraint eformat 1
- if {![string equal [format %g 5e-5] 5e-05]} {
- testConstraint eformat 0
- }
+ ConstraintInitializer eformat {string equal [format %g 5e-5] 5e-05}
# Test to see if execed commands such as cat, echo, rm and so forth
# are present on this machine.
- testConstraint unixExecs 1
- if {[string equal macintosh $tcl_platform(platform)]} {
- testConstraint unixExecs 0
- }
- if {[testConstraint unixExecs]
- && [string equal windows $tcl_platform(platform)]} {
- set file "_tcl_test_remove_me.txt"
- if {[catch {
- set fid [open $file w]
- puts $fid "hello"
- close $fid
- }]} {
- testConstraint unixExecs 0
- } elseif {
- [catch {exec cat $file}] ||
- [catch {exec echo hello}] ||
- [catch {exec sh -c echo hello}] ||
- [catch {exec wc $file}] ||
- [catch {exec sleep 1}] ||
- [catch {exec echo abc > $file}] ||
- [catch {exec chmod 644 $file}] ||
- [catch {exec rm $file}] ||
- [string equal {} [auto_execok mkdir]] ||
- [string equal {} [auto_execok fgrep]] ||
- [string equal {} [auto_execok grep]] ||
- [string equal {} [auto_execok ps]]
+ ConstraintInitializer unixExecs {
+ set code 1
+ if {[string equal macintosh $::tcl_platform(platform)]} {
+ set code 0
+ }
+ if {[string equal windows $::tcl_platform(platform)]} {
+ if {[catch {
+ set file _tcl_test_remove_me.txt
+ makeFile {hello} $file
+ }]} {
+ set code 0
+ } elseif {
+ [catch {exec cat $file}] ||
+ [catch {exec echo hello}] ||
+ [catch {exec sh -c echo hello}] ||
+ [catch {exec wc $file}] ||
+ [catch {exec sleep 1}] ||
+ [catch {exec echo abc > $file}] ||
+ [catch {exec chmod 644 $file}] ||
+ [catch {exec rm $file}] ||
+ [llength [auto_execok mkdir]] == 0 ||
+ [llength [auto_execok fgrep]] == 0 ||
+ [llength [auto_execok grep]] == 0 ||
+ [llength [auto_execok ps]] == 0
} {
- testConstraint unixExecs 0
- }
- file delete -force $file
- }
-
- # Locate tcltest executable
- if {![info exists tk_version]} {
- interpreter [info nameofexecutable]
+ set code 0
+ }
+ removeFile $file
+ }
+ set code
}
- testConstraint stdio 0
- catch {
- catch {file delete -force tmp}
- set f [open tmp w]
- puts $f {
- exit
+ ConstraintInitializer stdio {
+ set code 0
+ if {![catch {set f [open "|[list [interpreter]]" w]}]} {
+ if {![catch {puts $f exit}]} {
+ if {![catch {close $f}]} {
+ set code 1
+ }
+ }
}
- close $f
-
- set f [open "|[list [interpreter] tmp]" r]
- close $f
-
- testConstraint stdio 1
+ set code
}
- catch {file delete -force tmp}
# Deliberately call socket with the wrong number of arguments. The
# error message you get will indicate whether sockets are available
# on this system.
- catch {socket} msg
- testConstraint socket [string compare $msg \
- "sockets are not available on this system"]
+ ConstraintInitializer socket {
+ catch {socket} msg
+ string compare $msg "sockets are not available on this system"
+ }
# Check for internationalization
-
- if {[llength [info commands testlocale]] == 0} {
- # No testlocale command, no tests...
- testConstraint hasIsoLocale 0
- } else {
- testConstraint hasIsoLocale \
- [string length [SetIso8859_1_Locale]]
- RestoreLocale
+ ConstraintInitializer hasIsoLocale {
+ if {[llength [info commands testlocale]] == 0} {
+ set code 0
+ } else {
+ set code [string length [SetIso8859_1_Locale]]
+ RestoreLocale
+ }
+ set code
}
+
}
#####################################################################
@@ -1399,12 +1416,12 @@ proc tcltest::ProcessFlags {flagArray} {
# Use the -constraints flag, if given, to turn on constraints that
# are turned off by default: userInteractive knownBug nonPortable.
- # This code fragment must be run after constraints are initialized.
if {[info exists flag(-constraints)]} {
foreach elt $flag(-constraints) {
testConstraint $elt 1
}
+ ConstraintsSpecifiedByCommandLineArgument $flag(-constraints)
}
# Use the -limitconstraints flag, if given, to tell the harness to
@@ -2220,7 +2237,6 @@ proc tcltest::RunTest {
variable numTests
variable skip
variable match
- variable limitConstraints
variable testConstraints
variable originalTclPlatform
variable coreModTime
@@ -2264,7 +2280,7 @@ proc tcltest::RunTest {
if {[string equal {} $constraints]} {
# If we're limited to the listed constraints and there aren't
# any listed, then we shouldn't run the test.
- if {$limitConstraints} {
+ if {[limitConstraints]} {
AddToSkippedBecause userSpecifiedLimitConstraint
if {$testLevel == 1} {
incr numTests(Skipped)
@@ -3309,7 +3325,25 @@ proc tcltest::threadReap {} {
# Initialize the constraints and set up command line arguments
namespace eval tcltest {
- InitConstraints
+ # Define initializers for all the built-in contraint definitions
+ DefineConstraintInitializers
+
+ # Set up the constraints in the testConstraints array to be lazily
+ # initialized by a registered initializer, or by "false" if no
+ # initializer is registered.
+ trace variable testConstraints r [namespace code SafeFetch]
+
+ # Only initialize constraints at package load time if an
+ # [initConstraintsHook] has been pre-defined. This is only
+ # for compatibility support. The modern way to add a custom
+ # test constraint is to just call the [testConstraint] command
+ # straight away, without all this "hook" nonsense.
+ if {[string equal [namespace current] \
+ [namespace qualifiers [namespace which initConstraintsHook]]]} {
+ InitConstraints
+ } else {
+ proc initConstraintsHook {} {}
+ }
ProcessCmdLineArgs
# Save the names of files that already exist in