# # Tests for inheritance and scope handling # ---------------------------------------------------------------------- # AUTHOR: Michael J. McLennan Phone: (610)712-2842 # AT&T Bell Laboratories E-mail: michael.mclennan@att.com # # RCS: inherit.test,v 1.3 1994/04/08 13:40:20 mmc Exp # ---------------------------------------------------------------------- # Copyright (c) 1993 AT&T Bell Laboratories # ====================================================================== # Permission to use, copy, modify, and distribute this software and its # documentation for any purpose and without fee is hereby granted, # provided that the above copyright notice appear in all copies and that # both that the copyright notice and warranty disclaimer appear in # supporting documentation, and that the names of AT&T Bell Laboratories # any of their entities not be used in advertising or publicity # pertaining to distribution of the software without specific, written # prior permission. # # AT&T disclaims all warranties with regard to this software, including # all implied warranties of merchantability and fitness. In no event # shall AT&T be liable for any special, indirect or consequential # damages or any damages whatsoever resulting from loss of use, data or # profits, whether in an action of contract, negligence or other # tortuous action, arising out of or in connection with the use or # performance of this software. # ====================================================================== # ---------------------------------------------------------------------- # MULTIPLE BASE-CLASS ERROR DETECTION # ---------------------------------------------------------------------- test {Cannot inherit from the same base class more than once} { catch "VirtualErr" errmsg set errmsg } { $result == {error while autoloading "VirtualErr": class "VirtualErr" inherits base class "Foo" more than once: VirtualErr->Mongrel->FooBar->Foo VirtualErr->Foo VirtualErr->BarFoo->Foo} } # ---------------------------------------------------------------------- # CONSTRUCTION # ---------------------------------------------------------------------- test {Constructors should be invoked implicitly} { set WATCH "" concat [Mongrel m] / $WATCH } { $result == "m / Mongrel FooBar Foo Bar Geek" } test {Initialization of shadowed variables works properly} { concat [m info public blit -value] / [m info public Foo::blit -value] } { $result == "nonnull / " } # ---------------------------------------------------------------------- # PUBLIC VARIABLES # ---------------------------------------------------------------------- test {Inherited "config" method works on derived classes} { m config -blit xyz -Foo::blit pdq } { $result == "Mongrel::blit Foo::blit" } test {Inherited "config" method works on derived classes} { m config -blit xyz -Foo::blit pdq concat [m info public blit -value] / [m info public Foo::blit -value] } { $result == "xyz / pdq" } test {Inherited "config" method works on derived classes} { m config -tag #0000 } { $result == "Mongrel::tag" } # ---------------------------------------------------------------------- # INHERITANCE INFO # ---------------------------------------------------------------------- test {Info: class} { m info class } { $result == "Mongrel" } test {Info: inherit} { m info inherit } { $result == "FooBar Geek" } test {Info: heritage} { m info heritage } { $result == "Mongrel FooBar Foo Bar Geek" } test {Built-in "isa" method} { set status 1 foreach c [m info heritage] { set status [expr {$status && [m isa $c]}] } set status } { $result == 1 } test {Built-in "isa" method} { m isa Watermelon } { $result == 0 } # ---------------------------------------------------------------------- # SCOPE MANIPULATION # ---------------------------------------------------------------------- test {commands normally execute in the scope of their class} { m Foo::do {info class} } { $result == "Foo says 'Foo'" } test {"virtual" command moves scope to most specific class} { m Foo::do {virtual info class} } { $result == "Foo says 'Mongrel'" } test {"previous" command moves scope upward in hierarchy} { m do {virtual previous info class} } { $result == "Foo says 'FooBar'" } test {"previous" command can be chained} { m do {virtual previous previous info class} } { $result == "Foo says 'Foo'" } # ---------------------------------------------------------------------- # METHOD INVOCATION # ---------------------------------------------------------------------- test {Simple method names are assigned based on heritage} { m do {concat "$this ([virtual info class]) at scope [info class]::"} } { $result == "Foo says 'm (Mongrel) at scope Foo::'" } test {Explicit scoping can be used to reach shadowed members} { m Geek::do {concat "$this ([virtual info class]) at scope [info class]::"} } { $result == "Geek says 'm (Mongrel) at scope Geek::'" } test {Methods execute in local scope of class, e.g., Foo::do} { m config -blit abc -Foo::blit def m Foo::do {set blit xyz} concat [m info public blit -value] / [m info public Foo::blit -value] } { $result == "abc / xyz" } # ---------------------------------------------------------------------- # DESTRUCTION # ---------------------------------------------------------------------- test {Destructors should be invoked implicitly} { set WATCH "" concat [m delete] / $WATCH } { $result == "/ Mongrel Geek Bar Foo FooBar" } # ---------------------------------------------------------------------- # OBJECT INFO # ---------------------------------------------------------------------- foreach obj [itcl_info objects] { $obj delete } Mongrel m FooBar fb Foo f Geek g test {Object queries can be restricted by object name} { itcl_info objects f* } { [test_cmp_lists $result {f fb}] } test {Object queries can be restricted to specific classes} { itcl_info objects -class Foo } { $result == "f" } test {Object queries can be restricted by object heritage} { itcl_info objects -isa Foo } { [test_cmp_lists $result {m f fb}] } test {Object queries can be restricted by object name / specific classes} { itcl_info objects f* -class Foo } { $result == "f" } test {Object queries can be restricted by object name / object heritage} { itcl_info objects f* -isa Foo } { [test_cmp_lists $result {f fb}] } # ---------------------------------------------------------------------- # ERROR HANDLING ACROSS CLASS BOUNDARIES # ---------------------------------------------------------------------- Mongrel m1 FooBar fb2 test {Errors and detected and reported across class boundaries} { set status [catch {m1 do {fb2 do {error "test"}}} mesg] format "$mesg $status" } { $result == "test 1" } test {Stack trace unwinds properly across class boundaries} { catch {m1 do {fb2 do {error "test"}}} mesg format "$errorInfo" } { $result == {test while executing "error "test"" ("eval" body line 1) invoked from within "eval $cmds" invoked from within "return "Foo says '[eval $cmds]..." (object "fb2" method "FooBar::do" body line 2) invoked from within "fb2 do {error "test"}" invoked from within "fb2 do {error "test"}" ("eval" body line 1) invoked from within "eval $cmds" invoked from within "return "Foo says '[eval $cmds]..." (object "m1" method "Mongrel::do" body line 2) invoked from within "m1 do {fb2 do {error "test"}}"} } test {Stack trace unwinds properly across class boundaries} { catch {m1 do {fb2 do {error "test" "some error"}}} mesg format "$errorInfo" } { $result == {some error ("eval" body line 2) invoked from within "eval $cmds" invoked from within "return "Foo says '[eval $cmds]..." (object "fb2" method "FooBar::do" body line 2) invoked from within "fb2 do {error "test" "some error"}" invoked from within "fb2 do {error "test" "some error"}" ("eval" body line 1) invoked from within "eval $cmds" invoked from within "return "Foo says '[eval $cmds]..." (object "m1" method "Mongrel::do" body line 2) invoked from within "m1 do {fb2 do {error "test" "some error"}}"} } test {Error codes are preserved across class boundaries} { catch {m1 do {fb2 do {error "test" "some error" CODE-BLUE}}} mesg format "$errorCode" } { $result == "CODE-BLUE" }