# Functionality covered: this file contains a collection of tests for the
# procedures in tclNamesp.c that implement Tcl's basic support for
# namespaces. Other namespace-related tests appear in variable.test.
#
# Sourcing this file into Tcl runs the tests and generates output for
# errors. No output means no errors were found.
#
# Copyright (c) 1997 Sun Microsystems, Inc.
# Copyright (c) 1998-2000 by Scriptics Corporation.
#
# See the file "license.terms" for information on usage and redistribution
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.

if {[lsearch [namespace children] ::tcltest] == -1} {
    package require tcltest 2
    namespace import -force ::tcltest::*
}

#
# REMARK: the tests for 'namespace upvar' are not done here. They are to be
# found in the file 'upvar.test'.
#

# Clear out any namespaces called test_ns_*
catch {namespace delete {*}[namespace children :: test_ns_*]}

proc fq {ns} {
    if {[string match ::* $ns]} {return $ns}
    set current [uplevel 1 {namespace current}]
    return [string trimright $current :]::[string trimleft $ns :]
}

test namespace-1.1 {TclInitNamespaces, GetNamespaceFromObj, NamespaceChildrenCmd} {
    namespace children :: test_ns_*
} {}

catch {unset l}
test namespace-2.1 {Tcl_GetCurrentNamespace} {
    list [namespace current] [namespace eval {} {namespace current}] \
        [namespace eval {} {namespace current}]
} {:: :: ::}
test namespace-2.2 {Tcl_GetCurrentNamespace} {
    set l {}
    lappend l [namespace current]
    namespace eval test_ns_1 {
        lappend l [namespace current]
        namespace eval foo {
            lappend l [namespace current]
        }
    }
    lappend l [namespace current]
    set l
} {:: ::test_ns_1 ::test_ns_1::foo ::}

test namespace-3.1 {Tcl_GetGlobalNamespace} {
    namespace eval test_ns_1 {namespace eval foo {namespace eval bar {} } }
    # namespace children uses Tcl_GetGlobalNamespace 
    namespace eval test_ns_1 {namespace children foo b*}
} {::test_ns_1::foo::bar}

test namespace-4.1 {Tcl_PushCallFrame with isProcCallFrame=1} {
    namespace eval test_ns_1 {
        variable v 123
        proc p {} {
            variable v
            return $v
        }
    }
    test_ns_1::p    ;# does Tcl_PushCallFrame to push p's namespace
} {123}
test namespace-4.2 {Tcl_PushCallFrame with isProcCallFrame=0} {
    namespace eval test_ns_1::baz {}  ;# does Tcl_PushCallFrame to create baz
    proc test_ns_1::baz::p {} {
        variable v
        set v 789
        set v}
    test_ns_1::baz::p
} {789}

test namespace-5.1 {Tcl_PopCallFrame, no vars} {
    namespace eval test_ns_1::blodge {}  ;# pushes then pops frame
} {}
test namespace-5.2 {Tcl_PopCallFrame, local vars must be deleted} {
    proc test_ns_1::r {} {
        set a 123
    }
    test_ns_1::r   ;# pushes then pop's r's frame
} {123}

test namespace-6.1 {Tcl_CreateNamespace} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [lsort [namespace children :: test_ns_*]] \
        [namespace eval test_ns_1 {namespace current}] \
	[namespace eval test_ns_2 {namespace current}] \
	[namespace eval ::test_ns_3 {namespace current}] \
	[namespace eval ::test_ns_4 \
            {namespace eval foo {namespace current}}] \
	[namespace eval ::test_ns_5 \
            {namespace eval ::test_ns_6 {namespace current}}] \
        [lsort [namespace children :: test_ns_*]]
} {{} ::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4::foo ::test_ns_6 {::test_ns_1 ::test_ns_2 ::test_ns_3 ::test_ns_4 ::test_ns_5 ::test_ns_6}}
test namespace-6.2 {Tcl_CreateNamespace, odd number of :'s in name is okay} {
    list [namespace eval :::test_ns_1::::foo {namespace current}] \
         [namespace eval test_ns_2:::::foo {namespace current}]
} {::test_ns_1::foo ::test_ns_2::foo}
test namespace-6.3 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    list [catch {namespace eval test_ns_7::: {namespace current}} msg] $msg 
} {0 ::test_ns_7}
test namespace-6.4 {Tcl_CreateNamespace, trailing ::s in ns name are ignored} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1:: {
        namespace eval test_ns_2:: {}
        namespace eval test_ns_3:: {}
    }
    lsort [namespace children ::test_ns_1]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_3}]
test namespace-6.5 {Tcl_CreateNamespace, relative ns names now only looked up in current ns} {
    set trigger {
        namespace eval test_ns_2 {namespace current}
    }
    set l {}
    lappend l [namespace eval test_ns_1 $trigger]
    namespace eval test_ns_1::test_ns_2 {}
    lappend l [namespace eval test_ns_1 $trigger]
} {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_2}

test namespace-7.1 {Tcl_DeleteNamespace, active call frames in ns} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    list [test_ns_1::p] [catch {test_ns_1::p} msg] $msg
} {::test_ns_1 1 {invalid command name "test_ns_1::p"}}
test namespace-7.2 {Tcl_DeleteNamespace, no active call frames in ns} {
    namespace eval test_ns_2 {
        proc p {} {
            return [namespace current]
        }
    }
    list [test_ns_2::p] [namespace delete test_ns_2]
} {::test_ns_2 {}}
test namespace-7.3 {recursive Tcl_DeleteNamespace, active call frames in ns} {
    # [Bug 1355942]
    namespace eval test_ns_2 {
        set x 1
	trace add variable x unset "namespace delete [namespace current];#"
	namespace delete [namespace current]
    }
} {}
test namespace-7.4 {recursive Tcl_DeleteNamespace, active call frames in ns} {
    # [Bug 1355942]
    namespace eval test_ns_2 {
        proc x {} {}
	trace add command x delete "namespace delete [namespace current];#"
	namespace delete [namespace current]
    }
} {}
test namespace-7.5 {recursive Tcl_DeleteNamespace, no active call frames in ns} {
    # [Bug 1355942]
    namespace eval test_ns_2 {
        set x 1
	trace add variable x unset "namespace delete [namespace current];#"
    }
    namespace delete test_ns_2
} {}
test namespace-7.6 {recursive Tcl_DeleteNamespace, no active call frames in ns} {
    # [Bug 1355942]
    namespace eval test_ns_2 {
        proc x {} {}
	trace add command x delete "namespace delete [namespace current];#"
    }
    namespace delete test_ns_2
} {}
test namespace-7.7 {Bug 1655305} -setup {
    interp create slave
    # Can't invoke through the ensemble, since deleting the global namespace
    # (indirectly, via deleting ::tcl) deletes the ensemble.
    slave eval {rename ::tcl::info::commands ::infocommands}
    slave hide infocommands
    slave eval {
	proc foo {} {
	    namespace delete ::
	}
    }
} -body {
    slave eval foo
    slave invokehidden infocommands
} -cleanup {
    interp delete slave
} -result {}


test namespace-8.1 {TclTeardownNamespace, delete global namespace} {
    catch {interp delete test_interp}
    interp create test_interp
    interp eval test_interp {
        namespace eval test_ns_1 {
            namespace export p
            proc p {} {
                return [namespace current]
            }
        }
        namespace eval test_ns_2 {
            namespace import ::test_ns_1::p
            variable v 27
            proc q {} {
                variable v
                return "[p] $v"
            }
        }
        set x [test_ns_2::q]
        catch {set xxxx}
    }
    list [interp eval test_interp {test_ns_2::q}] \
         [interp eval test_interp {namespace delete ::}] \
         [catch {interp eval test_interp {set a 123}} msg] $msg \
         [interp delete test_interp]
} {{::test_ns_1 27} {} 1 {invalid command name "set"} {}}
test namespace-8.2 {TclTeardownNamespace, remove deleted ns from parent} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1]
} {::test_ns_1::test_ns_2 {} {}}
test namespace-8.3 {TclTeardownNamespace, delete child namespaces} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2::test_ns_3a {proc p {} {}}
    namespace eval test_ns_1::test_ns_2::test_ns_3b {proc q {} {}}
    list [namespace children test_ns_1] \
         [namespace delete test_ns_1::test_ns_2] \
         [namespace children test_ns_1] \
         [catch {namespace children test_ns_1::test_ns_2} msg] $msg \
         [info commands test_ns_1::test_ns_2::test_ns_3a::*]
} {::test_ns_1::test_ns_2 {} {} 1 {namespace "test_ns_1::test_ns_2" not found in "::"} {}}
test namespace-8.4 {TclTeardownNamespace, cmds imported from deleted ns go away} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1 cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
        proc p {} {return foo}
    }
    list [lsort [info commands test_ns_import::*]] \
         [namespace delete test_ns_export] \
         [info commands test_ns_import::*]
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1 ::test_ns_import::cmd2}] {} ::test_ns_import::p]
test namespace-8.5 {TclTeardownNamespace: preserve errorInfo; errorCode values} {
    interp create slave
    slave eval {trace add execution error leave {namespace delete :: ;#}}
    catch {slave eval error foo bar baz}
    interp delete slave
    set ::errorInfo
} {bar
    invoked from within
"slave eval error foo bar baz"}
test namespace-8.6 {TclTeardownNamespace: preserve errorInfo; errorCode values} {
    interp create slave 
    slave eval {trace add variable errorCode write {namespace delete :: ;#}}
    catch {slave eval error foo bar baz}
    interp delete slave
    set ::errorInfo
} {bar
    invoked from within
"slave eval error foo bar baz"}
test namespace-8.7 {TclTeardownNamespace: preserve errorInfo; errorCode values} {
    interp create slave
    slave eval {trace add execution error leave {namespace delete :: ;#}}
    catch {slave eval error foo bar baz}
    interp delete slave
    set ::errorCode
} baz

test namespace-9.1 {Tcl_Import, empty import pattern} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_import {namespace import {}}} msg] $msg
} {1 {empty import pattern}}
test namespace-9.2 {Tcl_Import, unknown namespace in import pattern} {
    list [catch {namespace eval test_ns_import {namespace import fred::x}} msg] $msg
} {1 {unknown namespace in import pattern "fred::x"}}
test namespace-9.3 {Tcl_Import, import ns == export ns} {
    list [catch {namespace eval test_ns_import {namespace import ::test_ns_import::puts}} msg] $msg
} {1 {import pattern "::test_ns_import::puts" tries to import from namespace "test_ns_import" into itself}}
test namespace-9.4 {Tcl_Import, simple import} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
        proc p {} {return [cmd1 123]}
    }
    test_ns_import::p
} {cmd1: 123}
test namespace-9.5 {Tcl_Import, RFE 1230597} {
    list [catch {namespace eval test_ns_import {namespace import ::test_ns_export::*}} msg] $msg
} {0 {}}
test namespace-9.6 {Tcl_Import, cmd redefinition ok if allowOverwrite!=0} {
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
        cmd1 555
    }
} {cmd1: 555}
test namespace-9.7 {Tcl_Import, links are preserved if cmd is redefined} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    namespace eval test_ns_import {
        namespace import -force ::test_ns_export::*
    }
    list [test_ns_import::cmd1 a b c] \
         [test_ns_export::cmd1 d e f] \
         [proc test_ns_export::cmd1 {args} {return "new1: $args"}] \
         [namespace origin test_ns_import::cmd1] \
         [namespace origin test_ns_export::cmd1] \
         [test_ns_import::cmd1 g h i] \
         [test_ns_export::cmd1 j k l]
} {{cmd1: a b c} {cmd1: d e f} {} ::test_ns_export::cmd1 ::test_ns_export::cmd1 {new1: g h i} {new1: j k l}}

test namespace-9.8 {Tcl_Import: Bug 1017299} -setup {
    namespace eval one {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval two {
	namespace export cmd
	proc other args {}
    }
    namespace eval two \
	    [list namespace import [namespace current]::one::cmd]
    namespace eval three \
	    [list namespace import [namespace current]::two::cmd]
    namespace eval three {
	rename cmd other
	namespace export other
    }
} -body {
    namespace eval two [list namespace import -force \
	    [namespace current]::three::other]
    namespace origin two::other
} -cleanup {
    namespace delete one two three
} -match glob -result *::one::cmd

test namespace-9.9 {Tcl_Import: Bug 1017299} -setup {
    namespace eval one {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval two namespace export cmd
    namespace eval two \
	    [list namespace import [namespace current]::one::cmd]
    namespace eval three namespace export cmd
    namespace eval three \
	    [list namespace import [namespace current]::two::cmd]
} -body {
    namespace eval two [list namespace import -force \
	    [namespace current]::three::cmd]
    namespace origin two::cmd
} -cleanup {
    namespace delete one two three
} -returnCodes error -match glob -result {import pattern * would create a loop*}

test namespace-10.1 {Tcl_ForgetImport, check for valid namespaces} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace forget xyzzy::*} msg] $msg
} {1 {unknown namespace in namespace forget pattern "xyzzy::*"}}
test namespace-10.2 {Tcl_ForgetImport, ignores patterns that don't match} {
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_import {
        namespace forget ::test_ns_export::wombat
    }
} {}
test namespace-10.3 {Tcl_ForgetImport, deletes matching imported cmds} {
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
        proc p {} {return [cmd1 123]}
        set l {}
        lappend l [lsort [info commands ::test_ns_import::*]]
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
        lappend l [catch {cmd1 777} msg] $msg
    }
} [list [lsort {::test_ns_import::p ::test_ns_import::cmd1}] ::test_ns_import::p 1 {invalid command name "cmd1"}]

test namespace-10.4 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval unrelated {
	proc cmd {} {}
    }
    namespace eval my \
	    [list namespace import [namespace current]::origin::cmd]
} -body {
    namespace eval my \
	    [list namespace forget [namespace current]::unrelated::cmd]
    my::cmd
} -cleanup {
    namespace delete origin unrelated my
}

test namespace-10.5 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval my \
	    [list namespace import [namespace current]::origin::cmd]
    namespace eval my rename cmd newname
} -body {
    namespace eval my \
	    [list namespace forget [namespace current]::origin::cmd]
    my::newname
} -cleanup {
    namespace delete origin my
} -returnCodes error -match glob -result *

test namespace-10.6 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval my \
	    [list namespace import [namespace current]::origin::cmd]
    namespace eval your {}
    namespace eval my \
	    [list rename cmd [namespace current]::your::newname]
} -body {
    namespace eval your namespace forget newname
    your::newname
} -cleanup {
    namespace delete origin my your
} -returnCodes error -match glob -result *

test namespace-10.7 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval link namespace export cmd
    namespace eval link \
	    [list namespace import [namespace current]::origin::cmd]
    namespace eval link2 namespace export cmd
    namespace eval link2 \
	    [list namespace import [namespace current]::link::cmd]
    namespace eval my \
	    [list namespace import [namespace current]::link2::cmd]
} -body {
    namespace eval my \
	    [list namespace forget [namespace current]::origin::cmd]
    my::cmd
} -cleanup {
    namespace delete origin link link2 my
} -returnCodes error -match glob -result *

test namespace-10.8 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval link namespace export cmd
    namespace eval link \
	    [list namespace import [namespace current]::origin::cmd]
    namespace eval link2 namespace export cmd
    namespace eval link2 \
	    [list namespace import [namespace current]::link::cmd]
    namespace eval my \
	    [list namespace import [namespace current]::link2::cmd]
} -body {
    namespace eval my \
	    [list namespace forget [namespace current]::link::cmd]
    my::cmd
} -cleanup {
    namespace delete origin link link2 my
}

test namespace-10.9 {Tcl_ForgetImport: Bug 560297} -setup {
    namespace eval origin {
	namespace export cmd
	proc cmd {} {}
    }
    namespace eval link namespace export cmd
    namespace eval link \
	    [list namespace import [namespace current]::origin::cmd]
    namespace eval link2 namespace export cmd
    namespace eval link2 \
	    [list namespace import [namespace current]::link::cmd]
    namespace eval my \
	    [list namespace import [namespace current]::link2::cmd]
} -body {
    namespace eval my \
	    [list namespace forget [namespace current]::link2::cmd]
    my::cmd
} -cleanup {
    namespace delete origin link link2 my
} -returnCodes error -match glob -result *

test namespace-11.1 {TclGetOriginalCommand, check if not imported cmd} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
    }
    list [namespace origin set] [namespace origin test_ns_export::cmd1]
} {::set ::test_ns_export::cmd1}
test namespace-11.2 {TclGetOriginalCommand, directly imported cmd} {
    namespace eval test_ns_import1 {
        namespace import ::test_ns_export::*
        namespace export *
        proc p {} {namespace origin cmd1}
    }
    list [test_ns_import1::p] [namespace origin test_ns_import1::cmd1]
} {::test_ns_export::cmd1 ::test_ns_export::cmd1}
test namespace-11.3 {TclGetOriginalCommand, indirectly imported cmd} {
    namespace eval test_ns_import2 {
        namespace import ::test_ns_import1::*
        proc q {} {return [cmd1 123]}
    }
    list [test_ns_import2::q] [namespace origin test_ns_import2::cmd1]
} {{cmd1: 123} ::test_ns_export::cmd1}

test namespace-12.1 {InvokeImportedCmd} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_export {
        namespace export cmd1
        proc cmd1 {args} {namespace current}
    }
    namespace eval test_ns_import {
        namespace import ::test_ns_export::*
    }
    list [test_ns_import::cmd1]
} {::test_ns_export}

test namespace-13.1 {DeleteImportedCmd, deletes imported cmds} {
    namespace eval test_ns_import {
        set l {}
        lappend l [info commands ::test_ns_import::*]
        namespace forget ::test_ns_export::cmd1
        lappend l [info commands ::test_ns_import::*]
    }
} {::test_ns_import::cmd1 {}}
test namespace-13.2 {DeleteImportedCmd, Bug a4494e28ed} {
    # Will panic if still buggy
    namespace eval src {namespace export foo; proc foo {} {}}
    namespace eval dst {namespace import [namespace parent]::src::foo}
    trace add command src::foo delete \
        "[list namespace delete [namespace current]::dst] ;#"
    proc src::foo {} {}
    namespace delete src
} {}

test namespace-14.1 {TclGetNamespaceForQualName, absolute names} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    variable v 10
    namespace eval test_ns_1::test_ns_2 {
        variable v 20
    }
    namespace eval test_ns_2 {
        variable v 30
    }
    namespace eval test_ns_1 {
        list $::v $::test_ns_2::v $::test_ns_1::test_ns_2::v \
		[lsort [namespace children :: test_ns_*]]
    }
} [list 10 30 20 [lsort {::test_ns_1 ::test_ns_2}]]
test namespace-14.2 {TclGetNamespaceForQualName, invalid absolute names} {
    namespace eval test_ns_1 {
        list [catch {set ::test_ns_777::v} msg] $msg \
             [catch {namespace children test_ns_777} msg] $msg
    }
} {1 {can't read "::test_ns_777::v": no such variable} 1 {namespace "test_ns_777" not found in "::test_ns_1"}}
test namespace-14.3 {TclGetNamespaceForQualName, relative names} {
    namespace eval test_ns_1 {
        list $v $test_ns_2::v
    }
} {10 20}
test namespace-14.4 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} {
    namespace eval test_ns_1::test_ns_2 {
        namespace eval foo {}
    }
    namespace eval test_ns_1 {
        list [namespace children test_ns_2] \
             [catch {namespace children test_ns_1} msg] $msg
    }
} {::test_ns_1::test_ns_2::foo 1 {namespace "test_ns_1" not found in "::test_ns_1"}}
test namespace-14.5 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} {
    namespace eval ::test_ns_2 {
        namespace eval bar {}
    }
    namespace eval test_ns_1 {
        set l [list [catch {namespace delete test_ns_2::bar} msg] $msg]
    }
    set l
} {1 {unknown namespace "test_ns_2::bar" in namespace delete command}}
test namespace-14.6 {TclGetNamespaceForQualName, relative ns names looked up only in current ns} {
    namespace eval test_ns_1::test_ns_2 {
        namespace eval foo {}
    }
    namespace eval test_ns_1 {
        list [namespace children test_ns_2] \
             [catch {namespace children test_ns_1} msg] $msg
    }
} {::test_ns_1::test_ns_2::foo 1 {namespace "test_ns_1" not found in "::test_ns_1"}}
test namespace-14.7 {TclGetNamespaceForQualName, ignore extra :s if ns} {
    namespace children test_ns_1:::
} {::test_ns_1::test_ns_2}
test namespace-14.8 {TclGetNamespaceForQualName, ignore extra :s if ns} {
    namespace children :::test_ns_1:::::test_ns_2:::
} {::test_ns_1::test_ns_2::foo}
test namespace-14.9 {TclGetNamespaceForQualName, extra ::s are significant for vars} {
    set l {}
    lappend l [catch {set test_ns_1::test_ns_2::} msg] $msg
    namespace eval test_ns_1::test_ns_2 {variable {} 2525}
    lappend l [set test_ns_1::test_ns_2::]
} {1 {can't read "test_ns_1::test_ns_2::": no such variable} 2525}
test namespace-14.10 {TclGetNamespaceForQualName, extra ::s are significant for vars} {
    catch {unset test_ns_1::test_ns_2::}
    set l {}
    lappend l [catch {set test_ns_1::test_ns_2::} msg] $msg
    set test_ns_1::test_ns_2:: 314159
    lappend l [set test_ns_1::test_ns_2::]
} {1 {can't read "test_ns_1::test_ns_2::": no such variable} 314159}
test namespace-14.11 {TclGetNamespaceForQualName, extra ::s are significant for commands} {
    catch {rename test_ns_1::test_ns_2:: {}}
    set l {}
    lappend l [catch {test_ns_1::test_ns_2:: hello} msg] $msg
    proc test_ns_1::test_ns_2:: {args} {return "\{\}: $args"}
    lappend l [test_ns_1::test_ns_2:: hello]
} {1 {invalid command name "test_ns_1::test_ns_2::"} {{}: hello}}
test namespace-14.12 {TclGetNamespaceForQualName, extra ::s are significant for vars} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        variable {}
        set test_ns_1::(x) y
    }
    set test_ns_1::(x)
} y
test namespace-14.13 {TclGetNamespaceForQualName, namespace other than global ns can't have empty name} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace eval test_ns_1 {proc {} {} {}; namespace eval {} {}; {}}} msg] $msg
} {1 {can't create namespace "": only global namespace can have empty name}}

test namespace-15.1 {Tcl_FindNamespace, absolute name found} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_delete {
        namespace eval test_ns_delete2 {}
        proc cmd {args} {namespace current}
    }
    list [namespace delete ::test_ns_delete::test_ns_delete2] \
         [namespace children ::test_ns_delete]
} {{} {}}
test namespace-15.2 {Tcl_FindNamespace, absolute name not found} {
    list [catch {namespace delete ::test_ns_delete::test_ns_delete2} msg] $msg
} {1 {unknown namespace "::test_ns_delete::test_ns_delete2" in namespace delete command}}
test namespace-15.3 {Tcl_FindNamespace, relative name found} {
    namespace eval test_ns_delete {
        namespace eval test_ns_delete2 {}
        namespace eval test_ns_delete3 {}
        list [namespace delete test_ns_delete2] \
             [namespace children [namespace current]]
    }
} {{} ::test_ns_delete::test_ns_delete3}
test namespace-15.4 {Tcl_FindNamespace, relative name not found} {
    namespace eval test_ns_delete2 {}
    namespace eval test_ns_delete {
        list [catch {namespace delete test_ns_delete2} msg] $msg
    }
} {1 {unknown namespace "test_ns_delete2" in namespace delete command}}

test namespace-16.1 {Tcl_FindCommand, absolute name found} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc cmd {args} {return "[namespace current]::cmd: $args"}
        variable v "::test_ns_1::cmd"
        eval $v one
    }
} {::test_ns_1::cmd: one}
test namespace-16.2 {Tcl_FindCommand, absolute name found} {
    eval $test_ns_1::v two
} {::test_ns_1::cmd: two}
test namespace-16.3 {Tcl_FindCommand, absolute name not found} {
    namespace eval test_ns_1 {
        variable v2 "::test_ns_1::ladidah"
        list [catch {eval $v2} msg] $msg
    }
} {1 {invalid command name "::test_ns_1::ladidah"}}

# save the "unknown" proc, which is redefined by the following two tests
catch {rename unknown unknown.old}
proc unknown {args} {
    return "unknown: $args"
}
test namespace-16.4 {Tcl_FindCommand, absolute name and TCL_GLOBAL_ONLY} {
    ::test_ns_1::foobar x y z
} {unknown: ::test_ns_1::foobar x y z}
test namespace-16.5 {Tcl_FindCommand, absolute name and TCL_GLOBAL_ONLY} {
    ::foobar 1 2 3 4 5
} {unknown: ::foobar 1 2 3 4 5}
test namespace-16.6 {Tcl_FindCommand, relative name and TCL_GLOBAL_ONLY} {
    test_ns_1::foobar x y z
} {unknown: test_ns_1::foobar x y z}
test namespace-16.7 {Tcl_FindCommand, relative name and TCL_GLOBAL_ONLY} {
    foobar 1 2 3 4 5
} {unknown: foobar 1 2 3 4 5}
# restore the "unknown" proc saved previously
catch {rename unknown {}}
catch {rename unknown.old unknown}

test namespace-16.8 {Tcl_FindCommand, relative name found} {
    namespace eval test_ns_1 {
        cmd a b c
    }
} {::test_ns_1::cmd: a b c}
test namespace-16.9 {Tcl_FindCommand, relative name found} {
    catch {rename cmd2 {}}
    proc cmd2 {args} {return "[namespace current]::cmd2: $args"}
    namespace eval test_ns_1 {
       cmd2 a b c
    }
} {::::cmd2: a b c}
test namespace-16.10 {Tcl_FindCommand, relative name found, only look in current then global ns} {
    namespace eval test_ns_1 {
        proc cmd2 {args} {
            return "[namespace current]::cmd2 in test_ns_1: $args"
        }
        namespace eval test_ns_12 {
            cmd2 a b c
        }
    }
} {::::cmd2: a b c}
test namespace-16.11 {Tcl_FindCommand, relative name not found} {
    namespace eval test_ns_1 {
       list [catch {cmd3 a b c} msg] $msg
    }
} {1 {invalid command name "cmd3"}}

catch {unset x}
test namespace-17.1 {Tcl_FindNamespaceVar, absolute name found} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    set x 314159
    namespace eval test_ns_1 {
        set ::x
    }
} {314159}
test namespace-17.2 {Tcl_FindNamespaceVar, absolute name found} {
    namespace eval test_ns_1 {
        variable x 777
        set ::test_ns_1::x
    }
} {777}
test namespace-17.3 {Tcl_FindNamespaceVar, absolute name found} {
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            variable x 1111
        }
        set ::test_ns_1::test_ns_2::x
    }
} {1111}
test namespace-17.4 {Tcl_FindNamespaceVar, absolute name not found} {
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            variable x 1111
        }
        list [catch {set ::test_ns_1::test_ns_2::y} msg] $msg
    }
} {1 {can't read "::test_ns_1::test_ns_2::y": no such variable}}
test namespace-17.5 {Tcl_FindNamespaceVar, absolute name and TCL_GLOBAL_ONLY} {
    namespace eval test_ns_1 {
        namespace eval test_ns_3 {
            variable ::test_ns_1::test_ns_2::x 2222
        }
    }
    set ::test_ns_1::test_ns_2::x
} {2222}
test namespace-17.6 {Tcl_FindNamespaceVar, relative name found} {
    namespace eval test_ns_1 {
        set x
    }
} {777}
test namespace-17.7 {Tcl_FindNamespaceVar, relative name found} {
    namespace eval test_ns_1 {
        unset x
        set x  ;# must be global x now
    }
} {314159}
test namespace-17.8 {Tcl_FindNamespaceVar, relative name not found} {
    namespace eval test_ns_1 {
        list [catch {set wuzzat} msg] $msg
    }
} {1 {can't read "wuzzat": no such variable}}
test namespace-17.9 {Tcl_FindNamespaceVar, relative name and TCL_GLOBAL_ONLY} {
    namespace eval test_ns_1 {
        variable a hello
    }
    set test_ns_1::a
} {hello}
test namespace-17.10 {Tcl_FindNamespaceVar, interference with cached varNames} {
    namespace eval test_ns_1 {}
    proc test_ns {} {
	set ::test_ns_1::a 0
    }
    test_ns
    rename test_ns {}
    namespace eval test_ns_1 unset a
    set a 0
    namespace eval test_ns_1 set a 1
    namespace delete test_ns_1
    set a
} 1
catch {unset a}
catch {unset x}

catch {unset l}
catch {rename foo {}}
test namespace-18.1 {TclResetShadowedCmdRefs, one-level check for command shadowing} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    proc foo {} {return "global foo"}
    namespace eval test_ns_1 {
        proc trigger {} {
            return [foo]
        }
    }
    set l ""
    lappend l [test_ns_1::trigger]
    namespace eval test_ns_1 {
        # force invalidation of cached ref to "foo" in proc trigger
        proc foo {} {return "foo in test_ns_1"}
    }
    lappend l [test_ns_1::trigger]
    set l
} {{global foo} {foo in test_ns_1}}
test namespace-18.2 {TclResetShadowedCmdRefs, multilevel check for command shadowing} {
    namespace eval test_ns_2 {
        proc foo {} {return "foo in ::test_ns_2"}
    }
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {}
        proc trigger {} {
            return [test_ns_2::foo]
        }
    }
    set l ""
    lappend l [test_ns_1::trigger]
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            # force invalidation of cached ref to "foo" in proc trigger
            proc foo {} {return "foo in ::test_ns_1::test_ns_2"}
        }
    }
    lappend l [test_ns_1::trigger]
    set l
} {{foo in ::test_ns_2} {foo in ::test_ns_1::test_ns_2}}
catch {unset l}
catch {rename foo {}}

test namespace-19.1 {GetNamespaceFromObj, global name found} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace children ::test_ns_1
} {::test_ns_1::test_ns_2}
test namespace-19.2 {GetNamespaceFromObj, relative name found} {
    namespace eval test_ns_1 {
        namespace children test_ns_2
    }
} {}
test namespace-19.3 {GetNamespaceFromObj, name not found} -body {
    namespace eval test_ns_1 {
        namespace children test_ns_99
    }
} -returnCodes error -result {namespace "test_ns_99" not found in "::test_ns_1"}
test namespace-19.4 {GetNamespaceFromObj, invalidation of cached ns refs} {
    namespace eval test_ns_1 {
        proc foo {} {
            return [namespace children test_ns_2]
        }
        list [catch {namespace children test_ns_99} msg] $msg
    }
    set l {}
    lappend l [test_ns_1::foo]
    namespace delete test_ns_1::test_ns_2
    namespace eval test_ns_1::test_ns_2::test_ns_3 {}
    lappend l [test_ns_1::foo]
    set l
} {{} ::test_ns_1::test_ns_2::test_ns_3}

test namespace-20.1 {Tcl_NamespaceObjCmd, bad subcommand} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace} msg] $msg
} {1 {wrong # args: should be "namespace subcommand ?arg ...?"}}
test namespace-20.2 {Tcl_NamespaceObjCmd, bad subcommand} -body {
    namespace wombat {}
} -returnCodes error -match glob -result {bad option "wombat": must be *}
test namespace-20.3 {Tcl_NamespaceObjCmd, abbreviations are okay} {
    namespace ch :: test_ns_*
} {}

test namespace-21.1 {NamespaceChildrenCmd, no args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    expr {[string first ::test_ns_1 [namespace children]] != -1}
} {1}
test namespace-21.2 {NamespaceChildrenCmd, no args} {
    namespace eval test_ns_1 {
        namespace children
    }
} {::test_ns_1::test_ns_2}
test namespace-21.3 {NamespaceChildrenCmd, ns name given} {
    namespace children ::test_ns_1
} {::test_ns_1::test_ns_2}
test namespace-21.4 {NamespaceChildrenCmd, ns name given} {
    namespace eval test_ns_1 {
        namespace children test_ns_2
    }
} {}
test namespace-21.5 {NamespaceChildrenCmd, too many args} {
    namespace eval test_ns_1 {
        list [catch {namespace children test_ns_2 xxx yyy} msg] $msg
    }
} {1 {wrong # args: should be "namespace children ?name? ?pattern?"}}
test namespace-21.6 {NamespaceChildrenCmd, glob-style pattern given} {
    namespace eval test_ns_1::test_ns_foo {}
    namespace children test_ns_1 *f*
} {::test_ns_1::test_ns_foo}
test namespace-21.7 {NamespaceChildrenCmd, glob-style pattern given} {
    namespace eval test_ns_1::test_ns_foo {}
    lsort [namespace children test_ns_1 test*]
} [lsort {::test_ns_1::test_ns_2 ::test_ns_1::test_ns_foo}]
test namespace-21.8 {NamespaceChildrenCmd, trivial pattern starting with ::} {
    namespace eval test_ns_1 {}
    namespace children [namespace current] [fq test_ns_1]
} [fq test_ns_1]

test namespace-22.1 {NamespaceCodeCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace code} msg] $msg \
         [catch {namespace code xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace code arg"} 1 {wrong # args: should be "namespace code arg"}}
test namespace-22.2 {NamespaceCodeCmd, arg is already scoped value} {
    namespace eval test_ns_1 {
        proc cmd {} {return "test_ns_1::cmd"}
    }
    namespace code {::namespace inscope ::test_ns_1 cmd}
} {::namespace inscope ::test_ns_1 cmd}
test namespace-22.3 {NamespaceCodeCmd, arg is already scoped value} {
    namespace code {namespace     inscope     ::test_ns_1 cmd}
} {::namespace inscope :: {namespace     inscope     ::test_ns_1 cmd}}
test namespace-22.4 {NamespaceCodeCmd, in :: namespace} {
    namespace code unknown
} {::namespace inscope :: unknown}
test namespace-22.5 {NamespaceCodeCmd, in other namespace} {
    namespace eval test_ns_1 {
        namespace code cmd
    }
} {::namespace inscope ::test_ns_1 cmd}
test namespace-22.6 {NamespaceCodeCmd, in other namespace} { 
    namespace eval test_ns_1 { 
	variable v 42 
    } 
    namespace eval test_ns_2 { 
	proc namespace args {} 
    } 
    namespace eval test_ns_2 [namespace eval test_ns_1 { 
	namespace code {set v} 
    }] 
} {42} 
test namespace-22.7 {NamespaceCodeCmd, Bug 3202171} {
    namespace eval demo {
	proc namespace args {puts $args}
	::namespace code {namespace inscope foo}
    }
} [list ::namespace inscope [fq demo] {namespace inscope foo}]

test namespace-23.1 {NamespaceCurrentCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace current xxx} msg] $msg \
         [catch {namespace current xxx yyy} msg] $msg
} {1 {wrong # args: should be "namespace current"} 1 {wrong # args: should be "namespace current"}}
test namespace-23.2 {NamespaceCurrentCmd, at global level} {
    namespace current
} {::}
test namespace-23.3 {NamespaceCurrentCmd, in nested ns} {
    namespace eval test_ns_1::test_ns_2 {
        namespace current
    }
} {::test_ns_1::test_ns_2}

test namespace-24.1 {NamespaceDeleteCmd, no args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace delete
} {}
test namespace-24.2 {NamespaceDeleteCmd, one arg} {
    namespace eval test_ns_1::test_ns_2 {}
    namespace delete ::test_ns_1
} {}
test namespace-24.3 {NamespaceDeleteCmd, two args} {
    namespace eval test_ns_1::test_ns_2 {}
    list [namespace delete ::test_ns_1::test_ns_2] [namespace delete ::test_ns_1]
} {{} {}}
test namespace-24.4 {NamespaceDeleteCmd, unknown ns} {
    list [catch {namespace delete ::test_ns_foo} msg] $msg
} {1 {unknown namespace "::test_ns_foo" in namespace delete command}}

test namespace-25.1 {NamespaceEvalCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace eval} msg] $msg
} {1 {wrong # args: should be "namespace eval name arg ?arg...?"}}
test namespace-25.2 {NamespaceEvalCmd, bad args} -body {
    namespace test_ns_1
} -returnCodes error -match glob -result {bad option "test_ns_1": must be *}
catch {unset v}
test namespace-25.3 {NamespaceEvalCmd, new namespace} {
    set v 123
    namespace eval test_ns_1 {
        variable v 314159
        proc p {} {
            variable v
            return $v
        }
    }
    test_ns_1::p
} {314159}
test namespace-25.4 {NamespaceEvalCmd, existing namespace} {
    namespace eval test_ns_1 {
        proc q {} {return [expr {[p]+1}]}
    }
    test_ns_1::q
} {314160}
test namespace-25.5 {NamespaceEvalCmd, multiple args} {
    namespace eval test_ns_1 "set" "v"
} {314159}
test namespace-25.6 {NamespaceEvalCmd, error in eval'd script} {
    list [catch {namespace eval test_ns_1 {xxxx}} msg] $msg $::errorInfo
} {1 {invalid command name "xxxx"} {invalid command name "xxxx"
    while executing
"xxxx"
    (in namespace eval "::test_ns_1" script line 1)
    invoked from within
"namespace eval test_ns_1 {xxxx}"}}
test namespace-25.7 {NamespaceEvalCmd, error in eval'd script} {
    list [catch {namespace eval test_ns_1 {error foo bar baz}} msg] $msg $::errorInfo
} {1 foo {bar
    (in namespace eval "::test_ns_1" script line 1)
    invoked from within
"namespace eval test_ns_1 {error foo bar baz}"}}
test namespace-25.8 {NamespaceEvalCmd, error in eval'd script} {
    list [catch {namespace eval test_ns_1 error foo bar baz} msg] $msg $::errorInfo
} {1 foo {bar
    (in namespace eval "::test_ns_1" script line 1)
    invoked from within
"namespace eval test_ns_1 error foo bar baz"}}
catch {unset v}
test namespace-25.9 {NamespaceEvalCmd, 545325} {
    namespace eval test_ns_1 info level 0
} {namespace eval test_ns_1 info level 0}

test namespace-26.1 {NamespaceExportCmd, no args and new ns} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace export
} {}
test namespace-26.2 {NamespaceExportCmd, just -clear arg} {
    namespace export -clear
} {}
test namespace-26.3 {NamespaceExportCmd, pattern can't specify a namespace} {
    namespace eval test_ns_1 {
        list [catch {namespace export ::zzz} msg] $msg
    }
} {1 {invalid export pattern "::zzz": pattern can't specify a namespace}}
test namespace-26.4 {NamespaceExportCmd, one pattern} {
    namespace eval test_ns_1 {
        namespace export cmd1
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
        proc cmd3 {args} {return "cmd3: $args"}
        proc cmd4 {args} {return "cmd4: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
    }
    list [info commands test_ns_2::*] [test_ns_2::cmd1 hello]
} {::test_ns_2::cmd1 {cmd1: hello}}
test namespace-26.5 {NamespaceExportCmd, sequence of patterns, patterns accumulate} {
    namespace eval test_ns_1 {
        namespace export cmd1 cmd3
    }
    namespace eval test_ns_2 {
        namespace import -force ::test_ns_1::*
    }
    list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd3 hello]
} [list [lsort {::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd3: hello}]
test namespace-26.6 {NamespaceExportCmd, no patterns means return uniq'ed export list} {
    namespace eval test_ns_1 {
        namespace export
    }
} {cmd1 cmd3}
test namespace-26.7 {NamespaceExportCmd, -clear resets export list} {
    namespace eval test_ns_1 {
        namespace export -clear cmd4
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
    }
    list [lsort [info commands test_ns_2::*]] [test_ns_2::cmd4 hello]
} [list [lsort {::test_ns_2::cmd4 ::test_ns_2::cmd1 ::test_ns_2::cmd3}] {cmd4: hello}]
test namespace-26.8 {NamespaceExportCmd, -clear resets export list} {
    catch {namespace delete foo}
    namespace eval foo {
	namespace export x
	namespace export -clear
    }
    list [namespace eval foo namespace export] [namespace delete foo]
} {{} {}}

test namespace-27.1 {NamespaceForgetCmd, no args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace forget
} {}
test namespace-27.2 {NamespaceForgetCmd, args must be valid namespaces} {
    list [catch {namespace forget ::test_ns_1::xxx} msg] $msg
} {1 {unknown namespace in namespace forget pattern "::test_ns_1::xxx"}}
test namespace-27.3 {NamespaceForgetCmd, arg is forgotten} {
    namespace eval test_ns_1 {
        namespace export cmd*
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands ::test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-28.1 {NamespaceImportCmd, no args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    lsort [namespace import]
} {bytestring cleanupTests configure customMatch debug errorChannel errorFile getMatchingFiles interpreter limitConstraints loadFile loadScript loadTestedCommands mainThread makeDirectory makeFile match matchDirectories matchFiles normalizeMsg normalizePath outputChannel outputFile preserveCore removeDirectory removeFile restoreState runAllTests saveState singleProcess skip skipDirectories skipFiles temporaryDirectory test testConstraint testsDirectory threadReap verbose viewFile workingDirectory}
test namespace-28.2 {NamespaceImportCmd, no args and just "-force"} {
    namespace import -force
} {}
test namespace-28.3 {NamespaceImportCmd, arg is imported} {
    namespace eval test_ns_1 {
        namespace export cmd2
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace import ::test_ns_1::*
        namespace forget ::test_ns_1::cmd1
    }
    info commands test_ns_2::*
} {::test_ns_2::cmd2}

test namespace-29.1 {NamespaceInscopeCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace inscope} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.2 {NamespaceInscopeCmd, bad args} {
    list [catch {namespace inscope ::} msg] $msg
} {1 {wrong # args: should be "namespace inscope name arg ?arg...?"}}
test namespace-29.3 {NamespaceInscopeCmd, specified ns must exist} -body {
    namespace inscope test_ns_1 {set v}
} -returnCodes error -result {namespace "test_ns_1" not found in "::"}
test namespace-29.4 {NamespaceInscopeCmd, simple case} {
    namespace eval test_ns_1 {
        variable v 747
        proc cmd {args} {
            variable v
            return "[namespace current]::cmd: v=$v, args=$args"
        }
    }
    namespace inscope test_ns_1 cmd
} {::test_ns_1::cmd: v=747, args=}
test namespace-29.5 {NamespaceInscopeCmd, has lappend semantics} {
    list [namespace inscope test_ns_1 cmd x y z] \
         [namespace eval test_ns_1 [concat cmd [list x y z]]]
} {{::test_ns_1::cmd: v=747, args=x y z} {::test_ns_1::cmd: v=747, args=x y z}}
test namespace-29.6 {NamespaceInscopeCmd, 1400572} {
    namespace inscope test_ns_1 {info level 0}
} {namespace inscope test_ns_1 {info level 0}}


test namespace-30.1 {NamespaceOriginCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace origin} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.2 {NamespaceOriginCmd, bad args} {
    list [catch {namespace origin x y} msg] $msg
} {1 {wrong # args: should be "namespace origin name"}}
test namespace-30.3 {NamespaceOriginCmd, command not found} {
    list [catch {namespace origin fred} msg] $msg
} {1 {invalid command name "fred"}}
test namespace-30.4 {NamespaceOriginCmd, command isn't imported} {
    namespace origin set
} {::set}
test namespace-30.5 {NamespaceOriginCmd, imported command} {
    namespace eval test_ns_1 {
        namespace export cmd*
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace export *
        namespace import ::test_ns_1::*
        proc p {} {}
    }
    namespace eval test_ns_3 {
        namespace import ::test_ns_2::*
        list [namespace origin foreach] \
             [namespace origin p] \
             [namespace origin cmd1] \
             [namespace origin ::test_ns_2::cmd2]
    }
} {::foreach ::test_ns_2::p ::test_ns_1::cmd1 ::test_ns_1::cmd2}

test namespace-31.1 {NamespaceParentCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace parent a b} msg] $msg
} {1 {wrong # args: should be "namespace parent ?name?"}}
test namespace-31.2 {NamespaceParentCmd, no args} {
    namespace parent
} {}
test namespace-31.3 {NamespaceParentCmd, namespace specified} {
    namespace eval test_ns_1 {
        namespace eval test_ns_2 {
            namespace eval test_ns_3 {}
        }
    }
    list [namespace parent ::] \
         [namespace parent test_ns_1::test_ns_2] \
         [namespace eval test_ns_1::test_ns_2::test_ns_3 {namespace parent ::test_ns_1::test_ns_2}]
} {{} ::test_ns_1 ::test_ns_1}
test namespace-31.4 {NamespaceParentCmd, bad namespace specified} -body {
    namespace parent test_ns_1::test_ns_foo
} -returnCodes error -result {namespace "test_ns_1::test_ns_foo" not found in "::"}

test namespace-32.1 {NamespaceQualifiersCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace qualifiers} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.2 {NamespaceQualifiersCmd, bad args} {
    list [catch {namespace qualifiers x y} msg] $msg
} {1 {wrong # args: should be "namespace qualifiers string"}}
test namespace-32.3 {NamespaceQualifiersCmd, simple name} {
    namespace qualifiers foo
} {}
test namespace-32.4 {NamespaceQualifiersCmd, leading ::} {
    namespace qualifiers ::x::y::z
} {::x::y}
test namespace-32.5 {NamespaceQualifiersCmd, no leading ::} {
    namespace qualifiers a::b
} {a}
test namespace-32.6 {NamespaceQualifiersCmd, :: argument} {
    namespace qualifiers ::
} {}
test namespace-32.7 {NamespaceQualifiersCmd, odd number of :s} {
    namespace qualifiers :::::
} {}
test namespace-32.8 {NamespaceQualifiersCmd, odd number of :s} {
    namespace qualifiers foo:::
} {foo}

test namespace-33.1 {NamespaceTailCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace tail} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.2 {NamespaceTailCmd, bad args} {
    list [catch {namespace tail x y} msg] $msg
} {1 {wrong # args: should be "namespace tail string"}}
test namespace-33.3 {NamespaceTailCmd, simple name} {
    namespace tail foo
} {foo}
test namespace-33.4 {NamespaceTailCmd, leading ::} {
    namespace tail ::x::y::z
} {z}
test namespace-33.5 {NamespaceTailCmd, no leading ::} {
    namespace tail a::b
} {b}
test namespace-33.6 {NamespaceTailCmd, :: argument} {
    namespace tail ::
} {}
test namespace-33.7 {NamespaceTailCmd, odd number of :s} {
    namespace tail :::::
} {}
test namespace-33.8 {NamespaceTailCmd, odd number of :s} {
    namespace tail foo:::
} {}

test namespace-34.1 {NamespaceWhichCmd, bad args} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    list [catch {namespace which} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.2 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which -fred x} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.3 {NamespaceWhichCmd, single arg is always command name} {
    namespace which -command
} {}
test namespace-34.4 {NamespaceWhichCmd, bad args} {
    list [catch {namespace which a b} msg] $msg
} {1 {wrong # args: should be "namespace which ?-command? ?-variable? name"}}
test namespace-34.5 {NamespaceWhichCmd, command lookup} {
    namespace eval test_ns_1 {
        namespace export cmd*
        variable v1 111
        proc cmd1 {args} {return "cmd1: $args"}
        proc cmd2 {args} {return "cmd2: $args"}
    }
    namespace eval test_ns_2 {
        namespace export *
        namespace import ::test_ns_1::*
        variable v2 222
        proc p {} {}
    }
    namespace eval test_ns_3 {
        namespace import ::test_ns_2::*
        variable v3 333
        list [namespace which -command foreach] \
             [namespace which -command p] \
             [namespace which -command cmd1] \
             [namespace which -command ::test_ns_2::cmd2] \
             [catch {namespace which -command ::test_ns_2::noSuchCmd} msg] $msg
    }
} {::foreach ::test_ns_3::p ::test_ns_3::cmd1 ::test_ns_2::cmd2 0 {}}
test namespace-34.6 {NamespaceWhichCmd, -command is default} {
    namespace eval test_ns_3 {
        list [namespace which foreach] \
             [namespace which p] \
             [namespace which cmd1] \
             [namespace which ::test_ns_2::cmd2]
    }
} {::foreach ::test_ns_3::p ::test_ns_3::cmd1 ::test_ns_2::cmd2}
test namespace-34.7 {NamespaceWhichCmd, variable lookup} {
    namespace eval test_ns_3 {
        list [namespace which -variable env] \
             [namespace which -variable v3] \
             [namespace which -variable ::test_ns_2::v2] \
             [catch {namespace which -variable ::test_ns_2::noSuchVar} msg] $msg
    }
} {::env ::test_ns_3::v3 ::test_ns_2::v2 0 {}}

test namespace-35.1 {FreeNsNameInternalRep, resulting ref count > 0} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {
        proc p {} {
            namespace delete [namespace current]
            return [namespace current]
        }
    }
    test_ns_1::p
} {::test_ns_1}
test namespace-35.2 {FreeNsNameInternalRep, resulting ref count == 0} {
    namespace eval test_ns_1 {
        proc q {} {
            return [namespace current]
        }
    }
    list [test_ns_1::q] \
         [namespace delete test_ns_1] \
         [catch {test_ns_1::q} msg] $msg
} {::test_ns_1 {} 1 {invalid command name "test_ns_1::q"}}

catch {unset x}
catch {unset y}
test namespace-36.1 {DupNsNameInternalRep} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1 {}
    set x "::test_ns_1"
    list [namespace parent $x] [set y $x] [namespace parent $y]
} {:: ::test_ns_1 ::}
catch {unset x}
catch {unset y}

test namespace-37.1 {SetNsNameFromAny, ns name found} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval test_ns_1::test_ns_2 {}
    namespace eval test_ns_1 {
        namespace children ::test_ns_1
    }
} {::test_ns_1::test_ns_2}
test namespace-37.2 {SetNsNameFromAny, ns name not found} -body {
    namespace eval test_ns_1 {
        namespace children ::test_ns_1::test_ns_foo
    }
} -returnCodes error -result {namespace "::test_ns_1::test_ns_foo" not found}

test namespace-38.1 {UpdateStringOfNsName} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    ;# Tcl_NamespaceObjCmd calls UpdateStringOfNsName to get subcmd name
    list [namespace eval {} {namespace current}] \
         [namespace eval {} {namespace current}]
} {:: ::}

test namespace-39.1 {NamespaceExistsCmd} {
    catch {namespace delete {*}[namespace children :: test_ns_*]}
    namespace eval ::test_ns_z::test_me { variable foo }
    list [namespace exists ::] \
	    [namespace exists ::bogus_namespace] \
	    [namespace exists ::test_ns_z] \
	    [namespace exists test_ns_z] \
	    [namespace exists ::test_ns_z::foo] \
	    [namespace exists ::test_ns_z::test_me] \
	    [namespace eval ::test_ns_z { namespace exists ::test_me }] \
	    [namespace eval ::test_ns_z { namespace exists test_me }] \
	    [namespace exists :::::test_ns_z]
} {1 0 1 1 0 1 0 1 1}
test namespace-39.2 {NamespaceExistsCmd error} {
    list [catch {namespace exists} msg] $msg
} {1 {wrong # args: should be "namespace exists name"}}
test namespace-39.3 {NamespaceExistsCmd error} {
    list [catch {namespace exists a b} msg] $msg
} {1 {wrong # args: should be "namespace exists name"}}

test namespace-40.1 {Ignoring namespace proc "unknown"} {
    rename unknown _unknown
    proc unknown args {return global}
    namespace eval ns {proc unknown args {return local}}
    set l [list [namespace eval ns aaa bbb] [namespace eval ns aaa]]
    rename unknown {}   
    rename _unknown unknown
    namespace delete ns
    set l
} {global global}

test namespace-41.1 {Shadowing byte-compiled commands, Bug: 231259} {
    set res {}
    namespace eval ns {
	set res {}
	proc test {} {
	    set ::g 0
	}  
	lappend ::res [test]
	proc set {a b} {
	    ::set a [incr b]
	}
	lappend ::res [test]
    }
    namespace delete ns
    set res
} {0 1}

test namespace-41.2 {Shadowing byte-compiled commands, Bug: 231259} {
    set res {}
    namespace eval ns {}
    proc ns::a {i} {
	variable b
	proc set args {return "New proc is called"}
	return [set b $i]
    }
    ns::a 1
    set res [ns::a 2]
    namespace delete ns
    set res
} {New proc is called}

test namespace-41.3 {Shadowing byte-compiled commands, Bugs: 231259, 729692} {
    set res {}
    namespace eval ns {
	variable b 0
    }

    proc ns::a {i} {
	variable b
	proc set args {return "New proc is called"}
	return [set b $i]
    }
    
    set res [list [ns::a 1] $ns::b]
    namespace delete ns
    set res
} {{New proc is called} 0}

# Ensembles (TIP#112)

test namespace-42.1 {ensembles: basic} {
    namespace eval ns {
	namespace export x
	proc x {} {format 1}
	namespace ensemble create
    }
    list [info command ns] [ns x] [namespace delete ns] [info command ns]
} {ns 1 {} {}}
test namespace-42.2 {ensembles: basic} {
    namespace eval ns {
	namespace export x
	proc x {} {format 1}
	namespace ensemble create
    }
    rename ns foo
    list [info command foo] [foo x] [namespace delete ns] [info command foo]
} {foo 1 {} {}}
test namespace-42.3 {ensembles: basic} {
    namespace eval ns {
	namespace export x*
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	namespace ensemble create
    }
    set result [list [ns x1] [ns x2]]
    lappend result [catch {ns x} msg] $msg
    rename ns {}
    lappend result [info command ns::x1]
    namespace delete ns
    lappend result [info command ns::x1]
} {1 2 1 {unknown or ambiguous subcommand "x": must be x1, or x2} ::ns::x1 {}}
test namespace-42.4 {ensembles: basic} {
    namespace eval ns {
	namespace export y*
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	namespace ensemble create
    }
    set result [list [catch {ns x} msg] $msg]
    namespace delete ns
    set result
} {1 {unknown subcommand "x": namespace ::ns does not export any commands}}
test namespace-42.5 {ensembles: basic} {
    namespace eval ns {
	namespace export x*
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	proc x3 {} {format 3}
	namespace ensemble create
    }
    set result [list [catch {ns x} msg] $msg]
    namespace delete ns
    set result
} {1 {unknown or ambiguous subcommand "x": must be x1, x2, or x3}}
test namespace-42.6 {ensembles: nested} {
    namespace eval ns {
	namespace export x*
	namespace eval x0 {
	    proc z {} {format 0}
	    namespace export z
	    namespace ensemble create
	}
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	proc x3 {} {format 3}
	namespace ensemble create
    }
    set result [list [ns x0 z] [ns x1] [ns x2] [ns x3]]
    namespace delete ns
    set result
} {0 1 2 3}
test namespace-42.7 {ensembles: nested} {
    namespace eval ns {
	namespace export x*
	namespace eval x0 {
	    proc z {} {list [info level] [info level 1]}
	    namespace export z
	    namespace ensemble create
	}
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	proc x3 {} {format 3}
	namespace ensemble create
    }
    set result [list [ns x0 z] [ns x1] [ns x2] [ns x3]]
    namespace delete ns
    set result
} {{1 ::ns::x0::z} 1 2 3}
test namespace-42.8 {ensembles: [Bug 1670091]} -setup {
    proc demo args {}
    variable target [list [namespace which demo] x]
    proc trial args {variable target; string length $target}
    trace add execution demo enter [namespace code trial]
    namespace ensemble create -command foo -map [list bar $target]
} -body {
    foo bar
} -cleanup {
    unset target
    rename demo {}
    rename trial {}
    rename foo {}
} -result {}

test namespace-43.1 {ensembles: dict-driven} {
    namespace eval ns {
	namespace export x*
	proc x1 {} {format 1}
	proc x2 {} {format 2}
	namespace ensemble create -map {a x1 b x2}
    }
    set result [list [catch {ns c} msg] $msg [namespace ensemble exists ns]]
    rename ns {}
    lappend result [namespace ensemble exists ns]
} {1 {unknown or ambiguous subcommand "c": must be a, or b} 1 0}
test namespace-43.2 {ensembles: dict-driven} {
    namespace eval ns {
	namespace export x*
	proc x1 {args} {list 1 $args}
	proc x2 {args} {list 2 [llength $args]}
	namespace ensemble create -map {
	    a ::ns::x1 b ::ns::x2 c {::ns::x1 .} d {::ns::x2 .}
	}
    }
    set result [list [ns a] [ns b] [ns c] [ns c foo] [ns d] [ns d foo]]
    namespace delete ns
    set result
} {{1 {}} {2 0} {1 .} {1 {. foo}} {2 1} {2 2}}
set SETUP {
    namespace eval ns {
	namespace export a b
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c}
    }
}
test namespace-43.3 {ensembles: list-driven} -setup $SETUP -body {
    namespace delete ns
} -result {}
test namespace-43.4 {ensembles: list-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.5 {ensembles: list-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.6 {ensembles: list-driven} -setup $SETUP -body {
    ns c foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 3,5
test namespace-43.7 {ensembles: list-driven} -setup $SETUP -body {
    ns d foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "d": must be b, or c}
set SETUP {
    namespace eval ns {
	namespace export a b
	proc a args {format 1,[llength $args]}
	proc b args {format 2,[llength $args]}
	proc c args {format 3,[llength $args]}
	proc d args {format 4,[llength $args]}
	namespace ensemble create -subcommands {b c} -map {c ::ns::d}
    }
}
test namespace-43.8 {ensembles: list-and-map-driven} -setup $SETUP -body {
    namespace delete ns
} -result {}
test namespace-43.9 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns a foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "a": must be b, or c}
test namespace-43.10 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns b foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 2,5
test namespace-43.11 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns c foo bar boo spong wibble
} -cleanup {namespace delete ns} -result 4,5
test namespace-43.12 {ensembles: list-and-map-driven} -setup $SETUP -body {
    ns d foo bar boo spong wibble
} -cleanup {namespace delete ns} -returnCodes error -result {unknown or ambiguous subcommand "d": must be b, or c}
set SETUP {
    namespace eval ns {
	namespace export *
	proc foo args {format bar}
	proc spong args {format wibble}
	namespace ensemble create -prefixes off
    }
}
test namespace-43.13 {ensembles: turn off prefixes} -setup $SETUP -body {
    namespace delete ns
} -result {}
test namespace-43.14 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns fo
} -cleanup {namespace delete ns} -returnCodes error -result {unknown subcommand "fo": must be foo, or spong}
test namespace-43.15 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns foo
} -cleanup {namespace delete ns} -result bar
test namespace-43.16 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns s
} -cleanup {namespace delete ns} -returnCodes error -result {unknown subcommand "s": must be foo, or spong}
test namespace-43.17 {ensembles: turn off prefixes} -setup $SETUP -body {
    ns spong
} -cleanup {namespace delete ns} -result wibble

test namespace-44.1 {ensemble: errors} {
    list [catch {namespace ensemble} msg] $msg
} {1 {wrong # args: should be "namespace ensemble subcommand ?arg ...?"}}
test namespace-44.2 {ensemble: errors} {
    list [catch {namespace ensemble ?} msg] $msg
} {1 {bad subcommand "?": must be configure, create, or exists}}
test namespace-44.3 {ensemble: errors} {
    namespace eval ns {
	list [catch {namespace ensemble create -map x} msg] $msg
    }
} {1 {missing value to go with key}}
test namespace-44.4 {ensemble: errors} {
    namespace eval ns {
	list [catch {namespace ensemble create -map {x {}}} msg] $msg
    }
} {1 {ensemble subcommand implementations must be non-empty lists}}
test namespace-44.5 {ensemble: errors} -setup {
    namespace ensemble create -command foobar -subcommands {foobarcget foobarconfigure}
} -body {
    foobar foobarcon
} -cleanup {
    rename foobar {}
} -returnCodes error -result {invalid command name "::foobarconfigure"}

test namespace-45.1 {ensemble: introspection} {
    namespace eval ns {
	namespace export x
	proc x {} {}
	namespace ensemble create
	set ::result [namespace ensemble configure ::ns]
    }
    namespace delete ns
    set result
} {-map {} -namespace ::ns -prefixes 1 -subcommands {} -unknown {}}
test namespace-45.2 {ensemble: introspection} {
    namespace eval ns {
	namespace export x
	proc x {} {}
	namespace ensemble create -map {A x}
	set ::result [namespace ensemble configure ::ns -map]
    }
    namespace delete ns
    set result
} {A ::ns::x}

test namespace-46.1 {ensemble: modification} {
    namespace eval ns {
	namespace export x
	proc x {} {format 123}

	# Ensemble maps A->x
	namespace ensemble create -command ns -map {A ::ns::x}
	set ::result [list [namespace ensemble configure ns -map] [ns A]]

	# Ensemble maps B->x
	namespace ensemble configure ns -map {B ::ns::x}
	lappend ::result [namespace ensemble configure ns -map] [ns B]

	# Ensemble maps x->x
	namespace ensemble configure ns -map {}
	lappend ::result [namespace ensemble configure ns -map] [ns x]
    }
    namespace delete ns
    set result
} {{A ::ns::x} 123 {B ::ns::x} 123 {} 123}
test namespace-46.2 {ensemble: ensembles really use current export list} {
    namespace eval ns {
	namespace export x1
	proc x1 {} {format 1}
	proc x2 {} {format 1}
	namespace ensemble create
    }
    catch {ns ?} msg; set result [list $msg]
    namespace eval ns {namespace export x*}
    catch {ns ?} msg; lappend result $msg
    rename ns::x1 {}
    catch {ns ?} msg; lappend result $msg
    namespace delete ns
    set result
} {{unknown or ambiguous subcommand "?": must be x1} {unknown or ambiguous subcommand "?": must be x1, or x2} {unknown or ambiguous subcommand "?": must be x2}}
test namespace-46.3 {ensemble: implementation errors} {
    namespace eval ns {
	variable count 0
	namespace ensemble create -map {
	    a {::lappend ::result}
	    b {::incr ::ns::count}
	}
    }
    set result {}
    lappend result [catch { ns } msg] $msg
    ns a [ns b 10]
    catch {rename p {}}
    rename ns p
    p a [p b 3000]
    lappend result $ns::count
    namespace delete ns
    lappend result [info command p]
} {1 {wrong # args: should be "ns subcommand ?argument ...?"} 10 3010 3010 {}}
test namespace-46.4 {ensemble: implementation errors} {
    namespace eval ns {
	namespace ensemble create
    }
    set result [info command ns]
    lappend result [catch {ns ?} msg] $msg
    namespace delete ns
    set result
} {ns 1 {unknown subcommand "?": namespace ::ns does not export any commands}}
test namespace-46.5 {ensemble: implementation errors} {
    namespace eval ns {
	namespace ensemble create -map {makeError ::error}
    }
    list [catch {ns makeError "an error happened"} msg] $msg $::errorInfo [namespace delete ns]
} {1 {an error happened} {an error happened
    while executing
"ns makeError "an error happened""} {}}
test namespace-46.6 {ensemble: implementation renames/deletes itself} {
    namespace eval ns {
	namespace ensemble create -map {to ::rename}
    }
    ns to ns foo
    foo to foo bar
    bar to bar spong
    spong to spong {}
    namespace delete ns
} {}
test namespace-46.7 {ensemble: implementation deletes its namespace} {
    namespace eval ns {
	namespace ensemble create -map {kill {::namespace delete}}
    }
    ns kill ns
} {}
test namespace-46.8 {ensemble: implementation deletes its namespace} {
    namespace eval ns {
	namespace export *
	proc foo {} {
	    variable x 1
	    bar
	    # Tricky; what is the correct return value anyway?
	    info exist x
	}
	proc bar {} {
	    namespace delete [namespace current]
	}
	namespace ensemble create
    }
    list [ns foo] [info exist ns::x]
} {1 0}
test namespace-46.9 {ensemble: configuring really configures things} {
    namespace eval ns {
	namespace ensemble create -map {a a} -prefixes 0
    }
    set result [list [catch {ns x} msg] $msg]
    namespace ensemble configure ns -map {b b}
    lappend result [catch {ns x} msg] $msg
    namespace delete ns
    set result
} {1 {unknown subcommand "x": must be a} 1 {unknown subcommand "x": must be b}}

test namespace-47.1 {ensemble: unknown handler} {
    set log {}
    namespace eval ns {
	namespace export {[a-z]*}
	proc Magic {ensemble subcmd args} {
	    global log
	    if {[string match {[a-z]*} $subcmd]} {
		lappend log "making $subcmd"
		proc $subcmd args {
		    global log
		    lappend log "running [info level 0]"
		    llength $args
		}
	    } else {
		lappend log "unknown $subcmd - args = $args"
		return -code error \
			"unknown or protected subcommand \"$subcmd\""
	    }
	}
	namespace ensemble create -unknown ::ns::Magic
    }
    set result {}
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns a b c} msg] $msg
    lappend result [catch {ns b c d} msg] $msg
    lappend result [catch {ns c d e} msg] $msg
    lappend result [catch {ns Magic foo bar spong wibble} msg] $msg
    list $result [lsort [info commands ::ns::*]] $log [namespace delete ns]
} {{0 2 0 2 0 2 0 2 1 {unknown or protected subcommand "Magic"}} {::ns::Magic ::ns::a ::ns::b ::ns::c} {{making a} {running ::ns::a b c} {running ::ns::a b c} {making b} {running ::ns::b c d} {making c} {running ::ns::c d e} {unknown Magic - args = foo bar spong wibble}} {}}
test namespace-47.2 {ensemble: unknown handler} {
    namespace eval ns {
	namespace export {[a-z]*}
	proc Magic {ensemble subcmd args} {
	    error foobar
	}
	namespace ensemble create -unknown ::ns::Magic
    }
    list [catch {ns spong} msg] $msg $::errorInfo [namespace delete ns]
} {1 foobar {foobar
    while executing
"error foobar"
    (procedure "::ns::Magic" line 2)
    invoked from within
"::ns::Magic ::ns spong"
    (ensemble unknown subcommand handler)
    invoked from within
"ns spong"} {}}
test namespace-47.3 {ensemble: unknown handler} {
    namespace eval ns {
	variable count 0
	namespace export {[a-z]*}
	proc a {} {}
	proc c {} {}
	proc Magic {ensemble subcmd args} {
	    variable count
	    incr count
	    proc b {} {}
	}
	namespace ensemble create -unknown ::ns::Magic
    }
    list [catch {ns spong} msg] $msg $ns::count [namespace delete ns]
} {1 {unknown or ambiguous subcommand "spong": must be a, b, or c} 1 {}}
test namespace-47.4 {ensemble: unknown handler} {
    namespace eval ns {
	namespace export {[a-z]*}
	proc Magic {ensemble subcmd args} {
	    return -code break
	}
	namespace ensemble create -unknown ::ns::Magic
    }
    list [catch {ns spong} msg] $msg $::errorInfo [namespace delete ns]
} {1 {unknown subcommand handler returned bad code: break} {unknown subcommand handler returned bad code: break
    result of ensemble unknown subcommand handler: ::ns::Magic ::ns spong
    invoked from within
"ns spong"} {}}
test namespace-47.5 {ensemble: unknown handler} {
    namespace ensemble create -command foo -unknown bar
    proc bar {args} {
	global result target
	lappend result "LOG $args"
	return $target
    }
    set result {}
    set target {}
    lappend result [catch {foo bar} msg] $msg
    set target {lappend result boo hoo}
    lappend result [catch {foo bar} msg] $msg [namespace ensemble config foo]
    rename foo {}
    set result
} {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo 0 {{LOG ::foo bar} 1 {unknown subcommand "bar": namespace :: does not export any commands} {LOG ::foo bar} boo hoo} {-map {} -namespace :: -prefixes 1 -subcommands {} -unknown bar}}
test namespace-47.6 {ensemble: unknown handler} {
    namespace ensemble create -command foo -unknown bar
    proc bar {args} {
	return "\{"
    }
    set result [list [catch {foo bar} msg] $msg $::errorInfo]
    rename foo {}
    set result
} {1 {unmatched open brace in list} {unmatched open brace in list
    while parsing result of ensemble unknown subcommand handler
    invoked from within
"foo bar"}}
test namespace-47.7 {ensemble: unknown handler, commands with spaces} {
    namespace ensemble create -command foo -unknown bar
    proc bar {args} {
	list ::set ::x [join $args |]
    }
    set result [foo {one two three}]
    rename foo {}
    set result
} {::foo|one two three}
test namespace-47.8 {ensemble: unknown handler, commands with spaces} {
    namespace ensemble create -command foo -unknown {bar boo}
    proc bar {args} {
	list ::set ::x [join $args |]
    }
    set result [foo {one two three}]
    rename foo {}
    set result
} {boo|::foo|one two three}

test namespace-48.1 {ensembles and namespace import: unknown handler} {
    namespace eval foo {
	namespace export bar
	namespace ensemble create -command bar -unknown ::foo::u -subcomm x
	proc u {ens args} {
	    global result
	    lappend result $ens $args
	    namespace ensemble config $ens -subcommand {x y}
	}
	proc u2 {ens args} {
	    global result
	    lappend result $ens $args
	    namespace ensemble config ::bar -subcommand {x y z}
	}
	proc x args {
	    global result
	    lappend result XXX $args
	}
	proc y args {
	    global result
	    lappend result YYY $args
	}
	proc z args {
	    global result
	    lappend result ZZZ $args
	}
    }
    namespace import -force foo::bar
    set result [list [namespace ensemble config bar]]
    bar x 123
    bar y 456
    namespace ensemble config bar -unknown ::foo::u2
    bar z 789
    namespace delete foo
    set result
} {{-map {} -namespace ::foo -prefixes 1 -subcommands x -unknown ::foo::u} XXX 123 ::foo::bar {y 456} YYY 456 ::foo::bar {z 789} ZZZ 789}
test namespace-48.2 {ensembles and namespace import: exists} {
    namespace eval foo {
	namespace ensemble create -command ::foo::bar
	namespace export bar
    }
    set result     [namespace ensemble exist foo::bar]
    lappend result [namespace ensemble exist bar]
    namespace import foo::bar
    lappend result [namespace ensemble exist bar]
    rename foo::bar foo::bar2
    lappend result [namespace ensemble exist bar] \
	    [namespace ensemble exist spong]
    rename bar spong
    lappend result [namespace ensemble exist bar] \
	    [namespace ensemble exist spong]
    rename foo::bar2 {}
    lappend result [namespace ensemble exist spong]
    namespace delete foo
    set result
} {1 0 1 1 0 0 1 0}
test namespace-48.3 {ensembles and namespace import: config} {
    catch {rename spong {}}
    namespace eval foo {
	namespace ensemble create -command ::foo::bar
	namespace export bar boo
	proc boo {} {}
    }
    namespace import foo::bar foo::boo
    set result [namespace ensemble config bar -namespace]
    lappend result [catch {namespace ensemble config boo} msg] $msg
    lappend result [catch {namespace ensemble config spong} msg] $msg
    namespace delete foo
    set result
} {::foo 1 {"boo" is not an ensemble command} 1 {unknown command "spong"}}

test namespace-49.1 {ensemble subcommand caching} -body {
    namespace ens cre -command a -map {b {lappend result 1}}
    namespace ens cre -command c -map {b {lappend result 2}}
    proc x {} {a b; c b; a b; c b}
    x
} -result {1 2 1 2} -cleanup {
    rename a {}
    rename c {}
    rename x {}
}
test namespace-49.2 {strange delete crash} -body {
    namespace eval foo {namespace ensemble create -command ::bar}
    trace add command ::bar delete DeleteTrace
    proc DeleteTrace {old new op} {
	trace remove command ::bar delete DeleteTrace
	rename $old ""
	# This next line caused a bus error in [Bug 1220058]
	namespace delete foo
    }
    rename ::bar ""
} -result "" -cleanup {
    rename DeleteTrace ""
}

test namespace-50.1 {ensembles affect proc arguments error messages} -body {
    namespace ens cre -command a -map {b {bb foo}}
    proc bb {c d {e f} args} {list $c $args}
    a b
} -returnCodes error -result "wrong # args: should be \"a b d ?e? ...\"" -cleanup {
    rename a {}
    rename bb {}
}
test namespace-50.2 {ensembles affect WrongNumArgs error messages} -body {
    namespace ens cre -command a -map {b {string is}}
    a b boolean
} -returnCodes error -result "wrong # args: should be \"a b class ?-strict? ?-failindex var? str\"" -cleanup {
    rename a {}
}
test namespace-50.3 {chained ensembles affect error messages} -body {
    namespace ens cre -command a -map {b c}
    namespace ens cre -command c -map {d e}
    proc e f {}
    a b d
} -returnCodes error -result "wrong # args: should be \"a b d f\"" -cleanup {
    rename a {}
}
test namespace-50.4 {chained ensembles affect error messages} -body {
    namespace ens cre -command a -map {b {c d}}
    namespace ens cre -command c -map {d {e f}}
    proc e f {}
    a b d
} -returnCodes error -result "wrong # args: should be \"a b\"" -cleanup {
    rename a {}
}

test namespace-51.1 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
	namespace path ::test_ns_1
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    test_ns_1::test_ns_2::pathtestA
} -result "global,2,global," -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.2 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    namespace path ::test_ns_1
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    ::test_ns_1::test_ns_2::pathtestA
} -result "1,2,global,::test_ns_1" -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.3 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    set result [::test_ns_1::test_ns_2::pathtestA]
    namespace eval ::test_ns_1::test_ns_2 {
	namespace path ::test_ns_1
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
    rename ::test_ns_1::pathtestB {}
    lappend result [::test_ns_1::test_ns_2::pathtestA]
} -result "global,2,global, 1,2,global,::test_ns_1 global,2,global,::test_ns_1" -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.4 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    set result [::test_ns_1::test_ns_2::pathtestA]
    namespace eval ::test_ns_1::test_ns_2 {
	namespace path ::test_ns_1
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
    namespace eval ::test_ns_1::test_ns_2 {
	namespace path {}
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
} -result "global,2,global, 1,2,global,::test_ns_1 global,2,global," -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.5 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	    namespace path ::test_ns_1
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
	proc pathtestD {} {
	    return 1
	}
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    set result [::test_ns_1::test_ns_2::pathtestA]
    namespace eval ::test_ns_1::test_ns_2 {
	namespace path {:: ::test_ns_1}
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
    rename ::test_ns_1::test_ns_2::pathtestC {}
    lappend result [::test_ns_1::test_ns_2::pathtestA]
} -result "1,2,1,::test_ns_1 {global,2,global,:: ::test_ns_1} {global,1,global,:: ::test_ns_1}" -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.6 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc pathtestA {} {
		::return [pathtestB],[pathtestC],[pathtestD],[namespace path]
	    }
	    proc pathtestC {} {
		::return 2
	    }
	    namespace path ::test_ns_1
	}
	proc pathtestB {} {
	    return 1
	}
	proc pathtestC {} {
	    return 1
	}
	proc pathtestD {} {
	    return 1
	}
    }
    proc ::pathtestB {} {
	return global
    }
    proc ::pathtestD {} {
	return global
    }
    set result [::test_ns_1::test_ns_2::pathtestA]
    namespace eval ::test_ns_1::test_ns_2 {
	namespace path {:: ::test_ns_1}
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
    rename ::test_ns_1::test_ns_2::pathtestC {}
    lappend result [::test_ns_1::test_ns_2::pathtestA]
    proc ::pathtestC {} {
	return global
    }
    lappend result [::test_ns_1::test_ns_2::pathtestA]
} -result "1,2,1,::test_ns_1 {global,2,global,:: ::test_ns_1} {global,1,global,:: ::test_ns_1} {global,global,global,:: ::test_ns_1}" -cleanup {
    namespace delete ::test_ns_1
    catch {rename ::pathtestB {}}
    catch {rename ::pathtestD {}}
}
test namespace-51.7 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
    }
    namespace eval ::test_ns_2 {
	namespace path ::test_ns_1
	proc getpath {} {namespace path}
    }
    list [::test_ns_2::getpath] [namespace delete ::test_ns_1] [::test_ns_2::getpath]
} -result {::test_ns_1 {} {}} -cleanup {
    catch {namespace delete ::test_ns_1}
    namespace delete ::test_ns_2
}
test namespace-51.8 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
    }
    namespace eval ::test_ns_2 {
    }
    namespace eval ::test_ns_3 {
    }
    namespace eval ::test_ns_4 {
	namespace path {::test_ns_1 ::test_ns_2 ::test_ns_3}
	proc getpath {} {namespace path}
    }
    list [::test_ns_4::getpath] [namespace delete ::test_ns_2] [::test_ns_4::getpath]
} -result {{::test_ns_1 ::test_ns_2 ::test_ns_3} {} {::test_ns_1 ::test_ns_3}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.9 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
    }
    namespace eval ::test_ns_2 {
    }
    namespace eval ::test_ns_3 {
    }
    namespace eval ::test_ns_4 {
	namespace path {::test_ns_1 ::test_ns_2 ::test_ns_3}
	proc getpath {} {namespace path}
    }
    list [::test_ns_4::getpath] [namespace delete ::test_ns_2] [namespace eval ::test_ns_2 {}] [::test_ns_4::getpath]
} -result {{::test_ns_1 ::test_ns_2 ::test_ns_3} {} {} {::test_ns_1 ::test_ns_3}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.10 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	namespace path does::not::exist
    }
} -returnCodes error -result {namespace "does::not::exist" not found in "::test_ns_1"} -cleanup {
    catch {namespace delete ::test_ns_1}
}
test namespace-51.11 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	proc foo {} {return 1}
    }
    namespace eval ::test_ns_2 {
	proc foo {} {return 2}
    }
    namespace eval ::test_ns_3 {
	namespace path ::test_ns_1
    }
    namespace eval ::test_ns_4 {
	namespace path {::test_ns_3 ::test_ns_2}
	foo
    }
} -result 2 -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.12 {name resolution path control} -body {
    namespace eval ::test_ns_1 {
	proc foo {} {return 1}
    }
    namespace eval ::test_ns_2 {
	proc foo {} {return 2}
    }
    namespace eval ::test_ns_3 {
	namespace path ::test_ns_1
    }
    namespace eval ::test_ns_4 {
	namespace path {::test_ns_3 ::test_ns_2}
	list [foo] [namespace delete ::test_ns_3] [foo]
    }
} -result {2 {} 2} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}

test namespace-51.13 {name resolution path control} -body {
    set ::result {}
    namespace eval ::test_ns_1 {
	proc foo {} {lappend ::result 1}
    }
    namespace eval ::test_ns_2 {
	proc foo {} {lappend ::result 2}
	trace add command foo delete {namespace eval ::test_ns_3 foo;#}
    }
    namespace eval ::test_ns_3 {
	proc foo {} {
	    lappend ::result 3
	    namespace delete [namespace current]
	    ::test_ns_4::bar
	}
    }
    namespace eval ::test_ns_4 {
	namespace path {::test_ns_2 ::test_ns_3 ::test_ns_1}
	proc bar {} {
	    list [foo] [namespace delete ::test_ns_2] [foo]
	}
	bar
    }
    # Should the result be "2 {} {2 3 2 1}" instead?
} -result {2 {} {2 3 1 1}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
    catch {namespace delete ::test_ns_4}
}
test namespace-51.14 {name resolution path control} -body {
    foreach cmd [info commands foo*] {
	rename $cmd {}
    }
    proc foo0 {} {}
    namespace eval ::test_ns_1 {
	proc foo1 {} {}
    }
    namespace eval ::test_ns_2 {
	proc foo2 {} {}
    }
    namespace eval ::test_ns_3 {
	variable result {}
	lappend result [info commands foo*]
	namespace path {::test_ns_1 ::test_ns_2}
	lappend result [info commands foo*]
	proc foo2 {} {}
	lappend result [info commands foo*]
	rename foo2 {}
	lappend result [info commands foo*]
	namespace delete ::test_ns_1
	lappend result [info commands foo*]
    }
} -result {foo0 {foo1 foo2 foo0} {foo2 foo1 foo0} {foo1 foo2 foo0} {foo2 foo0}} -cleanup {
    catch {namespace delete ::test_ns_1}
    catch {namespace delete ::test_ns_2}
    catch {namespace delete ::test_ns_3}
}
test namespace-51.15 {namespace resolution path control} -body {
    namespace eval ::test_ns_2 {
	proc foo {} {return 2}
    }
    namespace eval ::test_ns_1 {
	namespace eval test_ns_2 {
	    proc foo {} {return 1_2}
	}
	namespace eval test_ns_3 {
	    namespace path ::test_ns_1
	    test_ns_2::foo
	}
    }
} -result 1_2 -cleanup {
    namespace delete ::test_ns_1
    namespace delete ::test_ns_2
}
test namespace-51.16 {Bug 1566526} {
    interp create slave
    slave eval namespace eval demo namespace path ::
    interp delete slave
} {}
test namespace-51.17 {Bug 3185407} -setup {
    namespace eval ::test_ns_1 {}
} -body {
    namespace eval ::test_ns_1 {
	variable result {}
	namespace eval ns {proc foo {} {}}
	namespace eval ns2 {proc foo {} {}}
	namespace path {ns ns2}
	variable x foo
	lappend result [namespace which $x]
	proc foo {} {}
	lappend result [namespace which $x]
    }
} -cleanup {
    namespace delete ::test_ns_1
} -result {::test_ns_1::ns::foo ::test_ns_1::foo}

# TIP 181 - namespace unknown tests
test namespace-52.1 {unknown: default handler ::unknown} {
    set result [list [namespace eval foobar { namespace unknown }]]
    lappend result [namespace eval :: { namespace unknown }]
    namespace delete foobar
    set result
} {{} ::unknown}
test namespace-52.2 {unknown: default resolution global} {
    proc ::foo {} { return "GLOBAL" }
    namespace eval ::bar { proc foo {} { return "NAMESPACE" } }
    namespace eval ::bar::jim { proc test {} { foo } }
    set result [::bar::jim::test]
    namespace delete ::bar
    rename ::foo {}
    set result
} {GLOBAL}
test namespace-52.3 {unknown: default resolution local} {
    proc ::foo {} { return "GLOBAL" }
    namespace eval ::bar {
	proc foo {} { return "NAMESPACE" }
	proc test {} { foo }
    }
    set result [::bar::test]
    namespace delete ::bar
    rename ::foo {}
    set result
} {NAMESPACE}
test namespace-52.4 {unknown: set handler} {
    namespace eval foo {
	namespace unknown [list dispatch]
	proc dispatch {args} { return $args }
	proc test {} {
	    UnknownCmd a b c
	}
    }
    set result [foo::test]
    namespace delete foo
    set result
} {UnknownCmd a b c}
test namespace-52.5 {unknown: search path before unknown is unaltered} {
    proc ::test2 {args} { return "TEST2: $args" }
    namespace eval foo {
	namespace unknown [list dispatch]
	proc dispatch {args} { return "UNKNOWN: $args" }
	proc test1 {args} { return "TEST1: $args" }
	proc test {} {
	    set result [list [test1 a b c]]
	    lappend result [test2 a b c]
	    lappend result [test3 a b c]
	    return $result
	}
    }
    set result [foo::test]
    namespace delete foo
    rename ::test2 {}
    set result
} {{TEST1: a b c} {TEST2: a b c} {UNKNOWN: test3 a b c}}
test namespace-52.6 {unknown: deleting handler restores default} {
    rename ::unknown ::_unknown_orig
    proc ::unknown {args} { return "DEFAULT: $args" }
    namespace eval foo {
	namespace unknown dummy
	namespace unknown {}
    }
    set result [namespace eval foo { dummy a b c }]
    rename ::unknown {}
    rename ::_unknown_orig ::unknown
    namespace delete foo
    set result
} {DEFAULT: dummy a b c}
test namespace-52.7 {unknown: setting global unknown handler} {
    proc ::myunknown {args} { return "MYUNKNOWN: $args" }
    namespace eval :: { namespace unknown ::myunknown }
    set result [namespace eval foo { dummy a b c }]
    namespace eval :: { namespace unknown {} }
    rename ::myunknown {}
    namespace delete foo
    set result
} {MYUNKNOWN: dummy a b c}
test namespace-52.8 {unknown: destroying and redefining global namespace} {
    set i [interp create]
    $i hide proc
    $i hide namespace
    $i hide return
    $i invokehidden namespace delete ::
    $i expose return
    $i invokehidden proc unknown args { return "FINE" }
    $i eval { foo bar bob }
} {FINE}
test namespace-52.9 {unknown: refcounting} -setup {
    proc this args {
	unset args		;# stop sharing
	set copy [namespace unknown]
	string length $copy	;# shimmer away list rep
	info level 0
    }
    set handler [namespace unknown]
    namespace unknown {this is a test}
    catch {rename noSuchCommand {}}
} -body {
    noSuchCommand
} -cleanup {
    namespace unknown $handler
    rename this {}
} -result {this is a test noSuchCommand}
testConstraint testevalobjv [llength [info commands testevalobjv]]
test namespace-52.10 {unknown: with TCL_EVAL_GLOBAL} -constraints {
    testevalobjv
} -setup {
    rename ::unknown unknown.save
    proc ::unknown args {
	set caller [uplevel 1 {namespace current}]
	namespace eval $caller {
	    variable foo
	    return $foo
	}
    }
    catch {rename ::noSuchCommand {}}
} -body {
    namespace eval :: {
	variable foo SUCCESS
    }
    namespace eval test_ns_1 {
	variable foo FAIL
	testevalobjv 1 noSuchCommand
    }
} -cleanup {
    unset -nocomplain ::foo
    namespace delete test_ns_1
    rename ::unknown {}
    rename unknown.save ::unknown
} -result SUCCESS
test namespace-52.11 {unknown: with TCL_EVAL_INVOKE} -setup {
    set handler [namespace eval :: {namespace unknown}]
    namespace eval :: {namespace unknown unknown}
    rename ::unknown unknown.save
    namespace eval :: {
	proc unknown args {
	    return SUCCESS
	}
    }
    catch {rename ::noSuchCommand {}}
    set ::slave [interp create]
} -body {
    $::slave alias bar noSuchCommand
    namespace eval test_ns_1 {
	namespace unknown unknown
	proc unknown args {
	    return FAIL
	}
	$::slave eval bar
    }
} -cleanup {
    interp delete $::slave
    unset ::slave
    namespace delete test_ns_1
    rename ::unknown {}
    rename unknown.save ::unknown
    namespace eval :: [list namespace unknown $handler]
} -result SUCCESS
test namespace-52.12 {unknown: error case must not reset handler} -body {
    namespace eval foo {
	namespace unknown ok
	catch {namespace unknown {{}{}{}}}
	namespace unknown
    }
} -cleanup {
    namespace delete foo
} -result ok
    
# cleanup
catch {rename cmd1 {}}
catch {unset l}
catch {unset msg}
catch {unset trigger}
namespace delete {*}[namespace children :: test_ns_*]
::tcltest::cleanupTests
return

# Local Variables:
# mode: tcl
# End:
