#--------------------------------------------------------------------- # TITLE: # typefunction.test # # AUTHOR: # Arnulf Wiedemann with a lot of code form the snit tests by # Will Duquette # # DESCRIPTION: # Test cases for ::itcl::type proc, method, typemethod commands. # Uses the ::tcltest:: harness. # # There is at least Tcl 8.6a3 needed # # The tests assume tcltest 2.2 #----------------------------------------------------------------------- # ### ### ### ######### ######### ######### ## Declare the minimal version of Tcl required to run the package ## tested by this testsuite, and its dependencies. proc testsNeedTcl {version} { # This command ensures that a minimum version of Tcl is used to # run the tests in the calling testsuite. If the minimum is not # met by the active interpreter we forcibly bail out of the # testsuite calling the command. The command has to be called # immediately after loading the utilities. if {[package vsatisfies [package provide Tcl] ${version}-]} return puts " Aborting the tests found in \"[file tail [info script]]\"" puts " Requiring at least Tcl $version, have [package provide Tcl]." # This causes a 'return' in the calling scope. return -code return } # ### ### ### ######### ######### ######### ## Declare the minimum version of Tcltest required to run the ## testsuite. proc testsNeedTcltest {version} { # This command ensure that a minimum version of the Tcltest # support package is used to run the tests in the calling # testsuite. If the minimum is not met by the loaded package we # forcibly bail out of the testsuite calling the command. The # command has to be called after loading the utilities. The only # command allowed to come before it is 'textNeedTcl' above. # Note that this command will try to load a suitable version of # Tcltest if the package has not been loaded yet. if {[lsearch [namespace children] ::tcltest] == -1} { if {![catch { package require tcltest $version }]} { namespace import -force ::tcltest::* return } } elseif {[package vcompare [package present tcltest] $version] >= 0} { namespace import -force ::tcltest::* return } puts " Aborting the tests found in [file tail [info script]]." puts " Requiring at least tcltest $version, have [package present tcltest]" # This causes a 'return' in the calling scope. return -code return } # Set up for Tk tests: enter the event loop long enough to catch # any bgerrors. proc tkbide {{msg "tkbide"} {msec 500}} { set ::bideVar 0 set ::bideError "" set ::bideErrorInfo "" # It looks like update idletasks does the job. if {0} { after $msec {set ::bideVar 1} tkwait variable ::bideVar } update idletasks if {"" != $::bideError} { error "$msg: $::bideError" $::bideErrorInfo } } testsNeedTcl 8.6 testsNeedTcltest 2.2 interp alias {} type {} ::itcl::type interp alias {} widgetadaptor {} ::itcl::widgetadaptor # Marks tests which are only for Tk. tcltest::testConstraint tk [expr {![catch {package require Tk}]}] ::tcltest::loadTestedCommands package require itcl #----------------------------------------------------------------------- # Widgetadaptors test widgetadaptor-1.1 {creating a widget: hull hijacking } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] $self configure {*}$args } delegate method * to itcl_hull delegate option * to itcl_hull } set xx [mylabel create .label -text "My Label"] set a [.label cget -text] set b [::itcl::internal::widgets::hull1.label cget -text] destroy .label tkbide list $a $b } -cleanup { mylabel destroy } -result {{My Label} {My Label}} test widgetadaptor-1.2 {destroying a widget with destroy } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .label set a [lsort [namespace children ::itcl::internal::variables]] destroy .label set b [lsort [namespace children ::itcl::internal::variables]] tkbide list $a $b } -cleanup { mylabel destroy } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.3 {destroying two widgets of the same type with destroy } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 mylabel create .lab2 set a [lsort [namespace children ::itcl::internal::variables]] destroy .lab1 destroy .lab2 set b [lsort [namespace children ::itcl::internal::variables]] tkbide list $a $b } -cleanup { mylabel destroy } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.4 {destroying a widget with rename, then destroy type } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .label set a [lsort [namespace children ::itcl::internal::variables]] rename .label "" set b [lsort [namespace children ::itcl::internal::variables]] mylabel destroy tkbide list $a $b } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.5 {destroying two widgets of the same type with rename } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 mylabel create .lab2 set a [lsort [namespace children ::itcl::internal::variables]] rename .lab1 "" rename .lab2 "" set b [lsort [namespace children ::itcl::internal::variables]] mylabel destroy tkbide list $a $b } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.6 {create/destroy twice, with destroy } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 set a [namespace children ::itcl::internal::variables] destroy .lab1 mylabel create .lab1 set b [namespace children ::itcl::internal::variables] destroy .lab1 set c [namespace children ::itcl::internal::variables] mylabel destroy tkbide list $a $b $c } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.7 {create/destroy twice, with rename } -constraints { tk } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 set a [namespace children ::itcl::internal::variables] rename .lab1 "" mylabel create .lab1 set b [namespace children ::itcl::internal::variables] rename .lab1 "" set c [namespace children ::itcl::internal::variables] mylabel destroy tkbide list $a $b $c } -result {{::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::oo}} test widgetadaptor-1.8 {"create" is optional } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } method howdy {} {return "Howdy!"} } mylabel .label set a [.label howdy] destroy .label tkbide set a } -cleanup { mylabel destroy } -result {Howdy!} test widgetadaptor-1.10 {"create" is optional, but must be a valid name } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } method howdy {} {return "Howdy!"} } catch {mylabel foo} result tkbide set result } -cleanup { mylabel destroy } -result {bad window path name "foo"} test widgetadaptor-1.11 {user-defined destructors are called } -constraints { tk } -body { widgetadaptor mylabel { typevariable flag "" constructor {args} { installhull [label $self] set flag "created $self" } destructor { set flag "destroyed $self" } typemethod getflag {} { return $flag } } mylabel .label set a [mylabel getflag] destroy .label tkbide list $a [mylabel getflag] } -cleanup { mylabel destroy } -result {{created ::itcl::internal::widgets::hull1.label} {destroyed ::itcl::internal::widgets::hull1.label}} test widgetadaptor-1.12 {Constructor errors tolerated } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} {error foo} destructor {} } # Without bug fix this will crash mylabel .label } -cleanup { mylabel destroy } -returnCodes error -result foo test widgetadaptor-1.14 {hull can be repeatedly renamed } -constraints { tk } -body { widgetadaptor basetype { constructor {args} { installhull [label $self] } method basemethod {} { return "basemethod" } } widgetadaptor w1 { constructor {args} { installhull [basetype create $self] } } widgetadaptor w2 { constructor {args} { installhull [w1 $self] } } set a [w2 .foo] destroy .foo tkbide set a } -cleanup { w2 destroy w1 destroy basetype destroy } -result {.foo} test widgetadaptor-1.15 {widget names can be generated } -constraints { tk } -body { widgetadaptor unique { constructor {args} { installhull [label $self] } } set w [unique .#auto] destroy $w tkbide set w } -cleanup { unique destroy } -result {.unique0} test widgetadaptor-1.16 {snit::widgetadaptor as hull } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] if {[llength $args]} { $self configure {*}$args } } method method1 {} { return "method1" } delegate option * to itcl_hull } widgetadaptor mylabel2 { constructor {args} { installhull [mylabel $self] $self configure {*}$args } method method2 {} { return "method2: [$itcl_hull method1]" } delegate option * to itcl_hull } mylabel2 .label -text "Some Text" set a [.label method2] set b [.label cget -text] .label configure -text "More Text" set c [.label cget -text] set d [lsort [namespace children ::itcl::internal::variables]] destroy .label set e [lsort [namespace children ::itcl::internal::variables]] mylabel2 destroy mylabel destroy tkbide list $a $b $c $d $e } -result {{method2: method1} {Some Text} {More Text} {::itcl::internal::variables::mylabel ::itcl::internal::variables::mylabel2 ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::mylabel2 ::itcl::internal::variables::oo}} test widgetadaptor-1.17 {snit::widgetadaptor as hull; use rename } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] $self configure {*}$args } method method1 {} { return "method1" } delegate option * to itcl_hull } widgetadaptor mylabel2 { constructor {args} { installhull [mylabel $self] $self configure {*}$args } method method2 {} { return "method2: [$itcl_hull method1]" } delegate option * to itcl_hull } mylabel2 .label -text "Some Text" set a [.label method2] set b [.label cget -text] .label configure -text "More Text" set c [.label cget -text] set d [lsort [namespace children ::itcl::internal::variables]] rename .label "" set e [lsort [namespace children ::itcl::internal::variables]] mylabel2 destroy mylabel destroy tkbide list $a $b $c $d $e } -result {{method2: method1} {Some Text} {More Text} {::itcl::internal::variables::mylabel ::itcl::internal::variables::mylabel2 ::itcl::internal::variables::oo} {::itcl::internal::variables::mylabel ::itcl::internal::variables::mylabel2 ::itcl::internal::variables::oo}} test widgetadaptor-1.19 {error in widgetadaptor constructor } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { error "Simulated Error" } } mylabel .lab } -returnCodes { error } -cleanup { mylabel destroy } -result {Simulated Error} test install-1.3 {can't install until hull exists } -constraints { tk } -body { widgetadaptor myframe { # Delegate an option just to make sure the component variable # exists. delegate option -font to text constructor {args} { installcomponent text using text $win.text -background green } } myframe .frm } -returnCodes { error } -cleanup { myframe destroy } -result {cannot install "text" before "itcl_hull" exists} test installhull-1.3 { options delegated to a widgetadaptor's itcl_hull frame with the same name are initialized from the option database. Note that there's no explicit code in Snit to do this; there's no way to change the adapted hull widget's -class, so the widget is simply being initialized normally. } -constraints { tk } -body { widgetadaptor myframe { delegate option -background to itcl_hull typeconstructor { option add *Frame.background red option add *Frame.width 123 } constructor {args} { installhull using frame } method getwid {} { $itcl_hull cget -width } } myframe .frm set a [.frm cget -background] set b [.frm getwid] destroy .frm tkbide list $a $b } -cleanup { myframe destroy } -result {red 123} test installhull-1.4 { Options delegated to a widget's itcl_hull frame with a different name are initialized from the option database. } -constraints { tk } -body { widgetadaptor myframe { delegate option -mainbackground to itcl_hull as -background typeconstructor { option add *Frame.mainbackground red } constructor {args} { installhull using frame } } myframe .frm set a [.frm cget -mainbackground] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {red} test installhull-1.5 { Option values read from the option database are overridden by options explicitly passed, even if delegated under a different name. } -constraints { tk } -body { widgetadaptor myframe { delegate option -mainbackground to itcl_hull as -background typeconstructor { option add *Frame.mainbackground red option add *Frame.width 123 } constructor {args} { installhull using frame -background green -width 321 } method getwid {} { $itcl_hull cget -width } } myframe .frm set a [.frm cget -mainbackground] set b [.frm getwid] destroy .frm tkbide list $a $b } -cleanup { myframe destroy } -result {green 321} test option-2.5 {configure returns info, unknown options } -constraints { tk } -body { widgetadaptor myframe { option -foo a delegate option -width to itcl_hull delegate option * to itcl_hull constructor {args} { # need to reset because of test installhull-1.5 option add *Frame.width 0 installhull [frame $self] } } myframe .frm set a [.frm configure -foo] set b [.frm configure -width] set c [.frm configure -height] destroy .frm tkbide list $a $b $c } -cleanup { myframe destroy } -result {{-foo foo Foo a a} {-width width Width 0 0} {-height height Height 0 0}} test option-2.6 {configure -opt unknown to implicit component } -constraints { tk } -body { widgetadaptor myframe { delegate option * to itcl_hull constructor {args} { installhull [frame $self] } } myframe .frm catch {.frm configure -quux} result destroy .frm tkbide set result } -cleanup { myframe destroy } -result {unknown option "-quux"} test iinfo-6.5 {info options with unknown delegated options } -constraints { tk } -body { widgetadaptor myframe { option -foo a delegate option * to itcl_hull constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -match glob -result {-background *-bd -bg*-borderwidth -class -colormap -container -cursor -foo -height -highlightbackground -highlightcolor -highlightthickness -padx -pady -relief -takefocus*-visual -width} test iinfo-6.7 {info options with exceptions } -constraints { tk } -body { widgetadaptor myframe { option -foo a delegate option * to itcl_hull except -background constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -match glob -result {*-bd -bg*-borderwidth -class -colormap -container -cursor -foo -height -highlightbackground -highlightcolor -highlightthickness -padx -pady -relief -takefocus*-visual -width} test iinfo-6.8 {info options with pattern } -constraints { tk } -body { widgetadaptor myframe { option -foo a delegate option * to itcl_hull constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options -c*]] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {-class -colormap -container -cursor} test tinfo-3.2 {widget info instances } -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } } mylabel .lab1 mylabel .lab2 set result [mylabel info instances] destroy .lab1 destroy .lab2 tkbide lsort $result } -cleanup { mylabel destroy } -result {.lab1 .lab2} test widgetclass-1.2 {can't set widgetclass for itcl::widgetadaptors } -constraints { tk } -body { widgetadaptor dog { widgetclass Dog } } -returnCodes { error } -result {can't set widgetclass for ::itcl::widgetadaptor} test hulltype-1.2 {can't set hulltype for itcl::widgetadaptors } -constraints { tk } -body { widgetadaptor dog { hulltype Dog } } -returnCodes { error } -result {can't set hulltype for ::itcl::widgetadaptor} test wainfo-10.1 {widgetadaptor info widgetadaptors } -constraints { tk } -body { widgetadaptor dog { } widgetadaptor cat { } lsort [dog info widgetadaptors] } -cleanup { dog destroy cat destroy } -result {cat dog} test wainfo-10.2 {widgetadaptor info components } -constraints { tk } -body { widgetadaptor dog { component comp1 component comp2 } widgetadaptor cat { component comp1 component comp1a } set a [lsort [dog info components]] set b [lsort [cat info components]] list $a $b } -cleanup { dog destroy cat destroy } -result {{comp1 comp2 itcl_hull} {comp1 comp1a itcl_hull}} #--------------------------------------------------------------------- # Clean up ::tcltest::cleanupTests return