diff options
-rw-r--r-- | doc/safe.n | 135 | ||||
-rw-r--r-- | library/safe.tcl | 250 | ||||
-rw-r--r-- | library/tclIndex | 1 | ||||
-rw-r--r-- | tests/safe.test | 824 |
4 files changed, 1159 insertions, 51 deletions
@@ -23,10 +23,13 @@ safe \- Creating and manipulating safe interpreters .sp \fB::safe::interpFindInAccessPath\fR \fIslave\fR \fIdirectory\fR .sp +\fB::safe::setAutoPathSync\fR ?\fInewValue\fR? +.sp \fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? .SS OPTIONS .PP ?\fB\-accessPath\fR \fIpathList\fR? +?\fB\-autoPath\fR \fIpathList\fR? ?\fB\-statics\fR \fIboolean\fR? ?\fB\-noStatics\fR? ?\fB\-nested\fR \fIboolean\fR? ?\fB\-nestedLoadOk\fR? ?\fB\-deleteHook\fR \fIscript\fR? @@ -140,6 +143,15 @@ $slave eval [list set tk_library \e .CE .RE .TP +\fB::safe::setAutoPathSync\fR ?\fInewValue\fR? +This command is used to get or set the "Sync Mode" of the Safe Base. +When an argument is supplied, the command returns an error if the argument +is not a boolean value, or if any Safe Base interpreters exist. Typically +the value will be set as part of initialization - boolean true for +"Sync Mode" on (the default), false for "Sync Mode" off. With "Sync Mode" +on, the Safe Base keeps each slave interpreter's ::auto_path synchronized +with its access path. See the section \fBSYNC MODE\fR below for details. +.TP \fB::safe::setLogCmd\fR ?\fIcmd arg...\fR? This command installs a script that will be called when interesting life cycle events occur for a safe interpreter. @@ -191,6 +203,13 @@ master for auto-loading. See the section \fBSECURITY\fR below for more detail about virtual paths, tokens and access control. .TP +\fB\-autoPath\fR \fIdirectoryList\fR +This option sets the list of directories in the safe interpreter's +::auto_path. The option is undefined if the Safe Base has "Sync Mode" on +- in that case the safe interpreter's ::auto_path is managed by the Safe +Base and is a tokenized form of its access path. +See the section \fBSYNC MODE\fR below for details. +.TP \fB\-statics\fR \fIboolean\fR This option specifies if the safe interpreter will be allowed to load statically linked packages (like \fBload {} Tk\fR). @@ -323,7 +342,8 @@ list will be assigned a token that will be set in the slave \fBauto_path\fR and the first element of that list will be set as the \fBtcl_library\fR for that slave. .PP -If the access path argument is not given or is the empty list, +If the access path argument is not given to \fB::safe::interpCreate\fR or +\fB::safe::interpInit\fR or is the empty list, the default behavior is to let the slave access the same packages as the master has access to (Or to be more precise: only packages written in Tcl (which by definition cannot be dangerous @@ -349,8 +369,119 @@ When the \fIaccessPath\fR is changed after the first creation or initialization (i.e. through \fBinterpConfigure -accessPath \fR\fIlist\fR), an \fBauto_reset\fR is automatically evaluated in the safe interpreter to synchronize its \fBauto_index\fR with the new token list. +.SH SYNC MODE +Before Tcl version 8.6.x, the Safe Base kept each safe interpreter's +::auto_path synchronized with a tokenized form of its access path. +Limitations of Tcl 8.4 and earlier made this feature necessary. This +definition of ::auto_path did not conform its specification in library(n) +and pkg_mkIndex(n), but nevertheless worked perfectly well for the discovery +and loading of packages. The introduction of Tcl modules in Tcl 8.5 added a +large number of directories to the access path, and it is inconvenient to +have these additional directories unnecessarily appended to the ::auto_path. +.PP +In order to preserve compatibility with existing code, this synchronization +of the ::auto_path and access path ("Sync Mode" on) is still the default. +However, the Safe Base offers the option of limiting the safe interpreter's +::auto_path to the much shorter list of directories that is necessary for +it to perform its function ("Sync Mode" off). Use the command +\fB::safe::setAutoPathSync\fR to choose the mode before creating any Safe +Base interpreters. +.PP +In either mode, the most convenient way to initialize a safe interpreter is +to call \fB::safe::interpCreate\fR or \fB::safe::interpInit\fR without the +\fB\-accessPath\fR or \fB\-autoPath\fR options (or with the \fB\-accessPath\fR +option set to the +empty list), which will give the safe interpreter the same access as the +master interpreter to packages, modules, and autoloader files. With +"Sync Mode" off, the ::auto_path will be set to a tokenized form of the master's +::auto_path. +.PP +With "Sync Mode" off, if a value is specified for \fB\-autoPath\fR, even the empty +list, in a call to \fB::safe::interpCreate\fR, \fB::safe::interpInit\fR, or +\fB::safe::interpConfigure\fR, it will be tokenized and used as the safe +interpreter's ::auto_path. Any directories that do not also belong to the +access path cannot be tokenized and will be silently ignored. +.PP +With "Sync Mode" off, if the access path is reset to the values in the +master interpreter by calling \fB::safe::interpConfigure\fR with arguments +\fB\-accessPath\fR {}, then the ::auto_path will also be reset unless the argument +\fB\-autoPath\fR is supplied to specify a different value. +.PP +With "Sync Mode" off, if a non-empty value of \fB\-accessPath\fR is supplied, the +safe interpreter's ::auto_path will be set to {} (by +\fB::safe::interpCreate\fR, \fB::safe::interpInit\fR) or left unchanged +(by \fB::safe::interpConfigure\fR). If the same command specifies a new +value for \fB\-autoPath\fR, it will be applied after the \fB\-accessPath\fR argument has +been processed. + +Examples of use with "Sync Mode" off: any of these commands will set the +::auto_path to a tokenized form of its value in the master interpreter: +.RS +.PP +.CS + safe::interpCreate foo + safe::interpCreate foo -accessPath {} + safe::interpInit bar + safe::interpInit bar -accessPath {} + safe::interpConfigure foo -accessPath {} +.CE +.RE +.TP +Example of use with "Sync Mode" off: when initializing a safe interpreter +with a non-empty access path, the ::auto_path will be set to {} unless its +own value is also specified: +.RS +.PP +.CS + safe::interpCreate foo -accessPath { + /usr/local/TclHome/lib/tcl8.6 + /usr/local/TclHome/lib/tcl8.6/http1.0 + /usr/local/TclHome/lib/tcl8.6/opt0.4 + /usr/local/TclHome/lib/tcl8.6/msgs + /usr/local/TclHome/lib/tcl8.6/encoding + /usr/local/TclHome/lib + } + + # The slave's ::auto_path must be given a suitable value: + + safe::interpConfigure foo -autoPath { + /usr/local/TclHome/lib/tcl8.6 + /usr/local/TclHome/lib + } + + # The two commands can be combined: + + safe::interpCreate foo -accessPath { + /usr/local/TclHome/lib/tcl8.6 + /usr/local/TclHome/lib/tcl8.6/http1.0 + /usr/local/TclHome/lib/tcl8.6/opt0.4 + /usr/local/TclHome/lib/tcl8.6/msgs + /usr/local/TclHome/lib/tcl8.6/encoding + /usr/local/TclHome/lib + } -autoPath { + /usr/local/TclHome/lib/tcl8.6 + /usr/local/TclHome/lib + } +.CE +.RE +.TP +Example of use with "Sync Mode" off: the command +\fBsafe::interpAddToAccessPath\fR does not change the safe interpreter's +::auto_path, and so any necessary change must be made by the script: +.RS +.PP +.CS + safe::interpAddToAccessPath foo /usr/local/TclHome/lib/extras/Img1.4.11 + + lassign [safe::interpConfigure foo -autoPath] DUM slaveAutoPath + lappend slaveAutoPath /usr/local/TclHome/lib/extras/Img1.4.11 + safe::interpConfigure foo -autoPath $slaveAutoPath +.CE +.RE +.TP .SH "SEE ALSO" -interp(n), library(n), load(n), package(n), source(n), unknown(n) +interp(n), library(n), load(n), package(n), pkg_mkIndex(n), source(n), +tm(n), unknown(n) .SH KEYWORDS alias, auto\-loading, auto_mkindex, load, master interpreter, safe interpreter, slave interpreter, source diff --git a/library/safe.tcl b/library/safe.tcl index e3eabac..9218380 100644 --- a/library/safe.tcl +++ b/library/safe.tcl @@ -78,18 +78,29 @@ proc ::safe::InterpNested {} { # Interface/entry point function and front end for "Create" proc ::safe::interpCreate {args} { + variable AutoPathSync + if {$AutoPathSync} { + set autoPath {} + } set Args [::tcl::OptKeyParse ::safe::interpCreate $args] + + set withAutoPath [::tcl::OptProcArgGiven -autoPath] InterpCreate $slave $accessPath \ - [InterpStatics] [InterpNested] $deleteHook + [InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath } proc ::safe::interpInit {args} { + variable AutoPathSync + if {$AutoPathSync} { + set autoPath {} + } set Args [::tcl::OptKeyParse ::safe::interpIC $args] if {![::interp exists $slave]} { return -code error "\"$slave\" is not an interpreter" } + set withAutoPath [::tcl::OptProcArgGiven -autoPath] InterpInit $slave $accessPath \ - [InterpStatics] [InterpNested] $deleteHook + [InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath } # Check that the given slave is "one of us" @@ -115,6 +126,7 @@ proc ::safe::CheckInterp {slave} { # So this will be hopefully written and some integrated with opt1.0 # (hopefully for tcl8.1 ?) proc ::safe::interpConfigure {args} { + variable AutoPathSync switch [llength $args] { 1 { # If we have exactly 1 argument the semantic is to return all @@ -125,11 +137,17 @@ proc ::safe::interpConfigure {args} { CheckInterp $slave namespace upvar ::safe S$slave state - return [join [list \ + set TMP [list \ [list -accessPath $state(access_path)] \ [list -statics $state(staticsok)] \ [list -nested $state(nestedok)] \ - [list -deleteHook $state(cleanupHook)]]] + [list -deleteHook $state(cleanupHook)] \ + ] + if {!$AutoPathSync} { + set SLAP [DetokPath $slave [$slave eval set ::auto_path]] + lappend TMP [list -autoPath $SLAP] + } + return [join $TMP] } 2 { # If we have exactly 2 arguments the semantic is a "configure @@ -154,6 +172,14 @@ proc ::safe::interpConfigure {args} { -accessPath { return [list -accessPath $state(access_path)] } + -autoPath { + if {$AutoPathSync} { + return -code error "unknown flag $name (bug)" + } else { + set SLAP [DetokPath $slave [$slave eval set ::auto_path]] + return [list -autoPath $SLAP] + } + } -statics { return [list -statics $state(staticsok)] } @@ -197,6 +223,13 @@ proc ::safe::interpConfigure {args} { } else { set doreset 1 } + if {(!$AutoPathSync) && (![::tcl::OptProcArgGiven -autoPath])} { + set SLAP [DetokPath $slave [$slave eval set ::auto_path]] + set autoPath $SLAP + } elseif {$AutoPathSync} { + set autoPath {} + } else { + } if { ![::tcl::OptProcArgGiven -statics] && ![::tcl::OptProcArgGiven -noStatics] @@ -217,8 +250,10 @@ proc ::safe::interpConfigure {args} { set deleteHook $state(cleanupHook) } # we can now reconfigure : - set slave_tm_rel [InterpSetConfig $slave $accessPath $statics $nested $deleteHook] - # auto_reset the slave (to completly synch the new access_path) + set withAutoPath [::tcl::OptProcArgGiven -autoPath] + set slave_tm_rel [InterpSetConfig $slave $accessPath $statics $nested $deleteHook $autoPath $withAutoPath] + + # auto_reset the slave (to completely synch the new access_path) tests safe-9.8 safe-9.9 if {$doreset} { if {[catch {::interp eval $slave {auto_reset}} msg]} { Log $slave "auto_reset failed: $msg" @@ -269,10 +304,11 @@ proc ::safe::interpConfigure {args} { # Optional Arguments : # + slave name : if empty, generated name will be used # + access_path: path list controlling where load/source can occur, -# if empty: the master auto_path will be used. +# if empty: the master auto_path and its subdirectories will be +# used. # + staticsok : flag, if 0 :no static package can be loaded (load {} Xxx) # if 1 :static packages are ok. -# + nestedok: flag, if 0 :no loading to sub-sub interps (load xx xx sub) +# + nestedok : flag, if 0 :no loading to sub-sub interps (load xx xx sub) # if 1 : multiple levels are ok. # use the full name and no indent so auto_mkIndex can find us @@ -282,6 +318,8 @@ proc ::safe::InterpCreate { staticsok nestedok deletehook + autoPath + withAutoPath } { # Create the slave. if {$slave ne ""} { @@ -293,20 +331,25 @@ proc ::safe::InterpCreate { Log $slave "Created" NOTICE # Initialize it. (returns slave name) - InterpInit $slave $access_path $staticsok $nestedok $deletehook + InterpInit $slave $access_path $staticsok $nestedok $deletehook $autoPath $withAutoPath } # # InterpSetConfig (was setAccessPath) : -# Sets up slave virtual auto_path and corresponding structure within +# Sets up slave virtual access path and corresponding structure within # the master. Also sets the tcl_library in the slave to be the first # directory in the path. # NB: If you change the path after the slave has been initialized you # probably need to call "auto_reset" in the slave in order that it gets # the right auto_index() array values. +# +# It is the caller's responsibility, if it supplies a non-empty value for +# access_path, to make the first directory in the path suitable for use as +# tcl_library, and (if ![setAutoPathSync]), to set the slave's ::auto_path. -proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { +proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook autoPath withAutoPath} { global auto_path + variable AutoPathSync # determine and store the access path if empty if {$access_path eq ""} { @@ -329,14 +372,25 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { 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 $autoPath + } + + if {$withAutoPath} { + set raw_auto_path $autoPath } Log $slave "Setting accessPath=($access_path) staticsok=$staticsok\ nestedok=$nestedok deletehook=($deletehook)" NOTICE + if {!$AutoPathSync} { + Log $slave "Setting auto_path=($raw_auto_path)" NOTICE + } namespace upvar ::safe S$slave state @@ -346,7 +400,6 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { # We save the virtual form separately as well, as syncing it with the # slave has to be defered until the necessary commands are present for # setup. - set norm_access_path {} set slave_access_path {} set map_access_path {} @@ -365,6 +418,20 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { incr i } + # Set the slave auto_path to a tokenized raw_auto_path. + # Silently ignore any directories that are not in the access 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] + + # Add the tcl::tm directories to the access path. set morepaths [::tcl::tm::list] set firstpass 1 while {[llength $morepaths]} { @@ -430,14 +497,38 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { set state(cleanupHook) $deletehook SyncAccessPath $slave + return $slave_tm_rel } + +# +# DetokPath: +# Convert tokens to directories where possible. +# Leave undefined tokens unconverted. They are +# nonsense in both the slave and the master. # +proc ::safe::DetokPath {slave tokenPath} { + namespace upvar ::safe S$slave state + + set slavePath {} + foreach token $tokenPath { + if {[dict exists $state(access_path,map) $token]} { + lappend slavePath [dict get $state(access_path,map) $token] + } else { + lappend slavePath $token + } + } + return $slavePath +} + # -# FindInAccessPath: +# +# interpFindInAccessPath: # Search for a real directory and returns its virtual Id (including the # "$") +# +# When debugging, use TranslatePath for the inverse operation. proc ::safe::interpFindInAccessPath {slave path} { namespace upvar ::safe S$slave state @@ -448,6 +539,7 @@ proc ::safe::interpFindInAccessPath {slave path} { return [dict get $state(access_path,remap) $path] } + # # addToAccessPath: # add (if needed) a real directory to access path and return its @@ -483,9 +575,11 @@ proc ::safe::InterpInit { staticsok nestedok deletehook + autoPath + withAutoPath } { # Configure will generate an access_path when access_path is empty. - InterpSetConfig $slave $access_path $staticsok $nestedok $deletehook + InterpSetConfig $slave $access_path $staticsok $nestedok $deletehook $autoPath $withAutoPath # NB we need to add [namespace current], aliases are always absolute # paths. @@ -591,6 +685,15 @@ proc ::safe::interpDelete {slave} { 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 @@ -657,24 +760,28 @@ proc ::safe::setLogCmd {args} { # ------------------- END OF PUBLIC METHODS ------------ # -# Sets the slave auto_path to the master recorded value. Also sets -# tcl_library to the first token of the virtual path. +# Sets the slave auto_path to its recorded access path. Also sets +# tcl_library to the first token of the access 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 + # list of access path's. See -> InterpSetConfig for the code which # ensures this condition. ::interp eval $slave [list \ set tcl_library [lindex $slave_access_path 0]] + return } # Returns the virtual token for directory number N. @@ -734,6 +841,7 @@ proc ::safe::AliasFileSubcommand {slave subcommand name} { # 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 @@ -756,11 +864,15 @@ proc ::safe::AliasGlob {slave args} { 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 @@ -775,15 +887,20 @@ proc ::safe::AliasGlob {slave args} { 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'" + # unsafe/unnecessary options rejected: -path } default { break @@ -807,7 +924,7 @@ proc ::safe::AliasGlob {slave args} { 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] "/"]] } @@ -1100,16 +1217,21 @@ proc ::safe::Setup {} { # Setup the arguments parsing # #### + variable AutoPathSync # Share the descriptions - set temp [::tcl::OptKeyRegister { + set OptList { {-accessPath -list {} "access path for the slave"} {-noStatics "prevent loading of statically linked pkgs"} {-statics true "loading of statically linked pkgs"} {-nestedLoadOk "allow nested loading"} {-nested false "nested loading"} {-deleteHook -script {} "delete hook"} - }] + } + if {!$AutoPathSync} { + lappend OptList {-autoPath -list {} "::auto_path for the slave"} + } + set temp [::tcl::OptKeyRegister $OptList] # create case (slave is optional) ::tcl::OptKeyRegister { @@ -1146,8 +1268,72 @@ proc ::safe::Setup {} { return } +# Accessor method for ::safe::AutoPathSync +# Usage: ::safe::setAutoPathSync ?newValue? +# Respond to changes by calling Setup again, precerving any +# caller-defined logging. This allows complete equivalence with +# prior Safe Base behavior if AutoPathSync is true. +# +# >>> WARNING <<< +# +# DO NOT CHANGE AutoPathSync EXCEPT BY THIS COMMAND - IT IS VITAL THAT WHENEVER +# THE VALUE CHANGES, THE EXISTING PARSE TOKENS ARE DELETED AND Setup IS CALLED +# AGAIN. +# (The initialization of AutoPathSync at the end of this file is acceptable +# because Setup has not yet been called.) + +proc ::safe::setAutoPathSync {args} { + variable AutoPathSync + + if {[llength $args] == 0} { + } elseif {[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 set new value while Safe Base slaves exist" + } + if {($args != $AutoPathSync)} { + set AutoPathSync {*}$args + ::tcl::OptKeyDelete ::safe::interpCreate + ::tcl::OptKeyDelete ::safe::interpIC + set TmpLog [setLogCmd] + Setup + setLogCmd $TmpLog + } + } else { + set msg {wrong # args: should be "safe::setAutoPathSync ?newValue?"} + return -code error $msg + } + + return $AutoPathSync +} + 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 {} @@ -1169,6 +1355,10 @@ namespace eval ::safe { # staticsok : Value of option -statics # nestedok : Value of option -nested # cleanupHook : Value of option -deleteHook + # + # Because the slave can change its value of ::auto_path, the value of + # option -autoPath is not stored in the array but must be obtained from + # the slave. } ::safe::Setup diff --git a/library/tclIndex b/library/tclIndex index 87a2814..6bb3fa6 100644 --- a/library/tclIndex +++ b/library/tclIndex @@ -61,6 +61,7 @@ set auto_index(::safe::DirInAccessPath) [list ::tcl::Pkg::source [file join $dir set auto_index(::safe::Subset) [list ::tcl::Pkg::source [file join $dir safe.tcl]] set auto_index(::safe::AliasSubset) [list ::tcl::Pkg::source [file join $dir safe.tcl]] set auto_index(::safe::AliasEncoding) [list ::tcl::Pkg::source [file join $dir safe.tcl]] +set auto_index(::safe::setAutoPathSync) [list source [file join $dir safe.tcl]] set auto_index(tcl_wordBreakAfter) [list ::tcl::Pkg::source [file join $dir word.tcl]] set auto_index(tcl_wordBreakBefore) [list ::tcl::Pkg::source [file join $dir word.tcl]] set auto_index(tcl_endOfWord) [list ::tcl::Pkg::source [file join $dir word.tcl]] diff --git a/tests/safe.test b/tests/safe.test index 6838201..c01ce47 100644 --- a/tests/safe.test +++ b/tests/safe.test @@ -17,6 +17,8 @@ if {[lsearch [namespace children] ::tcltest] == -1} { namespace import -force ::tcltest::* } +testConstraint AutoSyncDefined 1 + foreach i [interp slaves] { interp delete $i } @@ -28,20 +30,20 @@ set ::auto_path [info library] # - Replaced here with tests using example packages provided in subdirectory # auto0 of the tests directory, which are independent of any changes # made to the packages provided with Tcl. -# - These are tests 7.1 7.2 7.4 9.10 9.12 +# - These are tests 7.1 7.2 7.4 9.10 9.12 18.1 18.2 18.4 # - Tests 7.0[a-f] test the example packages themselves before they # are used to test Safe Base interpreters. # - Alternatively use packages opt and (from cookiejar) tcl::idna. # - These alternative tests have suffix "opt". -# - These are 7.[124]opt, 9.1[02]opt -# - Tests 7.[124]opt, 9.1[02]opt use "package require opt". +# - These are 7.[124]opt, 9.1[02]opt, 18.[124]opt. +# - Tests 7.[124]opt, 9.1[02]opt, 18.[124]opt use "package require opt". # - Tests 9.1[02]opt also use "package require tcl::idna". # # When using package opt for testing positive/negative package search: # - The directory location and the error message depend on whether # and how the package is installed. -# Error message for tests 7.2opt for "package require opt". +# Error message for tests 7.2opt, 18.2opt for "package require opt". if {[string match *zipfs:/* [info library]]} { # pkgIndex.tcl is in [info library] # file to be sourced is in [info library]/opt* @@ -52,7 +54,7 @@ if {[string match *zipfs:/* [info library]]} { set pkgOptErrMsg {can't find package opt} } -# Directory of opt for tests 7.4opt, 9.10opt, 9.12opt +# Directory of opt for tests 7.4opt, 9.10opt, 9.12opt, 18.4opt # for "package require opt". if {[file exists [file join [info library] opt0.4]]} { # Installed files in lib8.7/opt0.4 @@ -80,7 +82,7 @@ set TestsDir [file normalize [file dirname [info script]]] set ZipMountPoint [zipfs root]auto-files zipfs mount $ZipMountPoint [file join $TestsDir auto-files.zip] -# Force actual loading of the safe package because we use un exported (and +# Force actual loading of the safe package because we use un-exported (and # thus un-autoindexed) APIs in this test result arguments: catch {safe::interpConfigure} @@ -463,8 +465,16 @@ test safe-7.0fz {example modules packages, test in master interpreter, append to } -match glob -result {0 0.5 0 1.0 0 2.0 -- res0 res1 res2} # high level general test -# Use example packages not http1.0 -test safe-7.1 {tests that everything works at high level} -setup { +# Use example packages not tcl8.x/opt +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 tmpAutoPath $::auto_path lappend ::auto_path [file join $TestsDir auto0] set i [safe::interpCreate] @@ -479,10 +489,21 @@ test safe-7.1 {tests that everything works at high level} -setup { set v } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result 1.2.3 # high level general test # Use zipped example packages not tcl8.x/opt -test safe-7.1z {tests that everything works at high level; zipfs} -setup { +test safe-7.1z {tests that everything works at high level with conventional AutoPathSync; zipfs} -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 tmpAutoPath $::auto_path lappend ::auto_path [file join $TestsDir auto0] set i [safe::interpCreate] @@ -497,9 +518,20 @@ test safe-7.1z {tests that everything works at high level; zipfs} -setup { set v } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result 1.2.3 # high level general test -test safe-7.1opt {tests that everything works at high level, uses pkg opt} -setup { +test safe-7.1opt {tests that everything works at high level with conventional AutoPathSync, use pkg opt} -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: @@ -511,8 +543,20 @@ test safe-7.1opt {tests that everything works at high level, uses pkg opt} -setu set v } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result 0.4.* -test safe-7.2 {tests specific path and interpFind/AddToAccessPath} -setup { +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) @@ -528,11 +572,23 @@ test safe-7.2 {tests specific path and interpFind/AddToAccessPath} -setup { [safe::interpConfigure $i]\ [safe::interpDelete $i] } -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:0:)} {\$p(:*:)} {\$p(:*:)} 1\ {can't find package SafeTestPackage1}\ {-accessPath {[list $tcl_library */dummy/unixlike/test/path $TestsDir/auto0]}\ -statics 0 -nested 1 -deleteHook {}} {}" -test safe-7.2z {tests specific path and interpFind/AddToAccessPath; zipfs} -setup { +test safe-7.2z {tests specific path and interpFind/AddToAccessPath with conventional AutoPathSync; zipfs} -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) @@ -548,11 +604,23 @@ test safe-7.2z {tests specific path and interpFind/AddToAccessPath; zipfs} -setu [safe::interpConfigure $i]\ [safe::interpDelete $i] } -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:0:)} {\$p(:*:)} {\$p(:*:)} 1\ {can't find package SafeTestPackage1}\ {-accessPath {[list $tcl_library */dummy/unixlike/test/path $TestsDir/auto0]}\ -statics 0 -nested 1 -deleteHook {}} {}" -test safe-7.2opt {tests specific path and interpFind/AddToAccessPath, uses pkg opt} -setup { +test safe-7.2opt {tests specific path and interpFind/AddToAccessPath with conventional AutoPathSync, use pkg opt} -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) @@ -566,6 +634,9 @@ test safe-7.2opt {tests specific path and interpFind/AddToAccessPath, uses pkg o [safe::interpConfigure $i]\ [safe::interpDelete $i] } -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:0:)} {\$p(:*:)} 1 {$pkgOptErrMsg}\ {-accessPath {[list $tcl_library */dummy/unixlike/test/path]}\ -statics 0 -nested 1 -deleteHook {}} {}" @@ -574,7 +645,16 @@ test safe-7.3 {check that safe subinterpreters work} { set j [safe::interpCreate [list $i x]] list [interp eval $j {join {o k} ""}] [safe::interpDelete $i] [interp exists $j] } {ok {} 0} -test safe-7.4 {tests specific path and positive search} -setup { +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) @@ -589,10 +669,22 @@ test safe-7.4 {tests specific path and positive search} -setup { # 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.2.3\ {-accessPath {[list $tcl_library * $TestsDir/auto0/auto1]}\ -statics 0 -nested 1 -deleteHook {}} {}" -test safe-7.4z {tests specific path and positive search; zipfs} -setup { +test safe-7.4z {tests specific path and positive search with conventional AutoPathSync; zipfs} -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) @@ -607,10 +699,22 @@ test safe-7.4z {tests specific path and positive search; zipfs} -setup { # 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.2.3\ {-accessPath {[list $tcl_library * $TestsDir/auto0/auto1]}\ -statics 0 -nested 1 -deleteHook {}} {}" -test safe-7.4opt {tests specific path and positive search, uses pkg opt} -setup { +test safe-7.4opt {tests specific path and positive search with conventional AutoPathSync, use pkg opt} -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) @@ -625,10 +729,42 @@ test safe-7.4opt {tests specific path and positive search, uses pkg opt} -setup # 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 0.4.*\ {-accessPath {[list $tcl_library *$tcl_library/$pkgOptDir]}\ -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 set i "a" test safe-8.1 {safe source control on file} -setup { @@ -822,8 +958,9 @@ test safe-9.6 {interpConfigure widget like behaviour} -body { 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}} - test safe-9.7 {interpConfigure widget like behaviour (demystified)} -body { # this test shall work, believed equivalent to 9.6 set i [safe::interpCreate \ @@ -847,8 +984,12 @@ test safe-9.7 {interpConfigure widget like behaviour (demystified)} -body { } -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}} - test safe-9.8 {interpConfigure change the access path; tclIndex commands unaffected by token rearrangement (dummy test of doreset)} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $TestsDir auto0 auto1] \ @@ -884,12 +1025,20 @@ test safe-9.8 {interpConfigure change the access path; tclIndex commands unaffec list $path1 $path2 $path3 $path4 $code3 $msg3 $code4 $msg4 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 ok1 0 ok2\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto1 $TestsDir/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto2 $TestsDir/auto0/auto1]*}\ -statics 1 -nested 0 -deleteHook {}}" test safe-9.8z {interpConfigure change the access path; tclIndex commands unaffected by token rearrangement (dummy test of doreset); zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $ZipMountPoint auto0 auto1] \ @@ -925,12 +1074,20 @@ test safe-9.8z {interpConfigure change the access path; tclIndex commands unaffe list $path1 $path2 $path3 $path4 $code3 $msg3 $code4 $msg4 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 ok1 0 ok2\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto1 $ZipMountPoint/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto2 $ZipMountPoint/auto0/auto1]*}\ -statics 1 -nested 0 -deleteHook {}}" test safe-9.9 {interpConfigure change the access path; tclIndex commands unaffected by token rearrangement (actual test of doreset)} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $TestsDir auto0 auto1] \ @@ -964,12 +1121,20 @@ test safe-9.9 {interpConfigure change the access path; tclIndex commands unaffec list $path1 $path2 $path3 $path4 $code3 $msg3 $code4 $msg4 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 ok1 0 ok2\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto1 $TestsDir/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto2 $TestsDir/auto0/auto1]*}\ -statics 1 -nested 0 -deleteHook {}}" test safe-9.9z {interpConfigure change the access path; tclIndex commands unaffected by token rearrangement (actual test of doreset); zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $ZipMountPoint auto0 auto1] \ @@ -1003,12 +1168,20 @@ test safe-9.9z {interpConfigure change the access path; tclIndex commands unaffe list $path1 $path2 $path3 $path4 $code3 $msg3 $code4 $msg4 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 ok1 0 ok2\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto1 $ZipMountPoint/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto2 $ZipMountPoint/auto0/auto1]*}\ -statics 1 -nested 0 -deleteHook {}}" test safe-9.10 {interpConfigure change the access path; pkgIndex.tcl packages unaffected by token rearrangement} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { # For complete correspondence to safe-9.10opt, include auto0 in access path. set i [safe::interpCreate -accessPath [list $tcl_library \ @@ -1049,6 +1222,9 @@ test safe-9.10 {interpConfigure change the access path; pkgIndex.tcl packages un } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:2:)} {\$p(:3:)} {\$p(:3:)} {\$p(:2:)} 0 1.2.3 0 2.3.4\ {-accessPath {[list $tcl_library $TestsDir/auto0 $TestsDir/auto0/auto1 $TestsDir/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ @@ -1056,6 +1232,11 @@ test safe-9.10 {interpConfigure change the access path; pkgIndex.tcl packages un -statics 1 -nested 0 -deleteHook {}}\ 0 OK1 0 OK2" test safe-9.10z {interpConfigure change the access path; pkgIndex.tcl packages unaffected by token rearrangement; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { # For complete correspondence to safe-9.10opt, include auto0 in access path. set i [safe::interpCreate -accessPath [list $tcl_library \ @@ -1096,6 +1277,9 @@ test safe-9.10z {interpConfigure change the access path; pkgIndex.tcl packages u } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:2:)} {\$p(:3:)} {\$p(:3:)} {\$p(:2:)} 0 1.2.3 0 2.3.4\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0 $ZipMountPoint/auto0/auto1 $ZipMountPoint/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ @@ -1103,6 +1287,11 @@ test safe-9.10z {interpConfigure change the access path; pkgIndex.tcl packages u -statics 1 -nested 0 -deleteHook {}}\ 0 OK1 0 OK2" test safe-9.10opt {interpConfigure change the access path; pkgIndex.tcl packages unaffected by token rearrangement, uses pkg opt and tcl::idna} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $tcl_library $pkgOptDir] \ @@ -1137,12 +1326,20 @@ test safe-9.10opt {interpConfigure change the access path; pkgIndex.tcl packages $confA $confB $code5 $msg5 $code6 $msg6 } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 1.* 0 0.4.*\ {-accessPath {[list $tcl_library $tcl_library/$pkgOptDir $tcl_library/$pkgJarDir]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library $tcl_library/$pkgJarDir $tcl_library/$pkgOptDir]*}\ -statics 1 -nested 0 -deleteHook {}} 0 0 0 example.com" test safe-9.11 {interpConfigure change the access path; pkgIndex.tcl packages unaffected by token rearrangement, 9.10 without path auto0} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $TestsDir auto0 auto1] \ @@ -1176,6 +1373,9 @@ test safe-9.11 {interpConfigure change the access path; pkgIndex.tcl packages un $code5 $msg5 $code6 $msg6 } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 1.2.3 0 2.3.4\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto1 $TestsDir/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ @@ -1183,6 +1383,11 @@ test safe-9.11 {interpConfigure change the access path; pkgIndex.tcl packages un -statics 1 -nested 0 -deleteHook {}}\ 0 OK1 0 OK2" test safe-9.11z {interpConfigure change the access path; pkgIndex.tcl packages unaffected by token rearrangement, 9.10 without path auto0; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $ZipMountPoint auto0 auto1] \ @@ -1216,6 +1421,9 @@ test safe-9.11z {interpConfigure change the access path; pkgIndex.tcl packages u $code5 $msg5 $code6 $msg6 } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:2:)} {\$p(:1:)} 0 1.2.3 0 2.3.4\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto1 $ZipMountPoint/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ @@ -1223,6 +1431,11 @@ test safe-9.11z {interpConfigure change the access path; pkgIndex.tcl packages u -statics 1 -nested 0 -deleteHook {}}\ 0 OK1 0 OK2" test safe-9.12 {interpConfigure change the access path; pkgIndex.tcl packages fail if directory de-listed} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $TestsDir auto0 auto1] \ @@ -1251,12 +1464,20 @@ test safe-9.12 {interpConfigure change the access path; pkgIndex.tcl packages fa list $path1 $path2 $code4 $path4 $code5 $path5 $code3 $msg3 $code6 $msg6 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} 1 {* not found in access path}\ 1 {* not found in access path} 1 {*} 1 {*}\ {-accessPath {[list $tcl_library $TestsDir/auto0/auto1 $TestsDir/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library]*} -statics 1 -nested 0 -deleteHook {}}" test safe-9.12z {interpConfigure change the access path; pkgIndex.tcl packages fail if directory de-listed; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $ZipMountPoint auto0 auto1] \ @@ -1285,12 +1506,20 @@ test safe-9.12z {interpConfigure change the access path; pkgIndex.tcl packages f list $path1 $path2 $code4 $path4 $code5 $path5 $code3 $msg3 $code6 $msg6 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} 1 {* not found in access path}\ 1 {* not found in access path} 1 {*} 1 {*}\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/auto1 $ZipMountPoint/auto0/auto2]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library]*} -statics 1 -nested 0 -deleteHook {}}" test safe-9.12opt {interpConfigure change the access path; pkgIndex.tcl packages fail if directory de-listed, uses pkg opt and tcl::idna} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } } -body { set i [safe::interpCreate -accessPath [list $tcl_library \ [file join $tcl_library $pkgOptDir] \ @@ -1319,12 +1548,20 @@ test safe-9.12opt {interpConfigure change the access path; pkgIndex.tcl packages list $path1 $path2 $code4 $path4 $code5 $path5 $code3 $msg3 $code6 $msg6 $confA $confB } -cleanup { safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} 1 {* not found in access path}\ 1 {* not found in access path} 1 {*} 1 {*}\ {-accessPath {[list $tcl_library $tcl_library/$pkgOptDir $tcl_library/$pkgJarDir]*}\ -statics 1 -nested 0 -deleteHook {}}\ {-accessPath {[list $tcl_library]*} -statics 1 -nested 0 -deleteHook {}}" test safe-9.20 {check module loading} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1356,6 +1593,9 @@ test safe-9.20 {check module loading} -setup { tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ 0 0.5 0 1.0 0 2.0 --\ {-accessPath {[list $tcl_library $TestsDir/auto0/modules \ @@ -1364,6 +1604,11 @@ test safe-9.20 {check module loading} -setup { -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.20z {check module loading; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1395,6 +1640,9 @@ test safe-9.20z {check module loading; zipfs} -setup { tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ 0 0.5 0 1.0 0 2.0 --\ {-accessPath {[list $tcl_library $ZipMountPoint/auto0/modules \ @@ -1403,6 +1651,11 @@ test safe-9.20z {check module loading; zipfs} -setup { -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.21 {interpConfigure change the access path; check module loading; stale data case 1} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1453,6 +1706,9 @@ test safe-9.21 {interpConfigure change the access path; check module loading; st tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1470,6 +1726,11 @@ test safe-9.21 {interpConfigure change the access path; check module loading; st -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.21z {interpConfigure change the access path; check module loading; stale data case 1; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1520,6 +1781,9 @@ test safe-9.21z {interpConfigure change the access path; check module loading; s tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1537,6 +1801,11 @@ test safe-9.21z {interpConfigure change the access path; check module loading; s -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.22 {interpConfigure change the access path; check module loading; stale data case 0} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1582,6 +1851,9 @@ test safe-9.22 {interpConfigure change the access path; check module loading; st tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1599,6 +1871,11 @@ test safe-9.22 {interpConfigure change the access path; check module loading; st -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.22z {interpConfigure change the access path; check module loading; stale data case 0; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1644,6 +1921,9 @@ test safe-9.22z {interpConfigure change the access path; check module loading; s tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1661,6 +1941,11 @@ test safe-9.22z {interpConfigure change the access path; check module loading; s -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.23 {interpConfigure change the access path; check module loading; stale data case 3} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1717,6 +2002,9 @@ test safe-9.23 {interpConfigure change the access path; check module loading; st tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1734,6 +2022,11 @@ test safe-9.23 {interpConfigure change the access path; check module loading; st -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.23z {interpConfigure change the access path; check module loading; stale data case 3; zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1790,6 +2083,9 @@ test safe-9.23z {interpConfigure change the access path; check module loading; s tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1807,6 +2103,11 @@ test safe-9.23z {interpConfigure change the access path; check module loading; s -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.24 {interpConfigure change the access path; check module loading; stale data case 2 (worst case)} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1857,6 +2158,9 @@ test safe-9.24 {interpConfigure change the access path; check module loading; st tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -1874,6 +2178,11 @@ test safe-9.24 {interpConfigure change the access path; check module loading; st -statics 1 -nested 0 -deleteHook {}} --\ res0 res1 res2" test safe-9.24z {interpConfigure change the access path; check module loading; stale data case 2 (worst case); zipfs} -setup { + set SyncExists [expr {[info commands ::safe::setAutoPathSync] ne {}}] + if {$SyncExists} { + set SyncVal_TMP [safe::setAutoPathSync] + safe::setAutoPathSync 1 + } set oldTm [tcl::tm::path list] foreach path $oldTm { tcl::tm::path remove $path @@ -1924,6 +2233,9 @@ test safe-9.24z {interpConfigure change the access path; check module loading; s tcl::tm::path add $path } safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } } -match glob -result "{\$p(:1:)} {\$p(:2:)} {\$p(:3:)} -- {{\$p(:1:)}} --\ {\$p(:3:)} {\$p(:4:)} {\$p(:5:)} -- {{\$p(:3:)}} --\ 0 0.5 0 1.0 0 2.0 --\ @@ -2363,7 +2675,481 @@ test safe-16.4 {Bug 3529949: defang ~user in globs} -setup { } -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 join $TestsDir auto0] + set ::auto_TMP $::auto_path + set ::auto_path [list $lib1 $lib2] + + set i [safe::interpCreate] + set ::auto_path $::auto_TMP +} -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 SafeTestPackage1}] + # no error shall occur: + interp eval $i HeresPackage1 + set v +} -cleanup { + safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result 1.2.3 +test safe-18.1z {cf. safe-7.1 - tests that everything works at high level without conventional AutoPathSync; zipfs} -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 join $ZipMountPoint auto0] + set ::auto_TMP $::auto_path + set ::auto_path [list $lib1 $lib2] + + set i [safe::interpCreate] + set ::auto_path $::auto_TMP +} -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 SafeTestPackage1}] + # no error shall occur: + interp eval $i HeresPackage1 + set v +} -cleanup { + safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result 1.2.3 +test safe-18.1opt {cf. safe-7.1opt - tests that everything works at high level without conventional AutoPathSync, use pkg opt} -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] + set ::auto_path $::auto_TMP +} -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 opt}] + # no error shall occur: + interp eval $i {::tcl::Lempty {a list}} + set v +} -cleanup { + safe::interpDelete $i + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result 0.4.* +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 p* (not p1 if master has a module path) + set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"] + # should add as p* (not p2 if master has a module path) + set token3 [safe::interpAddToAccessPath $i [file join $TestsDir auto0]] + # an error shall occur (SafeTestPackage1 is not anymore in the secure 0-level + # provided deep path) + list $auto1 $token1 $token2 $token3 \ + [catch {interp eval $i {package require SafeTestPackage1}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {\$p(:0:)} {\$p(:*:)} {\$p(:*:)}\ + 1 {can't find package SafeTestPackage1}\ + {-accessPath {[list $tcl_library \ + */dummy/unixlike/test/path \ + $TestsDir/auto0]}\ + -statics 0 -nested 1 -deleteHook {} -autoPath [list $tcl_library]} {}" +test safe-18.2z {cf. safe-7.2 - tests specific path and interpFind/AddToAccessPath without conventional AutoPathSync; zipfs} -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 p* (not p1 if master has a module path) + set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"] + # should add as p* (not p2 if master has a module path) + set token3 [safe::interpAddToAccessPath $i [file join $ZipMountPoint auto0]] + # an error shall occur (SafeTestPackage1 is not anymore in the secure 0-level + # provided deep path) + list $auto1 $token1 $token2 $token3 \ + [catch {interp eval $i {package require SafeTestPackage1}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {\$p(:0:)} {\$p(:*:)} {\$p(:*:)}\ + 1 {can't find package SafeTestPackage1}\ + {-accessPath {[list $tcl_library \ + */dummy/unixlike/test/path \ + $ZipMountPoint/auto0]}\ + -statics 0 -nested 1 -deleteHook {} -autoPath [list $tcl_library]} {}" +test safe-18.2opt {cf. safe-7.2opt - tests specific path and interpFind/AddToAccessPath without conventional AutoPathSync, use pkg opt} -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 p* (not p1 if master has a module path) + set token2 [safe::interpAddToAccessPath $i "/dummy/unixlike/test/path"] + # an error shall occur (opt is not anymore in the secure 0-level + # provided deep path) + list $auto1 $token1 $token2 \ + [catch {interp eval $i {package require opt}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {\$p(:0:)} {\$p(:*:)} 1 {$pkgOptErrMsg}\ + {-accessPath {[list $tcl_library */dummy/unixlike/test/path]}\ + -statics 0 -nested 1 -deleteHook {} -autoPath [list $tcl_library]} {}" +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 $::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 $TestsDir auto0]] + + # should add as p* (not p2 if master has a module path) + set token3 [safe::interpAddToAccessPath $i [file join $TestsDir auto0 auto1]] + + # should not have been changed by Safe Base: + set auto2 [interp eval $i {set ::auto_path}] + + set auto3 [interp eval $i [list set ::auto_path [list {$p(:0:)} $token2]]] + + # This time, unlike test safe-18.2 and the try above, SafeTestPackage1 should be found: + list $auto1 $auto2 $token1 $token2 $token3 \ + [catch {interp eval $i {package require SafeTestPackage1}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {{\$p(:0:)}} {\$p(:0:)} {\$p(:*:)} {\$p(:*:)} 0 1.2.3\ + {-accessPath {[list $tcl_library *$TestsDir/auto0 $TestsDir/auto0/auto1]}\ + -statics 0 -nested 1 -deleteHook {}\ + -autoPath {[list $tcl_library $TestsDir/auto0]}} {}" +test safe-18.4z {cf. safe-7.4 - tests specific path and positive search and auto_path without conventional AutoPathSync; zipfs} -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 $ZipMountPoint auto0]] + + # should add as p* (not p2 if master has a module path) + set token3 [safe::interpAddToAccessPath $i [file join $ZipMountPoint auto0 auto1]] + + # should not have been changed by Safe Base: + set auto2 [interp eval $i {set ::auto_path}] + + set auto3 [interp eval $i [list set ::auto_path [list {$p(:0:)} $token2]]] + + # This time, unlike test safe-18.2 and the try above, SafeTestPackage1 should be found: + list $auto1 $auto2 $token1 $token2 $token3 \ + [catch {interp eval $i {package require SafeTestPackage1}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {{\$p(:0:)}} {\$p(:0:)} {\$p(:*:)} {\$p(:*:)} 0 1.2.3\ + {-accessPath {[list $tcl_library *$ZipMountPoint/auto0 $ZipMountPoint/auto0/auto1]}\ + -statics 0 -nested 1 -deleteHook {}\ + -autoPath {[list $tcl_library $ZipMountPoint/auto0]}} {}" +test safe-18.4opt {cf. safe-7.4opt - tests specific path and positive search and auto_path without conventional AutoPathSync, use pkg opt} -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] $pkgOptDir]] + + # should not have been changed by Safe Base: + set auto2 [interp eval $i {set ::auto_path}] + + # This time, unlike test safe-18.2opt and the try above, opt should be found: + list $auto1 $auto2 $token1 $token2 \ + [catch {interp eval $i {package require opt}} msg] $msg \ + [safe::interpConfigure $i]\ + [safe::interpDelete $i] +} -cleanup { + if {$SyncExists} { + safe::setAutoPathSync $SyncVal_TMP + } +} -match glob -result "{} {{\$p(:0:)}} {\$p(:0:)} {\$p(:*:)} 0 0.4.*\ + {-accessPath {[list $tcl_library *$tcl_library/$pkgOptDir]}\ + -statics 0 -nested 1 -deleteHook {} -autoPath [list $tcl_library]} {}" +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 zipfs unmount ${ZipMountPoint} unset pkgOptErrMsg pkgOptDir pkgJarDir saveAutoPath TestsDir ZipMountPoint |