#---------------------------------------------------------------------
# TITLE:
#       typefunction.test
#
# AUTHOR:
#       Arnulf Wiedemann with a lot of code form the snit tests by
#       Will Duquette
#
# DESCRIPTION:
#       Test cases for ::itcl::type proc, method, typemethod commands.
#       Uses the ::tcltest:: harness.
#
#    The tests assume tcltest 2.2
#-----------------------------------------------------------------------

package require tcltest 2.2
namespace import ::tcltest::*
::tcltest::loadTestedCommands
package require itcl

interp alias {} type {} ::itcl::type

#-----------------------------------------------------------------------
# Type variables

test typevariable-1.2 {undefined typevariables are OK} -body {
    type dog {
        typevariable theValue
        method tset {value} {
            set theValue $value
        }

        method tget {} {
            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] ;# FIXME [set ::dog::greeting]
} -cleanup {
    dog destroy
} -result {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 {wrong # args: should be "typevariable varname ?init?"}

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 {wrong # args: should be "typevariable varname ?init|-array init?"}

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
} -match glob -result {::itcl::internal::variables::*::dog::somevar}

test ivariable-1.2 {undefined instance variables are OK} -body {
    type dog {
        variable greeting
        method setgreeting {value} {
            set greeting $value
        }

        method getgreeting {} {
            return $greeting
        }
    }

    set spot [dog create spot]
    spot setgreeting Hey

    dog create fido
    fido setgreeting Howdy

    list [spot getgreeting] [fido getgreeting] [set ::itcl::internal::variables[info object namespace spot]::dog::greeting]
} -cleanup {
    dog destroy
} -result {Hey Howdy Hey}

test ivariable-1.3 {instance variables are destroyed automatically} -body {
    type dog {
        variable greeting
        constructor {args} {
            set greeting Hi
        }
    }

    dog create spot
    set ns [info object namespace spot]
    set g1 [set ::itcl::internal::variables${ns}::dog::greeting]

    spot destroy
    list $g1 [info exists ::itcl::internal::variables${ns}::dog::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.9 {procs which define selfns see instance variables} -body {
    type dog {
        variable greeting Howdy

        method caller {} {
            return [callee $selfns]
        }

        proc callee {selfns} {
            return [set ${selfns}::greeting]
        }
    }

    dog create spot

    spot caller
} -cleanup {
    dog destroy
} -result {Howdy}

test ivariable-1.11 {variable with too many initializers throws an error} -body {
    type dog {
        variable color dark brown
    }
} -returnCodes {
    error
} -result {wrong # args: should be "variable name ?init?"}

test ivariable-1.12 {variable with too many initializers throws an error} -body {
    type dog {
        variable color -array dark brown
    }
} -returnCodes {
    error
} -result {wrong # args: should be "variable varname ?init|-array init?"}

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}


#---------------------------------------------------------------------
# Clean up

cleanupTests
return
