# -*- tcl -*- #--------------------------------------------------------------------- # TITLE: # snit.test # # AUTHOR: # Will Duquette # # DESCRIPTION: # Test cases for snit.tcl. Uses the ::tcltest:: harness. # # If Tcl is 8.5, Snit 2.0 is loaded. # If Tcl is 8.4, Snit 1.2 is loaded. # If Tcl is 8.3, Snit 1.2 is loaded. (Kenneth Green's backport). # # Tests back-ported to Tcl 8.3 for snit 1.2 backport by kmg # Backport of test made general by Andreas Kupries. # # The tests assume tcltest 2.2 #----------------------------------------------------------------------- # Back-port to Tcl8.3 by Kenneth Green (kmg) # # Global changes: # " eq " => "string equal" # " ne " -> "!string equal" #----------------------------------------------------------------------- source [file join \ [file dirname [file dirname [file join [pwd] [info script]]]] \ devtools testutilities.tcl] testsNeedTcl 8.3 testsNeedTcltest 2.2 #--------------------------------------------------------------------- # Set up a number of constraints. This also determines which # implementation of snit is loaded and tested. # WHD: Work around bugs in 8.5a3 tcltest::testConstraint bug8.5a3 [expr {![string equal [info patchlevel] "8.5a3"]}] # Marks tests which are only for Tk. tcltest::testConstraint tk [info exists tk_version] # If Tk is available, require BWidget tcltest::testConstraint bwidget [expr { [tcltest::testConstraint tk] && ![catch {package require BWidget}] }] # Determine which Snit version to load. If Tcl 8.5, use 2.x. # Otherwise, use 1.x. (Different variants depending on 8.3 vs 8.4) if {[package vsatisfies [package present Tcl] 8.5]} { set snitVersion 2 set snitFile snit2.tcl } else { set snitVersion 1 set snitFile snit.tcl } # Marks tests which are only for Snit 1 tcltest::testConstraint snit1 [expr {$snitVersion == 1}] # Marks tests which are only for Snit 2 tcltest::testConstraint snit2 [expr {$snitVersion == 2}] # Marks tests which are only for Snit 1 with Tcl 8.3 tcltest::testConstraint tcl83 [string equal [info tclversion] "8.3"] tcltest::testConstraint tcl84 [package vsatisfies [package present Tcl] 8.4] if {[package vsatisfies [package provide Tcl] 8.6]} { # 8.6+ proc expect {six default} { return $six } } else { # 8.4/8.5 proc expect {six default} { return $default } } #--------------------------------------------------------------------- # Load the snit package. testing { useLocal $snitFile snit } #--------------------------------------------------------------------- namespace import ::snit::* # Set up for Tk tests: Repeat background errors proc bgerror {msg} { global errorInfo set ::bideError $msg set ::bideErrorInfo $errorInfo } # 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 } } # cleanup type proc cleanupType {name} { if {[namespace exists $name]} { if {[catch {$name destroy} result]} { global errorInfo puts $errorInfo error "Could not cleanup $name!" } } tkbide "cleanupType $name" } # cleanup before each test proc cleanup {} { global errorInfo cleanupType ::dog cleanupType ::cat cleanupType ::mylabel cleanupType ::myframe cleanupType ::foo cleanupType ::bar cleanupType ::tail cleanupType ::papers cleanupType ::animal cleanupType ::confused-dog catch {option clear} if {![string equal [info commands "spot"] ""]} { puts "spot not erased!" error "spot not erased!" } if {![string equal [info commands "fido"] ""]} { puts "fido not erased!" error "fido not erased!" } } # catch error code and error proc codecatch {command} { if {![catch {uplevel 1 $command} result]} { error "expected error, got OK" } return "$::errorCode $result" } #----------------------------------------------------------------------- # Internals: tests for Snit utility functions test Expand-1.1 {template, no arguments} -body { snit::Expand "My %TEMPLATE%" } -result {My %TEMPLATE%} test Expand-1.2 {template, no matching arguments} -body { snit::Expand "My %TEMPLATE%" %FOO% foo } -result {My %TEMPLATE%} test Expand-1.3 {template with matching arguments} -body { snit::Expand "%FOO% %BAR% %FOO%" %FOO% bar %BAR% foo } -result {bar foo bar} test Expand-1.4 {template with odd number of arguments} -body { snit::Expand "%FOO% %BAR% %FOO%" %FOO% } -result {char map list unbalanced} -returnCodes error test Mappend-1.1 {template, no arguments} -body { set text "Prefix: " snit::Mappend text "My %TEMPLATE%" } -cleanup { unset text } -result {Prefix: My %TEMPLATE%} test Mappend-1.2 {template, no matching arguments} -body { set text "Prefix: " snit::Mappend text "My %TEMPLATE%" %FOO% foo } -cleanup { unset text } -result {Prefix: My %TEMPLATE%} test Mappend-1.3 {template with matching arguments} -body { set text "Prefix: " snit::Mappend text "%FOO% %BAR% %FOO%" %FOO% bar %BAR% foo } -cleanup { unset text } -result {Prefix: bar foo bar} test Mappend-1.4 {template with odd number of arguments} -body { set text "Prefix: " snit::Mappend text "%FOO% %BAR% %FOO%" %FOO% } -cleanup { unset text } -returnCodes error -result {char map list unbalanced} test RT.UniqueName-1.1 {no name collision} -body { set counter 0 # Standard qualified type name. set n1 [snit::RT.UniqueName counter ::mytype ::my::%AUTO%] # Standard qualified widget name. set n2 [snit::RT.UniqueName counter ::mytype .my.%AUTO%] list $n1 $n2 } -result {::my::mytype1 .my.mytype2} -cleanup { unset counter n1 n2 } test RT.UniqueName-1.2 {name collision} -body { set counter 0 # Create the first two equivalent procs. proc ::mytype1 {} {} proc ::mytype2 {} {} # Create a new name; it should skip to 3. snit::RT.UniqueName counter ::mytype ::%AUTO% } -cleanup { unset counter rename ::mytype1 "" rename ::mytype2 "" } -result {::mytype3} test RT.UniqueName-1.3 {nested type name} -body { set counter 0 snit::RT.UniqueName counter ::thisis::yourtype ::your::%AUTO% } -cleanup { unset counter } -result {::your::yourtype1} test RT.UniqueInstanceNamespace-1.1 {no name collision} -setup { namespace eval ::mytype:: {} } -body { set counter 0 snit::RT.UniqueInstanceNamespace counter ::mytype } -cleanup { unset counter namespace delete ::mytype:: } -result {::mytype::Snit_inst1} test RT.UniqueInstanceNamespace-1.2 {name collision} -setup { namespace eval ::mytype:: {} namespace eval ::mytype::Snit_inst1:: {} namespace eval ::mytype::Snit_inst2:: {} } -body { set counter 0 # Should skip to 3. snit::RT.UniqueInstanceNamespace counter ::mytype } -cleanup { unset counter namespace delete ::mytype:: } -result {::mytype::Snit_inst3} test Contains-1.1 {contains element} -constraints { snit1 } -setup { set mylist {foo bar baz} } -body { snit::Contains baz $mylist } -cleanup { unset mylist } -result {1} test Contains-1.2 {does not contain element} -constraints { snit1 } -setup { set mylist {foo bar baz} } -body { snit::Contains quux $mylist } -cleanup { unset mylist } -result {0} #----------------------------------------------------------------------- # type compilation # snit::compile returns two values, the qualified type name # and the script to execute to define the type. This section # only checks the length of the list and the type name; # the content of the script is validated by the remainder # of this test suite. test compile-1.1 {compile returns qualified type} -body { set compResult [compile type dog { }] list [llength $compResult] [lindex $compResult 0] } -result {2 ::dog} #----------------------------------------------------------------------- # type destruction test typedestruction-1.1 {type command is deleted} -body { type dog { } dog destroy info command ::dog } -result {} test typedestruction-1.2 {instance commands are deleted} -body { type dog { } dog create spot dog destroy info command ::spot } -result {} test typedestruction-1.3 {type namespace is deleted} -body { type dog { } dog destroy namespace exists ::dog } -result {0} test typedestruction-1.4 {type proc is destroyed on error} -body { catch {type dog { error "Error creating dog" }} result list [namespace exists ::dog] [info command ::dog] } -result {0 {}} test typedestruction-1.5 {unrelated namespaces are deleted, bug 2898640} -body { type dog {} namespace eval dog::unrelated {} dog destroy } -result {} #----------------------------------------------------------------------- # type and typemethods test type-1.1 {type names get qualified} -body { type dog {} } -cleanup { dog destroy } -result {::dog} test type-1.2 {typemethods can be defined} -body { type dog { typemethod foo {a b} { return [list $a $b] } } dog foo 1 2 } -cleanup { dog destroy } -result {1 2} test type-1.3 {upvar works in typemethods} -body { type dog { typemethod goodname {varname} { upvar $varname myvar set myvar spot } } set thename fido dog goodname thename set thename } -cleanup { dog destroy unset thename } -result {spot} test type-1.4 {typemethod args can't include type} -body { type dog { typemethod foo {a type b} { } } } -returnCodes error -result {typemethod foo's arglist may not contain "type" explicitly} test type-1.5 {typemethod args can't include self} -body { type dog { typemethod foo {a self b} { } } } -returnCodes error -result {typemethod foo's arglist may not contain "self" explicitly} test type-1.6 {typemethod args can span multiple lines} -body { # This case caused an error at definition time in 0.9 because the # arguments were included in a comment in the compile script, and # the subsequent lines weren't commented. type dog { typemethod foo { a b } { } } } -cleanup { dog destroy } -result {::dog} #----------------------------------------------------------------------- # typeconstructor test typeconstructor-1.1 {a typeconstructor can be defined} -body { type dog { typevariable a typeconstructor { set a 1 } typemethod aget {} { return $a } } dog aget } -cleanup { dog destroy } -result {1} test typeconstructor-1.2 {only one typeconstructor can be defined} -body { type dog { typevariable a typeconstructor { set a 1 } typeconstructor { set a 2 } } } -returnCodes error -result {too many typeconstructors} test typeconstructor-1.3 {type proc is destroyed on error} -body { catch { type dog { typeconstructor { error "Error creating dog" } } } result list [namespace exists ::dog] [info command ::dog] } -result {0 {}} #----------------------------------------------------------------------- # Type components test typecomponent-1.1 {typecomponent defines typevariable} -body { type dog { typecomponent mycomp typemethod test {} { return $mycomp } } dog test } -cleanup { dog destroy } -result {} test typecomponent-1.2 {typecomponent trace executes} -body { type dog { typecomponent mycomp typemethod test {} { typevariable Snit_typecomponents set mycomp foo return $Snit_typecomponents(mycomp) } } dog test } -cleanup { dog destroy } -result {foo} test typecomponent-1.3 {typecomponent -public works} -body { type dog { typecomponent mycomp -public string typeconstructor { set mycomp string } } dog string length foo } -cleanup { dog destroy } -result {3} test typecomponent-1.4 {typecomponent -inherit yes} -body { type dog { typecomponent mycomp -inherit yes typeconstructor { set mycomp string } } dog length foo } -cleanup { dog destroy } -result {3} #----------------------------------------------------------------------- # hierarchical type methods test htypemethod-1.1 {hierarchical method, two tokens} -body { type dog { typemethod {wag tail} {} { return "wags tail" } } dog wag tail } -cleanup { dog destroy } -result {wags tail} test htypemethod-1.2 {hierarchical method, three tokens} -body { type dog { typemethod {wag tail proudly} {} { return "wags tail proudly" } } dog wag tail proudly } -cleanup { dog destroy } -result {wags tail proudly} test htypemethod-1.3 {hierarchical method, four tokens} -body { type dog { typemethod {wag tail really high} {} { return "wags tail really high" } } dog wag tail really high } -cleanup { dog destroy } -result {wags tail really high} test htypemethod-1.4 {redefinition is OK} -body { type dog { typemethod {wag tail} {} { return "wags tail" } typemethod {wag tail} {} { return "wags tail briskly" } } dog wag tail } -cleanup { dog destroy } -result {wags tail briskly} # Case 1 test htypemethod-1.5 {proper error on missing submethod} -constraints { snit1 } -body { cleanup type dog { typemethod {wag tail} {} { } } dog wag } -returnCodes { error } -cleanup { dog destroy } -result {wrong number args: should be "::dog wag method args"} # Case 2 test htypemethod-1.6 {proper error on missing submethod} -constraints { snit2 } -body { cleanup type dog { typemethod {wag tail} {} { } } dog wag } -returnCodes { error } -cleanup { dog destroy } -result [expect \ {wrong # args: should be "dog wag subcommand ?arg ...?"} \ {wrong # args: should be "dog wag subcommand ?argument ...?"}] # Case 1 test htypemethod-1.7 {proper error on bogus submethod} -constraints { snit1 } -body { cleanup type dog { typemethod {wag tail} {} { } } dog wag ears } -returnCodes { error } -cleanup { dog destroy } -result {"::dog wag ears" is not defined} # Case 2 test htypemethod-1.8 {proper error on bogus submethod} -constraints { snit2 } -body { cleanup type dog { typemethod {wag tail} {} { } } dog wag ears } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "ears": namespace ::dog does not export any commands} test htypemethod-2.1 {prefix/method collision, level 1, order 1} -body { type dog { typemethod wag {} {} typemethod {wag tail} {} {} } } -returnCodes { error } -result {Error in "typemethod {wag tail}...", "wag" has no submethods.} test htypemethod-2.2 {prefix/method collision, level 1, order 2} -body { type dog { typemethod {wag tail} {} {} typemethod wag {} {} } } -returnCodes { error } -result {Error in "typemethod wag...", "wag" has submethods.} test htypemethod-2.3 {prefix/method collision, level 2, order 1} -body { type dog { typemethod {wag tail} {} {} typemethod {wag tail proudly} {} {} } } -returnCodes { error } -result {Error in "typemethod {wag tail proudly}...", "wag tail" has no submethods.} test htypemethod-2.4 {prefix/method collision, level 2, order 2} -body { type dog { typemethod {wag tail proudly} {} {} typemethod {wag tail} {} {} } } -returnCodes { error } -result {Error in "typemethod {wag tail}...", "wag tail" has submethods.} #----------------------------------------------------------------------- # Typemethod delegation test dtypemethod-1.1 {delegate typemethod to non-existent component} -body { set result "" type dog { delegate typemethod foo to bar } dog foo } -returnCodes { error } -result {::dog delegates typemethod "foo" to undefined typecomponent "bar"} test dtypemethod-1.2 {delegating to existing typecomponent} -body { type dog { delegate typemethod length to string typeconstructor { set string string } } dog length foo } -cleanup { dog destroy } -result {3} # Case 1 test dtypemethod-1.3 {delegating to existing typecomponent with error} -constraints { snit1 } -body { type dog { delegate typemethod length to string typeconstructor { set string string } } dog length foo bar } -returnCodes { error } -result {wrong # args: should be "string length string"} # Case 2 test dtypemethod-1.4 {delegating to existing typecomponent with error} -constraints { snit2 } -body { type dog { delegate typemethod length to string typeconstructor { set string string } } dog length foo bar } -returnCodes { error } -result {wrong # args: should be "dog length string"} test dtypemethod-1.5 {delegating unknown typemethods to existing typecomponent} -body { type dog { delegate typemethod * to string typeconstructor { set string string } } dog length foo } -cleanup { dog destroy } -result {3} # Case 1 test dtypemethod-1.6 {delegating unknown typemethod to existing typecomponent with error} -body { type dog { delegate typemethod * to stringhandler typeconstructor { set stringhandler string } } dog foo bar } -constraints { snit1 } -returnCodes { error } -result {bad option "foo": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart} test dtypemethod-1.6a {delegating unknown typemethod to existing typecomponent with error} -body { type dog { delegate typemethod * to stringhandler typeconstructor { set stringhandler string } } dog foo bar } -constraints { snit2 } -returnCodes { error } -result {unknown or ambiguous subcommand "foo": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, reverse, tolower, totitle, toupper, trim, trimleft, trimright, wordend, or wordstart} test dtypemethod-1.7 {can't delegate local typemethod: order 1} -body { type dog { typemethod foo {} {} delegate typemethod foo to bar } } -returnCodes { error } -result {Error in "delegate typemethod foo...", "foo" has been defined locally.} test dtypemethod-1.8 {can't delegate local typemethod: order 2} -body { type dog { delegate typemethod foo to bar typemethod foo {} {} } } -returnCodes { error } -result {Error in "typemethod foo...", "foo" has been delegated} # Case 1 test dtypemethod-1.9 {excepted methods are caught properly} -constraints { snit1 } -body { type dog { delegate typemethod * to string except {match index} typeconstructor { set string string } } catch {dog length foo} a catch {dog match foo} b catch {dog index foo} c list $a $b $c } -cleanup { dog destroy } -result {3 {"::dog match" is not defined} {"::dog index" is not defined}} # Case 2 test dtypemethod-1.10 {excepted methods are caught properly} -constraints { snit2 } -body { type dog { delegate typemethod * to string except {match index} typeconstructor { set string string } } catch {dog length foo} a catch {dog match foo} b catch {dog index foo} c list $a $b $c } -cleanup { dog destroy } -result {3 {unknown subcommand "match": must be length} {unknown subcommand "index": must be length}} test dtypemethod-1.11 {as clause can include arguments} -body { proc tail {a b} { return "<$a $b>" } type dog { delegate typemethod wag to tail as {wag briskly} typeconstructor { set tail tail } } dog wag } -cleanup { dog destroy rename tail "" } -result {} test dtypemethod-2.1 {'using "%c %m"' gets normal behavior} -body { type dog { delegate typemethod length to string using {%c %m} typeconstructor { set string string } } dog length foo } -cleanup { dog destroy } -result {3} test dtypemethod-2.2 {All relevant 'using' conversions are converted} -body { proc echo {args} { return $args } type dog { delegate typemethod {tail wag} using {echo %% %t %M %m %j %n %w %s %c} } dog tail wag } -cleanup { dog destroy rename echo "" } -result {% ::dog {tail wag} wag tail_wag %n %w %s %c} test dtypemethod-2.3 {"%%" is handled properly} -body { proc echo {args} { join $args "|" } type dog { delegate typemethod wag using {echo %%m %%%m} } dog wag } -cleanup { dog destroy rename echo "" } -result {%m|%wag} test dtypemethod-2.4 {Method "*" and "using"} -body { proc echo {args} { join $args "|" } type dog { delegate typemethod * using {echo %m} } list [dog wag] [dog bark loudly] } -cleanup { dog destroy rename echo "" } -result {wag bark|loudly} test dtypemethod-3.1 {typecomponent names can be changed dynamically} -body { proc echo {args} { join $args "|" } type dog { delegate typemethod length to mycomp typeconstructor { set mycomp string } typemethod switchit {} { set mycomp echo } } set a [dog length foo] dog switchit set b [dog length foo] list $a $b } -cleanup { dog destroy rename echo "" } -result {3 length|foo} test dtypemethod-4.1 {hierarchical typemethod, two tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {wag tail} to tail as wag } dog wag tail } -cleanup { dog destroy tail destroy } -result {wags tail} test dtypemethod-4.2 {hierarchical typemethod, three tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {wag tail proudly} to tail as wag } dog wag tail proudly } -cleanup { dog destroy tail destroy } -result {wags tail} test dtypemethod-4.3 {hierarchical typemethod, four tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {wag tail really high} to tail as wag } dog wag tail really high } -cleanup { dog destroy tail destroy } -result {wags tail} test dtypemethod-4.4 {redefinition is OK} -body { type tail { method {wag tail} {} {return "wags tail"} method {wag briskly} {} {return "wags tail briskly"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {wag tail} to tail as {wag tail} delegate typemethod {wag tail} to tail as {wag briskly} } dog wag tail } -cleanup { dog destroy tail destroy } -result {wags tail briskly} test dtypemethod-4.5 {last token is used by default} -body { type tail { method wag {} {return "wags tail"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {tail wag} to tail } dog tail wag } -cleanup { dog destroy tail destroy } -result {wags tail} test dtypemethod-4.6 {last token can be *} -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {tail *} to tail } list [dog tail wag] [dog tail droop] } -cleanup { dog destroy tail destroy } -result {wags droops} # Case 2 test dtypemethod-4.7 {except with multiple tokens} -constraints { snit1 } -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {tail *} to tail except droop } catch {dog tail droop} result list [dog tail wag] $result } -cleanup { dog destroy tail destroy } -result {wags {"::dog tail droop" is not defined}} # Case 2 test dtypemethod-4.8 {except with multiple tokens} -constraints { snit2 } -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { typeconstructor { set tail [tail %AUTO%] } delegate typemethod {tail *} to tail except droop } catch {dog tail droop} result list [dog tail wag] $result } -cleanup { dog destroy tail destroy } -result {wags {unknown subcommand "droop": namespace ::dog does not export any commands}} test dtypemethod-4.9 {"*" in the wrong spot} -body { type dog { delegate typemethod {tail * wag} to tail } } -returnCodes { error } -result {Error in "delegate typemethod {tail * wag}...", "*" must be the last token.} test dtypemethod-5.1 {prefix/typemethod collision} -body { type dog { delegate typemethod wag to tail delegate typemethod {wag tail} to tail as wag } } -returnCodes { error } -result {Error in "delegate typemethod {wag tail}...", "wag" has no submethods.} test dtypemethod-5.2 {prefix/typemethod collision} -body { type dog { delegate typemethod {wag tail} to tail as wag delegate typemethod wag to tail } } -returnCodes { error } -result {Error in "delegate typemethod wag...", "wag" has submethods.} test dtypemethod-5.3 {prefix/typemethod collision} -body { type dog { delegate typemethod {wag tail} to tail delegate typemethod {wag tail proudly} to tail as wag } } -returnCodes { error } -result {Error in "delegate typemethod {wag tail proudly}...", "wag tail" has no submethods.} test dtypemethod-5.4 {prefix/typemethod collision} -body { type dog { delegate typemethod {wag tail proudly} to tail as wag delegate typemethod {wag tail} to tail } } -returnCodes { error } -result {Error in "delegate typemethod {wag tail}...", "wag tail" has submethods.} #----------------------------------------------------------------------- # type creation test creation-1.1 {type instance names get qualified} -body { type dog { } dog create spot } -cleanup { dog destroy } -result {::spot} test creation-1.2 {type instance names can be generated} -body { type dog { } dog create my%AUTO% } -cleanup { dog destroy } -result {::mydog1} test creation-1.3 {"create" method is optional} -body { type dog { } dog fido } -cleanup { dog destroy } -result {::fido} test creation-1.4 {constructor arg can't be type} -body { type dog { constructor {type} { } } } -returnCodes { error } -result {constructor's arglist may not contain "type" explicitly} test creation-1.5 {constructor arg can't be self} -body { type dog { constructor {self} { } } } -returnCodes { error } -result {constructor's arglist may not contain "self" explicitly} test creation-1.6 {weird names are OK} -body { # I.e., names with non-identifier characters type confused-dog { method meow {} { return "$self meows." } } confused-dog spot spot meow } -cleanup { confused-dog destroy } -result {::spot meows.} # Case 1 test creation-1.7 {If -hasinstances yes, [$type] == [$type create %AUTO%]} -constraints { snit1 } -body { type dog { variable dummy } set mydog [dog] } -cleanup { $mydog destroy dog destroy } -result {::dog1} # Case 2 test creation-1.8 {If -hasinstances yes, [$type] == [$type create %AUTO%]} -constraints { snit2 } -body { type dog { # WHD: In Snit 1.0, this pragma was not needed. pragma -hastypemethods no variable dummy } set mydog [dog] } -cleanup { # [dog destroy] doesn't exist $mydog destroy namespace delete ::dog } -result {::dog1} # Case 1 test creation-1.9 {If -hasinstances no, [$type] != [$type create %AUTO%]} -constraints { snit1 } -body { type dog { pragma -hasinstances no } set mydog [dog] } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "::dog method args"} # Case 2 test creation-1.10 {If -hasinstances no, [$type] != [$type create %AUTO%]} -constraints { snit2 } -body { type dog { pragma -hasinstances no } set mydog [dog] } -cleanup { dog destroy } -returnCodes { error } -result [expect \ {wrong # args: should be "dog subcommand ?arg ...?"} \ {wrong # args: should be "dog subcommand ?argument ...?"}] # Case 1 test creation-1.11 {If widget, [$type] != [$type create %AUTO%]} -constraints { snit1 tk } -body { widget dog { variable dummy } set mydog [dog] } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "::dog method args"} # Case 2 test creation-1.12 {If widget, [$type] != [$type create %AUTO%]} -constraints { snit2 tk } -body { widget dog { variable dummy } set mydog [dog] } -cleanup { dog destroy } -returnCodes { error } -result [expect \ {wrong # args: should be "dog subcommand ?arg ...?"} \ {wrong # args: should be "dog subcommand ?argument ...?"}] test creation-1.13 {If -hastypemethods yes, [$type] == [$type create %AUTO%]} -constraints { snit1 } -body { type dog { variable dummy } set mydog [dog] } -cleanup { dog destroy } -result {::dog1} test creation-1.14 {If -hastypemethods yes, [$type] != [$type create %AUTO%]} -constraints { snit2 } -body { type dog { variable dummy } set mydog [dog] } -cleanup { dog destroy } -returnCodes { error } -result [expect \ {wrong # args: should be "dog subcommand ?arg ...?"} \ {wrong # args: should be "dog subcommand ?argument ...?"}] test creation-2.1 {Can't call "destroy" in constructor} -body { type dog { constructor {} { $self destroy } } dog spot } -cleanup { dog destroy } -returnCodes { error } -result {Error in constructor: Called 'destroy' method in constructor} #----------------------------------------------------------------------- # procs test proc-1.1 {proc args can span multiple lines} -body { # This case caused an error at definition time in 0.9 because the # arguments were included in a comment in the compile script, and # the subsequent lines weren't commented. type dog { proc foo { a b } { } } } -cleanup { dog destroy } -result {::dog} #----------------------------------------------------------------------- # methods test method-1.1 {methods get called} -body { type dog { method bark {} { return "$self barks" } } dog create spot spot bark } -cleanup { dog destroy } -result {::spot barks} test method-1.2 {methods can call other methods} -body { type dog { method bark {} { return "$self barks." } method chase {quarry} { return "$self chases $quarry; [$self bark]" } } dog create spot spot chase cat } -cleanup { dog destroy } -result {::spot chases cat; ::spot barks.} test method-1.3 {instances can call one another} -body { type dog { method bark {} { return "$self barks." } method chase {quarry} { return "$self chases $quarry; [$quarry bark] [$self bark]" } } dog create spot dog create fido spot chase ::fido } -cleanup { dog destroy } -result {::spot chases ::fido; ::fido barks. ::spot barks.} test method-1.4 {upvar works in methods} -body { type dog { method goodname {varname} { upvar $varname myvar set myvar spot } } dog create fido set thename fido fido goodname thename set thename } -cleanup { dog destroy } -result {spot} # Case 1 test method-1.5 {unknown methods get an error} -constraints { snit1 } -body { type dog { } dog create spot set result "" spot chase } -cleanup { dog destroy } -returnCodes { error } -result {"::spot chase" is not defined} # Case 2 test method-1.6 {unknown methods get an error} -constraints { snit2 } -body { type dog { } dog create spot set result "" spot chase } -cleanup { dog destroy } -returnCodes { error } -result {unknown subcommand "chase": namespace ::dog::Snit_inst1 does not export any commands} test method-1.7 {info type method returns the object's type} -body { type dog { } dog create spot spot info type } -cleanup { dog destroy } -result {::dog} test method-1.8 {instance method can call type method} -body { type dog { typemethod hello {} { return "Hello" } method helloworld {} { return "[$type hello], World!" } } dog create spot spot helloworld } -cleanup { dog destroy } -result {Hello, World!} test method-1.9 {type methods must be qualified} -body { type dog { typemethod hello {} { return "Hello" } method helloworld {} { return "[hello], World!" } } dog create spot spot helloworld } -cleanup { dog destroy } -returnCodes { error } -result {invalid command name "hello"} # Case 1 test method-1.10 {too few arguments} -constraints { snit1 } -body { type dog { method bark {volume} { } } dog create spot spot bark } -cleanup { dog destroy } -returnCodes { error } -result [tcltest::wrongNumArgs ::dog::Snit_methodbark {type selfns win self volume} 4] # Case 2 test method-1.11 {too few arguments} -constraints { snit2 } -body { type dog { method bark {volume} { } } dog create spot spot bark } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "spot bark volume"} # Case 1 test method-1.12 {too many arguments} -constraints { snit1 } -body { type dog { method bark {volume} { } } dog create spot spot bark really loud } -returnCodes { error } -result [tcltest::tooManyArgs ::dog::Snit_methodbark {type selfns win self volume}] # Case 2 test method-1.13 {too many arguments} -constraints { snit2 } -body { type dog { method bark {volume} { } } dog create spot spot bark really loud } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "spot bark volume"} test method-1.14 {method args can't include type} -body { type dog { method foo {a type b} { } } } -returnCodes { error } -result {method foo's arglist may not contain "type" explicitly} test method-1.15 {method args can't include self} -body { type dog { method foo {a self b} { } } } -returnCodes { error } -result {method foo's arglist may not contain "self" explicitly} test method-1.16 {method args can span multiple lines} -body { # This case caused an error at definition time in 0.9 because the # arguments were included in a comment in the compile script, and # the subsequent lines weren't commented. type dog { method foo { a b } { } } } -cleanup { dog destroy } -result {::dog} #----------------------------------------------------------------------- # hierarchical methods test hmethod-1.1 {hierarchical method, two tokens} -body { type dog { method {wag tail} {} { return "$self wags tail." } } dog spot spot wag tail } -cleanup { dog destroy } -result {::spot wags tail.} test hmethod-1.2 {hierarchical method, three tokens} -body { type dog { method {wag tail proudly} {} { return "$self wags tail proudly." } } dog spot spot wag tail proudly } -cleanup { dog destroy } -result {::spot wags tail proudly.} test hmethod-1.3 {hierarchical method, three tokens} -body { type dog { method {wag tail really high} {} { return "$self wags tail really high." } } dog spot spot wag tail really high } -cleanup { dog destroy } -result {::spot wags tail really high.} test hmethod-1.4 {redefinition is OK} -body { type dog { method {wag tail} {} { return "$self wags tail." } method {wag tail} {} { return "$self wags tail briskly." } } dog spot spot wag tail } -cleanup { dog destroy } -result {::spot wags tail briskly.} # Case 1 test hmethod-1.5 {proper error on missing submethod} -constraints { snit1 } -body { type dog { method {wag tail} {} { } } dog spot spot wag } -cleanup { dog destroy } -returnCodes { error } -result {wrong number args: should be "::spot wag method args"} # Case 2 test hmethod-1.6 {proper error on missing submethod} -constraints { snit2 } -body { type dog { method {wag tail} {} { } } dog spot spot wag } -cleanup { dog destroy } -returnCodes { error } -result [expect \ {wrong # args: should be "spot wag subcommand ?arg ...?"} \ {wrong # args: should be "spot wag subcommand ?argument ...?"}] test hmethod-1.7 {submethods called in proper objects} -body { # NOTE: This test was added in response to a bug report by # Anton Kovalenko. In Snit 2.0, submethod ensembles were # created in the type namespace. If a type defines a submethod # ensemble, then all objects of that type would end up sharing # a single ensemble. Ensembles are created lazily, so in this # test, the first call to "fido this tail wag" and "spot this tail wag" # will yield the correct result, but the second call to # "fido this tail wag" will yield the same as the call to # "spot this tail wag", because spot's submethod ensemble has # displaced fido's. Until the bug is fixed, that is. # # Fortunately, Anton provided the fix as well. type tail { option -manner method wag {} { return "wags tail $options(-manner)" } } type dog { delegate option -manner to tail delegate method {this tail wag} to tail constructor {args} { set tail [tail %AUTO%] $self configurelist $args } } dog fido -manner briskly dog spot -manner slowly list [fido this tail wag] [spot this tail wag] [fido this tail wag] } -cleanup { dog destroy tail destroy } -result {{wags tail briskly} {wags tail slowly} {wags tail briskly}} test hmethod-2.1 {prefix/method collision} -body { type dog { method wag {} {} method {wag tail} {} { return "$self wags tail." } } } -returnCodes { error } -result {Error in "method {wag tail}...", "wag" has no submethods.} test hmethod-2.2 {prefix/method collision} -body { type dog { method {wag tail} {} { return "$self wags tail." } method wag {} {} } } -returnCodes { error } -result {Error in "method wag...", "wag" has submethods.} test hmethod-2.3 {prefix/method collision} -body { type dog { method {wag tail} {} {} method {wag tail proudly} {} { return "$self wags tail." } } } -returnCodes { error } -result {Error in "method {wag tail proudly}...", "wag tail" has no submethods.} test hmethod-2.4 {prefix/method collision} -body { type dog { method {wag tail proudly} {} { return "$self wags tail." } method {wag tail} {} {} } } -returnCodes { error } -result {Error in "method {wag tail}...", "wag tail" has submethods.} #----------------------------------------------------------------------- # mymethod and renaming test rename-1.1 {mymethod uses name of instance name variable} -body { type dog { method mymethod {} { list [mymethod] [mymethod "A B"] [mymethod A B] } } dog fido fido mymethod } -cleanup { dog destroy } -result {{::snit::RT.CallInstance ::dog::Snit_inst1} {::snit::RT.CallInstance ::dog::Snit_inst1 {A B}} {::snit::RT.CallInstance ::dog::Snit_inst1 A B}} test rename-1.2 {instances can be renamed} -body { type dog { method names {} { list [mymethod] $selfns $win $self } } dog fido set a [fido names] rename fido spot set b [spot names] concat $a $b } -cleanup { dog destroy } -result {{::snit::RT.CallInstance ::dog::Snit_inst1} ::dog::Snit_inst1 ::fido ::fido {::snit::RT.CallInstance ::dog::Snit_inst1} ::dog::Snit_inst1 ::fido ::spot} test rename-1.3 {rename to "" deletes an instance} -constraints { bug8.5a3 } -body { type dog { } dog fido rename fido "" namespace children ::dog } -cleanup { dog destroy } -result {} test rename-1.4 {rename to "" deletes an instance even after a rename} -constraints { bug8.5a3 } -body { type dog { } dog fido rename fido spot rename spot "" namespace children ::dog } -cleanup { dog destroy } -result {} test rename-1.5 {creating an object twice destroys the first instance} -constraints { bug8.5a3 } -body { type dog { # Can't even test this normally. pragma -canreplace yes } dog fido set a [namespace children ::dog] dog fido set b [namespace children ::dog] fido destroy set c [namespace children ::dog] list $a $b $c } -cleanup { dog destroy } -result {::dog::Snit_inst1 ::dog::Snit_inst2 {}} #----------------------------------------------------------------------- # mymethod actually works test mymethod-1.1 {run mymethod handler} -body { type foo { option -command {} method runcmd {} { eval [linsert $options(-command) end $self snarf] return } } type bar { variable sub constructor {args} { set sub [foo fubar -command [mymethod Handler]] return } method Handler {args} { set ::RES $args } method test {} { $sub runcmd return } } set ::RES {} bar boogle boogle test set ::RES } -cleanup { bar destroy foo destroy } -result {::bar::fubar snarf} #----------------------------------------------------------------------- # myproc test myproc-1.1 {myproc qualifies proc names} -body { type dog { proc foo {} {} typemethod getit {} { return [myproc foo] } } dog getit } -cleanup { dog destroy } -result {::dog::foo} test myproc-1.2 {myproc adds arguments} -body { type dog { proc foo {} {} typemethod getit {} { return [myproc foo "a b"] } } dog getit } -cleanup { dog destroy } -result {::dog::foo {a b}} test myproc-1.3 {myproc adds arguments} -body { type dog { proc foo {} {} typemethod getit {} { return [myproc foo "a b" c d] } } dog getit } -cleanup { dog destroy } -result {::dog::foo {a b} c d} test myproc-1.4 {procs with selfns work} -body { type dog { variable datum foo method qualify {} { return [myproc getdatum $selfns] } proc getdatum {selfns} { return $datum } } dog create spot eval [spot qualify] } -cleanup { dog destroy } -result {foo} #----------------------------------------------------------------------- # mytypemethod test mytypemethod-1.1 {mytypemethod qualifies typemethods} -body { type dog { typemethod this {} {} typemethod a {} { return [mytypemethod this] } typemethod b {} { return [mytypemethod this x] } typemethod c {} { return [mytypemethod this "x y"] } typemethod d {} { return [mytypemethod this x y] } } list [dog a] [dog b] [dog c] [dog d] } -cleanup { dog destroy } -result {{::dog this} {::dog this x} {::dog this {x y}} {::dog this x y}} #----------------------------------------------------------------------- # typevariable test typevariable-1.1 {typevarname qualifies typevariables} -body { # Note: typevarname is DEPRECATED. Real code should use # mytypevar instead. type dog { method tvname {name} { typevarname $name } } dog create spot spot tvname myvar } -cleanup { dog destroy } -result {::dog::myvar} test typevariable-1.2 {undefined typevariables are OK} -body { type dog { method tset {value} { typevariable theValue set theValue $value } method tget {} { typevariable theValue return $theValue } } dog create spot dog create fido spot tset Howdy list [spot tget] [fido tget] [set ::dog::theValue] } -cleanup { dog destroy } -result {Howdy Howdy Howdy} test typevariable-1.3 {predefined typevariables are OK} -body { type dog { typevariable greeting Hello method tget {} { return $greeting } } dog create spot dog create fido list [spot tget] [fido tget] [set ::dog::greeting] } -cleanup { dog destroy } -result {Hello Hello Hello} test typevariable-1.4 {typevariables can be arrays} -body { type dog { typevariable greetings method fill {} { set greetings(a) Hi set greetings(b) Howdy } } dog create spot spot fill list $::dog::greetings(a) $::dog::greetings(b) } -cleanup { dog destroy } -result {Hi Howdy} test typevariable-1.5 {typevariables can used in typemethods} -body { type dog { typevariable greetings Howdy typemethod greet {} { return $greetings } } dog greet } -cleanup { dog destroy } -result {Howdy} test typevariable-1.6 {typevariables can used in procs} -body { type dog { typevariable greetings Howdy method greet {} { return [realGreet] } proc realGreet {} { return $greetings } } dog create spot spot greet } -cleanup { dog destroy } -result {Howdy} test typevariable-1.7 {mytypevar qualifies typevariables} -body { type dog { method tvname {name} { mytypevar $name } } dog create spot spot tvname myvar } -cleanup { dog destroy } -result {::dog::myvar} test typevariable-1.8 {typevariable with too many initializers throws an error} -body { type dog { typevariable color dark brown } } -returnCodes { error } -result {Error in "typevariable color...", too many initializers} test typevariable-1.9 {typevariable with too many initializers throws an error} -body { type dog { typevariable color -array dark brown } set result } -returnCodes { error } -result {Error in "typevariable color...", too many initializers} test typevariable-1.10 {typevariable can initialize array variables} -body { type dog { typevariable data -array { family jones color brown } typemethod getdata {item} { return $data($item) } } list [dog getdata family] [dog getdata color] } -cleanup { dog destroy } -result {jones brown} #----------------------------------------------------------------------- # instance variable test ivariable-1.1 {myvar qualifies instance variables} -body { type dog { method vname {name} { myvar $name } } dog create spot spot vname somevar } -cleanup { dog destroy } -result {::dog::Snit_inst1::somevar} test ivariable-1.2 {undefined instance variables are OK} -body { type dog { method setgreeting {value} { variable greeting set greeting $value } method getgreeting {} { variable greeting return $greeting } } set spot [dog create spot] spot setgreeting Hey dog create fido fido setgreeting Howdy list [spot getgreeting] [fido getgreeting] [set ::dog::Snit_inst1::greeting] } -cleanup { dog destroy } -result {Hey Howdy Hey} test ivariable-1.3 {instance variables are destroyed automatically} -body { type dog { constructor {args} { variable greeting set greeting Hi } } dog create spot set g1 $::dog::Snit_inst1::greeting spot destroy list $g1 [info exists ::dog::Snit_inst1::greeting] } -cleanup { dog destroy } -result {Hi 0} test ivariable-1.4 {defined instance variables need not be declared} -body { type dog { variable greetings method put {} { set greetings Howdy } method get {} { return $greetings } } dog create spot spot put spot get } -cleanup { dog destroy } -result {Howdy} test ivariable-1.5 {instance variables can be arrays} -body { type dog { variable greetings method fill {} { set greetings(a) Hi set greetings(b) Howdy } method vname {} { return [myvar greetings] } } dog create spot spot fill list [set [spot vname](a)] [set [spot vname](b)] } -cleanup { dog destroy } -result {Hi Howdy} test ivariable-1.6 {instance variables can be initialized in the definition} -body { type dog { variable greetings {Hi Howdy} variable empty {} method list {} { list $greetings $empty } } dog create spot spot list } -cleanup { dog destroy } -result {{Hi Howdy} {}} test ivariable-1.7 {variable is illegal when selfns is undefined} -body { type dog { method caller {} { callee } proc callee {} { variable foo } } dog create spot spot caller } -returnCodes { error } -cleanup { dog destroy } -result {can't read "selfns": no such variable} test ivariable-1.8 {myvar is illegal when selfns is undefined} -body { type dog { method caller {} { callee } proc callee {} { myvar foo } } dog create spot spot caller } -returnCodes { error } -cleanup { dog destroy } -result {can't read "selfns": no such variable} test ivariable-1.9 {procs which define selfns see instance variables} -body { type dog { variable greeting Howdy method caller {} { return [callee $selfns] } proc callee {selfns} { return $greeting } } dog create spot spot caller } -cleanup { dog destroy } -result {Howdy} test ivariable-1.10 {in methods, variable works with fully qualified names} -body { namespace eval ::somenamespace:: { set somevar somevalue } type dog { method get {} { variable ::somenamespace::somevar return $somevar } } dog create spot spot get } -cleanup { dog destroy } -result {somevalue} test ivariable-1.11 {variable with too many initializers throws an error} -body { type dog { variable color dark brown } } -returnCodes { error } -result {Error in "variable color...", too many initializers} test ivariable-1.12 {variable with too many initializers throws an error} -body { type dog { variable color -array dark brown } } -returnCodes { error } -result {Error in "variable color...", too many initializers} test ivariable-1.13 {variable can initialize array variables} -body { type dog { variable data -array { family jones color brown } method getdata {item} { return $data($item) } } dog spot list [spot getdata family] [spot getdata color] } -cleanup { dog destroy } -result {jones brown} #----------------------------------------------------------------------- # codename # # NOTE: codename is deprecated; myproc should be used instead. test codename-1.1 {codename qualifies procs} -body { type dog { method qualify {} { return [codename myproc] } proc myproc {} { } } dog create spot spot qualify } -cleanup { dog destroy } -result {::dog::myproc} test codename-1.2 {procs with selfns work} -body { type dog { variable datum foo method qualify {} { return [list [codename getdatum] $selfns] } proc getdatum {selfns} { return $datum } } dog create spot eval [spot qualify] } -cleanup { dog destroy } -result {foo} #----------------------------------------------------------------------- # Options test option-1.1 {options get default values} -body { type dog { option -color golden } dog create spot spot cget -color } -cleanup { dog destroy } -result {golden} test option-1.2 {options can be set} -body { type dog { option -color golden } dog create spot spot configure -color black spot cget -color } -cleanup { dog destroy } -result {black} test option-1.3 {multiple options can be set} -body { type dog { option -color golden option -akc 0 } dog create spot spot configure -color brown -akc 1 list [spot cget -color] [spot cget -akc] } -cleanup { dog destroy } -result {brown 1} test option-1.4 {options can be retrieved as instance variable} -body { type dog { option -color golden option -akc 0 method listopts {} { list $options(-color) $options(-akc) } } dog create spot spot configure -color black -akc 1 spot listopts } -cleanup { dog destroy } -result {black 1} test option-1.5 {options can be set as an instance variable} -body { type dog { option -color golden option -akc 0 method setopts {} { set options(-color) black set options(-akc) 1 } } dog create spot spot setopts list [spot cget -color] [spot cget -akc] } -cleanup { dog destroy } -result {black 1} test option-1.6 {options can be set at creation time} -body { type dog { option -color golden option -akc 0 } dog create spot -color white -akc 1 list [spot cget -color] [spot cget -akc] } -cleanup { dog destroy } -result {white 1} test option-1.7 {undefined option: cget} -body { type dog { option -color golden option -akc 0 } dog create spot spot cget -colour } -returnCodes { error } -cleanup { dog destroy } -result {unknown option "-colour"} test option-1.8 {undefined option: configure} -body { type dog { option -color golden option -akc 0 } dog create spot spot configure -colour blue } -returnCodes { error } -cleanup { dog destroy } -result {unknown option "-colour"} test option-1.9 {options default to ""} -body { type dog { option -color } dog create spot spot cget -color } -cleanup { dog destroy } -result {} test option-1.10 {spaces allowed in option defaults} -body { type dog { option -breed "golden retriever" } dog fido fido cget -breed } -cleanup { dog destroy } -result {golden retriever} test option-1.11 {brackets allowed in option defaults} -body { type dog { option -regexp {[a-z]+} } dog fido fido cget -regexp } -cleanup { dog destroy } -result {[a-z]+} test option-2.1 {configure returns info, local options only} -body { type dog { option -color black option -akc 1 } dog create spot spot configure -color red spot configure -akc 0 spot configure } -cleanup { dog destroy } -result {{-color color Color black red} {-akc akc Akc 1 0}} test option-2.2 {configure -opt returns info, local options only} -body { type dog { option -color black option -akc 1 } dog create spot spot configure -color red spot configure -color } -cleanup { dog destroy } -result {-color color Color black red} test option-2.3 {configure -opt returns info, explicit options} -body { type papers { option -akcflag 1 } type dog { option -color black delegate option -akc to papers as -akcflag constructor {args} { set papers [papers create $self.papers] } destructor { catch {$self.papers destroy} } } dog create spot spot configure -akc 0 spot configure -akc } -cleanup { dog destroy } -result {-akc akc Akc 1 0} test option-2.4 {configure -unknownopt} -body { type papers { option -akcflag 1 } type dog { option -color black delegate option -akc to papers as -akcflag constructor {args} { set papers [papers create $self.papers] } destructor { catch {$self.papers destroy} } } dog create spot spot configure -foo } -returnCodes { error } -cleanup { dog destroy papers destroy } -result {unknown option "-foo"} test option-2.5 {configure returns info, unknown options} -constraints { tk } -body { widgetadaptor myframe { option -foo a delegate option -width to hull delegate option * to hull constructor {args} { 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 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 option-3.1 {set option resource name explicitly} -body { type dog { option {-tailcolor tailColor} black } dog fido fido configure -tailcolor } -cleanup { dog destroy } -result {-tailcolor tailColor TailColor black black} test option-3.2 {set option class name explicitly} -body { type dog { option {-tailcolor tailcolor TailColor} black } dog fido fido configure -tailcolor } -cleanup { dog destroy } -result {-tailcolor tailcolor TailColor black black} test option-3.3 {delegated option's names come from owner} -body { type tail { option -color black } type dog { delegate option -tailcolor to tail as -color constructor {args} { set tail [tail fidotail] } } dog fido fido configure -tailcolor } -cleanup { dog destroy tail destroy } -result {-tailcolor tailcolor Tailcolor black black} test option-3.4 {delegated option's resource name set explicitly} -body { type tail { option -color black } type dog { delegate option {-tailcolor tailColor} to tail as -color constructor {args} { set tail [tail fidotail] } } dog fido fido configure -tailcolor } -cleanup { dog destroy tail destroy } -result {-tailcolor tailColor TailColor black black} test option-3.5 {delegated option's class name set explicitly} -body { type tail { option -color black } type dog { delegate option {-tailcolor tailcolor TailColor} to tail as -color constructor {args} { set tail [tail fidotail] } } dog fido fido configure -tailcolor } -cleanup { dog destroy tail destroy } -result {-tailcolor tailcolor TailColor black black} test option-3.6 {delegated option's default comes from component} -body { type tail { option -color black } type dog { delegate option -tailcolor to tail as -color constructor {args} { set tail [tail fidotail -color red] } } dog fido fido configure -tailcolor } -cleanup { dog destroy tail destroy } -result {-tailcolor tailcolor Tailcolor black red} test option-4.1 {local option name must begin with hyphen} -body { type dog { option nohyphen } } -returnCodes { error } -result {Error in "option nohyphen...", badly named option "nohyphen"} test option-4.2 {local option name must be lower case} -body { type dog { option -Upper } } -returnCodes { error } -result {Error in "option -Upper...", badly named option "-Upper"} test option-4.3 {local option name may not contain spaces} -body { type dog { option {"-with space"} } } -returnCodes { error } -result {Error in "option {"-with space"}...", badly named option "-with space"} test option-4.4 {delegated option name must begin with hyphen} -body { type dog { delegate option nohyphen to tail } } -returnCodes { error } -result {Error in "delegate option nohyphen...", badly named option "nohyphen"} test option-4.5 {delegated option name must be lower case} -body { type dog { delegate option -Upper to tail } } -returnCodes { error } -result {Error in "delegate option -Upper...", badly named option "-Upper"} test option-4.6 {delegated option name may not contain spaces} -body { type dog { delegate option {"-with space"} to tail } } -returnCodes { error } -result {Error in "delegate option {"-with space"}...", badly named option "-with space"} test option-5.1 {local widget options read from option database} -constraints { tk } -body { widget dog { option -foo a option -bar b typeconstructor { option add *Dog.bar bb } } dog .fido set a [.fido cget -foo] set b [.fido cget -bar] destroy .fido tkbide list $a $b } -cleanup { dog destroy } -result {a bb} test option-5.2 {local option database values available in constructor} -constraints { tk } -body { widget dog { option -bar b variable saveit typeconstructor { option add *Dog.bar bb } constructor {args} { set saveit $options(-bar) } method getit {} { return $saveit } } dog .fido set result [.fido getit] destroy .fido tkbide set result } -cleanup { dog destroy } -result {bb} test option-6.1 {if no options, no options variable} -body { type dog { variable dummy } dog spot spot info vars options } -cleanup { dog destroy } -result {} test option-6.2 {if no options, no options methods} -body { type dog { variable dummy } dog spot spot info methods c* } -cleanup { dog destroy } -result {} #----------------------------------------------------------------------- # onconfigure test onconfigure-1.1 {invalid onconfigure methods are caught} -body { type dog { onconfigure -color {value} { } } } -returnCodes { error } -result {onconfigure -color: option "-color" unknown} test onconfigure-1.2 {onconfigure methods take one argument} -body { type dog { option -color golden onconfigure -color {value badarg} { } } } -returnCodes { error } -result {onconfigure -color handler should have one argument, got "value badarg"} test onconfigure-1.3 {onconfigure methods work} -body { type dog { option -color golden onconfigure -color {value} { set options(-color) "*$value*" } } dog create spot spot configure -color brown spot cget -color } -cleanup { dog destroy } -result {*brown*} test onconfigure-1.4 {onconfigure arg can't be type} -body { type dog { option -color onconfigure -color {type} { } } } -returnCodes { error } -result {onconfigure -color's arglist may not contain "type" explicitly} test onconfigure-1.5 {onconfigure arg can't be self} -body { type dog { option -color onconfigure -color {self} { } } } -returnCodes { error } -result {onconfigure -color's arglist may not contain "self" explicitly} #----------------------------------------------------------------------- # oncget test oncget-1.1 {invalid oncget methods are caught} -body { type dog { oncget -color { } } } -returnCodes { error } -result {Error in "oncget -color...", option "-color" unknown} test oncget-1.2 {oncget methods work} -body { cleanup type dog { option -color golden oncget -color { return "*$options(-color)*" } } dog create spot spot configure -color brown spot cget -color } -cleanup { dog destroy } -result {*brown*} #----------------------------------------------------------------------- # constructor test constructor-1.1 {constructor can do things} -body { type dog { variable a variable b constructor {args} { set a 1 set b 2 } method foo {} { list $a $b } } dog create spot spot foo } -cleanup { dog destroy } -result {1 2} test constructor-1.2 {constructor with no configurelist ignores args} -body { type dog { constructor {args} { } option -color golden option -akc 0 } dog create spot -color white -akc 1 list [spot cget -color] [spot cget -akc] } -cleanup { dog destroy } -result {golden 0} test constructor-1.3 {constructor with configurelist gets args} -body { type dog { constructor {args} { $self configurelist $args } option -color golden option -akc 0 } dog create spot -color white -akc 1 list [spot cget -color] [spot cget -akc] } -cleanup { dog destroy } -result {white 1} test constructor-1.4 {constructor with specific args} -body { type dog { option -value "" constructor {a b args} { set options(-value) [list $a $b $args] } } dog spot retriever golden -akc 1 spot cget -value } -cleanup { dog destroy } -result {retriever golden {-akc 1}} test constructor-1.5 {constructor with list as one list arg} -body { type dog { option -value "" constructor {args} { set options(-value) $args } } dog spot {retriever golden} spot cget -value } -cleanup { dog destroy } -result {{retriever golden}} test constructor-1.6 {default constructor configures options} -body { type dog { option -color brown option -breed mutt } dog spot -color golden -breed retriever list [spot cget -color] [spot cget -breed] } -cleanup { dog destroy } -result {golden retriever} test constructor-1.7 {default constructor takes no args if no options} -body { type dog { variable color } dog spot -color golden } -returnCodes { error } -result "Error in constructor: [tcltest::tooManyArgs ::dog::Snit_constructor {type selfns win self}]" #----------------------------------------------------------------------- # destroy test destroy-1.1 {destroy cleans up the instance} -body { type dog { option -color golden } set a [namespace children ::dog::] dog create spot set b [namespace children ::dog::] spot destroy set c [namespace children ::dog::] list $a $b $c [info commands ::dog::spot] } -cleanup { dog destroy } -result {{} ::dog::Snit_inst1 {} {}} test destroy-1.2 {incomplete objects are destroyed} -body { array unset ::dog::snit_ivars type dog { option -color golden constructor {args} { $self configurelist $args if {"red" == [$self cget -color]} { error "No Red Dogs!" } } } catch {dog create spot -color red} result set names [array names ::dog::snit_ivars] list $result $names [info commands ::dog::spot] } -cleanup { dog destroy } -result {{Error in constructor: No Red Dogs!} {} {}} test destroy-1.3 {user-defined destructors are called} -body { type dog { typevariable flag "" constructor {args} { set flag "created $self" } destructor { set flag "destroyed $self" } typemethod getflag {} { return $flag } } dog create spot set a [dog getflag] spot destroy list $a [dog getflag] } -cleanup { dog destroy } -result {{created ::spot} {destroyed ::spot}} #----------------------------------------------------------------------- # delegate: general syntax tests test delegate-1.1 {can only delegate methods or options} -body { type dog { delegate foo bar to baz } } -returnCodes { error } -result {Error in "delegate foo bar...", "foo"?} test delegate-1.2 {"to" must appear in the right place} -body { type dog { delegate method foo from bar } } -returnCodes { error } -result {Error in "delegate method foo...", unknown delegation option "from"} test delegate-1.3 {"as" must have a target} -body { type dog { delegate method foo to bar as } } -returnCodes { error } -result {Error in "delegate method foo...", invalid syntax} test delegate-1.4 {"as" must have a single target} -body { type dog { delegate method foo to bar as baz quux } } -returnCodes { error } -result {Error in "delegate method foo...", unknown delegation option "quux"} test delegate-1.5 {"as" doesn't work with "*"} -body { type dog { delegate method * to hull as foo } } -returnCodes { error } -result {Error in "delegate method *...", cannot specify "as" with "*"} test delegate-1.6 {"except" must have a target} -body { type dog { delegate method * to bar except } } -returnCodes { error } -result {Error in "delegate method *...", invalid syntax} test delegate-1.7 {"except" must have a single target} -body { type dog { delegate method * to bar except baz quux } } -returnCodes { error } -result {Error in "delegate method *...", unknown delegation option "quux"} test delegate-1.8 {"except" works only with "*"} -body { type dog { delegate method foo to hull except bar } } -returnCodes { error } -result {Error in "delegate method foo...", can only specify "except" with "*"} test delegate-1.9 {only "as" or "except"} -body { type dog { delegate method foo to bar with quux } } -returnCodes { error } -result {Error in "delegate method foo...", unknown delegation option "with"} #----------------------------------------------------------------------- # delegated methods test dmethod-1.1 {delegate method to non-existent component} -body { type dog { delegate method foo to bar } dog create spot spot foo } -returnCodes { error } -cleanup { dog destroy } -result {::dog ::spot delegates method "foo" to undefined component "bar"} test dmethod-1.2 {delegating to existing component} -body { type dog { constructor {args} { set string string } delegate method length to string } dog create spot spot length foo } -cleanup { dog destroy } -result {3} # Case 1 test dmethod-1.3 {delegating to existing component with error} -constraints { snit1 } -body { type dog { constructor {args} { set string string } delegate method length to string } dog create spot spot length foo bar } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "string length string"} # Case 2 test dmethod-1.4 {delegating to existing component with error} -constraints { snit2 } -body { type dog { constructor {args} { set string string } delegate method length to string } dog create spot spot length foo bar } -cleanup { dog destroy } -returnCodes { error } -result {wrong # args: should be "spot length string"} test dmethod-1.5 {delegating unknown methods to existing component} -body { type dog { constructor {args} { set string string } delegate method * to string } dog create spot spot length foo } -cleanup { dog destroy } -result {3} test dmethod-1.6 {delegating unknown method to existing component with error} -body { type dog { constructor {args} { set stringhandler string } delegate method * to stringhandler } dog create spot spot foo bar } -constraints { snit1 } -returnCodes { error } -cleanup { dog destroy } -result {bad option "foo": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, tolower, toupper, totitle, trim, trimleft, trimright, wordend, or wordstart} test dmethod-1.6a {delegating unknown method to existing component with error} -body { type dog { constructor {args} { set stringhandler string } delegate method * to stringhandler } dog create spot spot foo bar } -constraints { snit2 } -returnCodes { error } -cleanup { dog destroy } -result {unknown or ambiguous subcommand "foo": must be bytelength, compare, equal, first, index, is, last, length, map, match, range, repeat, replace, reverse, tolower, totitle, toupper, trim, trimleft, trimright, wordend, or wordstart} test dmethod-1.7 {can't delegate local method: order 1} -body { type cat { method foo {} {} delegate method foo to hull } } -returnCodes { error } -result {Error in "delegate method foo...", "foo" has been defined locally.} test dmethod-1.8 {can't delegate local method: order 2} -body { type cat { delegate method foo to hull method foo {} {} } } -returnCodes { error } -result {Error in "method foo...", "foo" has been delegated} # Case 1 test dmethod-1.9 {excepted methods are caught properly} -constraints { snit1 } -body { type tail { method wag {} {return "wagged"} method flaunt {} {return "flaunted"} method tuck {} {return "tuck"} } type cat { method meow {} {} delegate method * to tail except {wag tuck} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi flaunt} a catch {fifi wag} b catch {fifi tuck} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {flaunted {"::fifi wag" is not defined} {"::fifi tuck" is not defined}} # Case 2 test dmethod-1.10 {excepted methods are caught properly} -constraints { snit2 } -body { type tail { method wag {} {return "wagged"} method flaunt {} {return "flaunted"} method tuck {} {return "tuck"} } type cat { method meow {} {} delegate method * to tail except {wag tuck} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi flaunt} a catch {fifi wag} b catch {fifi tuck} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {flaunted {unknown subcommand "wag": must be flaunt} {unknown subcommand "tuck": must be flaunt}} test dmethod-1.11 {as clause can include arguments} -body { type tail { method wag {adverb} {return "wagged $adverb"} } type dog { delegate method wag to tail as {wag briskly} constructor {args} { set tail [tail %AUTO%] } } dog spot spot wag } -cleanup { dog destroy tail destroy } -result {wagged briskly} test dmethod-2.1 {'using "%c %m"' gets normal behavior} -body { type tail { method wag {adverb} {return "wagged $adverb"} } type dog { delegate method wag to tail using {%c %m} constructor {args} { set tail [tail %AUTO%] } } dog spot spot wag briskly } -cleanup { dog destroy tail destroy } -result {wagged briskly} test dmethod-2.2 {All 'using' conversions are converted} -body { proc echo {args} { return $args } type dog { delegate method {tail wag} using {echo %% %t %M %m %j %n %w %s %c} } dog spot spot tail wag } -cleanup { dog destroy rename echo "" } -result {% ::dog {tail wag} wag tail_wag ::dog::Snit_inst1 ::spot ::spot %c} test dmethod-2.3 {"%%" is handled properly} -body { proc echo {args} { join $args "|" } type dog { delegate method wag using {echo %%m %%%m} } dog spot spot wag } -cleanup { dog destroy rename echo "" } -result {%m|%wag} test dmethod-2.4 {Method "*" and "using"} -body { proc echo {args} { join $args "|" } type dog { delegate method * using {echo %m} } dog spot list [spot wag] [spot bark loudly] } -cleanup { dog destroy rename echo "" } -result {wag bark|loudly} test dmethod-3.1 {component names can be changed dynamically} -body { type tail1 { method wag {} {return "wagged"} } type tail2 { method wag {} {return "drooped"} } type dog { delegate method wag to tail constructor {args} { set tail [tail1 %AUTO%] } method switchit {} { set tail [tail2 %AUTO%] } } dog fido set a [fido wag] fido switchit set b [fido wag] list $a $b } -cleanup { dog destroy tail1 destroy tail2 destroy } -result {wagged drooped} test dmethod-4.1 {hierarchical method, two tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {wag tail} to tail as wag } dog spot spot wag tail } -cleanup { dog destroy tail destroy } -result {wags tail} test dmethod-4.2 {hierarchical method, three tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {wag tail proudly} to tail as wag } dog spot spot wag tail proudly } -cleanup { dog destroy tail destroy } -result {wags tail} test dmethod-4.3 {hierarchical method, three tokens} -body { type tail { method wag {} {return "wags tail"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {wag tail really high} to tail as wag } dog spot spot wag tail really high } -cleanup { dog destroy tail destroy } -result {wags tail} test dmethod-4.4 {redefinition is OK} -body { type tail { method {wag tail} {} {return "wags tail"} method {wag briskly} {} {return "wags tail briskly"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {wag tail} to tail as {wag tail} delegate method {wag tail} to tail as {wag briskly} } dog spot spot wag tail } -cleanup { dog destroy tail destroy } -result {wags tail briskly} test dmethod-4.5 {all tokens are used by default} -body { type tail { method wag {} {return "wags tail"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {tail wag} to tail } dog spot spot tail wag } -cleanup { dog destroy tail destroy } -result {wags tail} test dmethod-4.6 {last token can be *} -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {tail *} to tail } dog spot list [spot tail wag] [spot tail droop] } -cleanup { dog destroy tail destroy } -result {wags droops} # Case 1 test dmethod-4.7 {except with multiple tokens} -constraints { snit1 } -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {tail *} to tail except droop } dog spot catch {spot tail droop} result list [spot tail wag] $result } -cleanup { dog destroy tail destroy } -result {wags {"::spot tail droop" is not defined}} # Case 2 test dmethod-4.8 {except with multiple tokens} -constraints { snit2 } -body { type tail { method wag {} {return "wags"} method droop {} {return "droops"} } type dog { constructor {} { set tail [tail %AUTO%] } delegate method {tail *} to tail except droop } dog spot catch {spot tail droop} result list [spot tail wag] $result } -cleanup { dog destroy tail destroy } -result {wags {unknown subcommand "droop": namespace ::dog::Snit_inst1 does not export any commands}} test dmethod-4.9 {"*" in the wrong spot} -body { type dog { delegate method {tail * wag} to tail } } -returnCodes { error } -result {Error in "delegate method {tail * wag}...", "*" must be the last token.} test dmethod-5.1 {prefix/method collision} -body { type dog { delegate method wag to tail delegate method {wag tail} to tail as wag } } -returnCodes { error } -result {Error in "delegate method {wag tail}...", "wag" has no submethods.} test dmethod-5.2 {prefix/method collision} -body { type dog { delegate method {wag tail} to tail as wag delegate method wag to tail } } -returnCodes { error } -result {Error in "delegate method wag...", "wag" has submethods.} test dmethod-5.3 {prefix/method collision} -body { type dog { delegate method {wag tail} to tail delegate method {wag tail proudly} to tail as wag } } -returnCodes { error } -result {Error in "delegate method {wag tail proudly}...", "wag tail" has no submethods.} test dmethod-5.4 {prefix/method collision} -body { type dog { delegate method {wag tail proudly} to tail as wag delegate method {wag tail} to tail } } -returnCodes { error } -result {Error in "delegate method {wag tail}...", "wag tail" has submethods.} #----------------------------------------------------------------------- # delegated options test doption-1.1 {delegate option to non-existent component} -body { type dog { delegate option -foo to bar } dog create spot spot cget -foo } -returnCodes { error } -cleanup { dog destroy } -result {component "bar" is undefined in ::dog ::spot} test doption-1.2 {delegating option to existing component: cget} -body { type cat { option -color "black" } cat create hershey type dog { constructor {args} { set catthing ::hershey } delegate option -color to catthing } dog create spot spot cget -color } -cleanup { dog destroy cat destroy } -result {black} test doption-1.3 {delegating option to existing component: configure} -body { type cat { option -color "black" } cat create hershey type dog { constructor {args} { set catthing ::hershey $self configurelist $args } delegate option -color to catthing } dog create spot -color blue list [spot cget -color] [hershey cget -color] } -cleanup { dog destroy cat destroy } -result {blue blue} test doption-1.4 {delegating unknown options to existing component} -body { type cat { option -color "black" } cat create hershey type dog { constructor {args} { set catthing ::hershey # Note: must do this after components are defined; this # may be a problem. $self configurelist $args } delegate option * to catthing } dog create spot -color blue list [spot cget -color] [hershey cget -color] } -cleanup { dog destroy cat destroy } -result {blue blue} test doption-1.5 {can't oncget for delegated option} -body { type dog { delegate option -color to catthing oncget -color { } } } -returnCodes { error } -result {Error in "oncget -color...", option "-color" is delegated} test doption-1.6 {can't onconfigure for delegated option} -body { type dog { delegate option -color to catthing onconfigure -color {value} { } } } -returnCodes { error } -result {onconfigure -color: option "-color" is delegated} test doption-1.7 {delegating unknown options to existing component: error} -body { type cat { option -color "black" } cat create hershey type dog { constructor {args} { set catthing ::hershey $self configurelist $args } delegate option * to catthing } dog create spot -colour blue } -returnCodes { error } -cleanup { dog destroy cat destroy } -result {Error in constructor: unknown option "-colour"} test doption-1.8 {can't delegate local option: order 1} -body { type cat { option -color "black" delegate option -color to hull } } -returnCodes { error } -result {Error in "delegate option -color...", "-color" has been defined locally} test doption-1.9 {can't delegate local option: order 2} -body { type cat { delegate option -color to hull option -color "black" } } -returnCodes { error } -result {Error in "option -color...", cannot define "-color" locally, it has been delegated} test doption-1.10 {excepted options are caught properly on cget} -body { type tail { option -a a option -b b option -c c } type cat { delegate option * to tail except {-b -c} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi cget -a} a catch {fifi cget -b} b catch {fifi cget -c} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {a {unknown option "-b"} {unknown option "-c"}} test doption-1.11 {excepted options are caught properly on configurelist} -body { type tail { option -a a option -b b option -c c } type cat { delegate option * to tail except {-b -c} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi configurelist {-a 1}} a catch {fifi configurelist {-b 1}} b catch {fifi configurelist {-c 1}} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {{} {unknown option "-b"} {unknown option "-c"}} test doption-1.12 {excepted options are caught properly on configure, 1} -body { type tail { option -a a option -b b option -c c } type cat { delegate option * to tail except {-b -c} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi configure -a 1} a catch {fifi configure -b 1} b catch {fifi configure -c 1} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {{} {unknown option "-b"} {unknown option "-c"}} test doption-1.13 {excepted options are caught properly on configure, 2} -body { type tail { option -a a option -b b option -c c } type cat { delegate option * to tail except {-b -c} constructor {args} { set tail [tail %AUTO%] } } cat fifi catch {fifi configure -a} a catch {fifi configure -b} b catch {fifi configure -c} c list $a $b $c } -cleanup { cat destroy tail destroy } -result {{-a a A a a} {unknown option "-b"} {unknown option "-c"}} test doption-1.14 {configure query skips excepted options} -body { type tail { option -a a option -b b option -c c } type cat { option -d d delegate option * to tail except {-b -c} constructor {args} { set tail [tail %AUTO%] } } cat fifi fifi configure } -cleanup { cat destroy tail destroy } -result {{-d d D d d} {-a a A a a}} #----------------------------------------------------------------------- # from test from-1.1 {getting default values} -body { type dog { option -foo FOO option -bar BAR constructor {args} { $self configure -foo [from args -foo AAA] $self configure -bar [from args -bar] } } dog create spot list [spot cget -foo] [spot cget -bar] } -cleanup { dog destroy } -result {AAA BAR} test from-1.2 {getting non-default values} -body { type dog { option -foo FOO option -bar BAR option -args constructor {args} { $self configure -foo [from args -foo] $self configure -bar [from args -bar] $self configure -args $args } } dog create spot -foo quux -baz frobnitz -bar frobozz list [spot cget -foo] [spot cget -bar] [spot cget -args] } -cleanup { dog destroy } -result {quux frobozz {-baz frobnitz}} #----------------------------------------------------------------------- # Widgetadaptors test widgetadaptor-1.1 {creating a widget: hull hijacking} -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] $self configurelist $args } delegate method * to hull delegate option * to hull } mylabel create .label -text "My Label" set a [.label cget -text] set b [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 [namespace children ::mylabel] destroy .label set b [namespace children ::mylabel] tkbide list $a $b } -cleanup { mylabel destroy } -result {::mylabel::Snit_inst1 {}} 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 [namespace children ::mylabel] destroy .lab1 destroy .lab2 set b [namespace children ::mylabel] tkbide list $a $b } -cleanup { mylabel destroy } -result {{::mylabel::Snit_inst1 ::mylabel::Snit_inst2} {}} test widgetadaptor-1.4 {destroying a widget with rename, then destroy type} -constraints { tk bug8.5a3 } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .label set a [namespace children ::mylabel] rename .label "" set b [namespace children ::mylabel] mylabel destroy tkbide list $a $b } -result {::mylabel::Snit_inst1 {}} test widgetadaptor-1.5 {destroying two widgets of the same type with rename} -constraints { tk bug8.5a3 } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 mylabel create .lab2 set a [namespace children ::mylabel] rename .lab1 "" rename .lab2 "" set b [namespace children ::mylabel] mylabel destroy tkbide list $a $b } -result {{::mylabel::Snit_inst1 ::mylabel::Snit_inst2} {}} 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 ::mylabel] destroy .lab1 mylabel create .lab1 set b [namespace children ::mylabel] destroy .lab1 set c [namespace children ::mylabel] mylabel destroy tkbide list $a $b $c } -result {::mylabel::Snit_inst1 ::mylabel::Snit_inst2 {}} test widgetadaptor-1.7 {create/destroy twice, with rename} -constraints { tk bug8.5a3 } -body { widgetadaptor mylabel { constructor {} { installhull [label $self] } } mylabel create .lab1 set a [namespace children ::mylabel] rename .lab1 "" mylabel create .lab1 set b [namespace children ::mylabel] rename .lab1 "" set c [namespace children ::mylabel] mylabel destroy tkbide list $a $b $c } -result {::mylabel::Snit_inst1 ::mylabel::Snit_inst2 {}} 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!} # Case 1 test widgetadaptor-1.9 {"create" is optional, but must be a valid name} -constraints { snit1 tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } method howdy {} {return "Howdy!"} } catch {mylabel foo} result tkbide set result } -cleanup { mylabel destroy } -result {"::mylabel foo" is not defined} # Case 2 test widgetadaptor-1.10 {"create" is optional, but must be a valid name} -constraints { snit2 tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } method howdy {} {return "Howdy!"} } catch {mylabel foo} result tkbide set result } -cleanup { mylabel destroy } -result {unknown subcommand "foo": namespace ::mylabel does not export any commands} 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 .label} {destroyed .label}} # Case 1 test widgetadaptor-1.12 {destroy method not defined for widget types} -constraints { snit1 tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } } mylabel .label catch {.label destroy} result destroy .label tkbide set result } -cleanup { mylabel destroy } -result {".label destroy" is not defined} # Case 2 test widgetadaptor-1.13 {destroy method not defined for widget types} -constraints { snit2 tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] } } mylabel .label catch {.label destroy} result destroy .label tkbide set result } -cleanup { mylabel destroy } -result {unknown subcommand "destroy": namespace ::mylabel::Snit_inst1 does not export any commands} 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 {.unique1} test widgetadaptor-1.16 {snit::widgetadaptor as hull} -constraints { tk } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] $self configurelist $args } method method1 {} { return "method1" } delegate option * to hull } widgetadaptor mylabel2 { constructor {args} { installhull [mylabel $self] $self configurelist $args } method method2 {} { return "method2: [$hull method1]" } delegate option * to 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 [namespace children ::mylabel2] set e [namespace children ::mylabel] destroy .label set f [namespace children ::mylabel2] set g [namespace children ::mylabel] mylabel2 destroy mylabel destroy tkbide list $a $b $c $d $e $f $g } -result {{method2: method1} {Some Text} {More Text} ::mylabel2::Snit_inst1 ::mylabel::Snit_inst1 {} {}} test widgetadaptor-1.17 {snit::widgetadaptor as hull; use rename} -constraints { tk bug8.5a3 } -body { widgetadaptor mylabel { constructor {args} { installhull [label $self] $self configurelist $args } method method1 {} { return "method1" } delegate option * to hull } widgetadaptor mylabel2 { constructor {args} { installhull [mylabel $self] $self configurelist $args } method method2 {} { return "method2: [$hull method1]" } delegate option * to 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 [namespace children ::mylabel2] set e [namespace children ::mylabel] rename .label "" set f [namespace children ::mylabel2] set g [namespace children ::mylabel] mylabel2 destroy mylabel destroy tkbide list $a $b $c $d $e $f $g } -result {{method2: method1} {Some Text} {More Text} ::mylabel2::Snit_inst1 ::mylabel::Snit_inst1 {} {}} test widgetadaptor-1.18 {BWidget Label as hull} -constraints { bwidget } -body { widgetadaptor mylabel { constructor {args} { installhull [Label $win] $self configurelist $args } delegate option * to hull } mylabel .label -text "Some Text" set a [.label cget -text] .label configure -text "More Text" set b [.label cget -text] set c [namespace children ::mylabel] destroy .label set d [namespace children ::mylabel] mylabel destroy tkbide list $a $b $c $d } -result {{Some Text} {More Text} ::mylabel::Snit_inst1 {}} 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 {Error in constructor: Simulated Error} #----------------------------------------------------------------------- # Widgets # A widget is just a widgetadaptor with an automatically created hull # component (a Tk frame). So the widgetadaptor tests apply; all we # need to test here is the frame creation. test widget-1.1 {creating a widget} -constraints { tk } -body { widget myframe { method hull {} { return $hull } delegate method * to hull delegate option * to hull } myframe create .frm -background green set a [.frm cget -background] set b [.frm hull] destroy .frm tkbide list $a $b } -cleanup { myframe destroy } -result {green ::hull1.frm} test widget-2.1 {can't redefine hull} -constraints { tk } -body { widget myframe { method resethull {} { set hull "" } } myframe .frm .frm resethull } -returnCodes { error } -cleanup { myframe destroy } -result {can't set "hull": The hull component cannot be redefined} #----------------------------------------------------------------------- # install # # The install command is used to install widget components, while getting # options for the option database. test install-1.1 {installed components are created properly} -constraints { tk } -body { widget myframe { # Delegate an option just to make sure the component variable # exists. delegate option -font to text constructor {args} { install text using text $win.text -background green } method getit {} { $win.text cget -background } } myframe .frm set a [.frm getit] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {green} test install-1.2 {installed components are saved properly} -constraints { tk } -body { widget myframe { # Delegate an option just to make sure the component variable # exists. delegate option -font to text constructor {args} { install text using text $win.text -background green } method getit {} { $text cget -background } } myframe .frm set a [.frm getit] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {green} 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} { install text using text $win.text -background green } } myframe .frm } -returnCodes { error } -cleanup { myframe destroy } -result {Error in constructor: tried to install "text" before the hull exists} test install-1.4 {install queries option database} -constraints { tk } -body { widget myframe { delegate option -font to text typeconstructor { option add *Myframe.font Courier } constructor {args} { install text using text $win.text } } myframe .frm set a [.frm cget -font] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {Courier} test install-1.5 {explicit options override option database} -constraints { tk } -body { widget myframe { delegate option -font to text typeconstructor { option add *Myframe.font Courier } constructor {args} { install text using text $win.text -font Times } } myframe .frm set a [.frm cget -font] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {Times} test install-1.6 {option db works with targetted options} -constraints { tk } -body { widget myframe { delegate option -textfont to text as -font typeconstructor { option add *Myframe.textfont Courier } constructor {args} { install text using text $win.text } } myframe .frm set a [.frm cget -textfont] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {Courier} test install-1.7 {install works for snit::types} -body { type tail { option -tailcolor black } type dog { delegate option -tailcolor to tail constructor {args} { install tail using tail $self.tail } } dog fido fido cget -tailcolor } -cleanup { dog destroy tail destroy } -result {black} test install-1.8 {install can install non-widget components} -constraints { tk } -body { type dog { option -tailcolor black } widget myframe { delegate option -tailcolor to thedog typeconstructor { option add *Myframe.tailcolor green } constructor {args} { install thedog using dog $win.dog } } myframe .frm set a [.frm cget -tailcolor] destroy .frm tkbide set a } -cleanup { dog destroy myframe destroy } -result {green} test install-1.9 {ok if no options are delegated to component} -constraints { tk } -body { type dog { option -tailcolor black } widget myframe { constructor {args} { install thedog using dog $win.dog } } myframe .frm destroy .frm tkbide # Test passes if no error is raised. list ok } -cleanup { myframe destroy dog destroy } -result {ok} test install-2.1 { delegate option * for a non-shadowed option. The text widget's -foreground and -font options should be set according to what's in the option database on the widgetclass. } -constraints { tk } -body { widget myframe { delegate option * to text typeconstructor { option add *Myframe.foreground red option add *Myframe.font {Times 14} } constructor {args} { install text using text $win.text } } myframe .frm set a [.frm cget -foreground] set b [.frm cget -font] destroy .frm tkbide list $a $b } -cleanup { myframe destroy } -result {red {Times 14}} test install-2.2 { Delegate option * for a shadowed option. Foreground is declared as a non-delegated option, hence it will pick up the option database default. -foreground is not included in the "delegate option *", so the text widget's -foreground option will not be set from the option database. } -constraints { tk } -body { widget myframe { option -foreground white delegate option * to text typeconstructor { option add *Myframe.foreground red } constructor {args} { install text using text $win.text } method getit {} { $text cget -foreground } } myframe .frm set a [.frm cget -foreground] set b [.frm getit] destroy .frm tkbide expr {![string equal $a $b]} } -cleanup { myframe destroy } -result {1} test install-2.3 { Delegate option * for a creation option. Because the text widget's -foreground is set explicitly by the constructor, that always overrides the option database. } -constraints { tk } -body { widget myframe { delegate option * to text typeconstructor { option add *Myframe.foreground red } constructor {args} { install text using text $win.text -foreground blue } } myframe .frm set a [.frm cget -foreground] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {blue} test install-2.4 { Delegate option * with an excepted option. Because the text widget's -state is excepted, it won't be set from the option database. } -constraints { tk } -body { widget myframe { delegate option * to text except -state typeconstructor { option add *Myframe.foreground red option add *Myframe.state disabled } constructor {args} { install text using text $win.text } method getstate {} { $text cget -state } } myframe .frm set a [.frm getstate] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {normal} #----------------------------------------------------------------------- # Advanced installhull tests # # installhull is used to install the hull widget for both widgets and # widget adaptors. It has two forms. In one form it installs a widget # created by some third party; in this form no querying of the option # database is needed, because we haven't taken responsibility for creating # it. But in the other form (installhull using) installhull actually # creates the widget, and takes responsibility for querying the # option database as needed. # # NOTE: "installhull using" is always used to create a widget's hull frame. # # That options passed into installhull override those from the # option database. test installhull-1.1 { options delegated to a widget's hull frame with the same name are initialized from the option database. Note that there's no explicit code in Snit to do this; it happens because we set the -class when the widget was created. In fact, it happens whether we delegate the option name or not. } -constraints { tk } -body { widget myframe { delegate option -background to hull typeconstructor { option add *Myframe.background red option add *Myframe.width 123 } method getwid {} { $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.2 { Options delegated to a widget's hull frame with a different name are initialized from the option database. } -constraints { tk } -body { widget myframe { delegate option -mainbackground to hull as -background typeconstructor { option add *Myframe.mainbackground red } } myframe .frm set a [.frm cget -mainbackground] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {red} test installhull-1.3 { options delegated to a widgetadaptor's 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 hull typeconstructor { option add *Frame.background red option add *Frame.width 123 } constructor {args} { installhull using frame } method getwid {} { $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 hull frame with a different name are initialized from the option database. } -constraints { tk } -body { widgetadaptor myframe { delegate option -mainbackground to 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 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 {} { $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} #----------------------------------------------------------------------- # Instance Introspection # Case 1 test iinfo-1.1 {object info too few args} -constraints { snit1 } -body { type dog { } dog create spot spot info } -returnCodes { error } -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.method.info {type selfns win self command args} 4] # Case 2 test iinfo-1.2 {object info too few args} -constraints { snit2 } -body { type dog { } dog create spot spot info } -returnCodes { error } -cleanup { dog destroy } -result [expect \ {wrong # args: should be "spot info command ?arg ...?"} \ {wrong # args: should be "spot info command ..."}] test iinfo-1.3 {object info too many args} -body { type dog { } dog create spot spot info type foo } -returnCodes { error } -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.method.info.type {type selfns win self}] test iinfo-2.1 {object info type} -body { type dog { } dog create spot spot info type } -cleanup { dog destroy } -result {::dog} test iinfo-3.1 {object info typevars} -body { type dog { typevariable thisvar 1 constructor {args} { typevariable thatvar 2 } } dog create spot lsort [spot info typevars] } -cleanup { dog destroy } -result {::dog::thatvar ::dog::thisvar} test iinfo-3.2 {object info typevars with pattern} -body { type dog { typevariable thisvar 1 constructor {args} { typevariable thatvar 2 } } dog create spot spot info typevars *this* } -cleanup { dog destroy } -result {::dog::thisvar} test iinfo-4.1 {object info vars} -body { type dog { variable hisvar 1 constructor {args} { variable hervar set hervar 2 } } dog create spot lsort [spot info vars] } -cleanup { dog destroy } -result {::dog::Snit_inst1::hervar ::dog::Snit_inst1::hisvar} test iinfo-4.2 {object info vars with pattern} -body { type dog { variable hisvar 1 constructor {args} { variable hervar set hervar 2 } } dog create spot spot info vars "*his*" } -cleanup { dog destroy } -result {::dog::Snit_inst1::hisvar} test iinfo-5.1 {object info no vars defined} -body { type dog { } dog create spot list [spot info vars] [spot info typevars] } -cleanup { dog destroy } -result {{} {}} test iinfo-6.1 {info options with no options} -body { type dog { } dog create spot llength [spot info options] } -cleanup { dog destroy } -result {0} test iinfo-6.2 {info options with only local options} -body { type dog { option -foo a option -bar b } dog create spot lsort [spot info options] } -cleanup { dog destroy } -result {-bar -foo} test iinfo-6.3 {info options with local and delegated options} -body { type dog { option -foo a option -bar b delegate option -quux to sibling } dog create spot lsort [spot info options] } -cleanup { dog destroy } -result {-bar -foo -quux} test iinfo-6.4 {info options with unknown delegated options} -constraints { tk tcl83 } -body { widgetadaptor myframe { option -foo a delegate option * to hull constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {-background -bd -bg -borderwidth -class -colormap -container -cursor -foo -height -highlightbackground -highlightcolor -highlightthickness -relief -takefocus -visual -width} test iinfo-6.5 {info options with unknown delegated options} -constraints { tk tcl84 } -body { widgetadaptor myframe { option -foo a delegate option * to hull constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {-background -bd -bg -borderwidth -class -colormap -container -cursor -foo -height -highlightbackground -highlightcolor -highlightthickness -padx -pady -relief -takefocus -visual -width} test iinfo-6.6 {info options with exceptions} -constraints { tk tcl83 } -body { widgetadaptor myframe { option -foo a delegate option * to hull except -background constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -result {-bd -bg -borderwidth -class -colormap -container -cursor -foo -height -highlightbackground -highlightcolor -highlightthickness -relief -takefocus -visual -width} test iinfo-6.7 {info options with exceptions} -constraints { tk tcl84 } -body { widgetadaptor myframe { option -foo a delegate option * to hull except -background constructor {args} { installhull [frame $self] } } myframe .frm set a [lsort [.frm info options]] destroy .frm tkbide set a } -cleanup { myframe destroy } -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 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 iinfo-7.1 {info typemethods, simple case} -body { type dog { } dog spot lsort [spot info typemethods] } -cleanup { dog destroy } -result {create destroy info} test iinfo-7.2 {info typemethods, with pattern} -body { type dog { } dog spot spot info typemethods i* } -cleanup { dog destroy } -result {info} test iinfo-7.3 {info typemethods, with explicit typemethods} -body { type dog { typemethod foo {} {} delegate typemethod bar to comp } dog spot lsort [spot info typemethods] } -cleanup { dog destroy } -result {bar create destroy foo info} test iinfo-7.4 {info typemethods, with implicit typemethods} -body { type dog { delegate typemethod * to comp typeconstructor { set comp string } } dog create spot set a [lsort [spot info typemethods]] dog length foo dog is boolean yes set b [lsort [spot info typemethods]] set c [spot info typemethods len*] list $a $b $c } -cleanup { dog destroy } -result {{create destroy info} {create destroy info is length} length} test iinfo-7.5 {info typemethods, with hierarchical typemethods} -body { type dog { delegate typemethod {comp foo} to comp typemethod {comp bar} {} {} } dog create spot lsort [spot info typemethods] } -cleanup { dog destroy } -result {{comp bar} {comp foo} create destroy info} test iinfo-8.1 {info methods, simple case} -body { type dog { } dog spot lsort [spot info methods] } -cleanup { dog destroy } -result {destroy info} test iinfo-8.2 {info methods, with pattern} -body { type dog { } dog spot spot info methods i* } -cleanup { dog destroy } -result {info} test iinfo-8.3 {info methods, with explicit methods} -body { type dog { method foo {} {} delegate method bar to comp } dog spot lsort [spot info methods] } -cleanup { dog destroy } -result {bar destroy foo info} test iinfo-8.4 {info methods, with implicit methods} -body { type dog { delegate method * to comp constructor {args} { set comp string } } dog create spot set a [lsort [spot info methods]] spot length foo spot is boolean yes set b [lsort [spot info methods]] set c [spot info methods len*] list $a $b $c } -cleanup { dog destroy } -result {{destroy info} {destroy info is length} length} test iinfo-8.5 {info methods, with hierarchical methods} -body { type dog { delegate method {comp foo} to comp method {comp bar} {} {} } dog create spot lsort [spot info methods] } -cleanup { dog destroy } -result {{comp bar} {comp foo} destroy info} test iinfo-9.1 {info args} -body { type dog { method bark {volume} {} } dog spot spot info args bark } -cleanup { dog destroy } -result {volume} test iinfo-9.2 {info args, too few args} -body { type dog { method bark {volume} {} } dog spot spot info args } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.method.info.args {type selfns win self method} 4] test iinfo-9.3 {info args, too many args} -body { type dog { method bark {volume} {} } dog spot spot info args bark wag } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.method.info.args {type selfns win self method}] test iinfo-9.4 {info args, unknown method} -body { type dog { } dog spot spot info args bark } -returnCodes error -cleanup { dog destroy } -result {Unknown method "bark"} test iinfo-9.5 {info args, delegated method} -body { type dog { component x delegate method bark to x } dog spot spot info args bark } -returnCodes error -cleanup { dog destroy } -result {Delegated method "bark"} test iinfo-10.1 {info default} -body { type dog { method bark {{volume 50}} {} } dog spot list [spot info default bark volume def] $def } -cleanup { dog destroy } -result {1 50} test iinfo-10.2 {info default, too few args} -body { type dog { method bark {volume} {} } dog spot spot info default } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.method.info.default {type selfns win self method aname dvar} 4] test iinfo-10.3 {info default, too many args} -body { type dog { method bark {volume} {} } dog spot spot info default bark wag def foo } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.method.info.default {type selfns win self method aname dvar}] test iinfo-10.4 {info default, unknown method} -body { type dog { } dog spot spot info default bark x var } -returnCodes error -cleanup { dog destroy } -result {Unknown method "bark"} test iinfo-10.5 {info default, delegated method} -body { type dog { component x delegate method bark to x } dog spot spot info default bark x var } -returnCodes error -cleanup { dog destroy } -result {Delegated method "bark"} test iinfo-11.1 {info body} -body { type dog { typevariable x variable y method bark {volume} { speaker on speaker play bark.snd speaker off } } dog spot spot info body bark } -cleanup { dog destroy } -result { speaker on speaker play bark.snd speaker off } test iinfo-11.2 {info body, too few args} -body { type dog { method bark {volume} {} } dog spot spot info body } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.method.info.body {type selfns win self method} 4] test iinfo-11.3 {info body, too many args} -body { type dog { method bark {volume} {} } dog spot spot info body bark wag } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.method.info.body {type selfns win self method}] test iinfo-11.4 {info body, unknown method} -body { type dog { } dog spot spot info body bark } -returnCodes error -cleanup { dog destroy } -result {Unknown method "bark"} test iinfo-11.5 {info body, delegated method} -body { type dog { component x delegate method bark to x } dog spot spot info body bark } -returnCodes error -cleanup { dog destroy } -result {Delegated method "bark"} #----------------------------------------------------------------------- # Type Introspection # Case 1 test tinfo-1.1 {type info too few args} -constraints { snit1 } -body { type dog { } dog info } -returnCodes { error } -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.typemethod.info {type command args} 1] # Case 2 test tinfo-1.2 {type info too few args} -constraints { snit2 } -body { type dog { } dog info } -returnCodes { error } -cleanup { dog destroy } -result [expect \ {wrong # args: should be "dog info command ?arg ...?"} \ {wrong # args: should be "dog info command ..."}] test tinfo-1.3 {type info too many args} -body { type dog { } dog info instances foo bar } -returnCodes { error } -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.typemethod.info.instances {type ?pattern?}] test tinfo-2.1 {type info typevars} -body { type dog { typevariable thisvar 1 constructor {args} { typevariable thatvar 2 } } dog create spot lsort [dog info typevars] } -cleanup { dog destroy } -result {::dog::thatvar ::dog::thisvar} test tinfo-3.1 {type info instances} -body { type dog { } dog create spot dog create fido lsort [dog info instances] } -cleanup { dog destroy } -result {::fido ::spot} 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 tinfo-3.3 {type info instances with non-global namespaces} -body { type dog { } dog create ::spot namespace eval ::dogs:: { set ::qname [dog create fido] } list $qname [lsort [dog info instances]] } -cleanup { dog destroy } -result {::dogs::fido {::dogs::fido ::spot}} test tinfo-3.4 {type info instances with pattern} -body { type dog { } dog create spot dog create fido dog info instances "*f*" } -cleanup { dog destroy } -result {::fido} test tinfo-3.5 {type info instances with unrelated child namespace, bug 2898640} -body { type dog { } namespace eval dog::unrelated {} dog create fido dog info instances } -cleanup { dog destroy } -result {::fido} test tinfo-4.1 {type info typevars with pattern} -body { type dog { typevariable thisvar 1 constructor {args} { typevariable thatvar 2 } } dog create spot dog info typevars *this* } -cleanup { dog destroy } -result {::dog::thisvar} test tinfo-5.1 {type info typemethods, simple case} -body { type dog { } lsort [dog info typemethods] } -cleanup { dog destroy } -result {create destroy info} test tinfo-5.2 {type info typemethods, with pattern} -body { type dog { } dog info typemethods i* } -cleanup { dog destroy } -result {info} test tinfo-5.3 {type info typemethods, with explicit typemethods} -body { type dog { typemethod foo {} {} delegate typemethod bar to comp } lsort [dog info typemethods] } -cleanup { dog destroy } -result {bar create destroy foo info} test tinfo-5.4 {type info typemethods, with implicit typemethods} -body { type dog { delegate typemethod * to comp typeconstructor { set comp string } } set a [lsort [dog info typemethods]] dog length foo dog is boolean yes set b [lsort [dog info typemethods]] set c [dog info typemethods len*] list $a $b $c } -cleanup { dog destroy } -result {{create destroy info} {create destroy info is length} length} test tinfo-5.5 {info typemethods, with hierarchical typemethods} -body { type dog { delegate typemethod {comp foo} to comp typemethod {comp bar} {} {} } lsort [dog info typemethods] } -cleanup { dog destroy } -result {{comp bar} {comp foo} create destroy info} test tinfo-6.1 {type info args} -body { type dog { typemethod bark {volume} {} } dog info args bark } -cleanup { dog destroy } -result {volume} test tinfo-6.2 {type info args, too few args} -body { type dog { typemethod bark {volume} {} } dog info args } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.typemethod.info.args {type method} 1] test tinfo-6.3 {type info args, too many args} -body { type dog { typemethod bark {volume} {} } dog info args bark wag } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.typemethod.info.args {type method}] test tinfo-6.4 {type info args, unknown method} -body { type dog { } dog info args bark } -returnCodes error -cleanup { dog destroy } -result {Unknown typemethod "bark"} test tinfo-6.5 {type info args, delegated method} -body { type dog { delegate typemethod bark to x } dog info args bark } -returnCodes error -cleanup { dog destroy } -result {Delegated typemethod "bark"} test tinfo-7.1 {type info default} -body { type dog { typemethod bark {{volume 50}} {} } list [dog info default bark volume def] $def } -cleanup { dog destroy } -result {1 50} test tinfo-7.2 {type info default, too few args} -body { type dog { typemethod bark {volume} {} } dog info default } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.typemethod.info.default {type method aname dvar} 1] test tinfo-7.3 {type info default, too many args} -body { type dog { typemethod bark {volume} {} } dog info default bark wag def foo } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.typemethod.info.default {type method aname dvar}] test tinfo-7.4 {type info default, unknown method} -body { type dog { } dog info default bark x var } -returnCodes error -cleanup { dog destroy } -result {Unknown typemethod "bark"} test tinfo-7.5 {type info default, delegated method} -body { type dog { delegate typemethod bark to x } dog info default bark x var } -returnCodes error -cleanup { dog destroy } -result {Delegated typemethod "bark"} test tinfo-8.1 {type info body} -body { type dog { typevariable x variable y typemethod bark {volume} { speaker on speaker play bark.snd speaker off } } dog info body bark } -cleanup { dog destroy } -result { speaker on speaker play bark.snd speaker off } test tinfo-8.2 {type info body, too few args} -body { type dog { typemethod bark {volume} {} } dog info body } -returnCodes error -cleanup { dog destroy } -result [tcltest::wrongNumArgs ::snit::RT.typemethod.info.body {type method} 1] test tinfo-8.3 {type info body, too many args} -body { type dog { typemethod bark {volume} {} } dog info body bark wag } -returnCodes error -cleanup { dog destroy } -result [tcltest::tooManyArgs ::snit::RT.typemethod.info.body {type method}] test tinfo-8.4 {type info body, unknown method} -body { type dog { } dog info body bark } -returnCodes error -cleanup { dog destroy } -result {Unknown typemethod "bark"} test tinfo-8.5 {type info body, delegated method} -body { type dog { delegate typemethod bark to x } dog info body bark } -returnCodes error -cleanup { dog destroy } -result {Delegated typemethod "bark"} #----------------------------------------------------------------------- # Setting the widget class explicitly test widgetclass-1.1 {can't set widgetclass for snit::types} -body { type dog { widgetclass Dog } } -returnCodes { error } -result {widgetclass cannot be set for snit::types} test widgetclass-1.2 {can't set widgetclass for snit::widgetadaptors} -constraints { tk } -body { widgetadaptor dog { widgetclass Dog } } -returnCodes { error } -result {widgetclass cannot be set for snit::widgetadaptors} test widgetclass-1.3 {widgetclass must begin with uppercase letter} -constraints { tk } -body { widget dog { widgetclass dog } } -returnCodes { error } -result {widgetclass "dog" does not begin with an uppercase letter} test widgetclass-1.4 {widgetclass can only be defined once} -constraints { tk } -body { widget dog { widgetclass Dog widgetclass Dog } } -returnCodes { error } -result {too many widgetclass statements} test widgetclass-1.5 {widgetclass set successfully} -constraints { tk } -body { widget dog { widgetclass DogWidget } # The test passes if no error is thrown. list ok } -cleanup { dog destroy } -result {ok} test widgetclass-1.6 {implicit widgetclass applied to hull} -constraints { tk } -body { widget dog { typeconstructor { option add *Dog.background green } method background {} { $hull cget -background } } dog .dog set bg [.dog background] destroy .dog set bg } -cleanup { dog destroy } -result {green} test widgetclass-1.7 {explicit widgetclass applied to hull} -constraints { tk } -body { widget dog { widgetclass DogWidget typeconstructor { option add *DogWidget.background green } method background {} { $hull cget -background } } dog .dog set bg [.dog background] destroy .dog set bg } -cleanup { dog destroy } -result {green} #----------------------------------------------------------------------- # hulltype statement test hulltype-1.1 {can't set hulltype for snit::types} -body { type dog { hulltype Dog } } -returnCodes { error } -result {hulltype cannot be set for snit::types} test hulltype-1.2 {can't set hulltype for snit::widgetadaptors} -constraints { tk } -body { widgetadaptor dog { hulltype Dog } } -returnCodes { error } -result {hulltype cannot be set for snit::widgetadaptors} test hulltype-1.3 {hulltype can be frame} -constraints { tk } -body { widget dog { delegate option * to hull hulltype frame } dog .fido catch {.fido configure -use} result destroy .fido tkbide set result } -cleanup { dog destroy } -result {unknown option "-use"} test hulltype-1.4 {hulltype can be toplevel} -constraints { tk } -body { widget dog { delegate option * to hull hulltype toplevel } dog .fido catch {.fido configure -use} result destroy .fido tkbide set result } -cleanup { dog destroy } -result {-use use Use {} {}} test hulltype-1.5 {hulltype can only be defined once} -constraints { tk } -body { widget dog { hulltype frame hulltype toplevel } } -returnCodes { error } -result {too many hulltype statements} test hulltype-2.1 {list of valid hulltypes} -constraints { tk } -body { lsort $::snit::hulltypes } -result {frame labelframe tk::frame tk::labelframe tk::toplevel toplevel ttk::frame ttk::labelframe} #----------------------------------------------------------------------- # expose statement test expose-1.1 {can't expose nothing} -body { type dog { expose } } -constraints { snit1 } -returnCodes { error } -result [tcltest::wrongNumArgs ::snit::Comp.statement.expose {component ?as? ?methodname?} 0] test expose-1.1a {can't expose nothing} -body { type dog { expose } } -constraints { snit2 } -returnCodes { error } -result [tcltest::wrongNumArgs expose {component ?as? ?methodname?} 0] test expose-1.2 {expose a component that's never installed} -body { type dog { expose tail } dog fido fido tail wag } -returnCodes { error } -cleanup { dog destroy } -result {undefined component "tail"} test expose-1.3 {exposed method returns component command} -body { type tail { } type dog { expose tail constructor {} { install tail using tail $self.tail } destructor { $tail destroy } } dog fido fido tail } -cleanup { dog destroy tail destroy } -result {::fido.tail} test expose-1.4 {exposed method calls component methods} -body { type tail { method wag {args} {return "wag<$args>"} method droop {} {return "droop"} } type dog { expose tail constructor {} { install tail using tail $self.tail } destructor { $tail destroy } } dog fido list [fido tail wag] [fido tail wag abc] [fido tail wag abc def] \ [fido tail droop] } -cleanup { dog destroy tail destroy } -result {wag<> wag {wag} droop} #----------------------------------------------------------------------- # Error handling # # This section verifies that errorInfo and errorCode are propagated # appropriately on error. test error-1.1 {typemethod errors propagate properly} -body { type dog { typemethod generr {} { error bogusError bogusInfo bogusCode } } catch {dog generr} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {bogusError 1 bogusCode} test error-1.2 {snit::type constructor errors propagate properly} -body { type dog { constructor {} { error bogusError bogusInfo bogusCode } } catch {dog fido} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {{Error in constructor: bogusError} 1 bogusCode} test error-1.3 {snit::widget constructor errors propagate properly} -constraints { tk } -body { widget dog { constructor {args} { error bogusError bogusInfo bogusCode } } catch {dog .fido} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {{Error in constructor: bogusError} 1 bogusCode} test error-1.4 {method errors propagate properly} -body { type dog { method generr {} { error bogusError bogusInfo bogusCode } } dog fido catch {fido generr} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {bogusError 1 bogusCode} test error-1.5 {onconfigure errors propagate properly} -body { type dog { option -generr onconfigure -generr {value} { error bogusError bogusInfo bogusCode } } dog fido catch {fido configure -generr 0} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {bogusError 1 bogusCode} test error-1.6 {oncget errors propagate properly} -body { type dog { option -generr oncget -generr { error bogusError bogusInfo bogusCode } } dog fido catch {fido cget -generr} result global errorInfo errorCode list $result [string match "*bogusInfo*" $errorInfo] $errorCode } -cleanup { dog destroy } -result {bogusError 1 bogusCode} #----------------------------------------------------------------------- # Externally defined typemethods test etypemethod-1.1 {external typemethods can be called as expected} -body { type dog { } typemethod dog foo {a} {return "+$a+"} dog foo bar } -cleanup { dog destroy } -result {+bar+} test etypemethod-1.2 {external typemethods can use typevariables} -body { type dog { typevariable somevar "Howdy" } typemethod dog getvar {} {return $somevar} dog getvar } -cleanup { dog destroy } -result {Howdy} test etypemethod-1.3 {typemethods can be redefined dynamically} -body { type dog { typemethod foo {} { return "foo" } } set a [dog foo] typemethod dog foo {} { return "bar"} set b [dog foo] list $a $b } -cleanup { dog destroy } -result {foo bar} test etypemethod-1.4 {can't define external typemethod if no type} -body { typemethod extremelyraredog foo {} { return "bar"} } -returnCodes { error } -result {no such type: "extremelyraredog"} test etypemethod-2.1 {external hierarchical method, two tokens} -body { type dog { } typemethod dog {wag tail} {} { return "wags tail" } dog wag tail } -cleanup { dog destroy } -result {wags tail} test etypemethod-2.2 {external hierarchical method, three tokens} -body { type dog { } typemethod dog {wag tail proudly} {} { return "wags tail proudly" } dog wag tail proudly } -cleanup { dog destroy } -result {wags tail proudly} test etypemethod-2.3 {external hierarchical method, three tokens} -body { type dog { } typemethod dog {wag tail really high} {} { return "wags tail really high" } dog wag tail really high } -cleanup { dog destroy } -result {wags tail really high} test etypemethod-2.4 {redefinition is OK} -body { type dog { } typemethod dog {wag tail} {} { return "wags tail" } typemethod dog {wag tail} {} { return "wags tail briskly" } dog wag tail } -cleanup { dog destroy } -result {wags tail briskly} test etypemethod-3.1 {prefix/method collision} -body { type dog { typemethod wag {} {} } typemethod dog {wag tail} {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail", "wag" has no submethods.} test etypemethod-3.2 {prefix/method collision} -body { type dog { typemethod {wag tail} {} {} } typemethod dog wag {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag", "wag" has submethods.} test etypemethod-3.3 {prefix/method collision} -body { type dog { typemethod {wag tail} {} {} } typemethod dog {wag tail proudly} {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail proudly", "wag tail" has no submethods.} test etypemethod-3.4 {prefix/method collision} -body { type dog { typemethod {wag tail proudly} {} {} } typemethod dog {wag tail} {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail", "wag tail" has submethods.} #----------------------------------------------------------------------- # Externally defined methods test emethod-1.1 {external methods can be called as expected} -body { type dog { } method dog bark {a} {return "+$a+"} dog spot spot bark woof } -cleanup { dog destroy } -result {+woof+} test emethod-1.2 {external methods can use typevariables} -body { type dog { typevariable somevar "Hello" } method dog getvar {} {return $somevar} dog spot spot getvar } -cleanup { dog destroy } -result {Hello} test emethod-1.3 {external methods can use variables} -body { type dog { variable somevar "Greetings" } method dog getvar {} {return $somevar} dog spot spot getvar } -cleanup { dog destroy } -result {Greetings} test emethod-1.4 {methods can be redefined dynamically} -body { type dog { method bark {} { return "woof" } } dog spot set a [spot bark] method dog bark {} { return "arf"} set b [spot bark] list $a $b } -cleanup { dog destroy } -result {woof arf} test emethod-1.5 {delegated methods can't be redefined} -body { type dog { delegate method bark to someotherdog } method dog bark {} { return "arf"} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "bark", "bark" has been delegated} test emethod-1.6 {can't define external method if no type} -body { method extremelyraredog foo {} { return "bar"} } -returnCodes { error } -result {no such type: "extremelyraredog"} test emethod-2.1 {external hierarchical method, two tokens} -body { type dog { } method dog {wag tail} {} { return "$self wags tail." } dog spot spot wag tail } -cleanup { dog destroy } -result {::spot wags tail.} test emethod-2.2 {external hierarchical method, three tokens} -body { type dog { } method dog {wag tail proudly} {} { return "$self wags tail proudly." } dog spot spot wag tail proudly } -cleanup { dog destroy } -result {::spot wags tail proudly.} test emethod-2.3 {external hierarchical method, three tokens} -body { type dog { } method dog {wag tail really high} {} { return "$self wags tail really high." } dog spot spot wag tail really high } -cleanup { dog destroy } -result {::spot wags tail really high.} test emethod-2.4 {redefinition is OK} -body { type dog { } method dog {wag tail} {} { return "$self wags tail." } method dog {wag tail} {} { return "$self wags tail briskly." } dog spot spot wag tail } -cleanup { dog destroy } -result {::spot wags tail briskly.} test emethod-3.1 {prefix/method collision} -body { type dog { method wag {} {} } method dog {wag tail} {} { return "$self wags tail." } } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail", "wag" has no submethods.} test emethod-3.2 {prefix/method collision} -body { type dog { method {wag tail} {} { return "$self wags tail." } } method dog wag {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag", "wag" has submethods.} test emethod-3.3 {prefix/method collision} -body { type dog { method {wag tail} {} {} } method dog {wag tail proudly} {} { return "$self wags tail." } } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail proudly", "wag tail" has no submethods.} test emethod-3.4 {prefix/method collision} -body { type dog { method {wag tail proudly} {} { return "$self wags tail." } } method dog {wag tail} {} {} } -returnCodes { error } -cleanup { dog destroy } -result {Cannot define "wag tail", "wag tail" has submethods.} #----------------------------------------------------------------------- # Macros test macro-1.1 {can't redefine non-macros} -body { snit::macro method {} {} } -returnCodes { error } -result {invalid macro name "method"} test macro-1.2 {can define and use a macro} -body { snit::macro hello {name} { method hello {} "return {Hello, $name!}" } type dog { hello World } dog spot spot hello } -cleanup { dog destroy } -result {Hello, World!} test macro-1.3 {can redefine macro} -body { snit::macro dup {} {} snit::macro dup {} {} set dummy "No error" } -result {No error} test macro-1.4 {can define macro in namespace} -body { snit::macro ::test::goodbye {name} { method goodbye {} "return {Goodbye, $name!}" } type dog { ::test::goodbye World } dog spot spot goodbye } -cleanup { dog destroy } -result {Goodbye, World!} test macro-1.5 {_proc and _variable are defined} -body { snit::macro testit {} { set a [info commands _variable] set b [info commands _proc] method testit {} "list $a $b" } type dog { testit } dog spot spot testit } -cleanup { dog destroy } -result {_variable _proc} test macro-1.6 {_variable works} -body { snit::macro test1 {} { _variable myvar "_variable works" } snit::macro test2 {} { _variable myvar method testit {} "return {$myvar}" } type dog { test1 test2 } dog spot spot testit } -cleanup { dog destroy } -result {_variable works} #----------------------------------------------------------------------- # Component Statement test component-1.1 {component defines an instance variable} -body { type dog { component tail } dog spot namespace tail [spot info vars tail] } -cleanup { dog destroy } -result {tail} test component-1.2 {-public exposes the component} -body { type tail { method wag {} { return "Wag, wag" } } type dog { component tail -public mytail constructor {} { set tail [tail %AUTO%] } } dog spot spot mytail wag } -cleanup { dog destroy tail destroy } -result {Wag, wag} test component-1.3 {-inherit requires a boolean value} -body { type dog { component animal -inherit foo } } -returnCodes { error } -result {component animal -inherit: expected boolean value, got "foo"} test component-1.4 {-inherit delegates unknown methods to the component} -body { type animal { method eat {} { return "Eat, eat." } } type dog { component animal -inherit yes constructor {} { set animal [animal %AUTO%] } } dog spot spot eat } -cleanup { dog destroy animal destroy } -result {Eat, eat.} test component-1.5 {-inherit delegates unknown options to the component} -body { type animal { option -size medium } type dog { component animal -inherit yes constructor {} { set animal [animal %AUTO%] } } dog spot spot cget -size } -cleanup { dog destroy animal destroy } -result {medium} #----------------------------------------------------------------------- # Typevariables, Variables, Typecomponents, Components test typevar_var-1.1 {variable/typevariable collisions not allowed: order 1} -body { type dog { typevariable var variable var } } -returnCodes { error } -result {Error in "variable var...", "var" is already a typevariable} test typevar_var-1.2 {variable/typevariable collisions not allowed: order 2} -body { type dog { variable var typevariable var } } -returnCodes { error } -result {Error in "typevariable var...", "var" is already an instance variable} test typevar_var-1.3 {component/typecomponent collisions not allowed: order 1} -body { type dog { typecomponent comp component comp } } -returnCodes { error } -result {Error in "component comp...", "comp" is already a typevariable} test typevar_var-1.4 {component/typecomponent collisions not allowed: order 2} -body { type dog { component comp typecomponent comp } } -returnCodes { error } -result {Error in "typecomponent comp...", "comp" is already an instance variable} test typevar_var-1.5 {can't delegate options to typecomponents} -body { type dog { typecomponent comp delegate option -opt to comp } } -returnCodes { error } -result {Error in "delegate option -opt...", "comp" is already a typevariable} test typevar_var-1.6 {can't delegate typemethods to instance components} -body { type dog { component comp delegate typemethod foo to comp } } -returnCodes { error } -result {Error in "delegate typemethod foo...", "comp" is already an instance variable} test typevar_var-1.7 {can delegate methods to typecomponents} -body { proc echo {args} {return [join $args "|"]} type dog { typecomponent tail typeconstructor { set tail echo } delegate method wag to tail } dog spot spot wag briskly } -cleanup { dog destroy rename echo "" } -result {wag|briskly} #----------------------------------------------------------------------- # Option syntax tests. # # This set of tests verifies that the option statement is interpreted # properly, that errors are caught, and that the type's optionInfo # array is initialized properly. # # TBD: At some point, this needs to be folded into the regular # option tests. test optionsyntax-1.1 {local option names are saved} -body { type dog { option -foo option -bar } set ::dog::Snit_optionInfo(local) } -cleanup { dog destroy } -result {-foo -bar} test optionsyntax-1.2 {islocal flag is set} -body { type dog { option -foo } set ::dog::Snit_optionInfo(islocal--foo) } -cleanup { dog destroy } -result {1} test optionsyntax-2.1 {implicit resource and class} -body { type dog { option -foo } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {foo Foo} test optionsyntax-2.2 {explicit resource, default class} -body { type dog { option {-foo ffoo} } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {ffoo Ffoo} test optionsyntax-2.3 {explicit resource and class} -body { type dog { option {-foo ffoo FFoo} } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {ffoo FFoo} test optionsyntax-2.4 {can't redefine explicit resource} -body { type dog { option {-foo ffoo} option {-foo foo} } } -returnCodes { error } -result {Error in "option {-foo foo}...", resource name redefined from "ffoo" to "foo"} test optionsyntax-2.5 {can't redefine explicit class} -body { type dog { option {-foo ffoo Ffoo} option {-foo ffoo FFoo} } } -returnCodes { error } -result {Error in "option {-foo ffoo FFoo}...", class name redefined from "Ffoo" to "FFoo"} test optionsyntax-2.6 {can redefine implicit resource and class} -body { type dog { option -foo option {-foo ffoo} option {-foo ffoo FFoo} option -foo } } -cleanup { dog destroy } -result {::dog} test optionsyntax-3.1 {no default value} -body { type dog { option -foo } set ::dog::Snit_optionInfo(default--foo) } -cleanup { dog destroy } -result {} test optionsyntax-3.2 {default value, old syntax} -body { type dog { option -foo bar } set ::dog::Snit_optionInfo(default--foo) } -cleanup { dog destroy } -result {bar} test optionsyntax-3.3 {option definition options can be set} -body { type dog { option -foo \ -default Bar \ -validatemethod Validate \ -configuremethod Configure \ -cgetmethod Cget \ -readonly 1 } list \ $::dog::Snit_optionInfo(default--foo) \ $::dog::Snit_optionInfo(validate--foo) \ $::dog::Snit_optionInfo(configure--foo) \ $::dog::Snit_optionInfo(cget--foo) \ $::dog::Snit_optionInfo(readonly--foo) } -cleanup { dog destroy } -result {Bar Validate Configure Cget 1} test optionsyntax-3.4 {option definition option values accumulate} -body { type dog { option -foo -default Bar option -foo -validatemethod Validate option -foo -configuremethod Configure option -foo -cgetmethod Cget option -foo -readonly 1 } list \ $::dog::Snit_optionInfo(default--foo) \ $::dog::Snit_optionInfo(validate--foo) \ $::dog::Snit_optionInfo(configure--foo) \ $::dog::Snit_optionInfo(cget--foo) \ $::dog::Snit_optionInfo(readonly--foo) } -cleanup { dog destroy } -result {Bar Validate Configure Cget 1} test optionsyntax-3.5 {option definition option values can be redefined} -body { type dog { option -foo -default Bar option -foo -validatemethod Validate option -foo -configuremethod Configure option -foo -cgetmethod Cget option -foo -readonly 1 option -foo -default Bar2 option -foo -validatemethod Validate2 option -foo -configuremethod Configure2 option -foo -cgetmethod Cget2 option -foo -readonly 0 } list \ $::dog::Snit_optionInfo(default--foo) \ $::dog::Snit_optionInfo(validate--foo) \ $::dog::Snit_optionInfo(configure--foo) \ $::dog::Snit_optionInfo(cget--foo) \ $::dog::Snit_optionInfo(readonly--foo) } -cleanup { dog destroy } -result {Bar2 Validate2 Configure2 Cget2 0} test optionsyntax-3.6 {option -readonly defaults to 0} -body { type dog { option -foo } set ::dog::Snit_optionInfo(readonly--foo) } -cleanup { dog destroy } -result {0} test optionsyntax-3.7 {option -readonly can be any boolean} -body { type dog { option -foo -readonly 0 option -foo -readonly 1 option -foo -readonly y option -foo -readonly n } } -cleanup { dog destroy } -result {::dog} test optionsyntax-3.8 {option -readonly must be a boolean} -body { type dog { option -foo -readonly foo } } -returnCodes { error } -result {Error in "option -foo...", -readonly requires a boolean, got "foo"} test optionsyntax-3.9 {option -readonly can't be empty} -body { type dog { option -foo -readonly {} } } -returnCodes { error } -result {Error in "option -foo...", -readonly requires a boolean, got ""} #----------------------------------------------------------------------- # 'delegate option' Syntax tests. # # This set of tests verifies that the 'delegation option' statement is # interpreted properly, and that the type's optionInfo # array is initialized properly. # # TBD: At some point, this needs to be folded into the regular # option tests. test delegateoptionsyntax-1.1 {'delegated' lists delegated option names} -body { type dog { delegate option -foo to comp delegate option -bar to comp } set ::dog::Snit_optionInfo(delegated) } -cleanup { dog destroy } -result {-foo -bar} test delegateoptionsyntax-1.2 {'delegated' does not include '*'} -body { type dog { delegate option * to comp } set ::dog::Snit_optionInfo(delegated) } -cleanup { dog destroy } -result {} test delegateoptionsyntax-1.3 {'islocal' is set to 0} -body { type dog { delegate option -foo to comp } set ::dog::Snit_optionInfo(islocal--foo) } -cleanup { dog destroy } -result {0} test delegateoptionsyntax-1.4 {'islocal' is not set for '*'} -body { type dog { delegate option * to comp } info exists ::dog::Snit_optionInfo(islocal-*) } -cleanup { dog destroy } -result {0} test delegateoptionsyntax-1.5 {'delegated-$comp' lists options for the component} -body { type dog { delegate option -foo to comp1 delegate option -bar to comp1 delegate option -baz to comp2 # The * won't show up. delegate option * to comp2 } list \ $::dog::Snit_optionInfo(delegated-comp1) \ $::dog::Snit_optionInfo(delegated-comp2) } -cleanup { dog destroy } -result {{-foo -bar} -baz} test delegateoptionsyntax-1.6 {'except' is empty by default} -body { type dog { delegate option -foo to comp } set ::dog::Snit_optionInfo(except) } -cleanup { dog destroy } -result {} test delegateoptionsyntax-1.7 {'except' lists exceptions} -body { type dog { delegate option * to comp except {-foo -bar -baz} } set ::dog::Snit_optionInfo(except) } -cleanup { dog destroy } -result {-foo -bar -baz} test delegateoptionsyntax-1.8 {'target-$opt' set with default} -body { type dog { delegate option -foo to comp } set ::dog::Snit_optionInfo(target--foo) } -cleanup { dog destroy } -result {comp -foo} test delegateoptionsyntax-1.9 {'target-$opt' set explicitly} -body { type dog { delegate option -foo to comp as -bar } set ::dog::Snit_optionInfo(target--foo) } -cleanup { dog destroy } -result {comp -bar} test delegateoptionsyntax-1.10 {'starcomp' is {} by default} -body { type dog { delegate option -foo to comp } set ::dog::Snit_optionInfo(starcomp) } -cleanup { dog destroy } -result {} test delegateoptionsyntax-1.11 {'starcomp' set for *} -body { type dog { delegate option * to comp } set ::dog::Snit_optionInfo(starcomp) } -cleanup { dog destroy } -result {comp} test delegatedoptionsyntax-2.1 {implicit resource and class} -body { type dog { delegate option -foo to comp } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {foo Foo} test delegatedoptionsyntax-2.2 {explicit resource, default class} -body { type dog { delegate option {-foo ffoo} to comp } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {ffoo Ffoo} test delegatedoptionsyntax-2.3 {explicit resource and class} -body { type dog { delegate option {-foo ffoo FFoo} to comp } list \ $::dog::Snit_optionInfo(resource--foo) \ $::dog::Snit_optionInfo(class--foo) } -cleanup { dog destroy } -result {ffoo FFoo} test delegatedoptionsyntax-2.4 {* doesn't get resource and class} -body { type dog { delegate option * to comp } list \ [info exist ::dog::Snit_optionInfo(resource-*)] \ [info exist ::dog::Snit_optionInfo(class-*)] } -cleanup { dog destroy } -result {0 0} #----------------------------------------------------------------------- # Cget cache test cgetcache-1.1 {Instance rename invalidates cache} -body { type dog { option -foo -default bar -cgetmethod getfoo method getfoo {option} { return $options($option) } } dog fido -foo quux # Cache the cget command. fido cget -foo rename fido spot spot cget -foo } -cleanup { dog destroy } -result {quux} test cgetcache-1.2 {Component rename invalidates cache} -body { type tail { option -foo bar } type dog { delegate option -foo to tail constructor {args} { set tail [tail %AUTO%] $tail configure -foo quux } method retail {} { set tail [tail %AUTO%] } } dog fido # Cache the cget command. fido cget -foo # Invalidate the cache fido retail fido cget -foo } -cleanup { dog destroy tail destroy } -result {bar} # case 1 test cgetcache-1.3 {Invalid -cgetmethod causes error} -constraints { snit1 } -body { type dog { option -foo -default bar -cgetmethod bogus } dog fido -foo quux fido cget -foo } -returnCodes { error } -cleanup { dog destroy } -result {can't cget -foo, "::fido bogus" is not defined} # case 2 test cgetcache-1.4 {Invalid -cgetmethod causes error} -constraints { snit2 } -body { type dog { option -foo -default bar -cgetmethod bogus } dog fido -foo quux fido cget -foo } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "bogus": must be cget, or configurelist} test cgetcache-1.5 {hierarchical -cgetmethod} -body { type dog { option -foo -default bar -cgetmethod {Get Opt} method {Get Opt} {option} { return Dummy } } dog fido fido cget -foo } -cleanup { dog destroy } -result {Dummy} #----------------------------------------------------------------------- # Configure cache test configurecache-1.1 {Instance rename invalidates cache} -body { type dog { option -foo -default bar -configuremethod setfoo method setfoo {option value} { $self setoption $option $value } method setoption {option value} { set options($option) $value } } # Set the option on creation; this will cache the # configure command. dog fido -foo quux rename fido spot spot configure -foo baz spot cget -foo } -cleanup { dog destroy } -result {baz} test configurecache-1.2 {Component rename invalidates cache} -body { type tail { option -foo bar } type dog { delegate option -foo to tail constructor {args} { set tail [tail thistail] $self configurelist $args } method retail {} { # Give it a new component set tail [tail thattail] } } # Set the tail's -foo, and cache the command. dog fido -foo quux # Invalidate the cache fido retail # Should recache, and set the new tail's option. fido configure -foo baz fido cget -foo } -cleanup { dog destroy tail destroy } -result {baz} # Case 1 test configurecache-1.3 {Invalid -configuremethod causes error} -constraints { snit1 } -body { type dog { option -foo -default bar -configuremethod bogus } dog fido fido configure -foo quux } -returnCodes { error } -cleanup { dog destroy } -result {can't configure -foo, "::fido bogus" is not defined} # Case 2 test configurecache-1.4 {Invalid -configuremethod causes error} -constraints { snit2 } -body { type dog { option -foo -default bar -configuremethod bogus } dog fido fido configure -foo quux } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "bogus": must be configure, or configurelist} test configurecache-1.5 {hierarchical -configuremethod} -body { type dog { option -foo -default bar -configuremethod {Set Opt} method {Set Opt} {option value} { set options($option) Dummy } } dog fido -foo NotDummy fido cget -foo } -cleanup { dog destroy } -result {Dummy} #----------------------------------------------------------------------- # option -validatemethod test validatemethod-1.1 {Validate method is called} -body { type dog { variable flag 0 option -color \ -default black \ -validatemethod ValidateColor method ValidateColor {option value} { set flag 1 } method getflag {} { return $flag } } dog fido -color brown fido getflag } -cleanup { dog destroy } -result {1} test validatemethod-1.2 {Validate method gets correct arguments} -body { type dog { option -color \ -default black \ -validatemethod ValidateColor method ValidateColor {option value} { if {![string equal $option "-color"] || ![string equal $value "brown"]} { error "Expected '-color brown'" } } } dog fido -color brown } -cleanup { dog destroy } -result {::fido} # Case 1 test validatemethod-1.3 {Invalid -validatemethod causes error} -constraints { snit1 } -body { type dog { option -foo -default bar -validatemethod bogus } dog fido fido configure -foo quux } -returnCodes { error } -cleanup { dog destroy } -result {can't validate -foo, "::fido bogus" is not defined} # Case 2 test validatemethod-1.4 {Invalid -validatemethod causes error} -constraints { snit2 } -body { type dog { option -foo -default bar -validatemethod bogus } dog fido fido configure -foo quux } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "bogus": must be configure, or configurelist} test validatemethod-1.5 {hierarchical -validatemethod} -body { type dog { option -foo -default bar -validatemethod {Val Opt} method {Val Opt} {option value} { error "Dummy" } } dog fido -foo value } -returnCodes { error } -cleanup { dog destroy } -result {Error in constructor: Dummy} #----------------------------------------------------------------------- # option -readonly semantics test optionreadonly-1.1 {Readonly options can be set at creation time} -body { type dog { option -color \ -default black \ -readonly true } dog fido -color brown fido cget -color } -cleanup { dog destroy } -result {brown} test optionreadonly-1.2 {Readonly options can't be set after creation} -body { type dog { option -color \ -default black \ -readonly true } dog fido fido configure -color brown } -returnCodes { error } -cleanup { dog destroy } -result {option -color can only be set at instance creation} test optionreadonly-1.3 {Readonly options can't be set after creation} -body { type dog { option -color \ -default black \ -readonly true } dog fido -color yellow fido configure -color brown } -returnCodes { error } -cleanup { dog destroy } -result {option -color can only be set at instance creation} #----------------------------------------------------------------------- # Pragma -hastypeinfo test hastypeinfo-1.1 {$type info is defined by default} -body { type dog { typevariable foo } dog info typevars } -cleanup { dog destroy } -result {::dog::foo} # Case 1 test hastypeinfo-1.2 {$type info can be disabled} -constraints { snit1 } -body { type dog { pragma -hastypeinfo no typevariable foo } dog info typevars } -returnCodes { error } -cleanup { dog destroy } -result {"::dog info" is not defined} # Case 2 test hastypeinfo-1.3 {$type info can be disabled} -constraints { snit2 } -body { type dog { pragma -hastypeinfo no typevariable foo } dog info typevars } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "info": namespace ::dog does not export any commands} #----------------------------------------------------------------------- # Pragma -hastypedestroy test hastypedestroy-1.1 {$type destroy is defined by default} -body { type dog { typevariable foo } dog destroy ::dog info typevars } -returnCodes { error } -result {invalid command name "::dog"} # Case 1 test hastypedestroy-1.2 {$type destroy can be disabled} -constraints { snit1 } -body { type dog { pragma -hastypedestroy no typevariable foo } dog destroy } -returnCodes { error } -cleanup { rename ::dog "" namespace delete ::dog } -result {"::dog destroy" is not defined} # Case 2 test hastypedestroy-1.3 {$type destroy can be disabled} -constraints { snit2 } -body { type dog { pragma -hastypedestroy no typevariable foo } dog destroy } -returnCodes { error } -cleanup { rename ::dog "" namespace delete ::dog } -result {unknown subcommand "destroy": namespace ::dog does not export any commands} #----------------------------------------------------------------------- # Pragma -hasinstances test hasinstances-1.1 {-hasinstances is true by default} -body { type dog { method bark {} { return "Woof" } } dog fido fido bark } -cleanup { dog destroy } -result {Woof} # Case 1 test hasinstances-1.2 {'-hasinstances no' disables explicit object creation} -constraints { snit1 } -body { type dog { pragma -hasinstances no } dog create fido } -returnCodes { error } -cleanup { dog destroy } -result {"::dog create" is not defined} # Case 2 test hasinstances-1.3 {'-hasinstances no' disables explicit object creation} -constraints { snit2 } -body { type dog { pragma -hasinstances no } dog create fido } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "create": namespace ::dog does not export any commands} # Case 1 test hasinstances-1.4 {'-hasinstances no' disables implicit object creation} -constraints { snit1 } -body { type dog { pragma -hasinstances no } dog fido } -returnCodes { error } -result {"::dog fido" is not defined} # Case 2 test hasinstances-1.5 {'-hasinstances no' disables implicit object creation} -constraints { snit2 } -body { type dog { pragma -hasinstances no } dog fido } -returnCodes { error } -result {unknown subcommand "fido": namespace ::dog does not export any commands} #----------------------------------------------------------------------- # pragma -canreplace test canreplace-1.1 {By default, "-canreplace no"} -body { type dog { # ... } dog fido dog fido } -returnCodes { error } -cleanup { dog destroy } -result {command "::fido" already exists} test canreplace-1.2 {Can replace commands when "-canreplace yes"} -constraints { bug8.5a3 } -body { type dog { pragma -canreplace yes } dog fido dog fido } -cleanup { dog destroy } -result {::fido} #----------------------------------------------------------------------- # pragma -hasinfo test hasinfo-1.1 {$obj info is defined by default} -body { type dog { variable foo "" } dog spot spot info vars } -cleanup { dog destroy } -result {::dog::Snit_inst1::foo} # Case 1 test hasinfo-1.2 {$obj info can be disabled} -constraints { snit1 } -body { type dog { pragma -hasinfo no variable foo } dog spot spot info vars } -returnCodes { error } -cleanup { dog destroy } -result {"::spot info" is not defined} # Case 2 test hasinfo-1.3 {$obj info can be disabled} -constraints { snit2 } -body { type dog { pragma -hasinfo no variable foo } dog spot spot info vars } -returnCodes { error } -cleanup { dog destroy } -result {unknown subcommand "info": namespace ::dog::Snit_inst1 does not export any commands} #----------------------------------------------------------------------- # pragma -hastypemethods # # The "-hastypemethods yes" case is tested by the bulk of this file. # We'll test the "-hastypemethods no" case here. test hastypemethods-1.1 {-hastypemethods no, $type foo creates instance.} -body { type dog { pragma -hastypemethods no variable foo } dog spot } -cleanup { spot destroy rename ::dog "" namespace delete ::dog } -result {::spot} test hastypemethods-1.2 {-hastypemethods no, $type create foo fails.} -body { type dog { pragma -hastypemethods no variable foo } dog create spot } -returnCodes { error } -cleanup { rename ::dog "" namespace delete ::dog } -result "Error in constructor: [tcltest::tooManyArgs ::dog::Snit_constructor {type selfns win self}]" test hastypemethods-1.3 {-hastypemethods no, $type info fails.} -body { type dog { pragma -hastypemethods no variable foo } dog info } -returnCodes { error } -cleanup { rename ::dog "" namespace delete ::dog } -result {command "::info" already exists} test hastypemethods-1.4 {-hastypemethods no, [$widget] fails.} -constraints { tk } -body { widget dog { pragma -hastypemethods no variable foo } dog } -returnCodes { error } -cleanup { rename ::dog "" namespace delete ::dog } -result {wrong # args: should be "::dog name args"} test hastypemethods-1.5 {-hastypemethods no, -hasinstances no fails.} -body { type dog { pragma -hastypemethods no pragma -hasinstances no variable foo } } -returnCodes { error } -result {type ::dog has neither typemethods nor instances} #----------------------------------------------------------------------- # -simpledispatch yes test simpledispatch-1.1 {not allowed with method delegation.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes delegate method foo to bar } } -returnCodes { error } -result {type ::dog requests -simpledispatch but delegates methods.} test simpledispatch-1.2 {normal methods work with simpledispatch.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes method barks {how} { return "$self barks $how." } } dog spot spot barks loudly } -cleanup { dog destroy } -result {::spot barks loudly.} test simpledispatch-1.3 {option methods work with simpledispatch.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes option -breed mutt } dog spot set a [spot cget -breed] spot configure -breed collie set b [spot cget -breed] spot configurelist [list -breed sheltie] set c [spot cget -breed] list $a $b $c } -cleanup { dog destroy } -result {mutt collie sheltie} test simpledispatch-1.4 {info method works with simpledispatch.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes option -breed mutt } dog spot spot info options } -cleanup { dog destroy } -result {-breed} test simpledispatch-1.5 {destroy method works with simpledispatch.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes option -breed mutt } dog spot set a [info commands ::spot] spot destroy set b [info commands ::spot] list $a $b } -cleanup { dog destroy } -result {::spot {}} test simpledispatch-1.6 {no hierarchical methods with simpledispatch.} -constraints { snit1 } -body { type dog { pragma -simpledispatch yes method {wag tail} {} {} } } -returnCodes { error } -result {type ::dog requests -simpledispatch but defines hierarchical methods.} #----------------------------------------------------------------------- # Exotic return codes test break-1.1 {Methods can "return -code break"} -body { snit::type dog { method bark {} {return -code break "Breaking"} } dog spot catch {spot bark} result } -cleanup { dog destroy } -result {3} test break-1.2 {Typemethods can "return -code break"} -body { snit::type dog { typemethod bark {} {return -code break "Breaking"} } catch {dog bark} result } -cleanup { dog destroy } -result {3} test break-1.3 {Methods called via mymethod "return -code break"} -body { snit::type dog { method bark {} {return -code break "Breaking"} method getbark {} { return [mymethod bark] } } dog spot catch {uplevel \#0 [spot getbark]} result } -cleanup { dog destroy } -result {3} #----------------------------------------------------------------------- # Namespace path test nspath-1.1 {Typemethods call commands from parent namespace} -constraints { snit2 } -body { namespace eval ::snit_test:: { proc bark {} {return "[namespace current]: Woof"} } snit::type ::snit_test::dog { typemethod bark {} { bark } } ::snit_test::dog bark } -cleanup { ::snit_test::dog destroy namespace forget ::snit_test } -result {::snit_test: Woof} test nspath-1.2 {Methods can call commands from parent namespace} -constraints { snit2 } -body { namespace eval ::snit_test:: { proc bark {} {return "[namespace current]: Woof"} } snit::type ::snit_test::dog { method bark {} { bark } } ::snit_test::dog spot spot bark } -cleanup { ::snit_test::dog destroy namespace forget ::snit_test } -result {::snit_test: Woof} #----------------------------------------------------------------------- # snit::boolean test boolean-1.1 {boolean: valid} -body { snit::boolean validate 1 snit::boolean validate 0 snit::boolean validate true snit::boolean validate false snit::boolean validate yes snit::boolean validate no snit::boolean validate on snit::boolean validate off } -result {off} test boolean-1.2 {boolean: invalid} -body { codecatch {snit::boolean validate quux} } -result {INVALID invalid boolean "quux", should be one of: 1, 0, true, false, yes, no, on, off} test boolean-2.1 {boolean subtype: valid} -body { snit::boolean subtype subtype validate 1 subtype validate 0 subtype validate true subtype validate false subtype validate yes subtype validate no subtype validate on subtype validate off } -cleanup { subtype destroy } -result {off} test boolean-2.2 {boolean subtype: invalid} -body { snit::boolean subtype codecatch {subtype validate quux} } -cleanup { subtype destroy } -result {INVALID invalid boolean "quux", should be one of: 1, 0, true, false, yes, no, on, off} #----------------------------------------------------------------------- # snit::double test double-1.1 {double: invalid -min} -body { snit::double obj -min abc } -returnCodes { error } -result {Error in constructor: invalid -min: "abc"} test double-1.2 {double: invalid -max} -body { snit::double obj -max abc } -returnCodes { error } -result {Error in constructor: invalid -max: "abc"} test double-1.3 {double: invalid, max < min} -body { snit::double obj -min 5 -max 0 } -returnCodes { error } -result {Error in constructor: -max < -min} test double-2.1 {double type: valid} -body { snit::double validate 1.5 } -result {1.5} test double-2.2 {double type: invalid} -body { codecatch {snit::double validate abc} } -result {INVALID invalid value "abc", expected double} test double-3.1 {double subtype: valid, no range} -body { snit::double subtype subtype validate 1.5 } -cleanup { subtype destroy } -result {1.5} test double-3.2 {double subtype: valid, min but no max} -body { snit::double subtype -min 0.5 subtype validate 1 } -cleanup { subtype destroy } -result {1} test double-3.3 {double subtype: valid, min and max} -body { snit::double subtype -min 0.5 -max 10.5 subtype validate 1.5 } -cleanup { subtype destroy } -result {1.5} test double-4.1 {double subtype: not a number} -body { snit::double subtype codecatch {subtype validate quux} } -cleanup { subtype destroy } -result {INVALID invalid value "quux", expected double} test double-4.2 {double subtype: less than min, no max} -body { snit::double subtype -min 0.5 codecatch {subtype validate -1} } -cleanup { subtype destroy } -result {INVALID invalid value "-1", expected double no less than 0.5} test double-4.3 {double subtype: less than min, with max} -body { snit::double subtype -min 0.5 -max 5.5 codecatch {subtype validate -1} } -cleanup { subtype destroy } -result {INVALID invalid value "-1", expected double in range 0.5, 5.5} #----------------------------------------------------------------------- # snit::enum test enum-1.1 {enum: valid} -body { snit::enum validate foo } -result {foo} test enum-2.1 {enum subtype: missing -values} -body { snit::enum subtype } -returnCodes { error } -result {Error in constructor: invalid -values: ""} test enum-3.1 {enum subtype: valid} -body { snit::enum subtype -values {foo bar baz} subtype validate foo subtype validate bar subtype validate baz } -cleanup { subtype destroy } -result {baz} test enum-3.2 {enum subtype: invalid} -body { snit::enum subtype -values {foo bar baz} codecatch {subtype validate quux} } -cleanup { subtype destroy } -result {INVALID invalid value "quux", should be one of: foo, bar, baz} #----------------------------------------------------------------------- # snit::fpixels test fpixels-1.1 {no suffix} -constraints tk -body { snit::fpixels validate 5 } -result {5} test fpixels-1.2 {suffix} -constraints tk -body { snit::fpixels validate 5i } -result {5i} test fpixels-1.3 {decimal} -constraints tk -body { snit::fpixels validate 5.5 } -result {5.5} test fpixels-1.4 {invalid} -constraints tk -body { codecatch {snit::fpixels validate 5.5abc} } -result {INVALID invalid value "5.5abc", expected fpixels} test fpixels-2.1 {bad -min} -constraints tk -body { snit::fpixels subtype -min abc } -returnCodes { error } -result {Error in constructor: invalid -min: "abc"} test fpixels-2.2 {bad -max} -constraints tk -body { snit::fpixels subtype -max abc } -returnCodes { error } -result {Error in constructor: invalid -max: "abc"} test fpixels-2.3 {-min > -max} -constraints tk -body { snit::fpixels subtype -min 10 -max 5 } -returnCodes { error } -result {Error in constructor: -max < -min} test fpixels-3.1 {subtype, no suffix} -constraints tk -body { snit::fpixels subtype subtype validate 5 } -cleanup { subtype destroy } -result {5} test fpixels-3.2 {suffix} -constraints tk -body { snit::fpixels subtype subtype validate 5i } -cleanup { subtype destroy } -result {5i} test fpixels-3.3 {decimal} -constraints tk -body { snit::fpixels subtype subtype validate 5.5 } -cleanup { subtype destroy } -result {5.5} test fpixels-3.4 {invalid} -constraints tk -body { snit::fpixels subtype codecatch {subtype validate 5.5abc} } -cleanup { subtype destroy } -result {INVALID invalid value "5.5abc", expected fpixels} test fpixels-3.5 {subtype -min} -constraints tk -body { snit::fpixels subtype -min 5 subtype validate 10 } -cleanup { subtype destroy } -result {10} test fpixels-3.6 {min of min, max} -constraints tk -body { snit::fpixels subtype -min 5 -max 20 subtype validate 5 } -cleanup { subtype destroy } -result {5} test fpixels-3.7 {max of min, max} -constraints tk -body { snit::fpixels subtype -min 5 -max 20 subtype validate 20 } -cleanup { subtype destroy } -result {20} test fpixels-3.8 {middle of min, max} -constraints tk -body { snit::fpixels subtype -min 5 -max 20 subtype validate 15 } -cleanup { subtype destroy } -result {15} test fpixels-3.9 {invalid, < min} -constraints tk -body { snit::fpixels subtype -min 5 codecatch {subtype validate 4} } -cleanup { subtype destroy } -result {INVALID invalid value "4", expected fpixels no less than 5} test fpixels-3.10 {invalid, > max} -constraints tk -body { snit::fpixels subtype -min 5 -max 20 codecatch {subtype validate 21} } -cleanup { subtype destroy } -result {INVALID invalid value "21", expected fpixels in range 5, 20} test fpixels-3.11 {invalid, > max, range with suffix} -constraints tk -body { snit::fpixels subtype -min 5i -max 10i codecatch {subtype validate 11i} } -cleanup { subtype destroy } -result {INVALID invalid value "11i", expected fpixels in range 5i, 10i} #----------------------------------------------------------------------- # snit::integer test integer-1.1 {integer: invalid -min} -body { snit::integer obj -min abc } -returnCodes { error } -result {Error in constructor: invalid -min: "abc"} test integer-1.2 {integer: invalid -max} -body { snit::integer obj -max abc } -returnCodes { error } -result {Error in constructor: invalid -max: "abc"} test integer-1.3 {integer: invalid, max < min} -body { snit::integer obj -min 5 -max 0 } -returnCodes { error } -result {Error in constructor: -max < -min} test integer-2.1 {integer type: valid} -body { snit::integer validate 1 } -result {1} test integer-2.2 {integer type: invalid} -body { codecatch {snit::integer validate abc} } -result {INVALID invalid value "abc", expected integer} test integer-3.1 {integer subtype: valid, no range} -body { snit::integer subtype subtype validate 1 } -cleanup { subtype destroy } -result {1} test integer-3.2 {integer subtype: valid, min but no max} -body { snit::integer subtype -min 0 subtype validate 1 } -cleanup { subtype destroy } -result {1} test integer-3.3 {integer subtype: valid, min and max} -body { snit::integer subtype -min 0 -max 10 subtype validate 1 } -cleanup { subtype destroy } -result {1} test integer-4.1 {integer subtype: not a number} -body { snit::integer subtype codecatch {subtype validate quux} } -cleanup { subtype destroy } -result {INVALID invalid value "quux", expected integer} test integer-4.2 {integer subtype: less than min, no max} -body { snit::integer subtype -min 0 codecatch {subtype validate -1} } -cleanup { subtype destroy } -result {INVALID invalid value "-1", expected integer no less than 0} test integer-4.3 {integer subtype: less than min, with max} -body { snit::integer subtype -min 0 -max 5 codecatch {subtype validate -1} } -cleanup { subtype destroy } -result {INVALID invalid value "-1", expected integer in range 0, 5} #----------------------------------------------------------------------- # snit::listtype test listtype-1.1 {listtype, length 0; valid} -body { snit::listtype validate "" } -result {} test listtype-1.2 {listtype, length 1; valid} -body { snit::listtype validate a } -result {a} test listtype-1.3 {listtype, length 2; valid} -body { snit::listtype validate {a b} } -result {a b} test listtype-2.1 {listtype subtype, length 0; valid} -body { snit::listtype subtype subtype validate "" } -cleanup { subtype destroy } -result {} test listtype-2.2 {listtype, length 1; valid} -body { snit::listtype subtype subtype validate a } -cleanup { subtype destroy } -result {a} test listtype-2.3 {listtype, length 2; valid} -body { snit::listtype subtype subtype validate {a b} } -cleanup { subtype destroy } -result {a b} test listtype-2.4 {listtype, invalid -minlen} -body { snit::listtype subtype -minlen abc } -returnCodes { error } -result {Error in constructor: invalid -minlen: "abc"} test listtype-2.5 {listtype, negative -minlen} -body { snit::listtype subtype -minlen -1 } -returnCodes { error } -result {Error in constructor: invalid -minlen: "-1"} test listtype-2.6 {listtype, invalid -maxlen} -body { snit::listtype subtype -maxlen abc } -returnCodes { error } -result {Error in constructor: invalid -maxlen: "abc"} test listtype-2.7 {listtype, -maxlen < -minlen} -body { snit::listtype subtype -minlen 10 -maxlen 9 } -returnCodes { error } -result {Error in constructor: -maxlen < -minlen} test listtype-3.1 {-minlen 2, length 2; valid} -body { snit::listtype subtype -minlen 2 subtype validate {a b} } -cleanup { subtype destroy } -result {a b} test listtype-3.2 {-minlen 2, length 3; valid} -body { snit::listtype subtype -minlen 2 subtype validate {a b c} } -cleanup { subtype destroy } -result {a b c} test listtype-3.3 {-minlen 2, length 1; invalid} -body { snit::listtype subtype -minlen 2 codecatch {subtype validate a} } -cleanup { subtype destroy } -result {INVALID value has too few elements; at least 2 expected} test listtype-3.4 {range 1 to 3, length 1; valid} -body { snit::listtype subtype -minlen 1 -maxlen 3 subtype validate a } -cleanup { subtype destroy } -result {a} test listtype-3.5 {range 1 to 3, length 3; valid} -body { snit::listtype subtype -minlen 1 -maxlen 3 subtype validate {a b c} } -cleanup { subtype destroy } -result {a b c} test listtype-3.6 {range 1 to 3, length 0; invalid} -body { snit::listtype subtype -minlen 1 -maxlen 3 codecatch {subtype validate {}} } -cleanup { subtype destroy } -result {INVALID value has too few elements; at least 1 expected} test listtype-3.7 {range 1 to 3, length 4; invalid} -body { snit::listtype subtype -minlen 1 -maxlen 3 codecatch {subtype validate {a b c d}} } -cleanup { subtype destroy } -result {INVALID value has too many elements; no more than 3 expected} test listtype-4.1 {boolean list, valid} -body { snit::listtype subtype -type snit::boolean subtype validate {yes 1 true} } -cleanup { subtype destroy } -result {yes 1 true} test listtype-4.2 {boolean list, invalid} -body { snit::listtype subtype -type snit::boolean codecatch {subtype validate {yes 1 abc no}} } -cleanup { subtype destroy } -result {INVALID invalid boolean "abc", should be one of: 1, 0, true, false, yes, no, on, off} #----------------------------------------------------------------------- # snit::pixels test pixels-1.1 {no suffix} -constraints tk -body { snit::pixels validate 5 } -result {5} test pixels-1.2 {suffix} -constraints tk -body { snit::pixels validate 5i } -result {5i} test pixels-1.3 {decimal} -constraints tk -body { snit::pixels validate 5.5 } -result {5.5} test pixels-1.4 {invalid} -constraints tk -body { codecatch {snit::pixels validate 5.5abc} } -result {INVALID invalid value "5.5abc", expected pixels} test pixels-2.1 {bad -min} -constraints tk -body { snit::pixels subtype -min abc } -returnCodes { error } -result {Error in constructor: invalid -min: "abc"} test pixels-2.2 {bad -max} -constraints tk -body { snit::pixels subtype -max abc } -returnCodes { error } -result {Error in constructor: invalid -max: "abc"} test pixels-2.3 {-min > -max} -constraints tk -body { snit::pixels subtype -min 10 -max 5 } -returnCodes { error } -result {Error in constructor: -max < -min} test pixels-3.1 {subtype, no suffix} -constraints tk -body { snit::pixels subtype subtype validate 5 } -cleanup { subtype destroy } -result {5} test pixels-3.2 {suffix} -constraints tk -body { snit::pixels subtype subtype validate 5i } -cleanup { subtype destroy } -result {5i} test pixels-3.3 {decimal} -constraints tk -body { snit::pixels subtype subtype validate 5.5 } -cleanup { subtype destroy } -result {5.5} test pixels-3.4 {invalid} -constraints tk -body { snit::pixels subtype codecatch {subtype validate 5.5abc} } -cleanup { subtype destroy } -result {INVALID invalid value "5.5abc", expected pixels} test pixels-3.5 {subtype -min} -constraints tk -body { snit::pixels subtype -min 5 subtype validate 10 } -cleanup { subtype destroy } -result {10} test pixels-3.6 {min of min, max} -constraints tk -body { snit::pixels subtype -min 5 -max 20 subtype validate 5 } -cleanup { subtype destroy } -result {5} test pixels-3.7 {max of min, max} -constraints tk -body { snit::pixels subtype -min 5 -max 20 subtype validate 20 } -cleanup { subtype destroy } -result {20} test pixels-3.8 {middle of min, max} -constraints tk -body { snit::pixels subtype -min 5 -max 20 subtype validate 15 } -cleanup { subtype destroy } -result {15} test pixels-3.9 {invalid, < min} -constraints tk -body { snit::pixels subtype -min 5 codecatch {subtype validate 4} } -cleanup { subtype destroy } -result {INVALID invalid value "4", expected pixels no less than 5} test pixels-3.10 {invalid, > max} -constraints tk -body { snit::pixels subtype -min 5 -max 20 codecatch {subtype validate 21} } -cleanup { subtype destroy } -result {INVALID invalid value "21", expected pixels in range 5, 20} test pixels-3.11 {invalid, > max, range with suffix} -constraints tk -body { snit::pixels subtype -min 5i -max 10i codecatch {subtype validate 11i} } -cleanup { subtype destroy } -result {INVALID invalid value "11i", expected pixels in range 5i, 10i} #----------------------------------------------------------------------- # snit::stringtype test stringtype-1.1 {stringtype, valid string} -body { snit::stringtype validate "" } -result {} test stringtype-2.1 {stringtype subtype: invalid -regexp} -body { snit::stringtype subtype -regexp "\[A-Z" } -returnCodes { error } -result {Error in constructor: invalid -regexp: "[A-Z"} test stringtype-2.2 {stringtype subtype: invalid -minlen} -body { snit::stringtype subtype -minlen foo } -returnCodes { error } -result {Error in constructor: invalid -minlen: "foo"} test stringtype-2.3 {stringtype subtype: invalid -maxlen} -body { snit::stringtype subtype -maxlen foo } -returnCodes { error } -result {Error in constructor: invalid -maxlen: "foo"} test stringtype-2.4 {stringtype subtype: -maxlen < -minlen} -body { snit::stringtype subtype -maxlen 1 -minlen 5 } -returnCodes { error } -result {Error in constructor: -maxlen < -minlen} test stringtype-2.5 {stringtype subtype: -minlen < 0} -body { snit::stringtype subtype -minlen -1 } -returnCodes { error } -result {Error in constructor: invalid -minlen: "-1"} test stringtype-2.6 {stringtype subtype: -maxlen < 0} -body { snit::stringtype subtype -maxlen -1 } -returnCodes { error } -result {Error in constructor: -maxlen < -minlen} test stringtype-3.1 {stringtype subtype: -glob, valid} -body { snit::stringtype subtype -glob "*FOO*" subtype validate 1FOO2 } -cleanup { subtype destroy } -result {1FOO2} test stringtype-3.2 {stringtype subtype: -glob, case-insensitive} -body { snit::stringtype subtype -nocase yes -glob "*FOO*" subtype validate 1foo2 } -cleanup { subtype destroy } -result {1foo2} test stringtype-3.3 {stringtype subtype: -glob invalid, case-sensitive} -body { snit::stringtype subtype -glob "*FOO*" codecatch {subtype validate 1foo2} } -cleanup { subtype destroy } -result {INVALID invalid value "1foo2"} test stringtype-5.4 {stringtype subtype: -glob invalid, case-insensitive} -body { snit::stringtype subtype -nocase yes -glob "*FOO*" codecatch {subtype validate bar} } -cleanup { subtype destroy } -result {INVALID invalid value "bar"} test stringtype-5.5 {stringtype subtype: -regexp valid, case-sensitive} -body { snit::stringtype subtype -regexp {^[A-Z]+$} subtype validate FOO } -cleanup { subtype destroy } -result {FOO} test stringtype-5.6 {stringtype subtype: -regexp valid, case-insensitive} -body { snit::stringtype subtype -nocase yes -regexp {^[A-Z]+$} subtype validate foo } -cleanup { subtype destroy } -result {foo} test stringtype-5.7 {stringtype subtype: -regexp invalid, case-sensitive} -body { snit::stringtype subtype -regexp {^[A-Z]+$} codecatch {subtype validate foo} } -cleanup { subtype destroy } -result {INVALID invalid value "foo"} test stringtype-5.8 {stringtype subtype: -regexp invalid, case-insensitive} -body { snit::stringtype subtype -nocase yes -regexp {^[A-Z]+$} codecatch {subtype validate foo1} } -cleanup { subtype destroy } -result {INVALID invalid value "foo1"} #----------------------------------------------------------------------- # snit::window test window-1.1 {window: valid} -constraints tk -body { snit::window validate . } -result {.} test window-1.2 {window: invalid} -constraints tk -body { codecatch {snit::window validate .nonesuch} } -result {INVALID invalid value ".nonesuch", value is not a window} test window-2.1 {window subtype: valid} -constraints tk -body { snit::window subtype subtype validate . } -cleanup { subtype destroy } -result {.} test window-2.2 {window subtype: invalid} -constraints tk -body { snit::window subtype codecatch {subtype validate .nonesuch} } -cleanup { subtype destroy } -result {INVALID invalid value ".nonesuch", value is not a window} #----------------------------------------------------------------------- # option -type specifications test optiontype-1.1 {-type is type object name} -body { type dog { option -akcflag -default no -type snit::boolean } dog create spot # Set -akcflag to a boolean value spot configure -akcflag yes spot configure -akcflag 1 spot configure -akcflag on spot configure -akcflag off # Set -akcflag to an invalid value spot configure -akcflag offf } -returnCodes { error } -cleanup { dog destroy } -result {invalid -akcflag value: invalid boolean "offf", should be one of: 1, 0, true, false, yes, no, on, off} test optiontype-1.2 {-type is type specification} -body { type dog { option -color -default brown \ -type {snit::enum -values {brown black white golden}} } dog create spot # Set -color to a valid value spot configure -color brown spot configure -color black spot configure -color white spot configure -color golden # Set -color to an invalid value spot configure -color green } -returnCodes { error } -cleanup { dog destroy } -result {invalid -color value: invalid value "green", should be one of: brown, black, white, golden} test optiontype-1.3 {-type catches invalid defaults} -body { type dog { option -color -default green \ -type {snit::enum -values {brown black white golden}} } dog spot } -returnCodes { error } -cleanup { dog destroy } -result {Error in constructor: invalid -color default: invalid value "green", should be one of: brown, black, white, golden} #----------------------------------------------------------------------- # Bug Fixes test bug-1.1 {Bug 1161779: destructor can't precede constructor} -body { type dummy { destructor { # No content } constructor {args} { $self configurelist $args } } } -cleanup { rename ::dummy "" } -result ::dummy test bug-2.1 {Bug 1106375: Widget Error on failed object's construction} -constraints { tk } -body { ::snit::widgetadaptor mylabel { delegate method * to hull delegate option * to hull constructor {args} { installhull using label error "simulated error" } } catch {mylabel .lab} result list [info commands .lab] $result } -cleanup { ::mylabel destroy } -result {{} {Error in constructor: simulated error}} test bug-2.2 {Bug 1106375: Widget Error on failed object's construction} -constraints { tk } -body { ::snit::widget myframe { delegate method * to hull delegate option * to hull constructor {args} { error "simulated error" } } catch {myframe .frm} result list [info commands .frm] $result } -cleanup { ::myframe destroy } -result {{} {Error in constructor: simulated error}} test bug-3.1 {Bug 1532791: snit2, snit::widget problem} -constraints { tk } -body { snit::widget mywidget { delegate method * to mylabel delegate option * to mylabel variable mylabel {} } mywidget .mylabel } -cleanup { destroy .mylabel } -result {.mylabel} #--------------------------------------------------------------------- # Clean up rename expect {} testsuiteCleanup