USING: accessors arrays assocs calendar classes classes.algebra classes.private classes.tuple classes.tuple.private columns combinators.short-circuit compiler.errors compiler.units definitions eval generic generic.single io.streams.string kernel kernel.private literals math math.constants memory namespaces parser parser.notes see sequences sequences.private slots splitting strings threads tools.test vectors vocabs words words.symbol ; IN: classes.tuple.tests TUPLE: rect x y w h ; : ( x y w h -- rect ) rect boa ; : move ( x rect -- rect ) [ + ] change-x ; { f } [ 10 20 30 40 dup clone 5 swap move = ] unit-test { t } [ 10 20 30 40 dup clone 0 swap move = ] unit-test ! Make sure we handle tuple class redefinition TUPLE: redefinition-test ; C: redefinition-test "redefinition-test" set { t } [ "redefinition-test" get redefinition-test? ] unit-test "IN: classes.tuple.tests TUPLE: redefinition-test ;" eval( -- ) { t } [ "redefinition-test" get redefinition-test? ] unit-test ! Make sure we handle changing shapes! TUPLE: point x y ; { } [ 100 200 point boa "p" set ] unit-test ! Use eval to sequence parsing explicitly { } [ "IN: classes.tuple.tests TUPLE: point x y z ;" eval( -- ) ] unit-test { 100 } [ "p" get x>> ] unit-test { 200 } [ "p" get y>> ] unit-test { f } [ "p" get "z>>" "accessors" lookup-word execute ] unit-test { } [ "p" get 300 ">>z" "accessors" lookup-word execute drop ] unit-test { 3 } [ "p" get tuple-size ] unit-test { 300 } [ "p" get "z>>" "accessors" lookup-word execute ] unit-test { } [ "IN: classes.tuple.tests TUPLE: point z y ;" eval( -- ) ] unit-test { 2 } [ "p" get tuple-size ] unit-test [ "p" get x>> ] must-fail { 200 } [ "p" get y>> ] unit-test { 300 } [ "p" get "z>>" "accessors" lookup-word execute ] unit-test TUPLE: slotty a b c ; { T{ slotty } } [ H{ } slotty from-slots ] unit-test { T{ slotty f 1 2 f } } [ H{ { "a" 1 } { "b" 2 } } slotty from-slots ] unit-test [ H{ { "d" 0 } } slotty new set-slots ] must-fail TUPLE: predicate-test ; C: predicate-test : predicate-test ( a -- ? ) drop f ; { t } [ predicate-test? ] unit-test PREDICATE: silly-pred < tuple class-of \ rect = ; GENERIC: area ( obj -- n ) M: silly-pred area dup w>> swap h>> * ; TUPLE: circle radius ; M: circle area radius>> sq pi * ; { 200 } [ T{ rect f 0 0 10 20 } area ] unit-test ! Hashcode breakage TUPLE: empty ; C: empty { t } [ hashcode fixnum? ] unit-test ! Compiler regression [ t length ] [ object>> t eq? ] must-fail-with { "" } [ "IN: classes.tuple.test TUPLE: constructor-test ; C: constructor-test" eval( -- ) last-word name>> ] unit-test TUPLE: size-test a b c d ; { t } [ T{ size-test } tuple-size size-test tuple-layout second = ] unit-test GENERIC: ( a -- b ) TUPLE: yo-momma ; { } [ "IN: classes.tuple.tests C: yo-momma" eval( -- ) ] unit-test { f } [ \ generic? ] unit-test ! Test forget [ [ t ] [ \ yo-momma class? ] unit-test [ ] [ \ yo-momma forget ] unit-test [ ] [ \ forget ] unit-test [ f ] [ \ yo-momma update-map get values member-eq? ] unit-test ] with-compilation-unit TUPLE: loc-recording ; { f } [ \ loc-recording where not ] unit-test ! 'forget' wasn't robust enough TUPLE: forget-robustness ; GENERIC: forget-robustness-generic ( a -- b ) M: forget-robustness forget-robustness-generic ; M: integer forget-robustness-generic ; [ [ ] [ \ forget-robustness-generic forget ] unit-test [ ] [ \ forget-robustness forget ] unit-test [ ] [ M\ forget-robustness forget-robustness-generic forget ] unit-test ] with-compilation-unit ! rapido found this one GENERIC#: m1 0 ( s n -- n ) GENERIC#: m2 1 ( s n -- v ) TUPLE: t1 ; M: t1 m1 drop ; M: t1 m2 nip ; TUPLE: t2 ; M: t2 m1 drop ; M: t2 m2 nip ; TUPLE: t3 ; M: t3 m1 drop ; M: t3 m2 nip ; TUPLE: t4 ; M: t4 m1 drop ; M: t4 m2 nip ; C: t4 { 1 } [ 1 m1 ] unit-test { 1 } [ 1 m2 ] unit-test ! another combination issue GENERIC: silly ( obj -- obj obj ) UNION: my-union slice repetition column array vector reversed ; M: my-union silly "x" ; M: array silly "y" ; M: column silly "fdsfds" ; M: repetition silly "zzz" ; M: reversed silly "zz" ; M: slice silly "tt" ; M: string silly "t" ; M: vector silly "z" ; { "zz" } [ 123 silly nip ] unit-test ! Typo SYMBOL: not-a-tuple-class ! Missing check [ not-a-tuple-class boa ] must-fail [ not-a-tuple-class new ] must-fail TUPLE: erg's-reshape-problem a b c d ; C: erg's-reshape-problem ! Inheritance TUPLE: computer cpu ram ; C: computer { "TUPLE: computer cpu ram ;" } [ [ \ computer see ] with-string-writer string-lines second ] unit-test TUPLE: laptop < computer battery ; C: laptop { t } [ laptop tuple-class? ] unit-test { t } [ laptop tuple class<= ] unit-test { t } [ laptop computer class<= ] unit-test { t } [ laptop computer classes-intersect? ] unit-test { } [ "Pentium" 128 3 hours "laptop" set ] unit-test { t } [ "laptop" get laptop? ] unit-test { t } [ "laptop" get computer? ] unit-test { t } [ "laptop" get tuple? ] unit-test : test-laptop-slot-values ( -- ) [ laptop ] [ "laptop" get class-of ] unit-test [ "Pentium" ] [ "laptop" get cpu>> ] unit-test [ 128 ] [ "laptop" get ram>> ] unit-test [ t ] [ "laptop" get battery>> 3 hours = ] unit-test ; test-laptop-slot-values { "TUPLE: laptop < computer battery ;" } [ [ \ laptop see ] with-string-writer string-lines second ] unit-test { { tuple computer laptop } } [ laptop superclasses-of ] unit-test TUPLE: server < computer rackmount ; C: server { t } [ server tuple-class? ] unit-test { t } [ server tuple class<= ] unit-test { t } [ server computer class<= ] unit-test { t } [ server computer classes-intersect? ] unit-test { } [ "PowerPC" 64 "1U" "server" set ] unit-test { t } [ "server" get server? ] unit-test { t } [ "server" get computer? ] unit-test { t } [ "server" get tuple? ] unit-test : test-server-slot-values ( -- ) [ server ] [ "server" get class-of ] unit-test [ "PowerPC" ] [ "server" get cpu>> ] unit-test [ 64 ] [ "server" get ram>> ] unit-test [ "1U" ] [ "server" get rackmount>> ] unit-test ; test-server-slot-values { f } [ "server" get laptop? ] unit-test { f } [ "laptop" get server? ] unit-test { f } [ server laptop class<= ] unit-test { f } [ laptop server class<= ] unit-test { f } [ laptop server classes-intersect? ] unit-test { f } [ 1 2 laptop? ] unit-test { f } [ \ + server? ] unit-test { "TUPLE: server < computer rackmount ;" } [ [ \ server see ] with-string-writer string-lines second ] unit-test [ "IN: classes.tuple.tests TUPLE: invalid-superclass < word ;" eval( -- ) ] must-fail ! Dynamically changing inheritance hierarchy TUPLE: electronic-device ; : computer?' ( a -- b ) computer? ; { t } [ laptop new computer?' ] unit-test { } [ "IN: classes.tuple.tests TUPLE: computer < electronic-device cpu ram ; C: computer C: laptop C: server" eval( -- ) ] unit-test { t } [ laptop new computer?' ] unit-test { f } [ electronic-device laptop class<= ] unit-test { t } [ server electronic-device class<= ] unit-test { t } [ laptop server class-or electronic-device class<= ] unit-test { t } [ "laptop" get electronic-device? ] unit-test { t } [ "laptop" get computer? ] unit-test { t } [ "laptop" get laptop? ] unit-test { f } [ "laptop" get server? ] unit-test { t } [ "server" get electronic-device? ] unit-test { t } [ "server" get computer? ] unit-test { f } [ "server" get laptop? ] unit-test { t } [ "server" get server? ] unit-test { } [ "IN: classes.tuple.tests TUPLE: computer cpu ram ; C: computer C: laptop C: server" eval( -- ) ] unit-test { f } [ "laptop" get electronic-device? ] unit-test { t } [ "laptop" get computer? ] unit-test { } [ "IN: classes.tuple.tests TUPLE: computer < electronic-device cpu ram disk ; C: computer C: laptop C: server" eval( -- ) ] unit-test test-laptop-slot-values test-server-slot-values { } [ "IN: classes.tuple.tests TUPLE: electronic-device voltage ; C: computer C: laptop C: server" eval( -- ) ] unit-test test-laptop-slot-values test-server-slot-values TUPLE: make-me-some-accessors voltage grounded? ; { f } [ "laptop" get voltage>> ] unit-test { f } [ "server" get voltage>> ] unit-test { } [ "laptop" get 220 >>voltage drop ] unit-test { } [ "server" get 110 >>voltage drop ] unit-test { } [ "IN: classes.tuple.tests TUPLE: electronic-device voltage grounded? ; C: computer" eval( -- ) ] unit-test test-laptop-slot-values test-server-slot-values { 220 } [ "laptop" get voltage>> ] unit-test { 110 } [ "server" get voltage>> ] unit-test { } [ "IN: classes.tuple.tests TUPLE: electronic-device grounded? voltage ; C: computer C: laptop C: server" eval( -- ) ] unit-test test-laptop-slot-values test-server-slot-values { 220 } [ "laptop" get voltage>> ] unit-test { 110 } [ "server" get voltage>> ] unit-test ! Reshaping superclass and subclass simultaneously { } [ "IN: classes.tuple.tests TUPLE: electronic-device voltage ; TUPLE: computer < electronic-device cpu ram ; C: computer C: laptop C: server" eval( -- ) ] unit-test test-laptop-slot-values test-server-slot-values { 220 } [ "laptop" get voltage>> ] unit-test { 110 } [ "server" get voltage>> ] unit-test ! Reshape crash TUPLE: test1 a ; TUPLE: test2 < test1 b ; "a" "b" test2 boa "test" set : test-a/b ( -- ) [ "a" ] [ "test" get a>> ] unit-test [ "b" ] [ "test" get b>> ] unit-test ; test-a/b { } [ "IN: classes.tuple.tests TUPLE: test1 a x ; TUPLE: test2 < test1 b y ;" eval( -- ) ] unit-test test-a/b { } [ "IN: classes.tuple.tests TUPLE: test1 a ; TUPLE: test2 < test1 b ;" eval( -- ) ] unit-test test-a/b ! Twice in the same compilation unit [ test1 tuple { "a" "x" "y" } define-tuple-class test1 tuple { "a" "y" } define-tuple-class ] with-compilation-unit test-a/b ! Moving slots up and down TUPLE: move-up-1 a b ; TUPLE: move-up-2 < move-up-1 c ; T{ move-up-2 f "a" "b" "c" } "move-up" set : test-move-up ( -- ) [ "a" ] [ "move-up" get a>> ] unit-test [ "b" ] [ "move-up" get b>> ] unit-test [ "c" ] [ "move-up" get c>> ] unit-test ; test-move-up { } [ "IN: classes.tuple.tests TUPLE: move-up-1 a b c ; TUPLE: move-up-2 < move-up-1 ;" eval( -- ) ] unit-test test-move-up { } [ "IN: classes.tuple.tests TUPLE: move-up-1 a c ; TUPLE: move-up-2 < move-up-1 b ;" eval( -- ) ] unit-test test-move-up { } [ "IN: classes.tuple.tests TUPLE: move-up-1 c ; TUPLE: move-up-2 < move-up-1 b a ;" eval( -- ) ] unit-test test-move-up { } [ "IN: classes.tuple.tests TUPLE: move-up-1 ; TUPLE: move-up-2 < move-up-1 a b c ;" eval( -- ) ] unit-test ! Constructors must be recompiled when changing superclass TUPLE: constructor-update-1 xxx ; TUPLE: constructor-update-2 < constructor-update-1 yyy zzz ; : ( a b c -- tuple ) constructor-update-2 boa ; { 3 1 } [ ] must-infer-as { } [ "IN: classes.tuple.tests TUPLE: constructor-update-1 xxx ttt www ;" eval( -- ) ] unit-test { 3 1 } [ ] must-infer-as [ 1 2 3 4 5 ] [ not-compiled? ] must-fail-with { } [ [ \ forget ] with-compilation-unit ] unit-test ! Redefinition problem TUPLE: redefinition-problem ; UNION: redefinition-problem' redefinition-problem integer ; { t } [ 3 redefinition-problem'? ] unit-test TUPLE: redefinition-problem-2 ; "IN: classes.tuple.tests TUPLE: redefinition-problem < redefinition-problem-2 ;" eval( -- ) { t } [ 3 redefinition-problem'? ] unit-test ! Hardcore unit tests \ thread "slots" word-prop "slots" set { } [ [ \ thread tuple { "xxx" } "slots" get append define-tuple-class ] with-compilation-unit [ 1337 sleep ] "Test" spawn drop [ \ thread tuple "slots" get define-tuple-class ] with-compilation-unit ] unit-test \ vocab "slots" word-prop "slots" set { } [ [ \ vocab identity-tuple { "xxx" } "slots" get append define-tuple-class ] with-compilation-unit all-words drop [ \ vocab identity-tuple "slots" get define-tuple-class ] with-compilation-unit ] unit-test [ "USE: words T{ word }" eval( -- ) ] [ error>> T{ no-method f word new } = ] must-fail-with ! Accessors not being forgotten... { [ ] } [ "IN: classes.tuple.tests TUPLE: forget-accessors-test x y z ;" "forget-accessors-test" parse-stream ] unit-test { t } [ "forget-accessors-test" "classes.tuple.tests" lookup-word class? ] unit-test : accessor-exists? ( name -- ? ) [ "forget-accessors-test" "classes.tuple.tests" lookup-word ] dip ">>" append "accessors" lookup-word ?lookup-method >boolean ; { t } [ "x" accessor-exists? ] unit-test { t } [ "y" accessor-exists? ] unit-test { t } [ "z" accessor-exists? ] unit-test { [ ] } [ "IN: classes.tuple.tests GENERIC: forget-accessors-test ( a -- b )" "forget-accessors-test" parse-stream ] unit-test { f } [ "forget-accessors-test" "classes.tuple.tests" lookup-word class? ] unit-test { f } [ "x" accessor-exists? ] unit-test { f } [ "y" accessor-exists? ] unit-test { f } [ "z" accessor-exists? ] unit-test TUPLE: another-forget-accessors-test ; { [ ] } [ "IN: classes.tuple.tests GENERIC: another-forget-accessors-test ( a -- b )" "another-forget-accessors-test" parse-stream ] unit-test { t } [ \ another-forget-accessors-test class? ] unit-test ! Shadowing test { f } [ f parser-quiet? [ [ "IN: classes.tuple.tests TUPLE: shadow-1 a b ; TUPLE: shadow-2 < shadow-1 a b ;" eval( -- ) ] with-string-writer empty? ] with-variable ] unit-test ! Missing error check [ "IN: classes.tuple.tests USE: words TUPLE: wrong-superclass < word ;" eval( -- ) ] must-fail ! Insufficient type checking [ \ vocab tuple>array drop ] must-fail ! Check type declarations TUPLE: declared-types { n fixnum } { m string } ; { T{ declared-types f 0 "hi" } } [ { declared-types 0 "hi" } >tuple ] unit-test [ { declared-types "hi" 0 } >tuple ] [ T{ bad-slot-value f "hi" fixnum } = ] must-fail-with ! Check fixnum coercer [ 0.0 "hi" declared-types boa n>> ] [ T{ no-method f 0.0 integer>fixnum-strict } = ] must-fail-with [ declared-types new 0.0 >>n n>> ] [ T{ no-method f 0.0 integer>fixnum-strict } = ] must-fail-with { T{ declared-types f 33333 "asdf" } } [ 33333 >bignum "asdf" declared-types boa ] unit-test [ 444444444444444444444444444444444444444444444444433333 >bignum "asdf" declared-types boa ] [ ${ KERNEL-ERROR ERROR-OUT-OF-FIXNUM-RANGE 444444444444444444444444444444444444444444444444433333 f } = ] must-fail-with ! Check bignum coercer TUPLE: bignum-coercer { n bignum initial: $[ 0 >bignum ] } ; { 13 bignum } [ 13.5 bignum-coercer boa n>> dup class-of ] unit-test { 13 bignum } [ bignum-coercer new 13.5 >>n n>> dup class-of ] unit-test ! Check float coercer TUPLE: float-coercer { n float } ; { 13.0 float } [ 13 float-coercer boa n>> dup class-of ] unit-test { 13.0 float } [ float-coercer new 13 >>n n>> dup class-of ] unit-test ! Check integer coercer TUPLE: integer-coercer { n integer } ; [ 13.5 integer-coercer boa n>> dup class-of ] [ T{ bad-slot-value f 13.5 integer } = ] must-fail-with [ integer-coercer new 13.5 >>n n>> dup class-of ] [ T{ bad-slot-value f 13.5 integer } = ] must-fail-with : foo ( a b -- c ) declared-types boa ; \ foo def>> must-infer [ 0.0 "hi" foo ] [ T{ no-method f 0.0 integer>fixnum-strict } = ] must-fail-with [ "hi" 0.0 declared-types boa ] [ T{ no-method f "hi" integer>fixnum-strict } = ] must-fail-with [ 0 { } declared-types boa ] [ T{ bad-slot-value f { } string } = ] must-fail-with [ "hi" 0.0 foo ] [ T{ no-method f "hi" integer>fixnum-strict } = ] must-fail-with [ 0 { } foo ] [ T{ bad-slot-value f { } string } = ] must-fail-with { T{ declared-types f 0 "" } } [ declared-types new ] unit-test : blah ( -- vec ) vector new ; [ vector new ] must-infer { V{ } } [ blah ] unit-test { } [ "IN: classes.tuple.tests TUPLE: forget-subclass-test ; TUPLE: forget-subclass-test' < forget-subclass-test ;" "forget-subclass-test" parse-stream drop ] unit-test { } [ "forget-subclass-test'" "classes.tuple.tests" lookup-word new "bad-object" set ] unit-test { } [ "IN: classes.tuple.tests TUPLE: forget-subclass-test a ;" "forget-subclass-test" parse-stream drop ] unit-test { } [ "IN: sequences TUPLE: reversed { seq read-only } ;" eval( -- ) ] unit-test TUPLE: bogus-hashcode-1 x ; TUPLE: bogus-hashcode-2 x ; M: bogus-hashcode-1 hashcode* 2drop 0 >bignum ; { } [ T{ bogus-hashcode-2 f T{ bogus-hashcode-1 } } hashcode drop ] unit-test DEFER: change-slot-test SLOT: kex { } [ "IN: classes.tuple.tests USING: kernel accessors ; TUPLE: change-slot-test ; SLOT: kex M: change-slot-test kex>> drop 3 ;" "change-slot-test" parse-stream drop ] unit-test { t } [ \ change-slot-test \ kex>> ?lookup-method >boolean ] unit-test { } [ "IN: classes.tuple.tests USING: kernel accessors ; TUPLE: change-slot-test kex ;" "change-slot-test" parse-stream drop ] unit-test { t } [ \ change-slot-test \ kex>> ?lookup-method >boolean ] unit-test { } [ "IN: classes.tuple.tests USING: kernel accessors ; TUPLE: change-slot-test ; SLOT: kex M: change-slot-test kex>> drop 3 ;" "change-slot-test" parse-stream drop ] unit-test { t } [ \ change-slot-test \ kex>> ?lookup-method >boolean ] unit-test { f } [ \ change-slot-test \ kex>> ?lookup-method "reading" word-prop ] unit-test DEFER: redefine-tuple-twice { } [ "IN: classes.tuple.tests TUPLE: redefine-tuple-twice ;" eval( -- ) ] unit-test { t } [ \ redefine-tuple-twice symbol? ] unit-test { } [ "IN: classes.tuple.tests DEFER: redefine-tuple-twice" eval( -- ) ] unit-test { t } [ \ redefine-tuple-twice deferred? ] unit-test { } [ "IN: classes.tuple.tests TUPLE: redefine-tuple-twice ;" eval( -- ) ] unit-test { t } [ \ redefine-tuple-twice symbol? ] unit-test ! Test reshaping with type declarations and slot attributes TUPLE: reshape-test x ; T{ reshape-test f "hi" } "tuple" set { } [ "IN: classes.tuple.tests TUPLE: reshape-test { x read-only } ;" eval( -- ) ] unit-test { f } [ \ reshape-test \ x<< ?lookup-method ] unit-test [ "tuple" get 5 >>x ] must-fail { "hi" } [ "tuple" get x>> ] unit-test { } [ "IN: classes.tuple.tests USE: math TUPLE: reshape-test { x integer read-only } ;" eval( -- ) ] unit-test { 0 } [ "tuple" get x>> ] unit-test { } [ "IN: classes.tuple.tests USE: math TUPLE: reshape-test { x fixnum initial: 4 read-only } ;" eval( -- ) ] unit-test { 0 } [ "tuple" get x>> ] unit-test TUPLE: boa-coercer-test { x array-capacity } ; { fixnum } [ 0 >bignum boa-coercer-test boa x>> class-of ] unit-test { T{ boa-coercer-test f 0 } } [ T{ boa-coercer-test } ] unit-test TUPLE: boa-iac { x integer-array-capacity initial: 77 } ; { fixnum bignum 77 } [ 30 boa-iac boa x>> class-of 10 >bignum boa-iac boa x>> class-of boa-iac new x>> ] unit-test [ -99 boa-iac boa ] [ bad-slot-value? ] must-fail-with ! Make sure that tuple reshaping updates code heap roots TUPLE: code-heap-ref ; : code-heap-ref' ( -- a ) T{ code-heap-ref } ; ! Push foo's literal to tenured space { } [ gc ] unit-test ! Reshape! { } [ "IN: classes.tuple.tests USE: math TUPLE: code-heap-ref { x integer initial: 5 } ;" eval( -- ) ] unit-test ! Code heap reference { t } [ code-heap-ref' code-heap-ref? ] unit-test { 5 } [ code-heap-ref' x>> ] unit-test ! Data heap reference { t } [ \ code-heap-ref' def>> first code-heap-ref? ] unit-test { 5 } [ \ code-heap-ref' def>> first x>> ] unit-test ! If the metaclass of a superclass changes into something other ! than a tuple class, the tuple needs to have its superclass reset TUPLE: metaclass-change ; TUPLE: metaclass-change-subclass < metaclass-change ; { metaclass-change } [ metaclass-change-subclass superclass-of ] unit-test { } [ "IN: classes.tuple.tests MIXIN: metaclass-change" eval( -- ) ] unit-test { t } [ metaclass-change-subclass tuple-class? ] unit-test { tuple } [ metaclass-change-subclass superclass-of ] unit-test ! Reshaping bug related to the above TUPLE: a-g ; TUPLE: g < a-g ; { } [ g new "g" set ] unit-test { } [ "IN: classes.tuple.tests MIXIN: a-g TUPLE: g ;" eval( -- ) ] unit-test { t } [ g new layout-of "g" get layout-of eq? ] unit-test ! Joe Groff discovered this bug DEFER: factor-crashes-anymore { } [ "IN: classes.tuple.tests TUPLE: unsafe-slot-access ; CONSTANT: unsafe-slot-access' T{ unsafe-slot-access }" eval( -- ) ] unit-test { } [ "IN: classes.tuple.tests USE: accessors TUPLE: unsafe-slot-access { x read-only initial: 31337 } ; : factor-crashes-anymore ( -- x ) unsafe-slot-access' x>> ;" eval( -- ) ] unit-test { 31337 } [ factor-crashes-anymore ] unit-test TUPLE: tuple-predicate-redefine-test ; { } [ "IN: classes.tuple.tests TUPLE: tuple-predicate-redefine-test ;" eval( -- ) ] unit-test { t } [ \ tuple-predicate-redefine-test? predicate? ] unit-test ! Final classes TUPLE: final-superclass ; TUPLE: final-subclass < final-superclass ; { final-superclass } [ final-subclass superclass-of ] unit-test ! Making the superclass final should change the superclass of the subclass { } [ "IN: classes.tuple.tests TUPLE: final-superclass ; final" eval( -- ) ] unit-test { tuple } [ final-subclass superclass-of ] unit-test { f } [ \ final-subclass final-class? ] unit-test ! Subclassing a final class should fail [ "IN: classes.tuple.tests TUPLE: final-subclass < final-superclass ;" eval( -- ) ] [ error>> bad-superclass? ] must-fail-with ! Making a final class non-final should work { } [ "IN: classes.tuple.tests TUPLE: final-superclass ;" eval( -- ) ] unit-test { } [ "IN: classes.tuple.tests TUPLE: final-subclass < final-superclass ; final" eval( -- ) ] unit-test ! Changing a superclass should not change the final status of a subclass { } [ "IN: classes.tuple.tests TUPLE: final-superclass x ;" eval( -- ) ] unit-test { t } [ \ final-subclass final-class? ] unit-test ! Test reset-class on tuples ! Should forget all accessors on rclasstest TUPLE: rclasstest a b ; { } [ [ \ rclasstest reset-class ] with-compilation-unit ] unit-test { f } [ \ rclasstest \ a>> ?lookup-method ] unit-test { f } [ \ rclasstest \ a<< ?lookup-method ] unit-test { f } [ \ rclasstest \ b>> ?lookup-method ] unit-test { f } [ \ rclasstest \ b<< ?lookup-method ] unit-test << \ rclasstest forget >> ! initial: should type check TUPLE: initial-class ; DEFER: initial-slot { } [ "IN: classes.tuple.tests TUPLE: initial-slot { x initial-class } ;" eval( -- ) ] unit-test { t } [ initial-slot new x>> initial-class? ] unit-test [ "IN: classes.tuple.tests TUPLE: initial-slot { x initial-class initial: f } ;" eval( -- ) ] [ error>> T{ bad-initial-value f "x" f initial-class } = ] must-fail-with [ "IN: classes.tuple.tests TUPLE: initial-slot { x initial-class initial: 3 } ;" eval( -- ) ] [ error>> T{ bad-initial-value f "x" 3 initial-class } = ] must-fail-with [ "IN: classes.tuple.tests USE: math TUPLE: foo < foo ;" eval( -- ) ] [ error>> bad-superclass? ] must-fail-with [ "IN: classes.tuple.tests USE: math TUPLE: foo < + ;" eval( -- ) ] [ error>> bad-superclass? ] must-fail-with ! Test no-slot error and get/set-slot-named TUPLE: no-slot-tuple0 a b c ; C: no-slot-tuple0 [ 1 2 3 "d" over get-slot-named ] [ { [ no-slot? ] [ tuple>> no-slot-tuple0? ] [ name>> "d" = ] } 1&& ] must-fail-with { 1 } [ 1 2 3 "a" swap get-slot-named ] unit-test { 2 } [ 1 2 3 "b" swap get-slot-named ] unit-test { 3 } [ 1 2 3 "c" swap get-slot-named ] unit-test { 4 } [ 1 2 3 4 "a" pick set-slot-named "a" swap get-slot-named ] unit-test [ 1 2 3 4 "d" pick set-slot-named ] [ { [ no-slot? ] [ tuple>> no-slot-tuple0? ] [ name>> "d" = ] } 1&& ] must-fail-with [ "IN: classes.tuple.tests TUPLE: too-many-slots-test a b c d ; T{ too-many-slots-test f 1 2 3 4 5 }" eval( -- x ) ] [ error>> too-many-slots? ] must-fail-with