# -*- Tcl -*-

package prefer latest

package req nx::test

#
# make sure, the defaultAccessor is "none"
#

#puts stderr "*** default defaultAccessor '[nx::configure defaultAccessor]'"
nx::configure defaultAccessor none

#####################################################################
# class-level properties
#####################################################################
#
# Test class-level properties and variables without -incremental
#
nx::test case class-level {

  nx::Class create C {
    :property {a a1}
    :property -accessor public {b b1}
    :property -accessor protected {c c1}
    :property -accessor private {d d1}
    :property -accessor none {e e1}
    :variable va va1
    :variable -accessor public vb vb1
    :variable -accessor protected vc vc1
    :variable -accessor private vd vd1
    :variable -accessor none ve ve1

    # a non-configurable property is a variable
    :property -accessor none -configurable false {vf vf1}
    
    :public method call-local {v} {: -local $v get}
    
    :create c1
  }

  #
  # just the public properties are accessible via the configure interface
  #
  ? {c1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  ? {lsort [C info slots]} "::C::slot::____C.d ::C::slot::____C.vd ::C::slot::a ::C::slot::b ::C::slot::c ::C::slot::e ::C::slot::va ::C::slot::vb ::C::slot::vc ::C::slot::ve ::C::slot::vf"


  ? {::C::slot::a definition} "::C property -accessor none {a a1}"
  ? {::C::slot::b definition} "::C property -accessor public {b b1}"
  ? {::C::slot::c definition} "::C variable -accessor protected c c1"
  ? {::C::slot::____C.d definition} "::C variable -accessor private d d1"
  ? {::C::slot::e definition} "::C property -accessor none {e e1}"
  ? {::C::slot::va definition} "::C variable -accessor none va va1"
  ? {::C::slot::vb definition} "::C variable -accessor public vb vb1"
  ? {::C::slot::vc definition} "::C variable -accessor protected vc vc1"
  ? {::C::slot::____C.vd definition} "::C variable -accessor private vd vd1"
  ? {::C::slot::ve definition} "::C variable -accessor none ve ve1"
  ? {::C::slot::vf definition} "::C variable -accessor none vf vf1"

  
  ? {c1 cget -a} a1
  ? {c1 cget -b} b1
  ? {c1 cget -c} "cget: unknown configure parameter -c"
  ? {c1 cget -d} "cget: unknown configure parameter -d"
  ? {c1 cget -va} "cget: unknown configure parameter -va"
  ? {c1 cget -vb} "cget: unknown configure parameter -vb"
  ? {c1 cget -vc} "cget: unknown configure parameter -vc"
  ? {c1 cget -vd} "cget: unknown configure parameter -vd"
  ? {c1 cget -ve} "cget: unknown configure parameter -ve"
  ? {c1 cget -vf} "cget: unknown configure parameter -vf"

  #
  # No incremental used, so "a" and "e" have no slots
  #
  
  ? {c1 info lookup method a} ""  
  ? {c1 info lookup method b} "::nsf::classes::C::b"
  ? {c1 info lookup method c} "::nsf::classes::C::c"
  ? {c1 info lookup method d} "::nsf::classes::C::d"
  ? {c1 info lookup method e} ""  
  ? {c1 info lookup method f} ""  

  ? {c1 info lookup method va} "" 
  ? {c1 info lookup method vb} "::nsf::classes::C::vb"
  ? {c1 info lookup method vc} "::nsf::classes::C::vc"
  ? {c1 info lookup method vd} "::nsf::classes::C::vd"
  ? {c1 info lookup method ve} "" 
  ? {c1 info lookup method vf} "" 

  #
  # Check protection of accessors
  #
  
  ? {nsf::method::property C b call-protected} 0
  ? {nsf::method::property C c call-protected} 1
  ? {nsf::method::property C d call-protected} 1  
  ? {nsf::method::property C vb call-protected} 0
  ? {nsf::method::property C vc call-protected} 1
  ? {nsf::method::property C vd call-protected} 1

  ? {nsf::method::property C b call-private} 0
  ? {nsf::method::property C c call-private} 0
  ? {nsf::method::property C d call-private} 1
  ? {nsf::method::property C vb call-private} 0
  ? {nsf::method::property C vc call-private} 0
  ? {nsf::method::property C vd call-private} 1

  #
  # do we have variables set?
  #
  
  ? {c1 eval "info exists :a"} 1
  ? {c1 eval "info exists :b"} 1
  ? {c1 eval "info exists :c"} 1
  ? {c1 eval "info exists :d"} 0
  ? {c1 eval "info exists :va"} 1
  ? {c1 eval "info exists :vb"} 1
  ? {c1 eval "info exists :vc"} 1
  ? {c1 eval "info exists :vd"} 0
  ? {c1 eval "info exists :ve"} 1
  ? {c1 eval "info exists :vf"} 1

  #
  # can we call the accessor directly or via "eval"
  #
  
  ? {c1 a} {::c1: unable to dispatch method 'a'}
  ? {c1 b get} b1
  ? {c1 c} {::c1: unable to dispatch method 'c'}
  ? {c1 d} {::c1: unable to dispatch method 'd'}
 
  ? {c1 eval ":a"} {::c1: unable to dispatch method 'a'}
  ? {c1 eval ":b get"} b1
  ? {c1 eval ":c get"} c1
  ? {c1 eval ":d"} {::c1: unable to dispatch method 'd'}
  
  
  ? {c1 va} {::c1: unable to dispatch method 'va'}
  ? {c1 vb get} vb1
  ? {c1 vc} {::c1: unable to dispatch method 'vc'}
  ? {c1 vd} {::c1: unable to dispatch method 'vd'}
  
  ? {c1 eval ":va"} {::c1: unable to dispatch method 'va'}
  ? {c1 eval ":vb get"} vb1
  ? {c1 eval ":vc get"} vc1
  ? {c1 eval ":vd"} {::c1: unable to dispatch method 'vd'}

  #
  # check the behavior of "private" properties and variables
  #
  ? {c1 call-local d} d1
  ? {c1 call-local vd} vd1

  ? {lsort [c1 info vars]} "__private a b c e va vb vc ve vf"
  ? {c1 eval "array get :__private"} "::C,vd vd1 ::C,d d1"

  #
  # check incremental operations for properties (should fail in all
  # cases)
  #

  set unknowns "valid are: {assign definition destroy get getParameterSpec getPropertyDefinitionOptions onError parameter reconfigure setCheckedInstVar}"
  ? {c1 b add x} {property b of ::C is not multivalued}
  #? {c1 b add x} "method 'add' unknown for slot ::C::slot::b; $unknowns"
  ? {c1 c add x} {::c1: unable to dispatch method 'c'}
  ? {c1 eval {:c add x}} {property c of ::C is not multivalued}
  #? {c1 eval {:c add x}} "method 'add' unknown for slot ::C::slot::c; $unknowns"
  ? {c1 d add x} {::c1: unable to dispatch method 'd'}
  ? {c1 eval {:d add x}} {::c1: unable to dispatch method 'd'}
  ? {c1 e add x} {::c1: unable to dispatch method 'e'}

  #
  # check incremental operations for variables (should fail in all
  # cases)
  #

  ? {c1 va add x} {::c1: unable to dispatch method 'va'}
  ? {c1 vb add x} {property vb of ::C is not multivalued}
  #? {c1 vb add x} "method 'add' unknown for slot ::C::slot::vb; $unknowns"
  ? {c1 vc add x} {::c1: unable to dispatch method 'vc'}
  ? {c1 eval {:vc add x}} {property vc of ::C is not multivalued}
  #? {c1 eval {:vc add x}} "method 'add' unknown for slot ::C::slot::vc; $unknowns"
  ? {c1 vd add x} {::c1: unable to dispatch method 'vd'}
  ? {c1 eval {:vd add x}} {::c1: unable to dispatch method 'vd'}
  ? {c1 ve add x} {::c1: unable to dispatch method 've'}


  #
  # The accessor should be a setter due to incremental
  #

  ? {C info method definition b} {::C public forward b -prefix value= ::C::slot::b %1 %self b}

  #
  # check error message on a typo. The following command does a
  # recreate.
  #
  ? {C property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none}

  #
  # The accessor is deleted due to the error
  #

  ? {C info method definition b} {}
}



 
#
# test class-level properties and variables with -incremental
#
nx::test case class-level-incremental {

  nx::Class create CC {
    :property -incremental {a a1}
    :property -accessor public -incremental {b b1}
    :property -accessor protected -incremental {c c1}
    :property -accessor private -incremental {d d1}
    :property -accessor none -incremental {e e1}
    
    :variable -incremental va va1
    :variable -accessor public -incremental vb vb1
    :variable -accessor protected -incremental vc vc1
    :variable -accessor private -incremental vd vd1
    :variable -accessor none -incremental ve ve1
    
    :public method call-local {v} {: -local $v get}
    :public method add-local {var value} {: -local $var add $value}
    
    :create c1
  }
  
  #
  # The use of "-incremental" implies multivalued
  #
  ? {c1 info lookup syntax configure} {?-e /value .../? ?-a /value .../? ?-b /value .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}
  
  ? {c1 cget -a} a1
  ? {c1 cget -b} b1
  ? {c1 cget -c} "cget: unknown configure parameter -c"
  ? {c1 cget -d} "cget: unknown configure parameter -d"
  ? {c1 cget -va} "cget: unknown configure parameter -va"
  ? {c1 cget -vb} "cget: unknown configure parameter -vb"
  ? {c1 cget -vc} "cget: unknown configure parameter -vc"
  ? {c1 cget -vd} "cget: unknown configure parameter -vd"

  #
  # The use of "-incremental" implies an accessor
  #
  
  ? {c1 info lookup method a} "::nsf::classes::CC::a"  ;# forcing accessor
  ? {c1 info lookup method b} "::nsf::classes::CC::b"
  ? {c1 info lookup method c} "::nsf::classes::CC::c"
  ? {c1 info lookup method d} "::nsf::classes::CC::d"

  ? {c1 info lookup method va} "::nsf::classes::CC::va" ;# forcing accessor
  ? {c1 info lookup method vb} "::nsf::classes::CC::vb"
  ? {c1 info lookup method vc} "::nsf::classes::CC::vc"
  ? {c1 info lookup method vd} "::nsf::classes::CC::vd"

  #
  # The use of "-incremental" implies an accessor, which is public
  #
  
  ? {nsf::method::property CC a call-protected} 0
  ? {nsf::method::property CC b call-protected} 0
  ? {nsf::method::property CC c call-protected} 1
  ? {nsf::method::property CC d call-protected} 1  
  ? {nsf::method::property CC va call-protected} 0
  ? {nsf::method::property CC vb call-protected} 0
  ? {nsf::method::property CC vc call-protected} 1
  ? {nsf::method::property CC vd call-protected} 1

  ? {nsf::method::property CC a call-private} 0
  ? {nsf::method::property CC b call-private} 0
  ? {nsf::method::property CC c call-private} 0
  ? {nsf::method::property CC d call-private} 1
  ? {nsf::method::property CC va call-private} 0
  ? {nsf::method::property CC vb call-private} 0
  ? {nsf::method::property CC vc call-private} 0
  ? {nsf::method::property CC vd call-private} 1

  #
  # do we have variables set?
  #
  
  ? {c1 eval "info exists :a"} 1
  ? {c1 eval "info exists :b"} 1
  ? {c1 eval "info exists :c"} 1
  ? {c1 eval "info exists :d"} 0
  ? {c1 eval "info exists :va"} 1
  ? {c1 eval "info exists :vb"} 1
  ? {c1 eval "info exists :vc"} 1
  ? {c1 eval "info exists :vd"} 0

  #
  # can we call the accessor directly or via "eval"
  #
  
  ? {c1 a get} a1
  ? {c1 b get} b1
  ? {c1 c} {::c1: unable to dispatch method 'c'}
  ? {c1 d} {::c1: unable to dispatch method 'd'}
 
  ? {c1 eval ":a get"} a1
  ? {c1 eval ":b get"} b1
  ? {c1 eval ":c get"} c1
  ? {c1 eval ":d"} {::c1: unable to dispatch method 'd'}
  
  
  ? {c1 va get} va1
  ? {c1 vb get} vb1
  ? {c1 vc} {::c1: unable to dispatch method 'vc'}
  ? {c1 vd} {::c1: unable to dispatch method 'vd'}
  
  ? {c1 eval ":va get"} va1
  ? {c1 eval ":vb get"} vb1
  ? {c1 eval ":vc get"} vc1
  ? {c1 eval ":vd get"} {::c1: unable to dispatch method 'vd'}

  #
  # check the behavior of "private" properties and variables
  #
  ? {c1 call-local d} d1
  ? {c1 call-local vd} vd1

  ? {lsort [c1 info vars]} "__private a b c e va vb vc ve"
  ? {c1 eval "array get :__private"} "::CC,vd vd1 ::CC,d d1"

  #
  # check incremental operations for properties
  #

  ? {c1 a add x} {x a1}

  ? {c1 b add x} {x b1}
  ? {c1 c add x} {::c1: unable to dispatch method 'c'}
  ? {c1 eval {:c add x}} {x c1}
  ? {c1 d add x} {::c1: unable to dispatch method 'd'}
  ? {c1 eval {:d add x}} {::c1: unable to dispatch method 'd'}
  ? {c1 add-local d x} {x d1}
  ? {c1 e add x} {x e1}
  ? {c1 e delete x} {e1}
  ? {c1 e get} {e1}
  ? {c1 e delete -nocomplain x} {e1}
  ? {c1 e delete x} "::c1: 'x' is not in variable 'e' (values are: 'e1')"
  ? {c1 e delete -nocomplain e1} ""
  ? {c1 e get} ""
  ? {c1 e unset} ""
  ? {c1 e get} {can't read "e": no such variable}

  #
  # check incremental operations for variables
  #

  ? {c1 va add x} {x va1}
  ? {c1 vb add x} {x vb1}
  ? {c1 vc add x} {::c1: unable to dispatch method 'vc'}
  ? {c1 eval {:vc add x}} {x vc1}
  ? {c1 vd add x} {::c1: unable to dispatch method 'vd'}
  ? {c1 eval {:vd add x}} {::c1: unable to dispatch method 'vd'}
  ? {c1 add-local vd x} {x vd1}
  ? {c1 ve add x} {x ve1}
  ? {c1 ve delete x} {ve1}
  ? {c1 ve get} {ve1}
  ? {c1 ve delete -nocomplain x} {ve1}
  ? {c1 ve delete x} "::c1: 'x' is not in variable 've' (values are: 've1')"
  ? {c1 ve delete -nocomplain ve1} ""
  ? {c1 ve get} ""
  ? {c1 ve unset} ""
  ? {c1 ve get} {can't read "ve": no such variable}

  #
  # The accessor should be a forwarder due to incremental
  #

  ? {CC info method definition b} {::CC public forward b -prefix value= ::CC::slot::b %1 %self b}

  #
  # check error message
  #
  ? {CC property -accessor proceted -incremental {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none}

  #
  # The accessor is deleted due to the error
  #
  ? {CC info method definition b} {}


}

#####################################################################
# object-level properties 
#####################################################################
#
# Test object-level properties and variables without -incremental
#
nx::test case object-level {
  
  nx::Object create o1 {
    :object property {a a1}
    :object property -accessor public {b b1}
    :object property -accessor protected {c c1}
    :object property -accessor private {d d1}
    :object property -accessor none {e e1}
    
    :object variable va va1
    :object variable -accessor public vb vb1
    :object variable -accessor protected vc vc1
    :object variable -accessor private vd vd1
    :object variable -accessor none ve ve1
    
    :public object method call-local {v} {: -local $v get}
    
  }
  
  #
  # check the slot for "a"
  #
  ? {o1 info lookup slots a} ::o1::per-object-slot::a

  #
  # just the public properties are accessible via the configure interface
  #
  
  ? {o1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  #
  # just the public properties are accessible via the cget interface
  #
  
  ? {o1 cget -a} a1
  ? {o1 cget -b} b1
  ? {o1 cget -c} {cget: unknown configure parameter -c}
  ? {o1 cget -d} {cget: unknown configure parameter -d}
  ? {o1 cget -va} {cget: unknown configure parameter -va}
  ? {o1 cget -vb} {cget: unknown configure parameter -vb}
  ? {o1 cget -vc} {cget: unknown configure parameter -vc}
  ? {o1 cget -vd} {cget: unknown configure parameter -vd}
  

  #
  # We do not have accessors in the default case and in the explicit "none" case.
  #

  ? {o1 info lookup method a} ""
  ? {o1 info lookup method b} "::o1::b"
  ? {o1 info lookup method c} "::o1::c"
  ? {o1 info lookup method d} "::o1::d" 
  ? {o1 info lookup method e} ""

  ? {o1 info lookup method va} ""
  ? {o1 info lookup method vb} "::o1::vb"
  ? {o1 info lookup method vc} "::o1::vc"
  ? {o1 info lookup method vd} "::o1::vd"
  ? {o1 info lookup method ve} ""

  #
  # check public/protected/private settings
  #
  ? {nsf::method::property o1 b call-protected} 0
  ? {nsf::method::property o1 c call-protected} 1
  ? {nsf::method::property o1 d call-protected} 1
  ? {nsf::method::property o1 vb call-protected} 0
  ? {nsf::method::property o1 vc call-protected} 1
  ? {nsf::method::property o1 vd call-protected} 1
  
  ? {nsf::method::property o1 b call-private} 0
  ? {nsf::method::property o1 c call-private} 0
  ? {nsf::method::property o1 d call-private} 1
  ? {nsf::method::property o1 vb call-private} 0
  ? {nsf::method::property o1 vc call-private} 0
  ? {nsf::method::property o1 vd call-private} 1

  #
  # check if instance variables are created
  #
  
  ? {o1 eval "info exists :a"} 1
  ? {o1 eval "info exists :b"} 1
  ? {o1 eval "info exists :c"} 1
  ? {o1 eval "info exists :d"} 0
  ? {o1 eval "info exists :e"} 1
  ? {o1 eval "info exists :va"} 1
  ? {o1 eval "info exists :vb"} 1
  ? {o1 eval "info exists :vc"} 1
  ? {o1 eval "info exists :vd"} 0
  ? {o1 eval "info exists :ve"} 1

  #
  # check if we can dispatch accessors directly or via "eval"
  #
  
  ? {o1 a} {::o1: unable to dispatch method 'a'}
  ? {o1 b get} b1
  ? {o1 c} {::o1: unable to dispatch method 'c'}
  ? {o1 d} {::o1: unable to dispatch method 'd'}
  
  ? {o1 eval ":a"} {::o1: unable to dispatch method 'a'}
  ? {o1 eval ":b get"} b1
  ? {o1 eval ":c get"} c1
  ? {o1 eval ":d"} {::o1: unable to dispatch method 'd'}

  ? {o1 va} {::o1: unable to dispatch method 'va'}
  ? {o1 vb get} vb1
  ? {o1 vc} {::o1: unable to dispatch method 'vc'}
  ? {o1 vd} {::o1: unable to dispatch method 'vd'}
  
  ? {o1 eval ":va"} {::o1: unable to dispatch method 'va'}
  ? {o1 eval ":vb get"} vb1
  ? {o1 eval ":vc get"} vc1
  ? {o1 eval ":vd"} {::o1: unable to dispatch method 'vd'}

  #
  # check dispatch of private accessors and private variables
  #
  ? {o1 call-local d} d1  
  ? {o1 call-local vd} vd1
  
  ? {lsort [o1 info vars]} "__private a b c e va vb vc ve"
  ? {o1 eval "array get :__private"} "::o1,d d1 ::o1,vd vd1"

  #
  # check error message
  #
  ? {o1 object property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none}
}

#
# test object-level properties and variables with -incremental
#
nx::test case object-level-incremental {

  nx::Object create o1 {
    :object property -incremental {a a1}
    :object property -accessor public -incremental {b b1}
    :object property -accessor protected -incremental {c c1}
    :object property -accessor private -incremental {d d1}
    :object property -accessor none -incremental {e e1}
    
    :object variable -incremental va va1
    :object variable -accessor public -incremental vb vb1
    :object variable -accessor protected -incremental vc vc1
    :object variable -accessor private -incremental vd vd1
    :object variable -accessor none -incremental ve ve1
    
    :public object method call-local {v} {: -local $v get}
    :public object method add-local {var value} {: -local $var add $value}
  }
  
  #
  # The use of "-incremental" implies multivalued
  #
  ? {o1 info lookup syntax configure} {?-e /value .../? ?-a /value .../? ?-b /value .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}
  
  ? {o1 cget -a} a1
  ? {o1 cget -b} b1
  ? {o1 cget -c} {cget: unknown configure parameter -c}
  ? {o1 cget -d} {cget: unknown configure parameter -d}
  ? {o1 cget -va} {cget: unknown configure parameter -va}
  ? {o1 cget -vb} {cget: unknown configure parameter -vb}
  ? {o1 cget -vc} {cget: unknown configure parameter -vc}
  ? {o1 cget -vd} {cget: unknown configure parameter -vd}

  #
  # The use of "-incremental" implies an accessor
  #
  
  ? {o1 info lookup method a} "::o1::a"  ;# forcing accessor
  ? {o1 info lookup method b} "::o1::b"
  ? {o1 info lookup method c} "::o1::c"
  ? {o1 info lookup method d} "::o1::d"

  ? {o1 info lookup method va} "::o1::va" ;# forcing accessor
  ? {o1 info lookup method vb} "::o1::vb"
  ? {o1 info lookup method vc} "::o1::vc"
  ? {o1 info lookup method vd} "::o1::vd"

  #
  # The use of "-incremental" implies an accessor, which is public
  #
  
  ? {nsf::method::property o1 a call-protected} 0
  ? {nsf::method::property o1 b call-protected} 0
  ? {nsf::method::property o1 c call-protected} 1
  ? {nsf::method::property o1 d call-protected} 1  
  ? {nsf::method::property o1 va call-protected} 0
  ? {nsf::method::property o1 vb call-protected} 0
  ? {nsf::method::property o1 vc call-protected} 1
  ? {nsf::method::property o1 vd call-protected} 1

  ? {nsf::method::property o1 a call-private} 0
  ? {nsf::method::property o1 b call-private} 0
  ? {nsf::method::property o1 c call-private} 0
  ? {nsf::method::property o1 d call-private} 1
  ? {nsf::method::property o1 va call-private} 0
  ? {nsf::method::property o1 vb call-private} 0
  ? {nsf::method::property o1 vc call-private} 0
  ? {nsf::method::property o1 vd call-private} 1

  #
  # do we have variables set?
  #
  
  ? {o1 eval "info exists :a"} 1
  ? {o1 eval "info exists :b"} 1
  ? {o1 eval "info exists :c"} 1
  ? {o1 eval "info exists :d"} 0
  ? {o1 eval "info exists :va"} 1
  ? {o1 eval "info exists :vb"} 1
  ? {o1 eval "info exists :vc"} 1
  ? {o1 eval "info exists :vd"} 0

  #
  # can we call the accessor directly or via "eval"
  #
  
  ? {o1 a get} a1
  ? {o1 b get} b1
  ? {o1 c} {::o1: unable to dispatch method 'c'}
  ? {o1 d} {::o1: unable to dispatch method 'd'}
 
  ? {o1 eval ":a get"} a1
  ? {o1 eval ":b get"} b1
  ? {o1 eval ":c get"} c1
  ? {o1 eval ":d"} {::o1: unable to dispatch method 'd'}
  
  
  ? {o1 va get} va1
  ? {o1 vb get} vb1
  ? {o1 vc} {::o1: unable to dispatch method 'vc'}
  ? {o1 vd} {::o1: unable to dispatch method 'vd'}
  
  ? {o1 eval ":va get"} va1
  ? {o1 eval ":vb get"} vb1
  ? {o1 eval ":vc get"} vc1
  ? {o1 eval ":vd"} {::o1: unable to dispatch method 'vd'}

  #
  # check the behavior of "private" properties and variables
  #
  ? {o1 call-local d} d1
  ? {o1 call-local vd} vd1

  ? {lsort [o1 info vars]} "__private a b c e va vb vc ve"
  ? {o1 eval "array get :__private"} "::o1,d d1 ::o1,vd vd1"

  #
  # check incremental operations for properties
  #

  ? {o1 a add x} {x a1}

  ? {o1 b add x} {x b1}
  ? {o1 c add x} {::o1: unable to dispatch method 'c'}
  ? {o1 eval {:c add x}} {x c1}
  ? {o1 d add x} {::o1: unable to dispatch method 'd'}
  ? {o1 eval {:d add x}} {::o1: unable to dispatch method 'd'}
  ? {o1 add-local d x} {x d1}
  ? {o1 e add x} {x e1}

  #
  # check incremental operations for variables
  #

  ? {o1 va add x} {x va1}
  ? {o1 vb add x} {x vb1}
  ? {o1 vc add x} {::o1: unable to dispatch method 'vc'}
  ? {o1 eval {:vc add x}} {x vc1}
  ? {o1 vd add x} {::o1: unable to dispatch method 'vd'}
  ? {o1 eval {:vd add x}} {::o1: unable to dispatch method 'vd'}
  ? {o1 add-local vd x} {x vd1}
  ? {o1 ve add x} {x ve1}


  #
  # The accessor should be a forwarder due to incremental
  #

  ? {o1 info object method definition b} {::o1 public object forward b -prefix value= ::o1::per-object-slot::b %1 %self b}

  #
  # check error message
  #
  ? {o1 object property -accessor proceted {b b1}} {accessor value 'proceted' invalid; might be one of public|protected|private or none}

  #
  # The accessor is deleted due to the error
  #

  ? {o1 info object method definition b} {}

}

#
# Tests for experimental "value add", "value assign" ...
#

# nx::test case property-value-incremental {

#   nx::Object create o1 {
#     :object property -incremental {a a1}
#   }

#   ? {o1 a add x} {x a1}
#   ? {o1 a assign {a1}} {a1}
  
#   nsf::configure debug 2
#   ? {o1 a value add x    } {x a1}
#   ? {o1 a value assign {a b c}} {a b c}
#   ? {o1 a value get      } {a b c}
#   ? {o1 a value add x    } {x a b c}
#   ? {o1 a value add z end} {x a b c z}
# }

#
# Test interactions between multiplicity and incremental
#
nx::test case property-incremental-multiplicity {

  nx::Object create o1 {
    :object property -incremental a:integer,0..n
    :object property -incremental b:integer,1..n
    :object property -incremental c:integer,0..1
    :object property -incremental d:integer,1..1 
  }

  ? {o1 info object slots a} "::o1::per-object-slot::a"
  ? {[o1 info object slots a] eval {set :multiplicity}} "0..n"
  ? {[o1 info object slots b] eval {set :multiplicity}} "1..n"
  ? {[o1 info object slots c] eval {set :multiplicity}} "0..n"
  ? {[o1 info object slots d] eval {set :multiplicity}} "1..n"

  ? {o1 info variable definition [o1 info object variables a]} \
      "::o1 object property -accessor public -incremental a:integer,0..n"
  ? {o1 info variable definition [o1 info object variables b]} \
      "::o1 object property -accessor public -incremental b:integer,1..n"
  ? {o1 info variable definition [o1 info object variables c]} \
      "::o1 object property -accessor public -incremental c:integer,0..n"
  ? {o1 info variable definition [o1 info object variables d]} \
      "::o1 object property -accessor public -incremental d:integer,1..n"

  ? {o1 a set {1 2 3}} {1 2 3}
  ? {o1 b set {1 2 3}} {1 2 3}

  ? {o1 a set ""} {}
  ? {o1 b set ""} {invalid value for parameter 'value': list is not allowed to be empty}
  ? {o1 c set ""} {}
  ? {o1 d set ""} {invalid value for parameter 'value': list is not allowed to be empty}
  
}

#####################################################################
# tests with class object
#####################################################################
#
# check performance of class-level configure and cget
#
nx::test case class-object-properties {

  nx::Class create C {
    :property {a a1}
    :variable va va1
    
    :object property {b b1}
    :object variable vb b1
    
    :create c1
  }

  #
  # just the public properties are accessible via the configure interface
  #
  
  ? {c1 info lookup syntax configure} {?-a /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  ? {c1 cget -a} a1
  ? {c1 configure -a a2} ""

  ? {C info lookup syntax configure} {?-b /value/? ?-mixins /mixinreg .../? ?-superclasses /class .../? ?-filters /filterreg .../? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  ? {C cget -b} b1
  ? {C configure -b b2} ""
  ? {C cget -b} b2
}

nx::test case exists-on-props {
  nx::Class create C {
    :object property {A A1}
    :property {a a1}
    
    :object property -accessor public {B B1}
    :property -accessor public {b b1}
    :object property -accessor public BB
    :property -accessor public bb

    :object property -accessor protected {C C1}
    :property -accessor protected {c c1}
    
    :object property -accessor private {D D1}
    :property -accessor private {d d1}

    :create c1

    :public object method do {args} {
      : {*}$args
    }

    :public method do {args} {
      : {*}$args
    }

    :public object method doLocal {args} {
      : -local {*}$args
    }
    
    :public method doLocal {args} {
      : -local {*}$args
    }
    
  }

  ? {::C A exists} \
      "method 'A' unknown for ::C; in order to create an instance of class ::C, consider using '::C create A ?...?'"
  ? {::c1 a exists} "::c1: unable to dispatch method 'a'"

  ? {::C B exists} 1
  ? {::c1 b exists} 1

  ? {::C B get} "B1"
  ? {::c1 b get} "b1"

  ? {::C BB exists} 0
  ? {::c1 bb exists} 0
  
  ? {::C do C exists} 1
  ? {::C eval {info exists :C}} 1
  ? {::c1 do c exists} 1
  ? {::c1 eval {info exists :c}} 1

  ? {::C do C unset} ""
  ? {::c1 do c unset} ""

  ? {::C do C exists} 0
  ? {::C eval {info exists :C}} 0
  ? {::c1 do c exists} 0
  ? {::c1 eval {info exists :c}} 0

  # interaction: exists + private
  
  ? {::C doLocal D exists} 1
  ? {::c1 doLocal d exists} 1

  ? {::C doLocal D unset} ""
  ? {::c1 doLocal d unset} ""

  ? {::C doLocal D exists} 0
  ? {::c1 doLocal d exists} 0

  ? {::C D exists} \
      "method 'D' unknown for ::C; in order to create an instance of class ::C, consider using '::C create D ?...?'"
  ? {::c1 d exists} "::c1: unable to dispatch method 'd'"
  
}


#####################################################################
# performance tests
#####################################################################
nx::test configure -count 10000
#
# check performance of class-level configure and cget
#
nx::test case class-level-perf {

  nx::Class create C {
    :property {a a1}
    :property -accessor public {b b1}
    :property -accessor protected {c c1}
    :property -accessor private {d d1}
    :property -accessor none {e e1}
    
    :variable va va1
    :variable -accessor public vb vb1
    :variable -accessor protected vc vc1
    :variable -accessor private vd vd1
    :variable -accessor none ve ve1
    
    :create c1
  }

  nx::Class create D {
    :object property {cp 101}
    :property {a a1}
    :property -accessor public {b b1}
    :property -accessor protected {c c1}
    :property -accessor private {d d1}
    :property -accessor none {e e1}
    
    :variable va va1
    :variable -accessor public vb vb1
    :variable -accessor protected vc vc1
    :variable -accessor private vd vd1
    :variable -accessor none ve ve1
    
    :create d1
  }

  #
  # just the public properties are accessible via the configure interface
  #
  package require nx::volatile
  
  ? {c1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  set e [C eval :__object_configureparameter]
  ? {C eval :__object_configureparameter} $e

  ? {c1 cget -a} a1
  ? {c1 configure -a a2} ""

  ? {C configure -class ::nx::Class} ""
  ? {C cget -class} ::nx::Class
  ? {C cget -mixin} ""
  ? {C cget -filter} ""
  
  #  ? {C cget -noinit} 0
  ? {C cget -volatile} 0

  #
  # check influence of class-level per-object properties
  #
  ? {d1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-volatile? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  set e [D eval :__object_configureparameter]
  ? {D eval :__object_configureparameter} $e

  ? {d1 cget -a} a1
  ? {d1 configure -a a2} ""

  ? {D configure -class ::nx::Class} ""
  ? {D cget -class} ::nx::Class

  ? {D cget -cp} 101
  ? {D configure -cp 102} ""
  ? {D cget -cp} 102
}

#
# check performance of class-level configure and cget
#

nx::test case object-level-perf {

  nx::Object create o1 {
    :object property {a a1}
    :object property -accessor public {b b1}
    :object property -accessor protected {c c1}
    :object property -accessor private {d d1}
    :object property -accessor none {e e1}
    
    :object variable va va1
    :object variable -accessor public vb vb1
    :object variable -accessor protected vc vc1
    :object variable -accessor private vd vd1
    :object variable -accessor none ve ve1
  }

  #
  # just the public properties are accessible via the configure interface
  #
  
  ? {o1 info lookup syntax configure} {?-e /value/? ?-a /value/? ?-b /value/? ?-object-mixins /mixinreg .../? ?-object-filters /filterreg .../? ?-class /class/? ?/__initblock/?}

  set e [o1 eval :__object_configureparameter]

  ? {o1 eval :__object_configureparameter} $e

  ? {o1 cget -a} a1
  ? {o1 configure -a a2} ""

  ? {o1 b get} b1
  ? {o1 b set b2} "b2"

  ? {o1 configure -class ::nx::Object} ""
  ? {o1 cget -class} ::nx::Object
}

nx::test case extend-parent-class-info {

  nx::Class create Foo
  nx::Class create Bar -superclass Foo
  ? {llength [Bar info lookup parameters create]} 5
  #
  # extend the superclass, subclass should become aware of this
  #
  Foo property y
  ? {llength [Bar info lookup parameters create]} 6
}

nx::test case extend-parent-class-info-cache {

  nx::Class create Foo
  nx::Class create Bar -superclass Foo
  ? {llength [Bar info lookup parameters create]} 5
  #
  # Let Bar cache the objectparameters, and extend later the
  # superclass
  #
  Bar new
  Foo property y
  ? {llength [Bar info lookup parameters create]} 6
}

nx::test case extend-parent-class-info-cache-configure {

  nx::Class create Foo
  nx::Class create Bar -superclass Foo
  ? {llength [Bar info lookup parameters create]} 5
  #
  # Let Bar cache the objectparameters, and extend later the
  # superclass
  #
  Bar create b1
  Foo property y
  # access objectparameter indirectly via configure
  ? {b1 configure -y 2} ""
}

nx::test case extend-class-mixin-info {
  
  nx::Class create Baz
  nx::Class create Foo -mixin Baz
  nx::Class create Bar -mixin Foo
  Bar create bar; # cache becomes hot!
  ? {llength [Bar info lookup parameters create]} 5

  Foo property y
  ? {llength [Bar info lookup parameters create]} 6

  Baz property z
  ? {llength [Bar info lookup parameters create]} 7

  Baz delete property z
  ? {llength [Bar info lookup parameters create]} 6

  Foo delete property y
  ? {llength [Bar info lookup parameters create]} 5

}

nx::test case extend-class-mixin-configure {
  
  nx::Class create Baz
  nx::Class create Foo -mixin Baz
  nx::Class create Bar -mixin Foo
  Bar create bar; # cache becomes hot!

  Foo property y
  bar configure -y 1
  ? {bar cget -y} 1

  Baz property z
  bar configure -z 2
  ? {bar cget -z} 2
  bar configure -y 3
  ? {bar cget -y} 3

  Bar property w
  bar configure -w 4
  ? {bar cget -w} 4

}

nx::test case dynamic-transitive-mixin-info {
  
  nx::Class create Foo
  nx::Class create Bar
  nx::Class create Baz

  Bar create bar; # cache object parameters in class Bar
  Baz create baz; # cache object parameters in class Baz

  ? {llength [Bar info lookup parameters create]} 5

  Foo property y
  ? {llength [Bar info lookup parameters create]} 5

  Bar mixins add Foo
  ? {llength [Bar info lookup parameters create]} 6
  ? {bar configure -y 1} ""

  ? {llength [Baz info lookup parameters create]} 5
  Baz mixins add Bar
  ? {llength [Baz info lookup parameters create]} 6

  Foo property z
  ? {llength [Baz info lookup parameters create]} 7
  ? {baz configure -z 1} ""
  ? {bar configure -z 1} ""

}

nx::test configure -count 1
nx::test case indirect-transitive-mixin-info {

  nx::Class create M0 {:public method foo {} {return M}}
  nx::Class create M1 -superclass M0
  nx::Class create M2 -superclass M1

  nx::Class create C {:public method foo {} {return C}}
  nx::Class create D -superclass C

  C create c1
  D create d1
  M0 create m0
  M1 create m1
  M2 create m2

  ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \
      "objectName object-mixins object-filters class __initblock"
  set base [llength [lmap p [C info lookup parameters create] {nsf::parameter::info name $p}]]

  ? [list set _ $base] 5

  ? {llength [C info lookup parameters create]} $base
  ? {llength [D info lookup parameters create]} $base
  ? {llength [M0 info lookup parameters create]} $base
  ? {llength [M1 info lookup parameters create]} $base
  ? {llength [M2 info lookup parameters create]} $base

  M0 property x

  ? {llength [M0 info lookup parameters create]} [expr {$base + 1}]
  ? {llength [M1 info lookup parameters create]} [expr {$base + 1}]
  ? {llength [M2 info lookup parameters create]} [expr {$base + 1}]

  ? {c1 foo} C
  ? {d1 foo} C

  ? {c1 info precedence} "::C ::nx::Object"
  ? {d1 info precedence} "::D ::C ::nx::Object"

  ? {C info subclasses -dependent} "::C ::D"
  ? {C info subclasses -closure} "::C ::D"
  ? {M0 info subclasses -dependent} "::M0 ::M1 ::M2"
  ? {M0 info subclasses -closure} "::M0 ::M1 ::M2"

  #puts stderr =========C-mixin-add-M2
  C mixins add M2
  #puts stderr =========

  ? {c1 foo} M
  ? {d1 foo} M

  ? {c1 info precedence} "::M2 ::M1 ::M0 ::C ::nx::Object"
  ? {d1 info precedence} "::M2 ::M1 ::M0 ::D ::C ::nx::Object"

  ? {C info heritage} "::M2 ::M1 ::M0 ::nx::Object"
  ? {D info heritage} "::M2 ::M1 ::M0 ::C ::nx::Object"

  ? {C info subclasses -dependent} "::C ::D"
  ? {C info subclasses -closure} "::C ::D"
  ? {M0 info subclasses -dependent} "::M0 ::M1 ::M2 ::C ::D"
  ? {M0 info subclasses -closure} "::M0 ::M1 ::M2"


  # Only M2 is a direct mixin, visible through "mixinof",
  # but query-able via transitive -closure operator

  ? {M2 info mixinof} "::C"
  ? {M2 info mixinof -closure} "::C ::D"

  ? {M1 info mixinof} ""
  ? {M1 info mixinof -closure} "::C ::D"

  ? {M0 info mixinof} ""
  ? {M0 info mixinof -closure} "::C ::D"

  ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \
      "objectName x object-mixins object-filters class __initblock"

  ? {llength [C info lookup parameters create]} [expr {$base + 1}]
  ? {llength [D info lookup parameters create]} [expr {$base + 1}]

  #puts stderr =========-M1-property
  M1 property y
  #puts stderr =========
  ? {C info heritage} "::M2 ::M1 ::M0 ::nx::Object"

  #::nsf::parameter::cache::classinvalidate ::C

  ? {lmap p [C info lookup parameters create] {nsf::parameter::info name $p}} \
      "objectName y x object-mixins object-filters class __initblock"

  ? {lmap p [M0 info lookup parameters create] {nsf::parameter::info name $p}} \
      "objectName x object-mixins object-filters class __initblock"

  ? {lmap p [M1 info lookup parameters create] {nsf::parameter::info name $p}} \
      "objectName y x object-mixins object-filters class __initblock"

  ? {llength [C info lookup parameters create]} [expr {$base + 2}]
  ? {llength [D info lookup parameters create]} [expr {$base + 2}]
  ? {llength [M0 info lookup parameters create]} [expr {$base + 1}]
  ? {llength [M1 info lookup parameters create]} [expr {$base + 2}]
  ? {llength [M2 info lookup parameters create]} [expr {$base + 2}]

  # clearning the mixin has to reset the orders of the instances of C and D
  #puts stderr =========C-mixin-clear
  C mixins clear
  #puts stderr =========

  ? {c1 foo} C
  ? {d1 foo} C

  ? {c1 info precedence} "::C ::nx::Object"
  ? {d1 info precedence} "::D ::C ::nx::Object"
}


#
# See bug report at:
# https://groups.google.com/forum/#!topic/comp.lang.tcl/F9cn_Ah4js4
#
nx::test case bug-clt-configurable-false-cget {
  nx::Class create D;
  D property -configurable false "nix";
  D create d;
  # Provide for a shared parameter name Tcl_Obj, to enable intrep
  # sharing between "cget" and "configure". The original bug report
  # ran into the critical path using an interactive shell, with intrep
  # sharing occurring via literals.
  set flag "-nix"; 
  catch {d cget $flag}
  catch {d configure $flag anix} msg opts
  ? [list string match "invalid non-positional argument '-nix', *"  [dict get $opts -errorinfo]] 1
}
 



#
# Local variables:
#    mode: tcl
#    tcl-indent-level: 2
#    indent-tabs-mode: nil
# End:

