Attachment "patch-to--trunk--4427cf5dccdac14a179717fe83f023116f09923c.patch" to
ticket [2964719fff]
added by
kjnash
2012-06-04 02:47:34.
Index: library/init.tcl
==================================================================
--- library/init.tcl
+++ library/init.tcl
@@ -36,32 +36,35 @@
# tcl_pkgPath, which is set by the platform-specific initialization routines
# On UNIX it is compiled in
# On Windows, it is not used
if {![info exists auto_path]} {
- if {[info exists env(TCLLIBPATH)]} {
+ if {[info exists env(TCLLIBPATH)] && (![interp issafe])} {
set auto_path $env(TCLLIBPATH)
} else {
set auto_path ""
}
}
namespace eval tcl {
variable Dir
- foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
+
+ if {![interp issafe]} {
+ foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
+ if {$Dir ni $::auto_path} {
+ lappend ::auto_path $Dir
+ }
+ }
+ set Dir [file join [file dirname [file dirname \
+ [info nameofexecutable]]] lib]
if {$Dir ni $::auto_path} {
lappend ::auto_path $Dir
}
- }
- set Dir [file join [file dirname [file dirname \
- [info nameofexecutable]]] lib]
- if {$Dir ni $::auto_path} {
- lappend ::auto_path $Dir
- }
- catch {
- foreach Dir $::tcl_pkgPath {
- if {$Dir ni $::auto_path} {
- lappend ::auto_path $Dir
+ catch {
+ foreach Dir $::tcl_pkgPath {
+ if {$Dir ni $::auto_path} {
+ lappend ::auto_path $Dir
+ }
}
}
}
if {![interp issafe]} {
Index: library/safe.tcl
==================================================================
--- library/safe.tcl
+++ library/safe.tcl
@@ -306,15 +306,19 @@
[lreplace $access_path $where $where] \
0 [info library]]
Log $slave "tcl_libray was not in first in auto_path,\
moved it to front of slave's access_path" NOTICE
}
+
+ set raw_auto_path $access_path
# Add 1st level sub dirs (will searched by auto loading from tcl
# code in the slave using glob and thus fail, so we add them here
# so by default it works the same).
set access_path [AddSubDirs $access_path]
+ } else {
+ set raw_auto_path {}
}
Log $slave "Setting accessPath=($access_path) staticsok=$staticsok\
nestedok=$nestedok deletehook=($deletehook)" NOTICE
@@ -341,11 +345,24 @@
lappend remap_access_path $dir $token
lappend norm_access_path [file normalize $dir]
incr i
}
+ # Set the slave auto_path.
+ # If [SetAutoPathSync], SyncAccessPath will overwrite this value with the
+ # full access path.
+ # If ![SetAutoPathSync], Safe Base code will not change this value.
+ set tokens_auto_path {}
+ foreach dir $raw_auto_path {
+ if {[dict exists $remap_access_path $dir]} {
+ lappend tokens_auto_path [dict get $remap_access_path $dir]
+ }
+ }
+ ::interp eval $slave [list set auto_path $tokens_auto_path]
+
set morepaths [::tcl::tm::list]
+ set firstpass 1
while {[llength $morepaths]} {
set addpaths $morepaths
set morepaths {}
foreach dir $addpaths {
@@ -359,11 +376,16 @@
lappend access_path $dir
lappend slave_access_path $token
lappend map_access_path $token $dir
lappend remap_access_path $dir $token
lappend norm_access_path [file normalize $dir]
- lappend slave_tm_path $token
+ if {$firstpass} {
+ # $dir is in [::tcl::tm::list] and belongs in the slave_tm_path.
+ # Later passes handle subdirectories, which belong in the
+ # access path but not in the module path.
+ lappend slave_tm_path $token
+ }
incr i
# [Bug 2854929]
# Recursively find deeper paths which may contain
# modules. Required to handle modules with names like
@@ -370,10 +392,11 @@
# 'platform::shell', which translate into
# 'platform/shell-X.tm', i.e arbitrarily deep
# subdirectories.
lappend morepaths {*}[glob -nocomplain -directory $dir -type d *]
}
+ set firstpass 0
}
set state(access_path) $access_path
set state(access_path,map) $map_access_path
set state(access_path,remap) $remap_access_path
@@ -544,10 +567,19 @@
proc ::safe::interpDelete {slave} {
Log $slave "About to delete" NOTICE
namespace upvar ::safe S$slave state
+
+ # Sub interpreters would be deleted automatically, but if they are managed
+ # by the Safe Base we also need to clean up, and this needs to be done
+ # independently of the cleanupHook.
+ foreach sub [interp slaves $slave] {
+ if {[info exists ::safe::S[list $slave $sub]]} {
+ ::safe::interpDelete [list $slave $sub]
+ }
+ }
# If the slave has a cleanup hook registered, call it. Check the
# existance because we might be called to delete an interp which has
# not been registered with us at all
@@ -615,17 +647,20 @@
#
# Sets the slave auto_path to the master recorded value. Also sets
# tcl_library to the first token of the virtual path.
#
proc ::safe::SyncAccessPath {slave} {
+ variable AutoPathSync
namespace upvar ::safe S$slave state
set slave_access_path $state(access_path,slave)
- ::interp eval $slave [list set auto_path $slave_access_path]
+ if {$AutoPathSync} {
+ ::interp eval $slave [list set auto_path $slave_access_path]
- Log $slave "auto_path in $slave has been set to $slave_access_path"\
- NOTICE
+ Log $slave "auto_path in $slave has been set to $slave_access_path"\
+ NOTICE
+ }
# This code assumes that info library is the first element in the
# list of auto_path's. See -> InterpSetConfig for the code which
# ensures this condition.
@@ -688,10 +723,11 @@
}
# AliasGlob is the target of the "glob" alias in safe interpreters.
proc ::safe::AliasGlob {slave args} {
+ variable AutoPathSync
Log $slave "GLOB ! $args" NOTICE
set cmd {}
set at 0
array set got {
-directory 0
@@ -710,14 +746,18 @@
set dir {}
set virtualdir {}
while {$at < [llength $args]} {
switch -glob -- [set opt [lindex $args $at]] {
- -nocomplain - -- - -join - -tails {
+ -nocomplain - -- - -tails {
lappend cmd $opt
set got($opt) 1
incr at
+ }
+ -join {
+ set got($opt) 1
+ incr at
}
-types - -type {
lappend cmd -types [lindex $args [incr at]]
incr at
}
@@ -729,15 +769,19 @@
set got($opt) 1
set virtualdir [lindex $args [incr at]]
incr at
}
pkgIndex.tcl {
- # Oops, this is globbing a subdirectory in regular package
- # search. That is not wanted. Abort, handler does catch
- # already (because glob was not defined before). See
- # package.tcl, lines 484ff in tclPkgUnknown.
- return -code error "unknown command glob"
+ if {$AutoPathSync} {
+ # Oops, this is globbing a subdirectory in regular package
+ # search. That is not wanted. Abort, handler does catch
+ # already (because glob was not defined before). See
+ # package.tcl, lines 484ff in tclPkgUnknown.
+ return -code error "unknown command glob"
+ } else {
+ break
+ }
}
-* {
Log $slave "Safe base rejecting glob option '$opt'"
return -code error "Safe base rejecting glob option '$opt'"
}
@@ -761,11 +805,11 @@
return -code error "permission denied"
}
lappend cmd -directory $dir
}
- # Apply the -join semantics ourselves
+ # Apply the -join semantics ourselves (hence -join not copied to $cmd)
if {$got(-join)} {
set args [lreplace $args $at end [join [lrange $args $at end] "/"]]
}
# Process remaining pattern arguments
@@ -1102,13 +1146,54 @@
# Log eventually.
# To enable error logging, set Log to {puts stderr} for instance,
# via setLogCmd.
return
}
+
+# Accessor method for ::safe::SetAutoPathSync
+# Usage: ::safe::SetAutoPathSync ?newValue?
+
+proc ::safe::SetAutoPathSync {args} {
+ variable AutoPathSync
+
+ if {[llength $args] == 1} {
+ set newValue [lindex $args 0]
+ if {![string is boolean -strict $newValue]} {
+ return -code error "new value must be a valid boolean"
+ }
+ set args [expr {$newValue && $newValue}]
+ if {([info vars ::safe::S*] ne {}) && ($args != $AutoPathSync)} {
+ return -code error \
+ "cannot change AutoPathSync while Safe Base slaves exist"
+ }
+ }
+
+ set AutoPathSync {*}$args
+}
namespace eval ::safe {
- # internal variables
+ # internal variables (must not begin with "S")
+
+ # AutoPathSync
+ #
+ # Set AutoPathSync to 0 to give a slave's ::auto_path the same meaning as
+ # for an unsafe interpreter: the package command will search its directories
+ # and first-level subdirectories for pkgIndex.tcl files; the auto-loader
+ # will search its directories for tclIndex files. The access path and
+ # module path will be maintained as separate values, and ::auto_path will
+ # not be updated when the user calls ::safe::interpAddToAccessPath to add to
+ # the access path. If the user specifies an access path when calling
+ # interpCreate, interpInit or interpConfigure, it is the user's
+ # responsibility to define the slave's auto_path. If these commands are
+ # called with no (or empty) access path, the slave's auto_path will be set
+ # to a tokenized form of the master's auto_path, and these directories and
+ # their first-level subdirectories will be added to the access path.
+ #
+ # Set to 1 for "traditional" behavior: a slave's entire access path and
+ # module path are copied to its ::auto_path, which is updated whenever
+ # the user calls ::safe::interpAddToAccessPath to add to the access path.
+ variable AutoPathSync 1
# Log command, set via 'setLogCmd'. Logging is disabled when empty.
variable Log {}
# The package maintains a state array per slave interp under its
Index: tests/safe.test
==================================================================
--- tests/safe.test
+++ tests/safe.test
@@ -15,10 +15,12 @@
if {[lsearch [namespace children] ::tcltest] == -1} {
package require tcltest 2
namespace import -force ::tcltest::*
}
+testConstraint AutoSyncDefined 1
+
foreach i [interp slaves] {
interp delete $i
}
set saveAutoPath $::auto_path
@@ -178,39 +180,127 @@
# More test should be added to check that hostname, nameofexecutable, aren't
# leaking infos, but they still do...
# high level general test
-test safe-7.1 {tests that everything works at high level} {
+test safe-7.1 {tests that everything works at high level with conventional AutoPathSync} -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 1
+ }
+
set i [safe::interpCreate]
+
+} -body {
# no error shall occur:
- # (because the default access_path shall include 1st level sub dirs so
- # package require in a slave works like in the master)
+ # (because the default access_path shall include 1st level sub dirs
+ # so package require in a slave works like in the master)
set v [interp eval $i {package require http 1}]
# no error shall occur:
interp eval $i {http_config}
- safe::interpDelete $i
set v
-} 1.0
-test safe-7.2 {tests specific path and interpFind/AddToAccessPath} -body {
+} -cleanup {
+ safe::interpDelete $i
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -result 1.0
+
+test safe-7.2 {tests specific path and interpFind/AddToAccessPath with conventional AutoPathSync} -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 1
+ } else {
+ set SyncVal_TMP 1
+ }
+} -body {
set i [safe::interpCreate -nostat -nested 1 -accessPath [list [info library]]]
# should not add anything (p0)
set token1 [safe::interpAddToAccessPath $i [info library]]
- # should add as p1
+ # should add as p* (not p1 if master has a module path)
set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"]
# an error shall occur (http is not anymore in the secure 0-level
# provided deep path)
list $token1 $token2 \
[catch {interp eval $i {package require http 1}} msg] $msg \
[safe::interpConfigure $i]\
[safe::interpDelete $i]
+} -cleanup {
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
} -match glob -result "{\$p(:0:)} {\$p(:*:)} 1 {can't find package http 1} {-accessPath {[list $tcl_library */dummy/unixlike/test/path]} -statics 0 -nested 1 -deleteHook {}} {}"
+
test safe-7.3 {check that safe subinterpreters work} {
set i [safe::interpCreate]
set j [safe::interpCreate [list $i x]]
- list [interp eval $j {join {o k} ""}] [safe::interpDelete $i] [interp exists $j]
-} {ok {} 0}
+ list [interp slaves $i] [interp slaves $j] [interp eval $j {join {o k} ""}] [safe::interpDelete $i] [interp exists $i] [interp exists $j] [info vars ::safe::S$i] [info vars ::safe::S$j]
+} {x {} ok {} 0 0 {} {}}
+
+test safe-7.4 {tests specific path and positive search with conventional AutoPathSync} -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 1
+ } else {
+ set SyncVal_TMP 1
+ }
+} -body {
+ set i [safe::interpCreate -nostat -nested 1 -accessPath [list [info library]]]
+ # should not add anything (p0)
+ set token1 [safe::interpAddToAccessPath $i [info library]]
+ # should add as p* (not p1 if master has a module path)
+ set token2 [safe::interpAddToAccessPath $i [file join [info library] http1.0]]
+ # this time, unlike test safe-7.2, http 1.0 should be found
+ list $token1 $token2 \
+ [catch {interp eval $i {package require http 1}} msg] $msg \
+ [safe::interpConfigure $i]\
+ [safe::interpDelete $i]
+ # Note that the glob match elides directories (those from the module path)
+ # other than the first and last in the access path.
+} -cleanup {
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -match glob -result "{\$p(:0:)} {\$p(:*:)} 0 1.0 {-accessPath {[list $tcl_library *$tcl_library/http1.0]} -statics 0 -nested 1 -deleteHook {}} {}"
+
+test safe-7.5 {tests positive and negative module loading with conventional AutoPathSync} -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 1
+ }
+
+ set i [safe::interpCreate]
+
+ interp eval $i {
+ package forget platform::shell
+ package forget platform
+ catch {namespace delete ::platform}
+ }
+} -body {
+ # Should raise an error (module ancestor directory issue)
+ set code1 [catch {interp eval $i {package require shell}} msg1]
+ # Should not raise an error
+ set code2 [catch {interp eval $i {package require platform::shell}} msg2]
+ return [list $code1 $msg1 $code2]
+} -cleanup {
+ safe::interpDelete $i
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -result {1 {can't find package shell} 0}
# test source control on file name
test safe-8.1 {safe source control on file} -setup {
set i "a"
catch {safe::interpDelete $i}
@@ -399,10 +489,12 @@
[safe::interpConfigure $i -DEL]\
[safe::interpConfigure $i -accessPath /blah -statics 1
safe::interpConfigure $i]\
[safe::interpConfigure $i -deleteHook toto -nosta -nested 0
safe::interpConfigure $i]
+} -cleanup {
+ safe::interpDelete $i
} -match glob -result {{-accessPath * -statics 0 -nested 1 -deleteHook {foo bar}} {-accessPath *} {-nested 1} {-statics 0} {-deleteHook {foo bar}} {-accessPath * -statics 1 -nested 1 -deleteHook {foo bar}} {-accessPath * -statics 0 -nested 0 -deleteHook toto}}
catch {teststaticpkg Safepkg1 0 0}
test safe-10.1 {testing statics loading} -constraints TcltestPackage -setup {
set i [safe::interpCreate]
@@ -747,14 +839,256 @@
::safe::interpAddToAccessPath $i $~$tcl_platform(user)
$i eval [list glob -nocomplain ~$tcl_platform(user)/*]
} -cleanup {
safe::interpDelete $i
} -result {}
+
+
+### 17. The first element in a slave's ::auto_path and access path must be [info library].
+
+test safe-17.1 {Check that first element of slave auto_path (and access path) is Tcl Library} -setup {
+ set lib1 [info library]
+ set lib2 [file dirname $lib1]
+ set ::auto_TMP $::auto_path
+ set ::auto_path [list $lib1 $lib2]
+
+ set i [safe::interpCreate]
+} -body {
+ set autoList {}
+ set token [lindex [$i eval set ::auto_path] 0]
+ set auto0 [dict get [set ::safe::S${i}(access_path,map)] $token]
+ set accessList [lindex [safe::interpConfigure $i -accessPath] 1]
+ return [list [lindex $accessList 0] $auto0]
+} -cleanup {
+ set ::auto_path $::auto_TMP
+ safe::interpDelete $i
+} -result [list [info library] [info library]]
+
+test safe-17.2 {Check that first element of slave auto_path (and access path) is Tcl Library, even if not true for master} -setup {
+ set lib1 [info library]
+ set lib2 [file dirname $lib1]
+ set ::auto_TMP $::auto_path
+ set ::auto_path [list $lib2 $lib1]
+ # Unexpected order, should be reversed in the slave
+
+ set i [safe::interpCreate]
+} -body {
+ set autoList {}
+ set token [lindex [$i eval set ::auto_path] 0]
+ set auto0 [dict get [set ::safe::S${i}(access_path,map)] $token]
+ set accessList [lindex [safe::interpConfigure $i -accessPath] 1]
+
+ return [list [lindex $accessList 0] $auto0]
+} -cleanup {
+ set ::auto_path $::auto_TMP
+ safe::interpDelete $i
+} -result [list [info library] [info library]]
+
+### 18. Tests for AutoSyncDefined without conventional AutoPathSync, i.e. with AutoPathSync off.
+
+test safe-18.1 {cf. safe-7.1 - tests that everything works at high level without conventional AutoPathSync} -constraints AutoSyncDefined -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 0
+ } else {
+ error {This test is meaningful only if the command ::safe::SetAutoPathSync is defined}
+ }
+
+ # Without AutoPathSync, we need a more complete auto_path, because the slave will use the same value.
+ set lib1 [info library]
+ set lib2 [file dirname $lib1]
+ set ::auto_TMP $::auto_path
+ set ::auto_path [list $lib1 $lib2]
+
+ set i [safe::interpCreate]
+} -body {
+ # no error shall occur:
+ # (because the default access_path shall include 1st level sub dirs
+ # so package require in a slave works like in the master)
+ set v [interp eval $i {package require http 1}]
+ # no error shall occur:
+ interp eval $i {http_config}
+ set v
+} -cleanup {
+ set ::auto_path $::auto_TMP
+ safe::interpDelete $i
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -result 1.0
+
+test safe-18.2 {cf. safe-7.2 - tests specific path and interpFind/AddToAccessPath without conventional AutoPathSync} -constraints AutoSyncDefined -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 0
+ } else {
+ error {This test is meaningful only if the command ::safe::SetAutoPathSync is defined}
+ }
+} -body {
+ set i [safe::interpCreate -nostat -nested 1 -accessPath [list [info library]]]
+ set auto1 [interp eval $i {set ::auto_path}]
+ interp eval $i {set ::auto_path [list {$p(:0:)}]}
+ # should not add anything (p0)
+ set token1 [safe::interpAddToAccessPath $i [info library]]
+ # should add as p1
+ set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"]
+ # an error shall occur (http is not anymore in the secure 0-level
+ # provided deep path)
+ list $auto1 $token1 $token2 \
+ [catch {interp eval $i {package require http 1}} msg] $msg \
+ [safe::interpConfigure $i]\
+ [safe::interpDelete $i]
+} -cleanup {
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -match glob -result "{} {\$p(:0:)} {\$p(:*:)} 1 {can't find package http 1} {-accessPath {[list $tcl_library */dummy/unixlike/test/path]} -statics 0 -nested 1 -deleteHook {}} {}"
+
+test safe-18.3 {Check that default auto_path is the same as in the master interpreter without conventional AutoPathSync} -constraints AutoSyncDefined -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 0
+ } else {
+ error {This test is meaningful only if the command ::safe::SetAutoPathSync is defined}
+ }
+
+ set i [safe::interpCreate]
+
+} -body {
+ # This file's header sets auto_path to a single directory [info library],
+ # which is the one required by Safe Base to be present & first in the list.
+
+ set ap {}
+ foreach token [$i eval set ::auto_path] {
+ lappend ap [dict get [set ::safe::S${i}(access_path,map)] $token]
+ }
+ return $ap
+} -cleanup {
+ safe::interpDelete $i
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -result [set ::auto_path]
+
+test safe-18.4 {cf. safe-7.4 - tests specific path and positive search and auto_path without conventional AutoPathSync} -constraints AutoSyncDefined -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 0
+ } else {
+ error {This test is meaningful only if the command ::safe::SetAutoPathSync is defined}
+ }
+} -body {
+ set i [safe::interpCreate -nostat -nested 1 -accessPath [list [info library]]]
+
+ # should not have been set by Safe Base:
+ set auto1 [interp eval $i {set ::auto_path}]
+
+ interp eval $i {set ::auto_path [list {$p(:0:)}]}
+
+ # should not add anything (p0)
+ set token1 [safe::interpAddToAccessPath $i [info library]]
+
+ # should add as p* (not p1 if master has a module path)
+ set token2 [safe::interpAddToAccessPath $i [file join [info library] http1.0]]
+
+ # should not have been changed by Safe Base:
+ set auto2 [interp eval $i {set ::auto_path}]
+
+ # This time, unlike test safe-18.2 and the try above, http 1.0 should be found:
+ list $auto1 $auto2 $token1 $token2 \
+ [catch {interp eval $i {package require http 1}} msg] $msg \
+ [safe::interpConfigure $i]\
+ [safe::interpDelete $i]
+} -cleanup {
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -match glob -result "{} {{\$p(:0:)}} {\$p(:0:)} {\$p(:*:)} 0 1.0 {-accessPath {[list $tcl_library *$tcl_library/http1.0]} -statics 0 -nested 1 -deleteHook {}} {}"
+
+test safe-18.5 {cf. safe-7.5 - tests positive and negative module loading without conventional AutoPathSync} -setup {
+ # All ::safe commands are loaded at start of file.
+ set SyncExists [expr {[info commands ::safe::SetAutoPathSync] ne {}}]
+
+ if {$SyncExists} {
+ set SyncVal_TMP [safe::SetAutoPathSync]
+ safe::SetAutoPathSync 0
+ } else {
+ error {This test is meaningful only if the command ::safe::SetAutoPathSync is defined}
+ }
+
+ set i [safe::interpCreate]
+
+ interp eval $i {
+ package forget platform::shell
+ package forget platform
+ catch {namespace delete ::platform}
+ }
+} -body {
+ # Should raise an error (tests module ancestor directory rule)
+ set code1 [catch {interp eval $i {package require shell}} msg1]
+ # Should not raise an error
+ set code2 [catch {interp eval $i {package require platform::shell}} msg2]
+ return [list $code1 $msg1 $code2]
+} -cleanup {
+ safe::interpDelete $i
+ if {$SyncExists} {
+ safe::SetAutoPathSync $SyncVal_TMP
+ }
+} -result {1 {can't find package shell} 0}
+
+### 19. Test tokenization of directories available to a slave.
+
+test safe-19.1 {Check that each directory of the default auto_path is a valid token} -setup {
+ set i [safe::interpCreate]
+} -body {
+ set badTokens {}
+ foreach dir [$i eval {set ::auto_path}] {
+ if {[regexp {^\$p\(:[0-9]+:\)$} $dir]} {
+ # Match - OK - token has expected form
+ } else {
+ # No match - possibly an ordinary path has not been tokenized
+ lappend badTokens $dir
+ }
+ }
+ set badTokens
+} -cleanup {
+ safe::interpDelete $i
+} -result {}
+
+test safe-19.2 {Check that each directory of the module path is a valid token} -setup {
+ set i [safe::interpCreate]
+} -body {
+ set badTokens {}
+ foreach dir [$i eval {::tcl::tm::path list}] {
+ if {[regexp {^\$p\(:[0-9]+:\)$} $dir]} {
+ # Match - OK - token has expected form
+ } else {
+ # No match - possibly an ordinary path has not been tokenized
+ lappend badTokens $dir
+ }
+ }
+ set badTokens
+} -cleanup {
+ safe::interpDelete $i
+} -result {}
+
set ::auto_path $saveAutoPath
# cleanup
::tcltest::cleanupTests
return
# Local Variables:
# mode: tcl
# End: