OpenFPGA/libs/EXTERNAL/tcl8.6.12/tests/oo.test

4194 lines
112 KiB
Plaintext
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# This file contains a collection of tests for Tcl's built-in object system.
# Sourcing this file into Tcl runs the tests and generates output for errors.
# No output means no errors were found.
#
# Copyright (c) 2006-2013 Donal K. Fellows
#
# See the file "license.terms" for information on usage and redistribution of
# this file, and for a DISCLAIMER OF ALL WARRANTIES.
package require TclOO 1.0.3
if {"::tcltest" ni [namespace children]} {
package require tcltest 2.5
namespace import -force ::tcltest::*
}
# The foundational objects oo::object and oo::class are sensitive to reference
# counting errors and are deallocated only when an interp is deleted, so in
# this test suite, interp creation and interp deletion are often used in
# leaktests in order to leverage this sensitivity.
testConstraint memory [llength [info commands memory]]
if {[testConstraint memory]} {
proc getbytes {} {
set lines [split [memory info] \n]
return [lindex $lines 3 3]
}
proc leaktest {script {iterations 3}} {
set end [getbytes]
for {set i 0} {$i < $iterations} {incr i} {
uplevel 1 $script
set tmp $end
set end [getbytes]
}
return [expr {$end - $tmp}]
}
}
test oo-0.1 {basic test of OO's ability to clean up its initial state} {
interp create t
t eval {
package require TclOO
}
interp delete t
} {}
test oo-0.2 {basic test of OO's ability to clean up its initial state} {
set i [interp create]
interp eval $i {
package require TclOO
namespace delete ::
}
interp delete $i
} {}
test oo-0.3 {basic test of OO's ability to clean up its initial state} -body {
leaktest {
[oo::object new] destroy
}
} -constraints memory -result 0
test oo-0.4 {basic test of OO's ability to clean up its initial state} -body {
leaktest {
oo::class create foo
foo new
foo destroy
}
} -constraints memory -result 0
test oo-0.5.1 {testing object foundation cleanup} memory {
leaktest {
interp create foo
interp delete foo
}
} 0
test oo-0.5.2 {testing literal leak on interp delete} memory {
leaktest {
interp create foo
foo eval {oo::object new}
interp delete foo
}
} 0
test oo-0.6 {cleaning the core class pair; way #1} -setup {
interp create t
} -body {
t eval {
package require TclOO
namespace path oo
list [catch {class destroy} m] $m [catch {object destroy} m] $m
}
} -cleanup {
interp delete t
} -result {0 {} 1 {invalid command name "object"}}
test oo-0.7 {cleaning the core class pair; way #2} -setup {
interp create t
} -body {
t eval {
package require TclOO
namespace path oo
list [catch {object destroy} m] $m [catch {class destroy} m] $m
}
} -cleanup {
interp delete t
} -result {0 {} 1 {invalid command name "class"}}
test oo-0.8 {leak in variable management} -setup {
oo::class create foo
} -constraints memory -body {
oo::define foo {
constructor {} {
variable v 0
}
}
leaktest {[foo new] destroy}
} -cleanup {
foo destroy
} -result 0
test oo-0.9 {various types of presence of the TclOO package} {
list [lsearch -nocase -all -inline [package names] tcloo] \
[package present TclOO] [expr {$::oo::patchlevel in [package versions TclOO]}]
} [list TclOO $::oo::patchlevel 1]
test oo-1.1 {basic test of OO functionality: no classes} {
set result {}
lappend result [oo::object create foo]
lappend result [oo::objdefine foo {
method bar args {
global result
lappend result {*}$args
return [llength $args]
}
}]
lappend result [foo bar a b c]
lappend result [foo destroy] [info commands foo]
} {::foo {} a b c 3 {} {}}
test oo-1.2 {basic test of OO functionality: no classes} -body {
oo::define oo::object method missingArgs
} -returnCodes 1 -result "wrong # args: should be \"oo::define oo::object method name args body\""
test oo-1.3 {basic test of OO functionality: no classes} {
catch {oo::define oo::object method missingArgs}
set errorInfo
} "wrong # args: should be \"oo::define oo::object method name args body\"
while executing
\"oo::define oo::object method missingArgs\""
test oo-1.4 {basic test of OO functionality} -body {
oo::object create {}
} -returnCodes 1 -result {object name must not be empty}
test oo-1.4.1 {fully-qualified nested name} -body {
oo::object create ::one::two::three
} -result {::one::two::three}
test oo-1.4.2 {automatic command name has same name as namespace} -body {
set obj [oo::object new]
expr {[info object namespace $obj] == $obj}
} -result 1
test oo-1.5 {basic test of OO functionality} -body {
oo::object doesnotexist
} -returnCodes 1 -result {unknown method "doesnotexist": must be create, destroy or new}
test oo-1.5.1 {basic test of OO functionality} -setup {
oo::object create aninstance
} -returnCodes error -body {
aninstance
} -cleanup {
rename aninstance {}
} -result {wrong # args: should be "aninstance method ?arg ...?"}
test oo-1.6 {basic test of OO functionality} -setup {
oo::object create aninstance
} -body {
oo::objdefine aninstance unexport destroy
aninstance doesnotexist
} -cleanup {
rename aninstance {}
} -returnCodes 1 -result {object "::aninstance" has no visible methods}
test oo-1.7 {basic test of OO functionality} -setup {
oo::object create aninstance
} -body {
oo::objdefine aninstance {
# Do not do this in real code! Ever! This is *not* supported!
::oo::define::method ha ha ha
}
} -returnCodes error -cleanup {
aninstance destroy
} -result {attempt to misuse API}
test oo-1.8 {basic test of OO functionality} -setup {
oo::object create obj
set result {}
} -cleanup {
obj destroy
} -body {
oo::objdefine obj method foo {} {return bar}
lappend result [obj foo]
oo::objdefine obj method foo {} {}
lappend result [obj foo]
} -result {bar {}}
test oo-1.9 {basic test of OO functionality} -setup {
oo::object create a
oo::object create b
} -cleanup {
catch {a destroy}
b destroy
} -body {
oo::objdefine a method foo {} { return A }
oo::objdefine b method foo {} { return B }
apply {{} {
set m foo
return [a $m],[a destroy],[b $m]
}}
} -result A,,B
test oo-1.10 {basic test of OO functionality} -body {
namespace eval foo {
namespace eval bar {
oo::object create o
namespace export o
}
namespace import bar::o
}
list [info object isa object foo::bar::o] [info object isa object foo::o]
} -cleanup {
namespace delete foo
} -result {1 1}
test oo-1.11 {basic test of OO functionality: abbreviating} -setup {
oo::class create c
} -cleanup {
c destroy
} -body {
oo::define c super oo::class
info class super c
} -result ::oo::class
test oo-1.12 {basic test of OO functionality: abbreviating} -setup {
oo::class create c
} -cleanup {
c destroy
} -body {
oo::define c {super oo::class}
info class super c
} -result ::oo::class
test oo-1.13 {basic test of OO functionality: abbreviating} -setup {
oo::class create c
} -cleanup {
c destroy
} -body {
oo::define c self {forw a b}
info object forw c a
} -result b
test oo-1.14 {basic test of OO functionality: abbreviating} -setup {
oo::class create c
} -cleanup {
c destroy
} -body {
oo::define c self forw a b
info object forw c a
} -result b
test oo-1.15 {basic test of OO functionality: abbreviating} -setup {
oo::object create o
} -cleanup {
o destroy
} -body {
oo::objdefine o {forw a b}
info object forw o a
} -result b
test oo-1.16 {basic test of OO functionality: abbreviating} -setup {
oo::object create o
} -cleanup {
o destroy
} -body {
oo::objdefine o forw a b
info object forw o a
} -result b
test oo-1.17 {basic test of OO functionality: Bug 2481109} -body {
namespace eval ::foo {oo::object create lreplace}
} -cleanup {
namespace delete ::foo
} -result ::foo::lreplace
# Check for Bug 2519474; problem in tclNamesp.c, but tested here...
test oo-1.18 {OO: create object in NS with same name as global cmd} -setup {
proc test-oo-1.18 {} return
oo::class create A
oo::class create B {superclass A}
} -body {
oo::define B constructor {} {A create test-oo-1.18}
B create C
} -cleanup {
rename test-oo-1.18 {}
A destroy
} -result ::C
test oo-1.18.1 {no memory leak: superclass} -setup {
} -constraints memory -body {
leaktest {
interp create t
t eval {
oo::class create A {
superclass oo::class
}
}
interp delete t
}
} -cleanup {
} -result 0
test oo-1.18.2 {Bug 75b8433707: memory leak in oo-1.18} -setup {
proc test-oo-1.18 {} return
} -constraints memory -body {
leaktest {
oo::class create A
oo::class create B {superclass A}
oo::define B constructor {} {A create test-oo-1.18}
B create C
A destroy
}
} -cleanup {
rename test-oo-1.18 {}
} -result 0
test oo-1.18.3 {Bug 21c144f0f5} -setup {
interp create child
} -body {
child eval {
oo::define [oo::class create foo] superclass oo::class
oo::class destroy
}
} -cleanup {
interp delete child
}
test oo-1.18.4 {correct handling of cleanup in superclass set error} -setup {
interp create child
} -body {
child eval {
oo::class create A
oo::class create B {
superclass oo::class
constructor {} {
next {superclass A}
next {superclass -append A}
}
}
[B create C] create d
}
} -returnCodes error -cleanup {
interp delete child
} -result {class should only be a direct superclass once}
test oo-1.18.5 {correct handling of cleanup in superclass set error} -setup {
interp create child
} -body {
child eval {
oo::class create A
oo::class create B {
superclass oo::class
constructor {c} {
next {superclass A}
next [list superclass -append {*}$c]
}
}
[B create C {B C}] create d
}
} -returnCodes error -cleanup {
interp delete child
} -result {attempt to form circular dependency graph}
test oo-1.19 {basic test of OO functionality: teardown order} -body {
oo::object create o
namespace delete [info object namespace o]
o destroy
# Crashes on error
} -returnCodes error -result {invalid command name "o"}
test oo-1.20 {basic test of OO functionality: my teardown post rename} -body {
oo::object create obj
rename [info object namespace obj]::my ::AGlobalName
obj destroy
info commands ::AGlobalName
} -result {}
test oo-1.21 {basic test of OO functionality: default relations} -setup {
set fresh [interp create]
} -body {
lmap x [$fresh eval {
foreach cmd {instances subclasses mixins superclass} {
foreach initial {object class Slot} {
lappend x [info class $cmd ::oo::$initial]
}
}
foreach initial {object class Slot} {
lappend x [info object class ::oo::$initial]
}
return $x
}] {lsort $x}
} -cleanup {
interp delete $fresh
} -result {{} {::oo::Slot ::oo::class ::oo::object} {::oo::define::filter ::oo::define::mixin ::oo::define::superclass ::oo::define::variable ::oo::objdefine::filter ::oo::objdefine::mixin ::oo::objdefine::variable} {::oo::Slot ::oo::class} {} {} {} {} {} {} ::oo::object ::oo::object ::oo::class ::oo::class ::oo::class}
test oo-2.1 {basic test of OO functionality: constructor} -setup {
# This is a bit complex because it needs to run in a sub-interp as
# we're modifying the root object class's constructor
interp create subinterp
subinterp eval {
package require TclOO
}
} -body {
subinterp eval {
oo::define oo::object constructor {} {
lappend ::result [info level 0]
}
lappend result 1
lappend result 2 [oo::object create foo]
}
} -cleanup {
interp delete subinterp
} -result {1 {oo::object create foo} 2 ::foo}
test oo-2.2 {basic test of OO functionality: constructor} {
oo::class create testClass {
constructor {} {
global result
lappend result "[self]->construct"
}
method bar {} {
global result
lappend result "[self]->bar"
}
}
set result {}
[testClass create foo] bar
testClass destroy
return $result
} {::foo->construct ::foo->bar}
test oo-2.4 {OO constructor - Bug 2531577} -setup {
oo::class create foo
} -body {
oo::define foo constructor {} return
[foo new] destroy
oo::define foo constructor {} {}
llength [info command [foo new]]
} -cleanup {
foo destroy
} -result 1
test oo-2.5 {OO constructor - Bug 2531577} -setup {
oo::class create foo
set result {}
} -body {
oo::define foo constructor {} {error x}
lappend result [catch {foo new}]
oo::define foo constructor {} {}
lappend result [llength [info command [foo new]]]
} -cleanup {
foo destroy
} -result {1 1}
test oo-2.6 {OO constructor and tailcall - Bug 2414858} -setup {
oo::class create foo
} -body {
oo::define foo {
constructor {} { tailcall my bar }
method bar {} { return bad }
}
namespace tail [foo create good]
} -cleanup {
foo destroy
} -result good
test oo-2.7 {construction, method calls and ensembles - Bug 3514761} -setup {
namespace eval k {}
} -body {
namespace eval k {
oo::class create s {
constructor {j} {
# nothing
}
}
namespace export s
namespace ensemble create
}
k s create X
} -returnCodes error -cleanup {
namespace delete k
} -result {wrong # args: should be "k s create X j"}
test oo-2.8 {construction, method calls and ensembles - Bug 3514761} -setup {
namespace eval k {}
} -body {
namespace eval k {
oo::class create s {
constructor {j} {
# nothing
}
}
oo::class create t {
superclass s
constructor args {
k next {*}$args
}
}
interp alias {} ::k::next {} ::oo::Helpers::next
namespace export t next
namespace ensemble create
}
k t create X
} -returnCodes error -cleanup {
namespace delete k
} -result {wrong # args: should be "k next j"}
test oo-2.9 {construction failures and self creation} -setup {
set ::result {}
oo::class create Root
} -body {
oo::class create A {
superclass Root
constructor {} {
lappend ::result "in A"
error "failure in A"
}
destructor {lappend ::result [self]}
}
oo::class create B {
superclass Root
constructor {} {
lappend ::result "in B [self]"
error "failure in B"
}
destructor {lappend ::result [self]}
}
lappend ::result [catch {A create a} msg] $msg
lappend ::result [catch {B create b} msg] $msg
} -cleanup {
Root destroy
} -result {{in A} ::a 1 {failure in A} {in B ::b} ::b 1 {failure in B}}
test oo-3.1 {basic test of OO functionality: destructor} -setup {
# This is a bit complex because it needs to run in a sub-interp as we're
# modifying the root object class's constructor
interp create subinterp
subinterp eval {
package require TclOO
}
} -body {
subinterp eval {
oo::define oo::object destructor {
lappend ::result died
}
lappend result 1 [oo::object create foo]
lappend result 2 [rename foo {}]
oo::define oo::object destructor {}
return $result
}
} -cleanup {
interp delete subinterp
} -result {1 ::foo died 2 {}}
test oo-3.2 {basic test of OO functionality: destructor} -setup {
# This is a bit complex because it needs to run in a sub-interp as
# we're modifying the root object class's constructor
interp create subinterp
subinterp eval {
package require TclOO
}
} -body {
subinterp eval {
oo::define oo::object destructor {
lappend ::result died
}
lappend result 1 [oo::object create foo]
lappend result 2 [rename foo {}]
}
} -cleanup {
interp delete subinterp
} -result {1 ::foo died 2 {}}
test oo-3.3 {basic test of OO functionality: destructor} -setup {
oo::class create foo
set result {}
} -cleanup {
foo destroy
} -body {
oo::define foo {
constructor {} {lappend ::result made}
destructor {lappend ::result died}
}
namespace delete [info object namespace [foo new]]
return $result
} -result {made died}
test oo-3.4 {basic test of OO functionality: my exists in destructor} -setup {
oo::class create cls
set result {}
} -cleanup {
cls destroy
} -body {
oo::define cls {
variable state
constructor {} {
proc localcmdexists {} {}
set state ok
}
forward Report lappend ::result
destructor {
objmy Report [catch {set state} msg] $msg
objmy Report [namespace which -var state]
objmy Report [info commands localcmdexists]
}
}
cls create obj
rename [info object namespace obj]::my ::objmy
obj destroy
lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.4a {basic test of OO functionality: my exists in destructor} -setup {
oo::class create cls
set result {}
} -cleanup {
cls destroy
} -body {
oo::define cls {
variable state
constructor {} {
proc localcmdexists {} {}
set state ok
}
forward Report lappend ::result
destructor {
objmy Report [catch {set state} msg] $msg
objmy Report [namespace which -var state]
objmy Report [info commands localcmdexists]
}
}
cls create obj
rename [info object namespace obj]::my ::objmy
rename obj {}
lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.5 {basic test of OO functionality: destructor: evil case for Itcl} -setup {
oo::class create cls
set result {}
} -cleanup {
cls destroy
} -body {
oo::define cls {
variable state
constructor {} {
proc localcmdexists {} {}
set state ok
}
forward Report lappend ::result
destructor {
objmy Report [catch {set state} msg] $msg
objmy Report [namespace which -var state]
objmy Report [info commands localcmdexists]
}
}
cls create obj
rename [info object namespace obj]::my ::objmy
namespace delete [info object namespace obj]
lappend result [info commands ::objmy]
} -match glob -result {0 ok *::state localcmdexists {}}
test oo-3.5a {basic test of OO functionality: destructor: evil case for Itcl} -setup {
oo::class create cls
set result {}
} -cleanup {
cls destroy
} -body {
oo::define cls {
variable state result
constructor {} {
proc localcmdexists {} {}
set state ok
my eval {upvar 0 ::result result}
}
method nuke {} {
namespace delete [namespace current]
return $result
}
destructor {
lappend result [self] $state [info commands localcmdexists]
}
}
cls create obj
namespace delete [info object namespace obj]
[cls create obj2] nuke
} -match glob -result {::obj ok localcmdexists ::obj2 ok localcmdexists}
test oo-3.6 {basic test of OO functionality: errors in destructor} -setup {
oo::class create cls
} -cleanup {
cls destroy
} -body {
oo::define cls destructor {error foo}
list [catch {[cls create obj] destroy} msg] $msg [info commands obj]
} -result {1 foo {}}
test oo-3.7 {basic test of OO functionality: errors in destructor} -setup {
oo::class create cls
set result {}
proc bgerror msg {lappend ::result $msg}
} -cleanup {
cls destroy
rename bgerror {}
} -body {
oo::define cls destructor {error foo}
list [rename [cls create obj] {}] \
[update idletasks] $result [info commands obj]
} -result {{} {} foo {}}
test oo-3.8 {basic test of OO functionality: errors in destructor} -setup {
oo::class create cls
set result {}
proc bgerror msg {lappend ::result $msg}
} -cleanup {
cls destroy
rename bgerror {}
} -body {
oo::define cls destructor {error foo}
list [namespace delete [info object namespace [cls create obj]]] \
[update idletasks] $result [info commands obj]
} -result {{} {} foo {}}
test oo-3.9 {Bug 2944404: deleting the object in the destructor} -setup {
oo::class create cls
set result {}
} -body {
oo::define cls {
destructor {
lappend ::result in destructor
[self] destroy
}
}
# This used to crash
[cls new] destroy
return $result
} -cleanup {
cls destroy
} -result {in destructor}
test oo-3.10 {Bug 3d96b7076e: killing the object's class in a method call} -setup {
oo::class create Super
} -body {
# Only reliably failed in a memdebug build
oo::class create Cls {
superclass Super
method mthd {} {
[self class] destroy
return ok
}
}
[Cls new] mthd
} -cleanup {
Super destroy
} -result ok
test oo-3.11 {Bug 3d96b7076e: killing the object's class in a method call} -setup {
oo::class create Super
oo::class create Sub {
superclass Super
}
} -body {
# Only reliably failed in a memdebug build
oo::class create Cls {
superclass Super
method mthd {} {
oo::objdefine [self] class Sub
Cls destroy
return ok
}
}
[Cls new] mthd
} -cleanup {
Super destroy
} -result ok
test oo-3.12 {Bug 3d96b7076e: killing the object's class in a method call} -setup {
oo::class create Super
} -body {
# Only reliably failed in a memdebug build
oo::class create Cls {
superclass Super
method mthd {} {
[self class] destroy
return ok
}
}
set o [Super new]
oo::objdefine $o mixin Cls
$o mthd
} -cleanup {
Super destroy
} -result ok
test oo-4.1 {basic test of OO functionality: export} {
set o [oo::object new]
set result {}
oo::objdefine $o method Foo {} {lappend ::result Foo; return}
lappend result [catch {$o Foo} msg] $msg
oo::objdefine $o export Foo
lappend result [$o Foo] [$o destroy]
} {1 {unknown method "Foo": must be destroy} Foo {} {}}
test oo-4.2 {basic test of OO functionality: unexport} {
set o [oo::object new]
set result {}
oo::objdefine $o method foo {} {lappend ::result foo; return}
lappend result [$o foo]
oo::objdefine $o unexport foo
lappend result [catch {$o foo} msg] $msg [$o destroy]
} {foo {} 1 {unknown method "foo": must be destroy} {}}
test oo-4.3 {exporting and error messages, Bug 1824958} -setup {
oo::class create testClass
} -cleanup {
testClass destroy
} -body {
oo::define testClass self export Bad
testClass Bad
} -returnCodes 1 -result {unknown method "Bad": must be create, destroy or new}
test oo-4.4 {exporting a class method from an object} -setup {
oo::class create testClass
testClass create testObject
} -cleanup {
testClass destroy
} -body {
oo::define testClass method Good {} { return ok }
oo::objdefine testObject export Good
testObject Good
} -result ok
test oo-4.5 {export creates proper method entries} -setup {
oo::class create testClass
} -body {
oo::define testClass {
export foo
method foo {} {return ok}
}
[testClass new] foo
} -cleanup {
testClass destroy
} -result ok
test oo-4.6 {export creates proper method entries} -setup {
oo::class create testClass
} -body {
oo::define testClass {
unexport foo
method foo {} {return ok}
}
[testClass new] foo
} -cleanup {
testClass destroy
} -result ok
test oo-5.1 {OO: manipulation of classes as objects} -setup {
set obj [oo::object new]
} -body {
oo::objdefine oo::object method foo {} { return "in object" }
catch {$obj foo} result
list [catch {$obj foo} result] $result [oo::object foo]
} -cleanup {
oo::objdefine oo::object deletemethod foo
$obj destroy
} -result {1 {unknown method "foo": must be destroy} {in object}}
test oo-5.2 {OO: manipulation of classes as objects} -setup {
set obj [oo::object new]
} -body {
oo::define oo::object self method foo {} { return "in object" }
catch {$obj foo} result
list [catch {$obj foo} result] $result [oo::object foo]
} -cleanup {
oo::objdefine oo::object deletemethod foo
$obj destroy
} -result {1 {unknown method "foo": must be destroy} {in object}}
test oo-5.3 {OO: manipulation of classes as objects} -setup {
set obj [oo::object new]
} -body {
oo::objdefine oo::object {
method foo {} { return "in object" }
}
catch {$obj foo} result
list [catch {$obj foo} result] $result [oo::object foo]
} -cleanup {
oo::objdefine oo::object deletemethod foo
$obj destroy
} -result {1 {unknown method "foo": must be destroy} {in object}}
test oo-5.4 {OO: manipulation of classes as objects} -setup {
set obj [oo::object new]
} -body {
oo::define oo::object {
self method foo {} { return "in object" }
}
catch {$obj foo} result
list [catch {$obj foo} result] $result [oo::object foo]
} -cleanup {
oo::objdefine oo::object deletemethod foo
$obj destroy
} -result {1 {unknown method "foo": must be destroy} {in object}}
test oo-5.5 {OO: manipulation of classes as objects} -setup {
set obj [oo::object new]
} -body {
oo::define oo::object {
self {
method foo {} { return "in object" }
}
}
catch {$obj foo} result
list [catch {$obj foo} result] $result [oo::object foo]
} -cleanup {
oo::objdefine oo::object deletemethod foo
$obj destroy
} -result {1 {unknown method "foo": must be destroy} {in object}}
test oo-6.1 {OO: forward} {
oo::object create foo
oo::objdefine foo {
forward a lappend
forward b lappend result
}
set result {}
foo a result 1
foo b 2
foo destroy
return $result
} {1 2}
test oo-6.2 {OO: forward resolution scope} -setup {
oo::class create fooClass
} -body {
proc foo {} {return bad}
oo::define fooClass {
constructor {} {
proc foo {} {return good}
}
forward bar foo
}
[fooClass new] bar
} -cleanup {
fooClass destroy
rename foo {}
} -result good
test oo-6.3 {OO: forward resolution scope} -setup {
oo::class create fooClass
} -body {
proc foo {} {return bad}
oo::define fooClass {
constructor {} {
proc foo {} {return good}
}
}
oo::define fooClass forward bar foo
[fooClass new] bar
} -cleanup {
fooClass destroy
rename foo {}
} -result good
test oo-6.4 {OO: forward resolution scope} -setup {
oo::class create fooClass
} -body {
proc foo {} {return good}
oo::define fooClass {
constructor {} {
proc foo {} {return bad}
}
forward bar ::foo
}
[fooClass new] bar
} -cleanup {
fooClass destroy
rename foo {}
} -result good
test oo-6.5 {OO: forward resolution scope} -setup {
oo::class create fooClass
namespace eval foo {}
} -body {
proc foo::foo {} {return good}
oo::define fooClass {
constructor {} {
proc foo {} {return bad}
}
forward bar foo::foo
}
[fooClass new] bar
} -cleanup {
fooClass destroy
namespace delete foo
} -result good
test oo-6.6 {OO: forward resolution scope} -setup {
oo::class create fooClass
namespace eval foo {}
} -body {
proc foo::foo {} {return bad}
oo::define fooClass {
constructor {} {
namespace eval foo {
proc foo {} {return good}
}
}
forward bar foo::foo
}
[fooClass new] bar
} -cleanup {
fooClass destroy
namespace delete foo
} -result good
test oo-6.7 {OO: forward resolution scope is per-object} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
constructor {} {
proc curns {} {namespace current}
}
forward ns curns
}
expr {[[fooClass new] ns] ne [[fooClass new] ns]}
} -cleanup {
fooClass destroy
} -result 1
test oo-6.8 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test my handler
method handler {a b c} {}
}
fooClass create ::foo
foo test
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.9 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test my handler
method handler {a b c} {list $a,$b,$c}
}
fooClass create ::foo
foo test 1 2 3
} -cleanup {
fooClass destroy
} -result 1,2,3
test oo-6.10 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test my handler
method handler {a b c} {list $a,$b,$c}
}
fooClass create ::foo
foo test 1 2
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.11 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::object create foo
} -body {
oo::objdefine foo {
forward test my handler
method handler {a b c} {}
}
foo test
} -returnCodes error -cleanup {
foo destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.12 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::object create foo
} -body {
oo::objdefine foo {
forward test my handler
method handler {a b c} {list $a,$b,$c}
}
foo test 1 2 3
} -cleanup {
foo destroy
} -result 1,2,3
test oo-6.13 {Bug 3400658: forwarding and wrongargs rewriting} -setup {
oo::object create foo
} -body {
oo::objdefine foo {
forward test my handler
method handler {a b c} {list $a,$b,$c}
}
foo test 1 2
} -returnCodes error -cleanup {
foo destroy
} -result {wrong # args: should be "foo test a b c"}
test oo-6.14 {Bug 3400658: forwarding and wrongargs rewriting - multistep} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test my handler1 p
forward handler1 my handler q
method handler {a b c} {}
}
fooClass create ::foo
foo test
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "foo test c"}
test oo-6.15 {Bug 3400658: forwarding and wrongargs rewriting - multistep} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test my handler1 p
forward handler1 my handler q
method handler {a b c} {list $a,$b,$c}
}
fooClass create ::foo
foo test 1
} -cleanup {
fooClass destroy
} -result q,p,1
test oo-6.16 {Bug 3400658: forwarding and wrongargs rewriting - via alias} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test handler1 foo bar
forward handler2 my handler x
method handler {a b c d} {list $a,$b,$c,$d}
export eval
}
fooClass create ::foo
foo eval {
interp alias {} [namespace current]::handler1 \
{} [namespace current]::my handler2
}
foo test 1 2 3
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "foo test d"}
test oo-6.17 {Bug 3400658: forwarding and wrongargs rewriting - via ensemble} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward test handler1 foo bar boo
forward handler2 my handler
method handler {a b c d} {list $a,$b,$c,$d}
export eval
}
fooClass create ::foo
foo eval {
namespace ensemble create \
-command [namespace current]::handler1 -parameters {p q} \
-map [list boo [list [namespace current]::my handler2]]
}
foo test 1 2 3
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "foo test c d"}
test oo-6.18 {Bug 3408830: more forwarding cases} -setup {
oo::class create fooClass
} -body {
oo::define fooClass {
forward len string length
}
[fooClass create foo] len a b
} -returnCodes error -cleanup {
fooClass destroy
} -result {wrong # args: should be "::foo len string"}
test oo-6.19 {Bug 3610404: forwarding resolution + traces} -setup {
oo::object create foo
unset -nocomplain ::result
set ::result {}
} -body {
proc ::my {method} {lappend ::result global}
oo::objdefine foo {
method target {} {lappend ::result instance}
forward bar my target
method bump {} {
set ns [info object namespace ::foo]
rename ${ns}::my ${ns}::
rename ${ns}:: ${ns}::my
}
}
proc harness {} {
foo target
foo bar
foo target
}
trace add execution harness enterstep {apply {{cmd args} {foo bump}}}
foo target
foo bar
foo bump
foo bar
harness
} -cleanup {
catch {rename harness {}}
catch {rename ::my {}}
foo destroy
} -result {instance instance instance instance instance instance}
test oo-6.20 {Bug 3610404: forwarding resolution + traces} -setup {
oo::class create fooClass
fooClass create foo
unset -nocomplain ::result
set ::result {}
} -body {
proc ::my {method} {lappend ::result global}
oo::define fooClass {
method target {} {lappend ::result class}
forward bar my target
method bump {} {
set ns [info object namespace [self]]
rename ${ns}::my ${ns}::
rename ${ns}:: ${ns}::my
}
}
proc harness {} {
foo target
foo bar
foo target
}
trace add execution harness enterstep {apply {{cmd args} {foo bump}}}
foo target
foo bar
foo bump
foo bar
harness
} -cleanup {
catch {rename harness {}}
catch {rename ::my {}}
fooClass destroy
} -result {class class class class class class}
test oo-7.1 {OO: inheritance 101} -setup {
oo::class create superClass
oo::class create subClass
subClass create instance
} -body {
oo::define superClass method doit x {lappend ::result $x}
oo::define subClass superclass superClass
set result [list [catch {subClass doit bad} msg] $msg]
instance doit ok
return $result
} -cleanup {
subClass destroy
superClass destroy
} -result {1 {unknown method "doit": must be create, destroy or new} ok}
test oo-7.2 {OO: inheritance 101} -setup {
oo::class create superClass
oo::class create subClass
subClass create instance
} -body {
oo::define superClass method doit x {
lappend ::result |$x|
}
oo::define subClass superclass superClass
oo::objdefine instance method doit x {
lappend ::result =$x=
next [incr x]
}
set result {}
instance doit 1
return $result
} -cleanup {
subClass destroy
superClass destroy
} -result {=1= |2|}
test oo-7.3 {OO: inheritance 101} -setup {
oo::class create superClass
oo::class create subClass
subClass create instance
} -body {
oo::define superClass method doit x {
lappend ::result |$x|
}
oo::define subClass {
superclass superClass
method doit x {lappend ::result -$x-; next [incr x]}
}
oo::objdefine instance method doit x {
lappend ::result =$x=;
next [incr x]
}
set result {}
instance doit 1
return $result
} -cleanup {
subClass destroy
superClass destroy
} -result {=1= -2- |3|}
test oo-7.4 {OO: inheritance from oo::class} -body {
oo::class create meta {
superclass oo::class
self {
unexport create new
method make {x {definitions {}}} {
if {![string match ::* $x]} {
set ns [uplevel 1 {::namespace current}]
set x ${ns}::$x
}
set o [my create $x]
lappend ::result "made $o"
oo::define $o $definitions
return $o
}
}
}
set result [list [catch {meta create foo} msg] $msg]
lappend result [meta make classinstance {
lappend ::result "in definition script in [namespace current]"
}]
lappend result [classinstance create instance]
} -cleanup {
catch {classinstance destroy}
catch {meta destroy}
} -result {1 {unknown method "create": must be destroy or make} {made ::classinstance} {in definition script in ::oo::define} ::classinstance ::instance}
test oo-7.5 {OO: inheritance from oo::class in the secondary chain} -body {
oo::class create other
oo::class create meta {
superclass other oo::class
self {
unexport create new
method make {x {definitions {}}} {
if {![string match ::* $x]} {
set ns [uplevel 1 {::namespace current}]
set x ${ns}::$x
}
set o [my create $x]
lappend ::result "made $o"
oo::define $o $definitions
return $o
}
}
}
set result [list [catch {meta create foo} msg] $msg]
lappend result [meta make classinstance {
lappend ::result "in definition script in [namespace current]"
}]
lappend result [classinstance create instance]
} -cleanup {
catch {classinstance destroy}
catch {meta destroy}
catch {other destroy}
} -result {1 {unknown method "create": must be destroy or make} {made ::classinstance} {in definition script in ::oo::define} ::classinstance ::instance}
test oo-7.6 {OO: inheritance 101 - overridden methods should be oblivious} -setup {
oo::class create Aclass
oo::class create Bclass
Bclass create Binstance
} -body {
oo::define Aclass {
method incr {var step} {
upvar 1 $var v
::incr v $step
}
}
oo::define Bclass {
superclass Aclass
method incr {var {step 1}} {
global result
lappend result $var $step
set r [next $var $step]
lappend result returning:$r
return $r
}
}
set result {}
set x 10
lappend result x=$x
lappend result [Binstance incr x]
lappend result x=$x
} -result {x=10 x 1 returning:11 11 x=11} -cleanup {
unset -nocomplain x
Aclass destroy
}
test oo-7.7 {OO: inheritance and errorInfo} -setup {
oo::class create A
oo::class create B
B create c
} -body {
oo::define A method foo {} {error foo!}
oo::define B {
superclass A
method foo {} { next }
}
oo::objdefine c method foo {} { next }
catch {c ?} msg
set result [list $msg]
catch {c foo} msg
lappend result $msg $errorInfo
} -cleanup {
A destroy
} -result {{unknown method "?": must be destroy or foo} foo! {foo!
while executing
"error foo!"
(class "::A" method "foo" line 1)
invoked from within
"next "
(class "::B" method "foo" line 1)
invoked from within
"next "
(object "::c" method "foo" line 1)
invoked from within
"c foo"}}
test oo-7.8 {OO: next at the end of the method chain} -setup {
set ::result ""
} -cleanup {
foo destroy
} -body {
oo::class create foo {
method bar {} {lappend ::result foo; lappend ::result [next] foo}
}
oo::class create foo2 {
superclass foo
method bar {} {lappend ::result foo2; lappend ::result [next] foo2}
}
lappend result [catch {[foo2 new] bar} msg] $msg
} -result {foo2 foo 1 {no next method implementation}}
test oo-7.9 {OO: defining inheritance in namespaces} -setup {
set ::result {}
oo::class create ::parent
namespace eval ::foo {
oo::class create mixin {superclass ::parent}
}
} -cleanup {
::parent destroy
namespace delete ::foo
} -body {
namespace eval ::foo {
oo::class create bar {superclass parent}
oo::class create boo
oo::define boo {superclass bar}
oo::define boo {mixin mixin}
oo::class create spong {superclass boo}
return
}
} -result {}
test oo-7.10 {OO: next after object deletion, bug [135804138e]} -setup {
set ::result ""
oo::class create c1 {
method m1 {} {
lappend ::result c1::m1
}
}
oo::class create c2 {
superclass c1
destructor {
lappend ::result c2::destructor
my m1
lappend ::result /c2::destructor
}
method m1 {} {
lappend ::result c2::m1
rename [self] {}
lappend ::result no-self
next
lappend ::result /c2::m1
}
}
} -body {
c2 create o
lappend ::result [catch {o m1} msg] $msg
} -cleanup {
c1 destroy
unset ::result
} -result {c2::m1 c2::destructor c2::m1 no-self c1::m1 /c2::m1 /c2::destructor no-self 1 {no next method implementation}}
test oo-8.1 {OO: global must work in methods} {
oo::object create foo
oo::objdefine foo method bar x {global result; lappend result $x}
set result {}
foo bar this
foo bar is
lappend result a
foo bar test
foo destroy
return $result
} {this is a test}
test oo-9.1 {OO: multiple inheritance} -setup {
oo::class create A
oo::class create B
oo::class create C
oo::class create D
D create foo
} -body {
oo::define A method test {} {lappend ::result A; return ok}
oo::define B {
superclass A
method test {} {lappend ::result B; next}
}
oo::define C {
superclass A
method test {} {lappend ::result C; next}
}
oo::define D {
superclass B C
method test {} {lappend ::result D; next}
}
set result {}
lappend result [foo test]
} -cleanup {
D destroy
C destroy
B destroy
A destroy
} -result {D B C A ok}
test oo-9.2 {OO: multiple inheritance} -setup {
oo::class create A
oo::class create B
oo::class create C
oo::class create D
D create foo
} -body {
oo::define A method test {} {lappend ::result A; return ok}
oo::define B {
superclass A
method test {} {lappend ::result B; next}
}
oo::define C {
superclass A
method test {} {lappend ::result C; next}
}
oo::define D {
superclass B C
method test {} {lappend ::result D; next}
}
set result {}
lappend result [foo test]
} -cleanup {
A destroy
} -result {D B C A ok}
test oo-10.1 {OO: recursive invoke and modify} -setup {
[oo::class create C] create O
} -cleanup {
C destroy
} -body {
oo::define C method foo x {
lappend ::result $x
if {$x} {
[self object] foo [incr x -1]
}
}
oo::objdefine O method foo x {
lappend ::result -$x-
if {$x == 1} {
oo::objdefine O deletemethod foo
}
next $x
}
set result {}
O foo 2
return $result
} -result {-2- 2 -1- 1 0}
test oo-10.2 {OO: recursive invoke and modify} -setup {
oo::object create O
} -cleanup {
O destroy
} -body {
oo::objdefine O method foo {} {
oo::objdefine [self] method foo {} {
error "not called"
}
return [format %s%s call ed]
}
O foo
} -result called
test oo-10.3 {OO: invoke and modify} -setup {
oo::class create A {
method a {} {return A.a}
method b {} {return A.b}
method c {} {return A.c}
}
oo::class create B {
superclass A
method a {} {return [next],B.a}
method b {} {return [next],B.b}
method c {} {return [next],B.c}
}
B create C
set result {}
} -cleanup {
A destroy
} -body {
lappend result [C a] [C b] [C c] -
oo::define B deletemethod b
lappend result [C a] [C b] [C c] -
oo::define B renamemethod a b
lappend result [C a] [C b] [C c] -
oo::define B deletemethod b c
lappend result [C a] [C b] [C c]
} -result {A.a,B.a A.b,B.b A.c,B.c - A.a,B.a A.b A.c,B.c - A.a A.b,B.a A.c,B.c - A.a A.b A.c}
test oo-10.4 {OO: invoke and modify} -setup {
oo::class create A {
method a {} {return A.a}
method b {} {return A.b}
method c {} {return A.c}
}
A create B
oo::objdefine B {
method a {} {return [next],B.a}
method b {} {return [next],B.b}
method c {} {return [next],B.c}
}
set result {}
} -cleanup {
A destroy
} -body {
lappend result [B a] [B b] [B c] -
oo::objdefine B deletemethod b
lappend result [B a] [B b] [B c] -
oo::objdefine B renamemethod a b
lappend result [B a] [B b] [B c] -
oo::objdefine B deletemethod b c
lappend result [B a] [B b] [B c]
} -result {A.a,B.a A.b,B.b A.c,B.c - A.a,B.a A.b A.c,B.c - A.a A.b,B.a A.c,B.c - A.a A.b A.c}
test oo-11.1 {OO: cleanup} {
oo::object create foo
set result [list [catch {oo::object create foo} msg] $msg]
lappend result [foo destroy] [oo::object create foo] [foo destroy]
} {1 {can't create object "foo": command already exists with that name} {} ::foo {}}
test oo-11.2 {OO: cleanup} {
oo::class create bar
bar create foo
set result [list [catch {bar create foo} msg] $msg]
lappend result [bar destroy] [oo::object create foo] [foo destroy]
} {1 {can't create object "foo": command already exists with that name} {} ::foo {}}
test oo-11.3 {OO: cleanup} {
oo::class create bar0
oo::class create bar
oo::define bar superclass bar0
bar create foo
set result [list [catch {bar create foo} msg] $msg]
lappend result [bar0 destroy] [oo::object create foo] [foo destroy]
} {1 {can't create object "foo": command already exists with that name} {} ::foo {}}
test oo-11.4 {OO: cleanup} {
oo::class create bar0
oo::class create bar1
oo::define bar1 superclass bar0
oo::class create bar2
oo::define bar2 {
superclass bar0
destructor {lappend ::result destroyed}
}
oo::class create bar
oo::define bar superclass bar1 bar2
bar create foo
set result [list [catch {bar create foo} msg] $msg]
lappend result [bar0 destroy] [oo::object create foo] [foo destroy] \
[oo::object create bar2] [bar2 destroy]
} {1 {can't create object "foo": command already exists with that name} destroyed {} ::foo {} ::bar2 {}}
test oo-11.5 {OO: cleanup} {
oo::class create obj1
trace add command obj1 delete {apply {{name1 name2 action} {
set namespace [info object namespace $name1]
namespace delete $namespace
}}}
rename obj1 {}
# No segmentation fault
return done
} done
test oo-11.6.1 {
OO: cleanup of when an class is mixed into itself
} -constraints memory -body {
leaktest {
interp create interp1
oo::class create obj1
::oo::define obj1 {self mixin [uplevel 1 {namespace which obj1}]}
rename obj1 {}
interp delete interp1
}
} -result 0 -cleanup {
}
test oo-11.6.2 {
OO: cleanup ReleaseClassContents() where class is mixed into one of its
instances
} -constraints memory -body {
leaktest {
interp create interp1
interp1 eval {
oo::class create obj1
::oo::copy obj1 obj2
rename obj2 {}
rename obj1 {}
}
interp delete interp1
}
} -result 0 -cleanup {
}
test oo-11.6.3 {
OO: cleanup ReleaseClassContents() where class is mixed into one of its
instances
} -constraints memory -body {
leaktest {
interp create interp1
interp1 eval {
oo::class create obj1
::oo::define obj1 {self mixin [uplevel 1 {namespace which obj1}]}
::oo::copy obj1 obj2
rename obj2 {}
rename obj1 {}
}
interp delete interp1
}
} -result 0 -cleanup {
}
test oo-11.6.4 {
OO: cleanup ReleaseClassContents() where class is mixed into one of its
instances
} -body {
oo::class create obj1
::oo::define obj1 {self mixin [uplevel 1 {namespace which obj1}]}
::oo::copy obj1 obj2
::oo::objdefine obj2 {mixin [uplevel 1 {namespace which obj2}]}
::oo::copy obj2 obj3
rename obj3 {}
rename obj2 {}
# No segmentation fault
return done
} -result done -cleanup {
rename obj1 {}
}
test oo-12.1 {OO: filters} {
oo::class create Aclass
Aclass create Aobject
oo::define Aclass {
method concatenate args {
global result
lappend result {*}$args
join $args {}
}
method logFilter args {
global result
lappend result "calling [self object]->[self method] $args"
set r [next {*}$args]
lappend result "result=$r"
return $r
}
}
oo::objdefine Aobject filter logFilter
set result {}
lappend result [Aobject concatenate 1 2 3 4 5]
Aclass destroy
return $result
} {{calling ::Aobject->logFilter 1 2 3 4 5} 1 2 3 4 5 result=12345 12345}
test oo-12.2 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method concatenate args {
global result
lappend result {*}$args
join $args {}
}
method logFilter args {
global result
lappend result "calling [self object]->[self method] $args"
set r [next {*}$args]
lappend result "result=$r"
return $r
}
}
oo::objdefine Aobject filter logFilter
set result {}
lappend result [Aobject concatenate 1 2 3 4 5] [Aobject destroy]
} -cleanup {
Aclass destroy
} -result {{calling ::Aobject->logFilter 1 2 3 4 5} 1 2 3 4 5 result=12345 {calling ::Aobject->logFilter } result= 12345 {}}
test oo-12.3 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method concatenate args {
global result
lappend result {*}$args
join $args {}
}
method logFilter args {
global result
lappend result "calling [self object]->[self method] $args"
set r [next {*}$args]
lappend result "result=$r"
return $r
}
filter logFilter
}
set result {}
lappend result [Aobject concatenate 1 2 3 4 5] [Aobject destroy]
} -cleanup {
Aclass destroy
} -result {{calling ::Aobject->logFilter 1 2 3 4 5} 1 2 3 4 5 result=12345 {calling ::Aobject->logFilter } result= 12345 {}}
test oo-12.4 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method foo {} { return foo }
method Bar {} { return 1 }
method boo {} { if {[my Bar]} { next } { error forbidden } }
filter boo
}
Aobject foo
} -cleanup {
Aclass destroy
} -result foo
test oo-12.5 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method foo {} { return foo }
method Bar {} { return [my Bar2] }
method Bar2 {} { return 1 }
method boo {} { if {[my Bar]} { next } { error forbidden } }
filter boo
}
Aobject foo
} -cleanup {
Aclass destroy
} -result foo
test oo-12.6 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method foo {} { return foo }
method Bar {} { return [my Bar2] }
method Bar2 {} { return [my Bar3] }
method Bar3 {} { return 1 }
method boo {} { if {[my Bar]} { next } { error forbidden } }
filter boo
}
Aobject foo
} -cleanup {
Aclass destroy
} -result foo
test oo-12.7 {OO: filters} -setup {
oo::class create Aclass
Aclass create Aobject
} -body {
oo::define Aclass {
method outerfoo {} { return [my InnerFoo] }
method InnerFoo {} { return foo }
method Bar {} { return [my Bar2] }
method Bar2 {} { return [my Bar3] }
method Bar3 {} { return 1 }
method boo {} {
lappend ::log [self target]
if {[my Bar]} { next } else { error forbidden }
}
filter boo
}
set log {}
list [Aobject outerfoo] $log
} -cleanup {
Aclass destroy
} -result {foo {{::Aclass outerfoo} {::Aclass InnerFoo}}}
test oo-12.8 {OO: filters and destructors} -setup {
oo::class create Aclass
Aclass create Aobject
set ::log {}
} -body {
oo::define Aclass {
constructor {} {
lappend ::log "in constructor"
}
destructor {
lappend ::log "in destructor"
}
method bar {} {
lappend ::log "in method"
}
method Boo args {
lappend ::log [self target]
next {*}$args
}
filter Boo
}
set obj [Aclass new]
$obj bar
$obj destroy
return $::log
} -cleanup {
Aclass destroy
} -result {{in constructor} {::Aclass bar} {in method} {::oo::object destroy} {in destructor}}
test oo-13.1 {OO: changing an object's class} {
oo::class create Aclass
oo::define Aclass {method bar {} {lappend ::result "in A [self object]"}}
oo::class create Bclass
oo::define Bclass {method bar {} {lappend ::result "in B [self object]"}}
set result [Aclass create foo]
foo bar
oo::objdefine foo class Bclass
foo bar
Aclass destroy
lappend result [info command foo]
Bclass destroy
return $result
} {::foo {in A ::foo} {in B ::foo} foo}
test oo-13.2 {OO: changing an object's class} -body {
oo::object create foo
oo::objdefine foo class oo::class
} -cleanup {
foo destroy
} -result {}
test oo-13.3 {OO: changing an object's class} -body {
oo::class create foo
oo::objdefine foo class oo::object
} -cleanup {
foo destroy
} -result {}
test oo-13.4 {OO: changing an object's class} -body {
oo::class create foo {
method m {} {
set result [list [self class] [info object class [self]]]
oo::objdefine [self] class ::bar
lappend result [self class] [info object class [self]]
}
}
oo::class create bar
[foo new] m
} -cleanup {
foo destroy
bar destroy
} -result {::foo ::foo ::foo ::bar}
test oo-13.5 {OO: changing an object's class: non-class to class} -setup {
oo::object create fooObj
} -body {
oo::objdefine fooObj {
class oo::class
}
oo::define fooObj {
method x {} {expr {1+2+3}}
}
[fooObj new] x
} -cleanup {
fooObj destroy
} -result 6
test oo-13.6 {OO: changing an object's class: class to non-class} -setup {
oo::class create foo
unset -nocomplain ::result
} -body {
set result dangling
oo::define foo {
method x {} {expr {1+2+3}}
}
oo::class create boo {
superclass foo
destructor {set ::result "ok"}
}
boo new
foo create bar
oo::objdefine foo {
class oo::object
}
list $result [catch {bar x} msg] $msg
} -cleanup {
catch {bar destroy}
foo destroy
} -result {ok 1 {invalid command name "bar"}}
test oo-13.7 {OO: changing an object's class} -setup {
oo::class create foo
oo::class create bar
unset -nocomplain result
} -body {
oo::define bar method x {} {return ok}
oo::define foo {
method x {} {expr {1+2+3}}
self mixin foo
}
lappend result [foo x]
oo::objdefine foo class bar
lappend result [foo x]
} -cleanup {
foo destroy
bar destroy
} -result {6 ok}
test oo-13.8 {OO: changing an object's class to itself} -setup {
oo::class create foo
} -body {
oo::define foo {
method x {} {expr {1+2+3}}
}
oo::objdefine foo class foo
} -cleanup {
foo destroy
} -returnCodes error -result {may not change classes into an instance of themselves}
test oo-13.9 {OO: changing an object's class: roots are special} -setup {
set i [interp create]
} -body {
$i eval {
oo::objdefine oo::object {
class oo::class
}
}
} -cleanup {
interp delete $i
} -returnCodes error -result {may not modify the class of the root object class}
test oo-13.10 {OO: changing an object's class: roots are special} -setup {
set i [interp create]
} -body {
$i eval {
oo::objdefine oo::class {
class oo::object
}
}
} -cleanup {
interp delete $i
} -returnCodes error -result {may not modify the class of the class of classes}
test oo-13.11 {OO: changing an object's class in a tricky place} -setup {
oo::class create cls
unset -nocomplain result
} -body {
set result gorp
list [catch {
oo::define cls {
method x {} {return}
self class oo::object
::set ::result ok
method y {} {return}; # I'm sorry, Dave. I'm afraid I can't do that.
}
} msg] $msg $result
} -cleanup {
cls destroy
} -result {1 {attempt to misuse API} ok}
# todo: changing a class subtype (metaclass) to another class subtype
test oo-14.1 {OO: mixins} {
oo::class create Aclass
oo::define Aclass method bar {} {lappend ::result "[self object] in bar"}
oo::class create Bclass
oo::define Bclass method boo {} {lappend ::result "[self object] in boo"}
oo::objdefine [Aclass create fooTest] mixin Bclass
oo::objdefine [Aclass create fooTest2] mixin Bclass
set result [list [catch {fooTest ?} msg] $msg]
fooTest bar
fooTest boo
fooTest2 bar
fooTest2 boo
oo::objdefine fooTest2 mixin
lappend result [Bclass destroy] [info command fooTest*] [Aclass destroy]
} {1 {unknown method "?": must be bar, boo or destroy} {::fooTest in bar} {::fooTest in boo} {::fooTest2 in bar} {::fooTest2 in boo} {} fooTest2 {}}
test oo-14.2 {OO: mixins} {
oo::class create Aclass {
method bar {} {return "[self object] in bar"}
}
oo::class create Bclass {
method boo {} {return "[self object] in boo"}
}
oo::define Aclass mixin Bclass
Aclass create fooTest
set result [list [catch {fooTest ?} msg] $msg]
lappend result [catch {fooTest bar} msg] $msg
lappend result [catch {fooTest boo} msg] $msg
lappend result [Bclass destroy] [info commands Aclass]
} {1 {unknown method "?": must be bar, boo or destroy} 0 {::fooTest in bar} 0 {::fooTest in boo} {} {}}
test oo-14.3 {OO and mixins and filters - advanced case} -setup {
oo::class create mix
oo::class create c {
mixin mix
}
c create i
} -body {
oo::define mix {
method foo {} {return >>[next]<<}
filter foo
}
oo::objdefine i method bar {} {return foobar}
i bar
} -cleanup {
mix destroy
if {[info object isa object i]} {
error "mixin deletion failed to destroy dependent instance"
}
} -result >>foobar<<
test oo-14.4 {OO: mixin error case} -setup {
oo::class create c
} -body {
oo::define c mixin c
} -returnCodes error -cleanup {
c destroy
} -result {may not mix a class into itself}
test oo-14.5 {OO and mixins and filters - advanced case} -setup {
oo::class create mix
oo::class create c {
mixin mix
}
c create i
} -body {
oo::define mix {
method foo {} {return >>[next]<<}
filter foo
}
oo::objdefine i method bar {} {return foobar}
i bar
} -cleanup {
c destroy
mix destroy
} -result >>foobar<<
test oo-14.6 {OO and mixins of mixins - Bug 1960703} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create A {
superclass parent
method egg {} {
return chicken
}
}
oo::class create B {
superclass parent
mixin A
method bar {} {
# mixin from A
my egg
}
}
oo::class create C {
superclass parent
mixin B
method foo {} {
# mixin from B
my bar
}
}
[C new] foo
} -result chicken
test oo-14.7 {OO and filters from mixins of mixins} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create A {
superclass parent
method egg {} {
return chicken
}
filter f
method f args {
set m [lindex [self target] 1]
return "($m) [next {*}$args] ($m)"
}
}
oo::class create B {
superclass parent
mixin A
filter f
method bar {} {
# mixin from A
my egg
}
}
oo::class create C {
superclass parent
mixin B
filter f
method foo {} {
# mixin from B
my bar
}
}
[C new] foo
} -result {(foo) (bar) (egg) chicken (egg) (bar) (foo)}
test oo-14.8 {OO: class mixin order - Bug 1998221} -setup {
set ::result {}
oo::class create parent {
method test {} {}
}
} -cleanup {
parent destroy
} -body {
oo::class create mix {
superclass parent
method test {} {lappend ::result mix; next; return $::result}
}
oo::class create cls {
superclass parent
mixin mix
method test {} {lappend ::result cls; next; return $::result}
}
[cls new] test
} -result {mix cls}
test oo-15.1 {OO: object cloning} {
oo::class create Aclass
oo::define Aclass method test {} {lappend ::result [self object]->test}
Aclass create Ainstance
set result {}
Ainstance test
oo::copy Ainstance Binstance
Binstance test
Ainstance test
Ainstance destroy
namespace eval foo {
oo::copy Binstance Cinstance
Cinstance test
}
Aclass destroy
namespace delete foo
lappend result [info commands Binstance]
} {::Ainstance->test ::Binstance->test ::Ainstance->test ::foo::Cinstance->test {}}
test oo-15.2 {OO: object cloning} {
oo::object create foo
oo::objdefine foo {
method m x {lappend ::result [self object] >$x<}
forward f ::lappend ::result fwd
}
set result {}
foo m 1
foo f 2
lappend result [oo::copy foo bar]
foo m 3
foo f 4
bar m 5
bar f 6
lappend result [foo destroy]
bar m 7
bar f 8
lappend result [bar destroy]
} {::foo >1< fwd 2 ::bar ::foo >3< fwd 4 ::bar >5< fwd 6 {} ::bar >7< fwd 8 {}}
catch {foo destroy}
catch {bar destroy}
test oo-15.3 {OO: class cloning} {
oo::class create foo {
method testme {} {lappend ::result [self class]->[self object]}
}
set result {}
foo create baseline
baseline testme
oo::copy foo bar
baseline testme
bar create tester
tester testme
foo destroy
tester testme
bar destroy
return $result
} {::foo->::baseline ::foo->::baseline ::bar->::tester ::bar->::tester}
test oo-15.4 {OO: object cloning - Bug 3474460} -setup {
oo::class create ArbitraryClass
} -body {
ArbitraryClass create foo
oo::objdefine foo variable a b c
oo::copy foo bar
info object variable bar
} -cleanup {
ArbitraryClass destroy
} -result {a b c}
test oo-15.5 {OO: class cloning - Bug 3474460} -setup {
oo::class create ArbitraryClass
} -body {
oo::class create Foo {
superclass ArbitraryClass
variable a b c
}
oo::copy Foo Bar
info class variable Bar
} -cleanup {
ArbitraryClass destroy
} -result {a b c}
test oo-15.6 {OO: object cloning copies namespace contents} -setup {
oo::class create ArbitraryClass {export eval}
} -body {
ArbitraryClass create a
a eval {proc foo x {
variable y
return [string repeat $x [incr y]]
}}
set result [list [a eval {foo 2}] [a eval {foo 3}]]
oo::copy a b
a eval {rename foo bar}
lappend result [b eval {foo 2}] [b eval {foo 3}] [a eval {bar 4}]
} -cleanup {
ArbitraryClass destroy
} -result {2 33 222 3333 444}
test oo-15.7 {OO: classes can be cloned anonymously} -setup {
oo::class create ArbitraryClassA
oo::class create ArbitraryClassB {superclass ArbitraryClassA}
} -body {
info object isa class [oo::copy ArbitraryClassB]
} -cleanup {
ArbitraryClassA destroy
} -result 1
test oo-15.8 {OO: intercept object cloning} -setup {
oo::class create Foo
set result {}
} -body {
oo::define Foo {
constructor {msg} {
variable v $msg
}
method <cloned> {from} {
next $from
lappend ::result cloned $from [self]
}
method check {} {
variable v
lappend ::result check [self] $v
}
}
Foo create foo ok
oo::copy foo bar
foo check
bar check
} -cleanup {
Foo destroy
} -result {cloned ::foo ::bar check ::foo ok check ::bar ok}
test oo-15.9 {ensemble rewriting must not bleed through oo::copy} -setup {
oo::class create Foo
} -body {
oo::define Foo {
method <cloned> {a b} {}
}
interp alias {} Bar {} oo::copy [Foo create foo]
Bar bar
} -returnCodes error -cleanup {
Foo destroy
} -result {wrong # args: should be "::bar <cloned> a b"}
test oo-15.10 {variable binding must not bleed through oo::copy} -setup {
oo::class create FooClass
set result {}
} -body {
set obj1 [FooClass new]
oo::objdefine $obj1 {
variable var
method m {} {
set var foo
}
method get {} {
return $var
}
export eval
}
$obj1 m
lappend result [$obj1 get]
set obj2 [oo::copy $obj1]
$obj2 eval {
set var bar
}
lappend result [$obj2 get]
$obj1 eval {
set var grill
}
lappend result [$obj1 get] [$obj2 get]
} -cleanup {
FooClass destroy
} -result {foo bar grill bar}
test oo-15.11 {OO: object cloning} -returnCodes error -body {
oo::copy
} -result {wrong # args: should be "oo::copy sourceName ?targetName? ?targetNamespace?"}
test oo-15.12 {OO: object cloning with target NS} -setup {
oo::class create Super
oo::class create Cls {superclass Super}
} -body {
namespace eval ::existing {}
oo::copy Cls {} ::existing
} -returnCodes error -cleanup {
Super destroy
catch {namespace delete ::existing}
} -result {::existing refers to an existing namespace}
test oo-15.13.1 {
OO: object cloning with target NS
Valgrind will report a leak if the reference count of the namespace isn't
properly incremented.
} -setup {
oo::class create Cls {}
} -body {
oo::copy Cls Cls2 ::dupens
return done
} -cleanup {
Cls destroy
Cls2 destroy
} -result done
test oo-15.13.2 {OO: object cloning with target NS} -setup {
oo::class create Super
oo::class create Cls {superclass Super}
} -body {
list [namespace exist ::dupens] [oo::copy Cls Cls2 ::dupens] [namespace exist ::dupens]
} -cleanup {
Super destroy
} -result {0 ::Cls2 1}
test oo-15.14 {OO: object cloning with target NS} -setup {
oo::class create Cls {export eval}
set result {}
} -body {
Cls create obj
obj eval {
proc test-15.14 {} {}
}
lappend result [info commands ::dupens::t*]
oo::copy obj obj2 ::dupens
lappend result [info commands ::dupens::t*]
} -cleanup {
Cls destroy
} -result {{} ::dupens::test-15.14}
test oo-15.15 {method cloning must ensure that there is a string representation of bodies} -setup {
oo::class create cls
} -body {
cls create foo
oo::objdefine foo {
method m1 {} [string map {a b} {return hello}]
}
[oo::copy foo] m1
} -cleanup {
cls destroy
} -result hello
test oo-16.1 {OO: object introspection} -body {
info object
} -returnCodes 1 -result "wrong \# args: should be \"info object subcommand ?arg ...?\""
test oo-16.1.1 {OO: object introspection} -body {
catch {info object} m o
dict get $o -errorinfo
} -result "wrong \# args: should be \"info object subcommand ?arg ...?\"
while executing
\"info object\""
test oo-16.2 {OO: object introspection} -body {
info object class NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-16.3 {OO: object introspection} -body {
info object gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, class, definition, filters, forward, isa, methods, methodtype, mixins, namespace, variables, or vars}
test oo-16.4 {OO: object introspection} -setup {
oo::class create meta { superclass oo::class }
[meta create instance1] create instance2
} -body {
list [list [info object class oo::object] \
[info object class oo::class] \
[info object class meta] \
[info object class instance1] \
[info object class instance2]] \
[list [info object isa class oo::object] \
[info object isa class meta] \
[info object isa class instance1] \
[info object isa class instance2]] \
[list [info object isa metaclass oo::object] \
[info object isa metaclass oo::class] \
[info object isa metaclass meta] \
[info object isa metaclass instance1] \
[info object isa metaclass instance2]] \
[list [info object isa object oo::object] \
[info object isa object oo::class] \
[info object isa object meta] \
[info object isa object instance1] \
[info object isa object instance2] \
[info object isa object oo::define] \
[info object isa object NOTANOBJECT]]
} -cleanup {
meta destroy
} -result {{::oo::class ::oo::class ::oo::class ::meta ::instance1} {1 1 1 0} {0 1 1 0 0} {1 1 1 1 1 0 0}}
test oo-16.5 {OO: object introspection} {info object methods oo::object} {}
test oo-16.6 {OO: object introspection} {
oo::object create foo
set result [list [info object methods foo]]
oo::objdefine foo method bar {} {...}
lappend result [info object methods foo] [foo destroy]
} {{} bar {}}
test oo-16.7 {OO: object introspection} -setup {
oo::object create foo
} -body {
oo::objdefine foo method bar {a {b c} args} {the body}
set result [info object methods foo]
lappend result [info object methodtype foo bar] \
[info object definition foo bar]
} -cleanup {
foo destroy
} -result {bar method {{a {b c} args} {the body}}}
test oo-16.8 {OO: object introspection} {
oo::object create foo
oo::class create bar
oo::objdefine foo mixin bar
set result [list [info object mixins foo] \
[info object isa mixin foo bar] \
[info object isa mixin foo oo::class]]
foo destroy
bar destroy
return $result
} {::bar 1 0}
test oo-16.9 {OO: object introspection} -body {
oo::class create Ac
oo::class create Bc; oo::define Bc superclass Ac
oo::class create Cc; oo::define Cc superclass Bc
oo::class create Dc; oo::define Dc mixin Cc
Cc create E
Dc create F
list [info object isa typeof E oo::class] \
[info object isa typeof E Ac] \
[info object isa typeof F Bc] \
[info object isa typeof F Cc]
} -cleanup {
catch {Ac destroy}
} -result {0 1 1 1}
test oo-16.10 {OO: object introspection} -setup {
oo::object create foo
} -body {
oo::objdefine foo export eval
foo eval {variable c 3 a 1 b 2 ddd 4 e}
lsort [info object vars foo ?]
} -cleanup {
foo destroy
} -result {a b c}
test oo-16.11 {OO: object introspection} -setup {
oo::class create foo
foo create bar
} -body {
oo::define foo method spong {} {...}
oo::objdefine bar method boo {a {b c} args} {the body}
list [lsort [info object methods bar -all]] [lsort [info object methods bar -all -private]]
} -cleanup {
foo destroy
} -result {{boo destroy spong} {<cloned> boo destroy eval spong unknown variable varname}}
test oo-16.12 {OO: object introspection} -setup {
oo::object create foo
} -cleanup {
rename foo {}
} -body {
oo::objdefine foo unexport {*}[info object methods foo -all]
info object methods foo -all
} -result {}
test oo-16.13 {OO: object introspection} -setup {
oo::object create foo
} -cleanup {
rename foo {}
} -body {
oo::objdefine foo method Bar {} {return "ok in foo"}
[info object namespace foo]::my Bar
} -result "ok in foo"
test oo-16.14 {OO: object introspection: TIP #436} -setup {
oo::class create meta { superclass oo::class }
[meta create instance1] create instance2
} -body {
list class [list [info object isa class NOTANOBJECT] \
[info object isa class list]] \
meta [list [info object isa metaclass NOTANOBJECT] \
[info object isa metaclass list] \
[info object isa metaclass oo::object]] \
type [list [info object isa typeof oo::object NOTANOBJECT] \
[info object isa typeof NOTANOBJECT oo::object] \
[info object isa typeof list NOTANOBJECT] \
[info object isa typeof NOTANOBJECT list] \
[info object isa typeof oo::object list] \
[info object isa typeof list oo::object]] \
mix [list [info object isa mixin oo::object NOTANOBJECT] \
[info object isa mixin NOTANOBJECT oo::object] \
[info object isa mixin list NOTANOBJECT] \
[info object isa mixin NOTANOBJECT list] \
[info object isa mixin oo::object list] \
[info object isa mixin list oo::object]]
} -cleanup {
meta destroy
} -result {class {0 0} meta {0 0 0} type {0 0 0 0 0 0} mix {0 0 0 0 0 0}}
test oo-17.1 {OO: class introspection} -body {
info class
} -returnCodes 1 -result "wrong \# args: should be \"info class subcommand ?arg ...?\""
test oo-17.1.1 {OO: class introspection} -body {
catch {info class} m o
dict get $o -errorinfo
} -result "wrong \# args: should be \"info class subcommand ?arg ...?\"
while executing
\"info class\""
test oo-17.2 {OO: class introspection} -body {
info class superclass NOTANOBJECT
} -returnCodes 1 -result {NOTANOBJECT does not refer to an object}
test oo-17.3 {OO: class introspection} -setup {
oo::object create foo
} -body {
info class superclass foo
} -returnCodes 1 -cleanup {
foo destroy
} -result {"foo" is not a class}
test oo-17.4 {OO: class introspection} -body {
info class gorp oo::object
} -returnCodes 1 -result {unknown or ambiguous subcommand "gorp": must be call, constructor, definition, destructor, filters, forward, instances, methods, methodtype, mixins, subclasses, superclasses, or variables}
test oo-17.5 {OO: class introspection} -setup {
oo::class create testClass
} -body {
testClass create foo
testClass create bar
testClass create spong
lsort [info class instances testClass]
} -cleanup {
testClass destroy
} -result {::bar ::foo ::spong}
test oo-17.6 {OO: class introspection} -setup {
oo::class create foo
} -body {
oo::define foo method bar {a {b c} args} {the body}
set result [info class methods foo]
lappend result [info class methodtype foo bar] \
[info class definition foo bar]
} -cleanup {
foo destroy
} -result {bar method {{a {b c} args} {the body}}}
test oo-17.7 {OO: class introspection} {
info class superclasses oo::class
} ::oo::object
test oo-17.8 {OO: class introspection} -setup {
oo::class create testClass
oo::class create superClass1
oo::class create superClass2
} -body {
oo::define testClass superclass superClass1 superClass2
list [info class superclasses testClass] \
[lsort [info class subclass oo::object ::superClass?]]
} -cleanup {
testClass destroy
superClass1 destroy
superClass2 destroy
} -result {{::superClass1 ::superClass2} {::superClass1 ::superClass2}}
test oo-17.9 {OO: class introspection} -setup {
oo::class create foo
oo::class create subfoo {superclass foo}
} -body {
oo::define foo {
method bar {a {b c} args} {the body}
self {
method bad {} {...}
}
}
oo::define subfoo method boo {a {b c} args} {the body}
list [lsort [info class methods subfoo -all]] \
[lsort [info class methods subfoo -all -private]]
} -cleanup {
foo destroy
} -result {{bar boo destroy} {<cloned> bar boo destroy eval unknown variable varname}}
test oo-17.10 {OO: class introspection} -setup {
oo::class create foo
} -cleanup {
rename foo {}
} -body {
oo::define foo unexport {*}[info class methods foo -all]
info class methods foo -all
} -result {}
set stdmethods {<cloned> destroy eval unknown variable varname}
test oo-17.11 {OO: object method unexport (bug 900cb0284bc)} -setup {
oo::object create o
oo::objdefine o unexport m
} -body {
lsort [info object methods o -all -private]
} -cleanup {
o destroy
} -result $stdmethods
test oo-17.12 {OO: instance method unexport (bug 900cb0284bc)} -setup {
oo::class create c
c create o
oo::objdefine o unexport m
} -body {
lsort [info object methods o -all -private]
} -cleanup {
o destroy
c destroy
} -result $stdmethods
test oo-17.13 {OO: class method unexport (bug 900cb0284bc)} -setup {
oo::class create c
oo::define c unexport m
} -body {
lsort [info class methods c -all -private]
} -cleanup {
c destroy
} -result $stdmethods
test oo-17.14 {OO: instance method unexport (bug 900cb0284bc)} -setup {
oo::class create c
oo::define c unexport m
c create o
} -body {
lsort [info object methods o -all -private]
} -cleanup {
o destroy
c destroy
} -result $stdmethods
test oo-18.1 {OO: define command support} {
list [catch {oo::define oo::object {error foo}} msg] $msg $errorInfo
} {1 foo {foo
while executing
"error foo"
(in definition script for class "::oo::object" line 1)
invoked from within
"oo::define oo::object {error foo}"}}
test oo-18.2 {OO: define command support} {
list [catch {oo::define oo::object error foo} msg] $msg $errorInfo
} {1 foo {foo
while executing
"oo::define oo::object error foo"}}
test oo-18.3 {OO: define command support} {
list [catch {oo::class create foo {error bar}} msg] $msg $errorInfo
} {1 bar {bar
while executing
"error bar"
(in definition script for class "::foo" line 1)
invoked from within
"oo::class create foo {error bar}"}}
test oo-18.3a {OO: define command support} {
list [catch {oo::class create foo {
error bar
}} msg] $msg $errorInfo
} {1 bar {bar
while executing
"error bar"
(in definition script for class "::foo" line 2)
invoked from within
"oo::class create foo {
error bar
}"}}
test oo-18.3b {OO: define command support} {
list [catch {oo::class create foo {
eval eval error bar
}} msg] $msg $errorInfo
} {1 bar {bar
while executing
"error bar"
("eval" body line 1)
invoked from within
"eval error bar"
("eval" body line 1)
invoked from within
"eval eval error bar"
(in definition script for class "::foo" line 2)
invoked from within
"oo::class create foo {
eval eval error bar
}"}}
test oo-18.4 {OO: more error traces from the guts} -setup {
oo::object create obj
} -body {
oo::objdefine obj method bar {} {my eval {error foo}}
list [catch {obj bar} msg] $msg $errorInfo
} -cleanup {
obj destroy
} -result {1 foo {foo
while executing
"error foo"
(in "my eval" script line 1)
invoked from within
"my eval {error foo}"
(object "::obj" method "bar" line 1)
invoked from within
"obj bar"}}
test oo-18.5 {OO: more error traces from the guts} -setup {
[oo::class create cls] create obj
set errorInfo {}
} -body {
oo::define cls {
method eval script {next $script}
export eval
}
oo::objdefine obj method bar {} {my eval {error foo}}
set result {}
lappend result [catch {obj bar} msg] $msg $errorInfo
lappend result [catch {obj eval {error bar}} msg] $msg $errorInfo
} -cleanup {
cls destroy
} -result {1 foo {foo
while executing
"error foo"
(in "my eval" script line 1)
invoked from within
"next $script"
(class "::cls" method "eval" line 1)
invoked from within
"my eval {error foo}"
(object "::obj" method "bar" line 1)
invoked from within
"obj bar"} 1 bar {bar
while executing
"error bar"
(in "::obj eval" script line 1)
invoked from within
"next $script"
(class "::cls" method "eval" line 1)
invoked from within
"obj eval {error bar}"}}
test oo-18.6 {class construction reference management and errors} -setup {
oo::class create super_abc
} -body {
catch {
oo::class create abc {
superclass super_abc
::rename abc ::def
::error foo
}
} msg opt
dict get $opt -errorinfo
} -cleanup {
super_abc destroy
} -result {foo
while executing
"::error foo"
(in definition script for class "::def" line 4)
invoked from within
"oo::class create abc {
superclass super_abc
::rename abc ::def
::error foo
}"}
test oo-18.7 {OO: objdefine command support} -setup {
oo::object create ::inst
} -body {
list [catch {oo::objdefine inst {rename ::inst ::INST;error foo}} msg] $msg $errorInfo
} -cleanup {
catch {::inst destroy}
catch {::INST destroy}
} -result {1 foo {foo
while executing
"error foo"
(in definition script for object "::INST" line 1)
invoked from within
"oo::objdefine inst {rename ::inst ::INST;error foo}"}}
test oo-18.8 {OO: define/self command support} -setup {
oo::class create parent
oo::class create ::foo {superclass parent}
} -body {
catch {oo::define foo {rename ::foo ::bar; self {error foobar}}} msg opt
dict get $opt -errorinfo
} -cleanup {
parent destroy
} -result {foobar
while executing
"error foobar"
(in definition script for class object "::bar" line 1)
invoked from within
"self {error foobar}"
(in definition script for class "::bar" line 1)
invoked from within
"oo::define foo {rename ::foo ::bar; self {error foobar}}"}
test oo-18.9 {OO: define/self command support} -setup {
oo::class create parent
set c [oo::class create now_this_is_a_very_very_long_class_name_indeed {
superclass parent
}]
} -body {
catch {oo::define $c {error err}} msg opt
dict get $opt -errorinfo
} -cleanup {
parent destroy
} -result {err
while executing
"error err"
(in definition script for class "::now_this_is_a_very_very_long..." line 1)
invoked from within
"oo::define $c {error err}"}
test oo-18.10 {OO: define/self command support} -setup {
oo::class create parent
oo::class create ::foo {superclass parent}
} -body {
catch {oo::define foo {self {rename ::foo {}; error foobar}}} msg opt
dict get $opt -errorinfo
} -cleanup {
parent destroy
} -result {foobar
while executing
"error foobar"
(in definition script for class object "::foo" line 1)
invoked from within
"self {rename ::foo {}; error foobar}"
(in definition script for class "::foo" line 1)
invoked from within
"oo::define foo {self {rename ::foo {}; error foobar}}"}
test oo-18.11 {OO: define/self command support} -setup {
oo::class create parent
oo::class create ::foo {superclass parent}
} -body {
catch {oo::define foo {rename ::foo {}; self {error foobar}}} msg opt
dict get $opt -errorinfo
} -cleanup {
parent destroy
} -result {this command cannot be called when the object has been deleted
while executing
"self {error foobar}"
(in definition script for class "::foo" line 1)
invoked from within
"oo::define foo {rename ::foo {}; self {error foobar}}"}
test oo-19.1 {OO: varname method} -setup {
oo::object create inst
oo::objdefine inst export eval
set result {}
inst eval { variable x }
} -body {
inst eval {trace add variable x write foo}
set ns [inst eval namespace current]
proc foo args {
global ns result
set context [uplevel 1 namespace current]
lappend result $args [expr {
$ns eq $context ? "ok" : [list $ns ne $context]
}] [expr {
"${ns}::x" eq [uplevel 1 my varname x] ? "ok" : [list ${ns}::x ne [uplevel 1 my varname x]]
}]
}
lappend result [inst eval set x 0]
} -cleanup {
inst destroy
rename foo {}
} -result {{x {} write} ok ok 0}
test oo-19.2 {OO: varname method: Bug 2883857} -setup {
oo::class create SpecialClass
oo::objdefine SpecialClass export createWithNamespace
SpecialClass createWithNamespace inst ::oo_test
oo::objdefine inst export varname eval
} -body {
inst eval { variable x; array set x {y z} }
inst varname x(y)
} -cleanup {
SpecialClass destroy
} -result ::oo_test::x(y)
test oo-19.3 {OO: varname method and variable decl: Bug 3603695} -setup {
oo::class create testClass {
variable foo
export varname
constructor {} {
variable foo x
}
method bar {obj} {
my varname foo
$obj varname foo
}
}
} -body {
testClass create A
testClass create B
lsearch [list [A varname foo] [B varname foo]] [B bar A]
} -cleanup {
testClass destroy
} -result 0
test oo-20.1 {OO: variable method} -body {
oo::class create testClass {
constructor {} {
my variable ok
set ok {}
}
}
lsort [info object vars [testClass new]]
} -cleanup {
catch {testClass destroy}
} -result ok
test oo-20.2 {OO: variable method} -body {
oo::class create testClass {
constructor {} {
my variable a b c
set a [set b [set c {}]]
}
}
lsort [info object vars [testClass new]]
} -cleanup {
catch {testClass destroy}
} -result {a b c}
test oo-20.3 {OO: variable method} -body {
oo::class create testClass {
export varname
method bar {} {
my variable a(b)
}
}
testClass create foo
array set [foo varname a] {b c}
foo bar
} -returnCodes 1 -cleanup {
catch {testClass destroy}
} -result {can't define "a(b)": name refers to an element in an array}
test oo-20.4 {OO: variable method} -body {
oo::class create testClass {
export varname
method bar {} {
my variable a(b)
}
}
testClass create foo
set [foo varname a] b
foo bar
} -returnCodes 1 -cleanup {
catch {testClass destroy}
} -result {can't define "a(b)": name refers to an element in an array}
test oo-20.5 {OO: variable method} -body {
oo::class create testClass {
method bar {} {
my variable a::b
}
}
testClass create foo
foo bar
} -returnCodes 1 -cleanup {
catch {testClass destroy}
} -result {variable name "a::b" illegal: must not contain namespace separator}
test oo-20.6 {OO: variable method} -setup {
oo::class create testClass {
export varname
self export eval
}
} -body {
testClass eval variable a 0
oo::objdefine [testClass create foo] method bar {other} {
$other variable a
set a 3
}
oo::objdefine [testClass create boo] export variable
set [foo varname a] 1
set [boo varname a] 2
foo bar boo
list [testClass eval set a] [set [foo varname a]] [set [boo varname a]]
} -cleanup {
testClass destroy
} -result {0 1 3}
test oo-20.7 {OO: variable method} -setup {
oo::class create cls
} -body {
oo::define cls {
method a {} {
my variable d b
lappend b $d
}
method e {} {
my variable b d
return [list $b $d]
}
method f {x y} {
my variable b d
set b $x
set d $y
}
}
cls create obj
obj f p q
obj a
obj a
obj e
} -cleanup {
cls destroy
} -result {{p q q} q}
# oo-20.8 tested explicitly for functionality removed due to [Bug 1959457]
test oo-20.9 {OO: variable method} -setup {
oo::object create obj
} -body {
oo::objdefine obj {
method a {} {
my variable ::b
}
}
obj a
} -returnCodes 1 -cleanup {
obj destroy
} -result {variable name "::b" illegal: must not contain namespace separator}
test oo-20.10 {OO: variable and varname methods refer to same things} -setup {
oo::object create obj
} -body {
oo::objdefine obj {
method a {} {
my variable b
set b [self]
return [my varname b]
}
}
list [set [obj a]] [namespace tail [obj a]]
} -cleanup {
obj destroy
} -result {::obj b}
test oo-20.11 {OO: variable mustn't crash when recursing} -body {
oo::class create A {
constructor {name} {
my variable np_name
set np_name $name
}
method copy {nm} {
set cpy [[info object class [self]] new $nm]
foreach var [info object vars [self]] {
my variable $var
set val [set $var]
if {[string match o_* $var]} {
set objs {}
foreach ref $val {
# call to "copy" crashes
lappend objs [$ref copy {}]
}
$cpy prop $var $objs
} else {
$cpy prop $var $val
}
}
return $cpy
}
method prop {name val} {
my variable $name
set $name $val
}
}
set o1 [A new {}]
set o2 [A new {}]
$o1 prop o_object $o2
$o1 copy aa
} -cleanup {
catch {A destroy}
} -match glob -result *
test oo-20.12 {OO: variable method accept zero args (TIP 323)} -setup {
oo::object create foo
} -cleanup {
foo destroy
} -body {
oo::objdefine foo method demo {} {
my variable
}
foo demo
} -result {}
test oo-20.13 {OO: variable method use in non-methods [Bug 2903811]} -setup {
oo::object create fooObj
oo::objdefine fooObj export variable
} -cleanup {
fooObj destroy
} -body {
apply {{} {fooObj variable x; set x ok; return}}
apply {{} {fooObj variable x; return $x}}
} -result ok
test oo-20.14 {OO: variable method use in non-methods [Bug 2903811]} -setup {
oo::object create fooObj
oo::objdefine fooObj export variable
namespace eval ns1 {}
namespace eval ns2 {}
set x bad
} -cleanup {
fooObj destroy
namespace delete ns1 ns2
unset x
} -body {
namespace eval ns1 {fooObj variable x; set x ok; subst ""}
set x bad
namespace eval ns2 {fooObj variable x; return $x}
} -result ok
test oo-20.15 {OO: variable method use in non-methods [Bug 2903811]} -setup {
oo::object create fooObj
oo::objdefine fooObj export variable varname
} -cleanup {
fooObj destroy
} -body {
apply {{} {fooObj variable x; set x ok; return}}
return [set [fooObj varname x]]
} -result ok
test oo-20.16 {variable method: leak per instance} -setup {
oo::class create foo
} -constraints memory -body {
oo::define foo {
constructor {} {
set [my variable v] 0
}
}
leaktest {[foo new] destroy}
} -cleanup {
foo destroy
} -result 0
test oo-21.1 {OO: inheritance ordering} -setup {
oo::class create A
} -body {
oo::define A method m {} {lappend ::result A}
oo::class create B {
superclass A
method m {} {lappend ::result B;next}
}
oo::class create C {
superclass A
method m {} {lappend ::result C;next}
}
oo::class create D {
superclass B C
method m {} {lappend ::result D;next}
}
D create o
oo::objdefine o method m {} {lappend ::result o;next}
set result {}
o m
return $result
} -cleanup {
A destroy
} -result {o D B C A}
test oo-21.2 {OO: inheritance ordering} -setup {
oo::class create A
} -body {
oo::define A method m {} {lappend ::result A}
oo::class create B {
superclass A
method m {} {lappend ::result B;next}
}
oo::class create C {
superclass A
method m {} {lappend ::result C;next}
}
oo::class create D {
superclass B C
method m {} {lappend ::result D;next}
}
oo::class create Emix {
superclass C
method m {} {lappend ::result Emix;next}
}
oo::class create Fmix {
superclass Emix
method m {} {lappend ::result Fmix;next}
}
D create o
oo::objdefine o {
method m {} {lappend ::result o;next}
mixin Fmix
}
set result {}
o m
return $result
} -cleanup {
A destroy
} -result {Fmix Emix o D B C A}
test oo-21.3 {OO: inheritance ordering} -setup {
oo::class create A
} -body {
oo::define A method m {} {lappend ::result A}
oo::class create B {
superclass A
method m {} {lappend ::result B;next}
method f {} {lappend ::result B-filt;next}
}
oo::class create C {
superclass A
method m {} {lappend ::result C;next}
}
oo::class create D {
superclass B C
method m {} {lappend ::result D;next}
}
oo::class create Emix {
superclass C
method m {} {lappend ::result Emix;next}
method f {} {lappend ::result Emix-filt;next}
}
oo::class create Fmix {
superclass Emix
method m {} {lappend ::result Fmix;next}
}
D create o
oo::objdefine o {
method m {} {lappend ::result o;next}
mixin Fmix
filter f
}
set result {}
o m
return $result
} -cleanup {
A destroy
} -result {Emix-filt B-filt Fmix Emix o D B C A}
test oo-21.4 {OO: inheritance ordering} -setup {
oo::class create A
} -body {
oo::define A method m {} {lappend ::result A}
oo::class create B {
superclass A
method m {} {lappend ::result B;next}
method f {} {lappend ::result B-filt;next}
method g {} {lappend ::result B-cfilt;next}
}
oo::class create C {
superclass A
method m {} {lappend ::result C;next}
}
oo::class create D {
superclass B C
method m {} {lappend ::result D;next}
method g {} {lappend ::result D-cfilt;next}
filter g
}
oo::class create Emix {
superclass C
method m {} {lappend ::result Emix;next}
method f {} {lappend ::result Emix-filt;next}
}
oo::class create Fmix {
superclass Emix
method m {} {lappend ::result Fmix;next}
}
D create o
oo::objdefine o {
method m {} {lappend ::result o;next}
mixin Fmix
filter f
}
set result {}
o m
return $result
} -cleanup {
A destroy
} -result {Emix-filt B-filt D-cfilt B-cfilt Fmix Emix o D B C A}
test oo-22.1 {OO and info frame} -setup {
oo::class create c
c create i
} -match glob -body {
oo::define c self method frame {} {
info frame 0
}
oo::define c {
method frames {} {
info frame 0
}
method level {} {
info frame
}
}
oo::objdefine i {
method frames {} {
list [next] [info frame 0]
}
method level {} {
expr {[next] - [info frame]}
}
}
list [i level] [i frames] [dict get [c frame] object]
} -cleanup {
c destroy
} -result {1 {{* cmd {info frame 0} method frames class ::c level 0} {* cmd {info frame 0} method frames object ::i level 0}} ::c}
test oo-22.2 {OO and info frame: Bug 3001438} -setup {
oo::class create c
} -body {
oo::define c method test {{x 1}} {
if {$x} {my test 0}
lsort {q w e r t y u i o p}; # Overwrite the Tcl stack
info frame 0
}
[c new] test
} -match glob -cleanup {
c destroy
} -result {* cmd {info frame 0} method test class ::c level 0}
# Prove that the issue in [Bug 1865054] isn't an issue any more
test oo-23.1 {Self-like derivation; complex case!} -setup {
oo::class create SELF {
superclass oo::class
unexport create new
# Next is just a convenience
method method args {oo::define [self] method {*}$args}
method derive {name} {
set o [my new [list superclass [self]]]
oo::objdefine $o mixin $o
uplevel 1 [list rename $o $name]\;[list namespace which $name]
}
self mixin SELF
}
set result {}
} -body {
[SELF derive foo1] method bar1 {} {return 1}
lappend result [foo1 bar1]
[foo1 derive foo2] method bar2 {} {return [my bar1],2}
lappend result [foo2 bar2]
[foo2 derive foo3] method bar3 {} {return [my bar2],3}
lappend result [foo3 bar3]
[foo3 derive foo4] method bar4 {} {return [my bar3],4}
lappend result [foo4 bar4]
foo2 method bar2 {} {return [my bar1],x}
lappend result [foo4 bar4]
} -cleanup {
SELF destroy
} -result {1 1,2 1,2,3 1,2,3,4 1,x,3,4}
test oo-24.1 {unknown method method - Bug 1965063} -setup {
oo::class create cls
} -cleanup {
cls destroy
} -returnCodes error -body {
oo::define cls {
method dummy {} {}
method unknown args {next {*}$args}
}
[cls new] foo bar
} -result {unknown method "foo": must be destroy, dummy or unknown}
test oo-24.2 {unknown method method - Bug 1965063} -setup {
oo::class create cls
} -cleanup {
cls destroy
} -returnCodes error -body {
oo::define cls {
method dummy {} {}
method unknown args {next {*}$args}
}
cls create obj
oo::objdefine obj {
method dummy2 {} {}
method unknown args {next {*}$args}
}
obj foo bar
} -result {unknown method "foo": must be destroy, dummy, dummy2 or unknown}
test oo-24.3 {unknown method method - absent method name} -setup {
set o [oo::object new]
} -cleanup {
$o destroy
} -body {
oo::objdefine $o method unknown args {
return "unknown: >>$args<<"
}
list [$o] [$o foobar] [$o foo bar]
} -result {{unknown: >><<} {unknown: >>foobar<<} {unknown: >>foo bar<<}}
# Probably need a better set of tests, but this is quite difficult to devise
test oo-25.1 {call chain caching} -setup {
oo::class create cls {
method ab {} {return ok}
}
set result {}
} -cleanup {
cls destroy
} -body {
cls create foo
cls create bar
set m1 ab
set m2 a; append m2 b ;# different object!
lappend result [foo $m1] [foo $m1] [bar $m1] [foo $m1]
lappend result [foo $m2] [bar $m2]
oo::objdefine foo method ab {} {return good}
lappend result [foo $m1] [bar $m2]
} -result {ok ok ok ok ok ok good ok}
test oo-25.2 {call chain caching - Bug #2120903} -setup {
set c [oo::class create MyClass]
set o [$c new]
} -body {
oo::define MyClass {
method name {} {return ok}
method isa o {MyClass name $o}
self method name o {$o name}
}
list [$o name] [$c name $o] [$o isa $o]
} -cleanup {
$c destroy
} -result {ok ok ok}
test oo-26.1 {Bug 2037727} -setup {
proc succeed args {}
oo::object create example
} -body {
oo::objdefine example method foo {} {succeed}
example foo
proc succeed {} {return succeed}
example foo
} -cleanup {
example destroy
rename succeed {}
} -result succeed
test oo-26.2 {Bug 2037727} -setup {
oo::class create example {
method localProc {args body} {proc called $args $body}
method run {} { called }
}
example create i1
example create i2
} -body {
i1 localProc args {}
i2 localProc args {return nonempty}
list [i1 run] [i2 run]
} -cleanup {
example destroy
} -result {{} nonempty}
test oo-26.3 {Bug 2037727} -setup {
oo::class create example {
method subProc {args body} {
namespace eval subns [list proc called $args $body]
}
method run {} { subns::called }
}
example create i1
example create i2
} -body {
i1 subProc args {}
i2 subProc args {return nonempty}
list [i1 run] [i2 run]
} -cleanup {
example destroy
} -result {{} nonempty}
test oo-27.1 {variables declaration - class introspection} -setup {
oo::class create foo
} -cleanup {
foo destroy
} -body {
oo::define foo variable a b c
info class variables foo
} -result {a b c}
test oo-27.2 {variables declaration - object introspection} -setup {
oo::object create foo
} -cleanup {
foo destroy
} -body {
oo::objdefine foo variable a b c
info object variables foo
} -result {a b c}
test oo-27.3 {variables declaration - basic behaviour} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x!
constructor {} {set x! 1}
method y {} {incr x!}
}
foo create bar
bar y
bar y
} -result 3
test oo-27.4 {variables declaration - destructors too} -setup {
oo::class create parent
set result bad!
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x!
constructor {} {set x! 1}
method y {} {incr x!}
destructor {set ::result ${x!}}
}
foo create bar
bar y
bar y
bar destroy
return $result
} -result 3
test oo-27.5 {variables declaration - object-bound variables} -setup {
oo::object create foo
} -cleanup {
foo destroy
} -body {
oo::objdefine foo {
variable x!
method y {} {incr x!}
}
foo y
foo y
} -result 2
test oo-27.6 {variables declaration - non-interference of levels} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x!
constructor {} {set x! 1}
method y {} {incr x!}
}
foo create bar
oo::objdefine bar {
variable y!
method y {} {list [next] [incr y!] [info var] [info local]}
export eval
}
bar y
list [bar y] [lsort [info object vars bar]] [bar eval {info vars *!}]
} -result {{3 2 y! {}} {x! y!} {x! y!}}
test oo-27.7 {variables declaration - one underlying variable space} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x!
constructor {} {set x! 1}
method y {} {incr x!}
}
oo::class create foo2 {
superclass foo
variable y!
constructor {} {set y! 42; next}
method x {} {incr y! -1}
}
foo2 create bar
oo::objdefine bar {
variable x! y!
method z {} {list ${x!} ${y!}}
}
bar y
bar x
list [bar y] [bar x] [bar z]
} -result {3 40 {3 40}}
test oo-27.8 {variables declaration - error cases - ns separators} -body {
oo::define oo::object variable bad::var
} -returnCodes error -result {invalid declared variable name "bad::var": must not contain namespace separators}
test oo-27.9 {variables declaration - error cases - arrays} -body {
oo::define oo::object variable bad(var)
} -returnCodes error -result {invalid declared variable name "bad(var)": must not refer to an array element}
test oo-27.10 {variables declaration - no instance var leaks with class resolvers} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable clsvar
constructor {} {
set clsvar 0
}
method step {} {
incr clsvar
return
}
method value {} {
return $clsvar
}
}
foo create inst1
inst1 step
foo create inst2
inst2 step
inst1 step
inst2 step
inst1 step
list [inst1 value] [inst2 value]
} -result {3 2}
test oo-27.11 {variables declaration - no instance var leaks with class resolvers} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable clsvar
constructor {} {
set clsvar 0
}
method step {} {
incr clsvar
return
}
method value {} {
return $clsvar
}
}
foo create inst1
oo::objdefine inst1 {
variable clsvar
method reinit {} {
set clsvar 0
}
}
foo create inst2
oo::objdefine inst2 {
variable clsvar
method reinit {} {
set clsvar 0
}
}
inst1 step
inst2 step
inst1 reinit
inst2 reinit
inst1 step
inst2 step
inst1 step
inst2 step
inst1 step
list [inst1 value] [inst2 value]
} -result {3 2}
test oo-27.12 {variables declaration: leak per instance} -setup {
oo::class create foo
} -constraints memory -body {
oo::define foo {
variable v
constructor {} {
set v 0
}
}
leaktest {[foo new] destroy}
} -cleanup {
foo destroy
} -result 0
# This test will actually (normally) crash if it fails!
test oo-27.13 {variables declaration: Bug 3185009: require refcount management} -setup {
oo::object create foo
} -body {
oo::objdefine foo {
variable x
method set v {set x $v}
method unset {} {unset x}
method exists {} {info exists x}
method get {} {return $x}
}
list [foo exists] [foo set 7] [foo exists] [foo get] [foo unset] \
[foo exists] [catch {foo get} msg] $msg
} -cleanup {
foo destroy
} -result {0 7 1 7 {} 0 1 {can't read "x": no such variable}}
test oo-27.14 {variables declaration - multiple use} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x
variable y
method boo {} {
return [incr x],[incr y]
}
}
foo create bar
list [bar boo] [bar boo]
} -result {1,1 2,2}
test oo-27.15 {variables declaration - multiple use} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable
variable x y
method boo {} {
return [incr x],[incr y]
}
}
foo create bar
list [bar boo] [bar boo]
} -result {1,1 2,2}
test oo-27.16 {variables declaration - multiple use} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x
variable -clear
variable y
method boo {} {
return [incr x],[incr y]
}
}
foo create bar
list [bar boo] [bar boo]
} -result {1,1 1,2}
test oo-27.17 {variables declaration - multiple use} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x
variable -set y
method boo {} {
return [incr x],[incr y]
}
}
foo create bar
list [bar boo] [bar boo]
} -result {1,1 1,2}
test oo-27.18 {variables declaration - multiple use} -setup {
oo::class create parent
} -cleanup {
parent destroy
} -body {
oo::class create foo {
superclass parent
variable x
variable -? y
method boo {} {
return [incr x],[incr y]
}
}
foo create bar
list [bar boo] [bar boo]
} -returnCodes error -match glob -result {unknown method "-?": must be *}
test oo-27.19 {variables declaration and [info vars]: Bug 2712377} -setup {
oo::class create Foo
set result {}
} -body {
# This is really a test of problems to do with Tcl's introspection when a
# variable resolver is present...
oo::define Foo {
variable foo bar
method setvars {f b} {
set foo $f
set bar $b
}
method dump1 {} {
lappend ::result <1>
foreach v [lsort [info vars *]] {
lappend ::result $v=[set $v]
}
lappend ::result [info locals] [info locals *]
}
method dump2 {} {
lappend ::result <2>
foreach v [lsort [info vars *]] {
lappend ::result $v=[set $v]
}
lappend ::result | foo=$foo [info locals] [info locals *]
}
}
Foo create stuff
stuff setvars what ever
stuff dump1
stuff dump2
return $result
} -cleanup {
Foo destroy
} -result {<1> bar=ever foo=what v v <2> bar=ever foo=what | foo=what v v}
test oo-27.20 {variables declaration and [info vars]: Bug 2712377} -setup {
oo::class create Foo
set result {}
} -body {
# This is really a test of problems to do with Tcl's introspection when a
# variable resolver is present...
oo::define Foo {
variable foo bar
method setvars {f b} {
set foo $f
set bar $b
}
method dump1 {} {
lappend ::result <1>
foreach v [lsort [info vars *o]] {
lappend ::result $v=[set $v]
}
lappend ::result [info locals] [info locals *]
}
method dump2 {} {
lappend ::result <2>
foreach v [lsort [info vars *o]] {
lappend ::result $v=[set $v]
}
lappend ::result | foo=$foo [info locals] [info locals *]
}
}
Foo create stuff
stuff setvars what ever
stuff dump1
stuff dump2
return $result
} -cleanup {
Foo destroy
} -result {<1> foo=what v v <2> foo=what | foo=what v v}
test oo-27.21 {variables declaration uniqueifies: Bug 3396896} -setup {
oo::class create Foo
} -body {
oo::define Foo variable v v v t t v t
info class variable Foo
} -cleanup {
Foo destroy
} -result {v t}
test oo-27.22 {variables declaration uniqueifies: Bug 3396896} -setup {
oo::object create foo
} -body {
oo::objdefine foo variable v v v t t v t
info object variable foo
} -cleanup {
foo destroy
} -result {v t}
test oo-27.23 {variable resolver leakage: Bug 1493a43044} -setup {
oo::class create Super
oo::class create parent {
superclass Super
variable member1 member2
constructor {} {
set member1 parent1
set member2 parent2
}
method getChild {} {
Child new [self]
}
}
oo::class create Child {
superclass Super
variable member1 result
constructor {m} {
set [namespace current]::member1 child1
set ns [info object namespace $m]
namespace upvar $ns member1 l1 member2 l2
upvar 1 member1 l3 member2 l4
[format namespace] upvar $ns member1 l5 member2 l6
[format upvar] 1 member1 l7 member2 l8
set result [list $l1 $l2 $l3 $l4 $l5 $l6 $l7 $l8]
}
method result {} {return $result}
}
} -body {
[[parent new] getChild] result
} -cleanup {
Super destroy
} -result {parent1 parent2 parent1 parent2 parent1 parent2 parent1 parent2}
# A feature that's not supported because the mechanism may change without
# warning, but is supposed to work...
test oo-28.1 {scripted extensions to oo::define} -setup {
interp create foo
foo eval {oo::class create cls {export eval}}
} -cleanup {
interp delete foo
} -body {
foo eval {
proc oo::define::privateMethod {name arguments body} {
uplevel 1 [list method $name $arguments $body]
uplevel 1 [list unexport $name]
}
oo::define cls privateMethod m {x y} {return $x,$y}
cls create obj
list [catch {obj m 1 2}] [obj eval my m 3 4]
}
} -result {1 3,4}
test oo-29.1 {self class with object-defined methods} -setup {
oo::object create obj
} -body {
oo::objdefine obj method demo {} {
self class
}
obj demo
} -returnCodes error -cleanup {
obj destroy
} -result {method not defined by a class}
test oo-30.1 {Bug 2903011: deleting an object in a constructor} -setup {
oo::class create cls
} -body {
oo::define cls {constructor {} {[self] destroy}}
cls new
} -returnCodes error -cleanup {
cls destroy
} -result {object deleted in constructor}
test oo-30.2 {Bug 2903011: deleting an object in a constructor} -setup {
oo::class create cls
} -body {
oo::define cls {constructor {} {my destroy}}
cls new
} -returnCodes error -cleanup {
cls destroy
} -result {object deleted in constructor}
test oo-31.1 {Bug 3111059: when objects and coroutines entangle} -setup {
oo::class create cls
} -constraints memory -body {
oo::define cls {
method justyield {} {
yield
}
constructor {} {
coroutine coro my justyield
}
}
list [leaktest {[cls new] destroy}] [info class instances cls]
} -cleanup {
cls destroy
} -result {0 {}}
test oo-31.2 {Bug 3111059: when objects and coroutines entangle} -setup {
oo::class create cls
} -constraints memory -body {
oo::define cls {
method justyield {} {
yield
}
constructor {} {
coroutine coro my justyield
}
destructor {
rename coro {}
}
}
list [leaktest {[cls new] destroy}] [info class instances cls]
} -cleanup {
cls destroy
} -result {0 {}}
proc SampleSlotSetup script {
set script0 {
oo::class create SampleSlot {
superclass oo::Slot
constructor {} {
variable contents {a b c} ops {}
}
method contents {} {variable contents; return $contents}
method ops {} {variable ops; return $ops}
method Get {} {
variable contents
variable ops
lappend ops [info level] Get
return $contents
}
method Set {lst} {
variable contents $lst
variable ops
lappend ops [info level] Set $lst
return
}
}
}
append script0 \n$script
}
proc SampleSlotCleanup script {
set script0 {
SampleSlot destroy
}
append script \n$script0
}
test oo-32.1 {TIP 380: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot contents] [sampleSlot ops]
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {a b c} {}}
test oo-32.2 {TIP 380: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot -clear] \
[sampleSlot contents] [sampleSlot ops]
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {} {} {1 Set {}}}
test oo-32.3 {TIP 380: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot -append g h i] \
[sampleSlot contents] [sampleSlot ops]
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {} {a b c g h i} {1 Get 1 Set {a b c g h i}}}
test oo-32.4 {TIP 380: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot -set d e f] \
[sampleSlot contents] [sampleSlot ops]
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {} {d e f} {1 Set {d e f}}}
test oo-32.5 {TIP 380: slots - class test} -setup [SampleSlotSetup {
SampleSlot create sampleSlot
}] -body {
list [info level] [sampleSlot -set d e f] [sampleSlot -append g h i] \
[sampleSlot contents] [sampleSlot ops]
} -cleanup [SampleSlotCleanup {
rename sampleSlot {}
}] -result {0 {} {} {d e f g h i} {1 Set {d e f} 1 Get 1 Set {d e f g h i}}}
test oo-33.1 {TIP 380: slots - defaulting} -setup [SampleSlotSetup {
set s [SampleSlot new]
}] -body {
list [$s x y] [$s contents]
} -cleanup [SampleSlotCleanup {
rename $s {}
}] -result {{} {a b c x y}}
test oo-33.2 {TIP 380: slots - defaulting} -setup [SampleSlotSetup {
set s [SampleSlot new]
}] -body {
list [$s destroy; $s unknown] [$s contents]
} -cleanup [SampleSlotCleanup {
rename $s {}
}] -result {{} {a b c destroy unknown}}
test oo-33.3 {TIP 380: slots - defaulting} -setup [SampleSlotSetup {
set s [SampleSlot new]
}] -body {
oo::objdefine $s forward --default-operation my -set
list [$s destroy; $s unknown] [$s contents] [$s ops]
} -cleanup [SampleSlotCleanup {
rename $s {}
}] -result {{} unknown {1 Set destroy 1 Set unknown}}
test oo-33.4 {TIP 380: slots - errors} -setup [SampleSlotSetup {
set s [SampleSlot new]
}] -body {
# Method names beginning with "-" are special to slots
$s -grill q
} -returnCodes error -cleanup [SampleSlotCleanup {
rename $s {}
}] -result \
{unknown method "-grill": must be -append, -clear, -set, contents or ops}
test oo-34.1 {TIP 380: slots - presence} -setup {
set obj [oo::object new]
set result {}
} -body {
oo::define oo::object {
::lappend ::result [::info object class filter]
::lappend ::result [::info object class mixin]
::lappend ::result [::info object class superclass]
::lappend ::result [::info object class variable]
}
oo::objdefine $obj {
::lappend ::result [::info object class filter]
::lappend ::result [::info object class mixin]
::lappend ::result [::info object class variable]
}
return $result
} -cleanup {
$obj destroy
} -result {::oo::Slot ::oo::Slot ::oo::Slot ::oo::Slot ::oo::Slot ::oo::Slot ::oo::Slot}
test oo-34.2 {TIP 380: slots - presence} {
lsort [info class instances oo::Slot]
} {::oo::define::filter ::oo::define::mixin ::oo::define::superclass ::oo::define::variable ::oo::objdefine::filter ::oo::objdefine::mixin ::oo::objdefine::variable}
proc getMethods obj {
list [lsort [info object methods $obj -all]] \
[lsort [info object methods $obj -private]]
}
test oo-34.3 {TIP 380: slots - presence} {
getMethods oo::define::filter
} {{-append -clear -set} {Get Set}}
test oo-34.4 {TIP 380: slots - presence} {
getMethods oo::define::mixin
} {{-append -clear -set} {--default-operation Get Set}}
test oo-34.5 {TIP 380: slots - presence} {
getMethods oo::define::superclass
} {{-append -clear -set} {--default-operation Get Set}}
test oo-34.6 {TIP 380: slots - presence} {
getMethods oo::define::variable
} {{-append -clear -set} {Get Set}}
test oo-34.7 {TIP 380: slots - presence} {
getMethods oo::objdefine::filter
} {{-append -clear -set} {Get Set}}
test oo-34.8 {TIP 380: slots - presence} {
getMethods oo::objdefine::mixin
} {{-append -clear -set} {--default-operation Get Set}}
test oo-34.9 {TIP 380: slots - presence} {
getMethods oo::objdefine::variable
} {{-append -clear -set} {Get Set}}
test oo-35.1 {Bug 9d61624b3d: Empty superclass must not cause crash} -setup {
oo::class create fruit {
method eat {} {}
}
set result {}
} -body {
lappend result [fruit create ::apple] [info class superclasses fruit]
oo::define fruit superclass
lappend result [info class superclasses fruit] \
[info object class apple oo::object] \
[info class call fruit destroy] \
[catch { apple }]
} -cleanup {
unset -nocomplain result
fruit destroy
} -result {::apple ::oo::object ::oo::object 1 {{method destroy ::oo::object {core method: "destroy"}}} 1}
test oo-35.2 {Bug 9d61624b3d: Empty superclass must not cause crash} -setup {
oo::class create fruitMetaclass {
superclass oo::class
method eat {} {}
}
set result {}
} -body {
lappend result [fruitMetaclass create ::appleClass] \
[appleClass create orange] \
[info class superclasses fruitMetaclass]
oo::define fruitMetaclass superclass
lappend result [info class superclasses fruitMetaclass] \
[info object class appleClass oo::class] \
[catch { orange }] [info object class orange] \
[appleClass create pear]
} -cleanup {
unset -nocomplain result
fruitMetaclass destroy
} -result {::appleClass ::orange ::oo::class ::oo::class 1 1 ::appleClass ::pear}
test oo-35.3 {Bug 593baa032c: superclass list teardown} {
# Bug makes this crash, especially with mem-debugging on
oo::class create B {}
oo::class create D {superclass B}
namespace eval [info object namespace D] [list [namespace which B] destroy]
} {}
test oo-35.4 {Bug 593baa032c: mixins list teardown} {
# Bug makes this crash, especially with mem-debugging on
oo::class create B {}
oo::class create D {mixin B}
namespace eval [info object namespace D] [list [namespace which B] destroy]
} {}
test oo-35.5 {Bug 1a56550e96: introspectors must traverse mixin links correctly} -setup {
oo::class create base {
unexport destroy
}
} -body {
oo::class create C {
superclass base
method c {} {}
}
oo::class create D {
superclass base
mixin C
method d {} {}
}
oo::class create E {
superclass D
method e {} {}
}
E create e1
list [lsort [info class methods E -all]] [lsort [info object methods e1 -all]]
} -cleanup {
base destroy
} -result {{c d e} {c d e}}
test oo-35.6 {
Bug : teardown of an object that is a class that is an instance of itself
} -setup {
oo::class create obj
oo::copy obj obj1 obj1
oo::objdefine obj1 {
mixin obj1 obj
}
oo::copy obj1 obj2
oo::objdefine obj2 {
mixin obj2 obj1
}
} -body {
rename obj2 {}
rename obj1 {}
# doesn't crash
return done
} -cleanup {
rename obj {}
} -result done
cleanupTests
return
# Local Variables:
# MODE: Tcl
# End: