if [llength [info commands p7proc]] { set Compiling true } else { set Compiling false source testing.tcl } if $Compiling { p7proc (void)okay {} { ::list } p7proc (void)bad {} { ::error "something was bad" } p7proc (void)bad { (tcl)what } { ::error "something was bad: $what" } p7proc (void)samei { (int)x (int)y } { if ( $x != $y ) { error "BAD samei: $x != $y" } } p7proc (void)test_if {} { set (int)a 10 if ( a < 20 ) { okay } if ( a < 5 ) { bad } if ( a < 30 ) { okay } else { bad } if ( a < 7 ) { bad } else { okay } if ( a < 5 ) { bad } elseif (a<8) {bad} else {okay} if ( a < 5 ) { bad } elseif (a>5) {okay} else {bad} if ( a < 30 ) { okay } elseif (a>5) {bad} else {bad} } p7proc (void)test_while_1 {} { set (int)n 100 set (int)z 0 while (n>0) { incr z $n incr n (0-1) } if ( z != 5050 ) { bad } } p7proc (void)test_while_2 {} { set (tcl)a [::string repeat "x " 100] set (int)z 0 while ([len $a]) { incr z set a [::lrange $a 1 end] } if ( z != 100 ) { bad } } p7proc (void)test_for_1 {} { set (int)z 0 for {set (int)i 0} (i<=100) {incr i} { incr z $i } if ( z != 5050 ) { bad } } p7proc (void)test_for_2 {} { set (int)z 0 for { set (tcl)a [::string repeat "x " 100] } ( [len (a)] ) { set a [::lrange $a 1 end] } { incr z 1 } if ( z != 100 ) { bad } } p7proc (void)test_loop {} { set (int)y 0 set (int)z 0 set (int)j # includes definition loop (int)i 101 { incr y $i } if ( $y != 5050 ) { bad } # j defined above loop j 101 { incr z $j } if ( z != (5050) ) { bad } # zero count, shouldn't change z loop j 0 { incr z 9999 } if ( z != (5050) ) { bad } # negative count, shouldn't change z loop j (0-99) { incr z 9999 } if ( z != (5050) ) { bad } } p7proc (void)test_break {} { set (int)z 0 for {set (int)i 0} (i<=9999) {incr i} { if (i==101) {break} incr z $i } if ( z != 5050 ) { ::puts $z; bad } set z 0 set i 0 while (i<=9999) { if (i==101) {break} incr z $i incr i } if ( z != 5050 ) { ::puts $z; bad } set z 0 loop i 9999 { if (i==101) {break} incr z $i } if ( z != 5050 ) { ::puts $z; bad } } p7proc (void)test_continue {} { set (int)z 0 for {set (int)i 0} (i<101) {incr i} { if (i==50) {continue} incr z $i } if ( z != 5000 ) { ::puts $z; bad } set z 0 set i 0 while (i<100) { incr i if (i==50) {continue} incr z $i } if ( z != 5000 ) { ::puts $z; bad } set z 0 loop i 101 { if (i==50) {continue} incr z $i } if ( z != 5000 ) { ::puts $z; bad } } p7proc (void)test_catch {} { set (int)e [catch { ::list a b c } (tcl)what] if (e) {bad} if ( $what ne "a b c" ) {bad} # test p7 error set e [catch { error [::list a b c] ; set e 99 } what] if (e!=1) {bad} if ( $what ne "a b c" ) {bad} # test tcl ::error set e [catch { ::error [::list a b c] } what] if (e!=1) {bad} if ( $what ne "a b c" ) {bad} set e [catch { ::list a b c } ] if (e) {bad} set e [catch { ::error [::list a b c] } ] if (e!=1) {bad} set e [catch { ::list [::return something ] } what] if (e!=2) { ::puts $e; bad} if ( $what ne "something" ) {bad} set e [catch { ::list [::break ] } ] if (e!=3) {bad} set e [catch { ::list [::continue ] } ] if (e!=4) {bad} ######## hmmm why does "catch" return "2" instead of "42" ? #set e [catch { ::list [::return -code 42 foo ] } ] #::puts e=$e #::puts EI=[::set ::errorInfo] #if (e!=42) {bad} } p7proc (void)test_incr {} { set (int)a 1 incr a if (a!=2) {bad} incr a 20 if (a!=22) {bad} incr a (0-10) if (a!=12) {bad} incr a $a if (a!=24) {bad} incr a (0-$a) if (a) {bad} incr (int)b 5 if (b!=5) {bad} } p7proc (void)test_set {} { # creates variables set (int)a 33 set (int)b ;# will be zero set (tcl)c "x y z" set (tcl)d ;# will be empty set (byt*)e "lmnop" set (utf*)f "lmnop" set (uni*)g "lmnop" set (byt*)h ;# will be empty set (utf*)i ;# will be empty set (uni*)j ;# will be empty set (int*)k [::list 10 20 30 40 50] set (int*)l ;# will be empty if (a!=33) {bad} if (b!=0) {bad} if (c ne [::list x y z] ) {bad} if (d) {bad} if (e ne "lmnop") {bad} if (f ne "lmnop") {bad} if (g ne "lmnop") {bad} if ([len $h]) {bad} if ([len $i]) {bad} if ([len $j]) {bad} if ([len $k] != 5) {bad} if ([len $l] != 0) {bad} # assigns variables set a 33 set b 0 set c "x y z" set d null ;# will be empty set e "lmnop" set f "lmnop" set g "lmnop" set h null set i null set j null set k [::list 10 20 30 40 50] set l null if (a!=33) {bad} if (b!=0) {bad} if (c ne [::list x y z] ) {bad} if (d) {bad} if (e ne "lmnop") {bad} if (f ne "lmnop") {bad} if (g ne "lmnop") {bad} if ([len $h]) {bad} if ([len $i]) {bad} if ([len $j]) {bad} if ([len $k] != 5) {bad} if ([len $l] != 0) {bad} # quoted, "null" is not a keyword for empty set d "null" if ( [len $d] != 1 ) {bad} append d foo if ( "nullfoo" ne d) {bad} # returns values of variables if ([set a]!=33) {bad} if ([set b]!=0) {bad} if ([set c] ne [::list x y z] ) {bad} if ([set d] ne "nullfoo" ) {bad} if ([set e] ne "lmnop") {bad} if ([set f] ne "lmnop") {bad} if ([set g] ne "lmnop") {bad} if ([len [set h]]) {bad} if ([len [set i]]) {bad} if ([len [set j]]) {bad} if ([len [set k]] != 5) {bad} if ([len [set l]] != 0) {bad} # without a variable name, it is a cast if ( [set (tcl) $a] ne "33" ) {bad} set c $a if ( [len [set (int*) $c]] != 1 ) {bad} if ( [len [set (byt*) $c]] != 2 ) {bad} if ( [set (int) [set (tcl) [set (byt*) $c]]] != [set (int) "33"] ) {bad} } p7proc (void)test_new_vector {} { # new with var name creates var new (int*)a 55 new (byt*)b 56 new (utf*)c 57 new (uni*)d 58 if ( [len $a] != 55 ) {bad} if ( [len $b] != 56 ) {bad} if ( [len $c] != 57 ) {bad} if ( [len $d] != 58 ) {bad} # new without var name is just a value set a [new (int*) 35] set b [new (byt*) 36] set c [new (utf*) 37] set d [new (uni*) 38] if ( [len $a] != 35 ) {bad} if ( [len $b] != 36 ) {bad} if ( [len $c] != 37 ) {bad} if ( [len $d] != 38 ) {bad} # length 0 is empty is null set a [new (int*) 0] set b [new (byt*) 0] set c [new (utf*) 0] set d [new (uni*) 0] if ( [len $a] != 0 ) {bad} if ( [len $b] != 0 ) {bad} if ( [len $c] != 0 ) {bad} if ( [len $d] != 0 ) {bad} if ( $a ne "" ) {bad} if ( $b ne "" ) {bad} if ( $c ne "" ) {bad} if ( $d ne "" ) {bad} if ( $a != null ) {bad} if ( $b != null ) {bad} if ( $c != null ) {bad} if ( $d != null ) {bad} # len on (tcl) is llength set (tcl)e "a b c d e" if ( [len $e] != 5 ) {bad} set (int*)aa [new (int*) 55] set (byt*)bb [new (byt*) 56] set (utf*)cc [new (utf*) 57] set (uni*)dd [new (uni*) 58] if ( [len $aa] != 55 ) {bad} if ( [len $bb] != 56 ) {bad} if ( [len $cc] != 57 ) {bad} if ( [len $dd] != 58 ) {bad} } p7global (int)HowManyBits { set (int)x 1 loop (int)i 999 { set x (x<<1) if (!x) { return (i+1) } } error "more than 999 bits?" } p7proc (void)test_arithmetic {} { set (int)a 10 set (int)b 20 set (int)c 30 samei 8 8 samei 0 0 samei (0-8) (0-8) samei 10 $a samei 20 (b) samei 20 ( c + -a ) set (int)d (b-c) samei $d (-a) samei -10 (-a) samei -11 (~a) samei 0 (!a) samei 1 (!!a) samei -60 (-a-b-c) samei 0 (-a-b--c) samei 1 (!(-a-b--c)) samei 21 ($b+1) samei 22 (b+2) samei 23 (3+$b) samei 24 (4+b) samei 30 (a+b) samei 30 ($a+$b) samei 19 ($b-1) samei 18 (b-2) samei 10 (30-$b) samei 20 (40-b) samei (0-10) ($b-30) samei (0-20) (b-40) samei 10 (b-a) samei 10 ($b-$a) samei 20 ($b*1) samei 40 (b*2) samei 60 (3*$b) samei 80 (4*b) samei 200 (a*b) samei 200 ($a*$b) samei 0 (a/b) samei 2 (b/a) samei 20 (b%c) samei 10 (c%b) samei 800 ( 10 * 20 + 20 * 30 ) samei 800 ( $a * 20 + 20 * 30 ) samei 800 ( a * 20 + 20 * 30 ) samei 800 ( a * b + 20 * 30 ) samei 800 ( a * b + $b * 30 ) samei 800 ( a * b + b * 30 ) samei 800 ( a * b + b * 30 ) samei 800 ( a * b + b * $c ) samei 800 ( a * b + b * c ) samei 12000 ( 10 * (20 + 20) * 30 ) samei 12000 ( a * ( b + b) * $c ) samei 12000 ((( ((a)) * (( (b) + ((b)) )) * ($c) ))) samei 1 ( 0 || "true" ) samei 8 8 samei 7 ( 1 | 2 | 4 ) samei 0 ( 1 & 2 & 4 ) samei 1 ( 1 || 2 || 4 ) samei 0 ( !1 || !2 || !4 ) samei 1 ( 1 || !2 || !4 ) samei 1 ( 1 && 2 && 4 ) samei 0 ( !1 && !2 && !4 ) samei 0 ( 1 && !2 && !4 ) samei 1 ( 1 | 2 & 4 ) samei 4 ( 1 & 2 | 4 ) samei 1 ( 1 || 2 && 4 ) samei 1 ( 1 && 2 || 4 ) samei 1 ( a < b ) samei 0 ( b < b ) samei 0 ( c < b ) samei 1 ( a <= b ) samei 1 ( b <= b ) samei 0 ( c <= b ) samei 0 ( a >= b ) samei 1 ( b >= b ) samei 1 ( c >= b ) samei 0 ( a > b ) samei 0 ( b > b ) samei 1 ( c > b ) samei 0 ( a == b ) samei 1 ( b == b ) samei 0 ( c == b ) samei 1 ( a != b ) samei 0 ( b != b ) samei 1 ( c != b ) samei 32 ( 2 << 4 ) samei 2 ( 32 >> 4 ) samei (0-1) ( (0-1) >> 4 ) samei (0-1) ( (0-1) >> 4 ) # we need a way to know if 32-bit, 64-bit, or what: ::puts " -- seems to be $HowManyBits bit (int)s -- " if ( $HowManyBits == 32 ) { samei 0x0FFFFFFF ( (0-1) >>> 4 ) } elseif ( $HowManyBits == 64 ) { samei "0x0FFFFFFFFFFFFFFF" ( (0-1) >>> 4 ) } else { error "weird -- is this a CYBER?" } } p7proc (void)test_ternary {} { set (int)z 0 set (int)a 1 set (int)b 2 samei 5 ( $a ? 5 : 7 ) samei 7 ( $z ? 5 : 7 ) samei 7 ( ! $a ? 5 : 7 ) samei 5 ( ! $z ? 5 : 7 ) samei 3 ( a || z ? a+b : a-b ) samei 1 ( a && z ? a+b : b-a ) samei 6 ( z ? 5 : a ? 6 : 7 ) samei 7 ( z ? 5 : z ? 6 : 7 ) } p7proc (void)test_pexpr {} { set (int)p 10 set (int)p2 $p set (int)p3 (p) set (int)p4 ($p) set (int)p5 (p+0) set (int)p6 [ k (p) ] set (int)p7 [ k ($p) ] set (int)p8 [ k (p+0) ] samei $p $p2 samei $p $p3 samei $p $p4 samei $p $p5 samei (p) $p6 samei (p) $p7 samei ($p) $p8 new (int*)a 6 set a(1) 101 set a(2) 102 set a(3) 103 set a(3+1) 104 set a(3+1) 105 set a(3-3) 100 set (int)one 1 set (int)two (one+one) samei 101 $a(1) samei 101 $a(one) samei 101 $a(two-one) samei 101 $a($two-$one) samei 102 ( $a(two) ) samei 102 ( a[two] ) samei 102 ( $a(3-one) ) samei 102 ( a[3-one] ) samei 0 [catch {set a(5) 5}] ;# not overflow samei 1 [catch {set a(6) 6}] ;# overflow samei 0 [catch {set (int) $a(5)}] ;# not overflow samei 1 [catch {set (int) $a(6)}] ;# overflow set (int)neg1 (0-1) samei 0 [catch {set a(0) 8}] ;# not overflow samei 1 [catch {set a(neg1) 8}] ;# overflow samei 0 [catch {set (int) $a(0)}] ;# not overflow samei 1 [catch {set (int) $a(neg1)}] ;# overflow # indexing a (tcl) list set (tcl)list "one two three" if ( list(1) ne "two" ) { bad two } # HOW DOES THIS WORK??? Is it reliable? Is it safe? set list(1) "dos" if ( list(1) ne "dos" ) { bad two } } p7proc (void)test_bytes {} { # (byt) is unsigned set (byt)byt 50 samei 50 $byt set byt 200 samei 200 $byt set byt -56 samei 200 $byt # but (utf) is signed set (utf)utf 50 samei 50 $utf set utf 200 samei (-56) $utf set utf -56 samei (-56) $utf # notice when not in parentheses, byt and utf are not typenames } p7class Object { (tcl)label } p7global (int)Count p7global (tcl)Explain p7global (Object)Favorite p7global (tcl*)Range { loop (int)i 100 { lappend (tcl)z (i+1) } ; k $z } # globals are initialized in order of appearance -- so RangeSum, below, can depend on Range, above. p7global (int)RangeSum { loop (int)i [len $Range] { incr (int)z $Range($i) } ; return $z } p7proc (void)incr_Count {} { incr Count set Explain "$Explain$Explain" set Explain "$Count" } p7proc (void)test_globals {} { set Favorite [new (Object)] set Favorite(label) "red" set Explain "hmm" set Count 0 incr_Count incr_Count incr_Count samei 3 $Count #bug# if ( "hmmhmmhmmhmmhmmhmmhmmhmm" ne Explain ) { bad } if ( "3" ne Explain ) { bad } if ( "red" ne Favorite.label ) { bad } ::puts $Range ::puts $RangeSum if ( [len $Range] != 100 ) { bad } if ( $RangeSum != 5050 ) { bad } } p7proc (void)test_k {} { if ( null ne [ k null ] ) { bad "k with null #1" } if ( null != [ k null ] ) { bad "k with null #2" } if ( 888 != [ k 888 777 666 ] ) { bad "k with 888 #1" } if ( 888 != [ k 888 "" null ] ) { bad "k with 888 #2" } # all arguments ARE evaluted, in order left to right, as in Tcl set (int)n 0 if ( 1 != [ k [incr n] [incr n] [incr n] ] ) { bad "k with three incrs" } if ( 3 != n ) { bad "after k with three incrs" } } p7proc (void)test_null_k {} { # k with no arguments returns null. this is a good time to test more null ... if ( 0 != [ k ] ) { bad "k with naught #1" } if ( "" ne [ k ] ) { bad "k with naught #2" } if ( [new (byt*) 0] != [ k ] ) { bad "k with byt* #1" } if ( [new (utf*) 0] != [ k ] ) { bad "k with utf* #1" } if ( [new (uni*) 0] != [ k ] ) { bad "k with uni* #1" } if ( [set (Object) null] != [ k ] ) { bad "k with Object* #1a" } if ( [set (Object)obj1 ] != [ k ] ) { bad "k with Object* #1b" } if ( [set (Object) ] != [ k ] ) { bad "k with Object* #1c" } if ( obj1 != [ k ] ) { bad "k with Object* #1d" } if ( [new (byt*) 0] ne [ k ] ) { bad "k with byt* #2" } if ( [new (utf*) 0] ne [ k ] ) { bad "k with utf* #2" } if ( [new (uni*) 0] ne [ k ] ) { bad "k with uni* #2" } if ( [set (Object) null] ne [ k ] ) { bad "k with Object* #2a" } if ( [set (Object)obj2 ] ne [ k ] ) { bad "k with Object* #2b" } if ( [set (Object) ] ne [ k ] ) { bad "k with Object* #2c" } if ( obj1 ne [ k ] ) { bad "k with Object* #2d" } } p7proc (void)test_double {} { if { 3 eq 3.1415 } { bad 3/pi } if { 3.1415 != 0 + 3.1415 } { bad 0+pi } if { [p7peek 3.1415 ] ne "double" } { bad peek-double } if { [p7peek 3] ne "int" } { bad peek-int } # This seems to be (double), although I thought it should be (tcl). # This is a borderline case; is it important? if { [p7peek 3. ] ne "double" } { bad peek-3. } } p7proc (void)test_funny_0 {} { # TODO: This first form still fails in some contexts? How to reproduce? if ( "" eq 0 ) { bad test_funny_0 } if ( "" eq [k 0] ) { bad test_funny_k_0 } if ( "" eq "0" ) { bad test_funny_quoted_0 } set (int)x 0 if ( "" eq x ) { bad test_funny_x } # The following do not compile. How like (int)0 should null be? # if ( 42 + null != 42 ) { bad 42+null } # if ( 42 + [ k ] != 42 ) { bad 42 } } p7proc (void)test_ternary_with_null {} { new (Object)a new (Object)b set (Object)x ( a ? a : null ) set (Object)y ( b ? null : b ) set (tcl)r ( a ? "good" : null ) set (tcl)s ( 0 ? "good" : null ) if ( $s ne "" ) { bad s-not-empty } } p7proc (tcl)add_an_i {(tcl)s} { return "${s}i" ; # was once a bug } p7proc (void)test_long_strings {} { set (tcl)a "one two three four" set (tcl)b {one two three four} if ( $a ne $b ) { bad } samei 18 [::string length $a] samei 18 [::string length $b] # len on (tcl) is llength samei 4 [len $a] samei 4 [len $b] set (uni*)c "\007\t\n\0\x7f\r" if ( c[0] != 7 ) { bad c0 } if ( c[1] != 9 ) { bad c1 } if ( c[2] != 10 ) { bad c2 } if ( c[3] != 0 ) { bad c3 } if ( c[4] != 127 ) { bad c4 } if ( c[5] != 13 ) { bad c5 } if ( '\007' != 7 ) { bad cc0 } if ( '\t' != 9 ) { bad cc1 } if ( '\n' != 10 ) { bad cc2 } if ( '\0' != 0 ) { bad cc3 } if ( '\x7f' != 127 ) { bad cc4 } if ( '\r' != 13 ) { bad cc5 } if ( "veri" ne [add_an_i ver] ) { bad ver } } p7proc (void)test_dots {} { new (Object)a set a.label "hello" set (tcl)b "foo bar" set (tcl)c $b.label if ( c ne "foo bar.label" ) { bad c!=foobar.lasel } set (tcl)d $a.label if ( d ne "hello" ) { bad d!=hello } set (tcl)e $b(1).label if ( e ne "bar.label" ) { bad e!=bar.label } set (tcl)f $a(label) if ( f ne "hello" ) { bad f!=hello } set b(1) "oh no" ;### TODO -- THIS SHOULD NOT BE LEGAL, BUT IT IS } } else { foreach t [lsort [info comm test_*]] { ::puts stdout " $t ... " nonewline ::flush stdout $t } ::puts "All Okay" }