! Praxix - a Z-Machine unit test ! by Zarf and Dannii ! Public domain, but please share your changes so we can improve the tests ! The indirect test is Copyright (C) 2003, Amir Karger ! TODO: ! @encode_text ! @erase_line ! @get_cursor ! @set_font ! @call 0 ! @random - check it's a good distribution ! @print_table - check line breaks are only printed between lines ! Consider making this test suite non-interactive, and have another test suite for interactive tests ! Move too any tests which are manually confirmed by eye, so that all of Praxix can be summed up by "All tests passed" ! Maybe add tests for @loadw/@storew etc to check they are casting array+word correctly ! 1.1 spec unicode texts Constant Story "Praxix"; Constant Headline "A Z-code interpreter unit test^"; Release 1; ! To compile this canonically, do "inform praxix.inf". No other ! options. Constant HDR_GAMERELEASE $02; ! word Constant HDR_GAMEFLAGS $10; ! word Constant HDR_GAMESERIAL $12; ! six ASCII characters Constant HDR_SPECREVISION $32; ! word Array buffer -> 123; ! Buffer for parsing main line of input Array parse buffer 63; ! Parse table mirroring it Global failures = 0; Global total_failures = 0; [ Main ix; ! deal with some compiler warnings ix = PrintShortName; new_line; Banner(); new_line; LookSub(); TestLoop(); print "^Goodbye.^"; ]; [ Keyboard; while (true) { print ">"; buffer->0 = 120; parse->0 = 15; read buffer parse; if (parse->1) break; } ]; [ Banner i; if (Story ~= 0) { #IfV5; style bold; #Endif; print (string) Story; #IfV5; style roman; #Endif; } if (Headline ~= 0) print ": ", (string) Headline; print "Release ", (HDR_GAMERELEASE-->0) & $03ff, " / Serial number "; for (i=0 : i<6 : i++) print (char) HDR_GAMESERIAL->i; print " / Inform v"; inversion; print ", compiler options "; #Ifdef STRICT_MODE; print "S"; #Endif; ! STRICT_MODE #Ifdef INFIX; print "X"; #Ifnot; #Ifdef DEBUG; print "D"; #Endif; ! DEBUG #Endif; ! INFIX new_line; ]; [ Version; ! Print the version number print HDR_SPECREVISION->0, ".", HDR_SPECREVISION->1; ]; [ TestLoop wd paddr plen ix obj found; while (true) { new_line; if (failures) { print failures, " uncounted test failures!^^"; failures = 0; } Keyboard(); wd = parse-->1; if (wd == 'quit' or 'q//') return; found = nothing; objectloop (obj ofclass TestClass) { paddr = obj.&name; plen = obj.#name / WORDSIZE; for (ix=0 : ixix == wd) { found = obj; break; } } if (found) break; } if (~~found) { print "I don't understand that command.^"; continue; } found.testfunc(); } ]; Attribute meta; Class TestClass with short_name 0, testfunc TestNothing, fail_count; [ PrintShortName obj addr; if (obj provides short_name && obj.short_name) { print (string) obj.short_name; rtrue; } if (obj ofclass TestClass) { addr = obj.&name; print (address) (addr-->0); rtrue; } print (object) obj; ]; ! Print out in base 16 a byte or word [ Hex val byte nibble i; print "$"; for (i=0 : i<2 : i++) { @log_shift val (-8) -> byte; @log_shift val (8) -> val; if (byte == 0 && i == 0) continue; nibble = byte & $0F; @log_shift byte (-4) -> byte; if (byte <= 9) print (char) (byte+'0'); else print (char) (byte-10+'A'); if (nibble <= 9) print (char) (nibble+'0'); else print (char) (nibble-10+'A'); } ]; [ check val wanted; if (val == wanted) { print val; rtrue; } failures++; print val, " (should be ", wanted, " FAIL)"; rfalse; ]; [ check_unspecified val wanted; if (val == wanted) { print val, " (Unspecified)"; rtrue; } print val, " (Unspecified but ", wanted, " is suggested)"; rfalse; ]; [ check_arr_3 arr v0 v1 v2; if (arr->0 == v0 && arr->1 == v1 && arr->2 == v2) { print v0, " ", v1, " ", v2; rtrue; } failures++; print arr->0, " ", arr->1, " ", arr->2; print " (should be ", v0, " ", v1, " ", v2, " FAIL)"; rfalse; ]; [ check_hex val wanted; if (val == wanted) { print (Hex) val; rtrue; } failures++; print (Hex) val, " (should be ", (Hex) wanted, " FAIL)"; rfalse; ]; [ check_hex_unspecified val wanted; if (val == wanted) { print (Hex) val, " (Unspecified)"; rtrue; } print (Hex) val, " (Unspecified but ", wanted, " is suggested)"; rfalse; ]; [ check_hex_min val min; if (val >= min) { print (Hex) val; rtrue; } failures++; print (Hex) val, " (should be >= ", (Hex) min, " FAIL)"; rfalse; ]; [ check_array test gold len func ix testch goldch; for (ix=0 : ixix; testch = test->ix; if (testch ~= goldch) { func(goldch, ix); check(testch, goldch); new_line; } } ]; [ count_failures val; print "^"; if (failures) { val = failures; total_failures = total_failures + failures; failures = 0; print_ret val, " tests failed."; } else { "Passed."; } ]; TestClass LookAction with name 'look' 'l//' 'help' '?//', testfunc LookSub, has meta; TestClass AllAction with name 'all', testfunc [ obj startfail res ix; print "All tests:^"; startfail = total_failures; objectloop (obj ofclass TestClass) { if (obj has meta) continue; res = total_failures; print "^"; obj.testfunc(); obj.fail_count = total_failures - res; } res = total_failures - startfail; if (res == 0) { "^All tests passed."; } else { print "^", res, " tests failed overall: "; ix = 0; objectloop (obj ofclass TestClass) { if (obj.fail_count) { if (ix) print ", "; print (name) obj, " (", obj.fail_count, ")"; ix++; } } "."; } ], has meta; [ TestNothing; "Nothing happens."; ]; [ LookSub obj ix; print "A voice booooms out: Welcome to the test chamber.^^"; print "Type ~help~ to repeat this message, ~quit~ to exit, ~all~ to run all tests, or one of the following test options: "; ix = 0; objectloop (obj ofclass TestClass) { if (obj has meta) continue; if (ix) print ", "; print "~", (name) obj, "~"; ix++; } print "."; print "^(Some tests check unspecified behaviour, and their results will be marked by (Unspecified).)^"; new_line; if (total_failures) { print "^", total_failures, " tests have failed so far in this run.^"; } ]; Global testglobal; Global testglobal2; TestClass OperandTest with name 'operand', testfunc [ ix val; print "Basic operand values:^^"; testglobal = 1; ix = 1; val = (ix == testglobal); print "(1==1)="; check(val, 1); print ", "; val = (1 == testglobal); print "(1==1)="; check(val, 1); print ", "; val = (1 == ix); print "(1==1)="; check(val, 1); print ", "; @push 1; val = 1; @je 1 sp ?jump1; val = 0; .jump1; print "(1==1)="; check(val, 1); print "^"; testglobal = -2; ix = -2; val = (ix == testglobal); print "(-2==-2)="; check(val, 1); print ", "; val = (-2 == testglobal); print "(-2==-2)="; check(val, 1); print ", "; val = (-2 == ix); print "(-2==-2)="; check(val, 1); print ", "; @push (-2); val = 1; @je (-2) sp ?jump2; val = 0; .jump2; print "(-2==-2)="; check(val, 1); print "^"; count_failures(); ]; TestClass ArithTest with name 'arith', testfunc [ val; print "Integer arithmetic:^^"; @add 2 2 val; print "2+2="; check(val, 4); print ", "; @add (-2) (-3) val; print "-2+-3="; check(val, -5); print ", "; @add 3 (-4) val; print "3+-4="; check(val, -1); print ", "; @add (-4) 5 val; print "-4+5="; check(val, 1); print ", "; @add $7FFF $7FFE val; print "$7FFF+$7FFE="; check(val, -3); print ", "; @add $8000 $8000 val; print "$8000+$8000="; check(val, 0); print "^"; testglobal = 6; testglobal2 = 8; @add testglobal testglobal2 val; print "Globals 6+8="; check(val, 14); print ", "; testglobal = $7FFE; testglobal2 = $7FFD; @add testglobal testglobal2 val; print "$7FFE+$7FFD="; check(val, -5); print "^"; @sub 2 2 val; print "2-2="; check(val, 0); print ", "; @sub (-2) 3 val; print "-2-3="; check(val, -5); print ", "; @sub 3 4 val; print "3-4="; check(val, -1); print ", "; @sub (-4) (-5) val; print "-4-(-5)="; check(val, 1); print ", "; @sub $7FFF $7FFE val; print "$7FFF-$7FFE="; check(val, 1); print ", "; @sub $8000 $8001 val; print "$8000-$8001="; check(val, -1); print ", "; @sub $7FFF $8001 val; print "$7FFF-$8001="; check(val, -2); print "^"; testglobal = 6; testglobal2 = 8; @sub testglobal testglobal2 val; print "Globals 6-8="; check(val, -2); print ", "; testglobal = $7FFD; testglobal2 = $7FFE; @sub testglobal testglobal2 val; print "$7FFD-$7FFE="; check(val, -1); print "^"; @mul 2 2 val; print "2*2="; check(val, 4); print ", "; @mul (-2) (-3) val; print "-2*-3="; check(val, 6); print ", "; @mul 3 (-4) val; print "3*-4="; check(val, -12); print ", "; @mul (-4) 5 val; print "-4*5="; check(val, -20); print ", "; @mul $100 $100 val; print "$100*$100 (trunc)="; check(val, 0); print ", "; @mul 311 373 val; print "311*373 (trunc)="; check_hex(val, -15069); print "^"; testglobal = -6; testglobal2 = -8; @mul testglobal testglobal2 val; print "Globals -6*-8="; check(val, 48); print ", "; testglobal = -311; testglobal2 = 373; @mul testglobal testglobal2 val; print "Globals -311*373="; check(val, 15069); print "^"; @div 12 3 val; print "12/3="; check(val, 4); print ", "; @div 11 2 val; print "11/2="; check(val, 5); print ", "; @div (-11) 2 val; print "-11/2="; check(val, -5); print ", "; @div 11 (-2) val; print "11/-2="; check(val, -5); print ", "; @div (-11) (-2) val; print "-11/-2="; check(val, 5); print ", "; @div $7fff 2 val; print "$7fff/2="; check_hex(val, $3fff); print ", "; @div $7fff (-2) val; print "$7fff/-2="; check_hex(val, -$3fff); print ", "; @div (-$7fff) 2 val; print "-$7fff/2="; check_hex(val, -$3fff); print ", "; @div (-$7fff) (-2) val; print "-$7fff/-2="; check_hex(val, $3fff); print ", "; @div $8000 2 val; print "$8000/2="; check_hex(val, $C000); print ", "; @div $8000 (-2) val; print "$8000/(-2)="; check_hex(val, $4000); print ", "; @div $8000 1 val; print "$8000/1="; check_hex(val, $8000); print "^"; testglobal = -48; testglobal2 = -8; @div testglobal testglobal2 val; print "Globals -48/-8="; check(val, 6); print ", "; testglobal = 48; testglobal2 = 7; @div testglobal testglobal2 val; print "48/7="; check(val, 6); print ", "; testglobal = 48; testglobal2 = -7; @div testglobal testglobal2 val; print "48/-7="; check(val, -6); print ", "; testglobal = -48; testglobal2 = 7; @div testglobal testglobal2 val; print "-48/7="; check(val, -6); print ", "; testglobal = -48; testglobal2 = -7; @div testglobal testglobal2 val; print "-48/-7="; check(val, 6); print "^"; @mod 12 3 val; print "12%3="; check(val, 0); print ", "; @mod 13 5 val; print "13%5="; check(val, 3); print ", "; @mod (-13) 5 val; print "-13%5="; check(val, -3); print ", "; @mod 13 (-5) val; print "13%-5="; check(val, 3); print ", "; @mod (-13) (-5) val; print "-13%-5="; check(val, -3); print ", "; @mod $7fff 11 val; print "$7fff%11="; check(val, 9); print ", "; @mod (-$7fff) 11 val; print "-$7fff%11="; check(val, -9); print ", "; @mod $7fff (-11) val; print "$7fff%-11="; check(val, 9); print ", "; @mod (-$7fff) (-11) val; print "-$7fff%-11="; check(val, -9); print ", "; @mod $8000 7 val; print "$8000%7="; check(val, -1); print ", "; @mod $8000 (-7) val; print "$8000%-7="; check(val, -1); print ", "; @mod $8000 2 val; print "$8000%2="; check(val, 0); print ", "; @mod $8000 (-2) val; print "$8000%-2="; check(val, 0); print ", "; @mod $8000 1 val; print "$8000%1="; check(val, 0); print "^"; testglobal = 49; testglobal2 = 8; @mod testglobal testglobal2 val; print "Globals 49%8="; check(val, 1); print ", "; testglobal = 49; testglobal2 = -8; @mod testglobal testglobal2 val; print "49%-8="; check(val, 1); print ", "; testglobal = -49; testglobal2 = 8; @mod testglobal testglobal2 val; print "-49%8="; check(val, -1); print ", "; testglobal = -49; testglobal2 = -8; @mod testglobal testglobal2 val; print "-49%-8="; check(val, -1); print "^"; count_failures(); ]; TestClass CompoundArithTest with name 'comarith' 'comparith', testfunc [ val xloc yloc zloc; print "Compound arithmetic expressions:^^"; testglobal = 7; yloc = 2; zloc = -4; val = (testglobal + yloc) * zloc; print "(7+2)*-4="; check(val, -36); print "^"; xloc = $7FFF; yloc = 2; zloc = 16; val = (xloc + yloc) / zloc; print "($7FFF+2)/16="; check(val, -$7FF); print "^"; xloc = -$7FFF; yloc = -2; zloc = 16; val = (xloc + yloc) / zloc; print "(-$7FFF+-2)/16="; check(val, $7FF); print "^"; xloc = -26103; yloc = -32647; val = (xloc + yloc) / 9; print "(-26103+-32647)/9="; check(val, 754); print "^"; xloc = -$7FFF; yloc = 2; zloc = 16; val = (xloc - yloc) / zloc; print "(-$7FFF-2)/16="; check(val, $7FF); print "^"; xloc = $7FFF; yloc = -2; zloc = 16; val = (xloc - yloc) / zloc; print "($7FFF--2)/16="; check(val, -$7FF); print "^"; xloc = -26103; yloc = 32647; val = (xloc - yloc) / 9; print "(-26103-32647)/9="; check(val, 754); print "^"; xloc = $100; yloc = $100; zloc = 16; val = (xloc * yloc) / zloc + 1; print "($100*$100)/16+1="; check(val, 1); print "^"; xloc = 311; yloc = 373; zloc = 16; val = (xloc * yloc) / zloc; print "(311*373)/16="; check(val, -941); print "^"; xloc = 311; zloc = 16; val = (xloc * -373) / zloc; print "(311*-373)/16="; check(val, 941); print "^"; yloc = 373; val = (111 * yloc) / 16; print "(111*373)/16="; check(val, -1508); print "^"; yloc = -373; val = (111 * yloc) / 16; print "(111*-373)/16="; check(val, 1508); print "^"; count_failures(); ]; TestClass BitwiseTest with name 'bitwise' 'bits' 'bit', testfunc [ val; print "Bitwise arithmetic:^^"; @and 0 0 val; print "0&0="; check_hex(val, 0); print ", "; @and $FFFF 0 val; print "$FFFF&0="; check_hex(val, 0); print ", "; @and $FFFF $FFFF val; print "$FFFF&$FFFF="; check_hex(val, $FFFF); print ", "; @and $013F $F310 val; print "$013F&$F310="; check_hex(val, $0110); print ", "; @and $F731 $137F val; print "$F731&$137F="; check_hex(val, $1331); print ", "; @and $35 $56 val; print "$35&56="; check_hex(val, $14); print "^"; @or 0 0 val; print "0|0="; check_hex(val, 0); print ", "; @or $FFFF 0 val; print "$FFFF|0="; check_hex(val, $FFFF); print ", "; @or $FFFF $FFFF val; print "$FFFF|$FFFF="; check_hex(val, $FFFF); print ", "; @or $3700 $0012 val; print "$3700|$0012="; check_hex(val, $3712); print ", "; @or $35 $56 val; print "$35|56="; check_hex(val, $77); print "^"; @not 0 val; print "!0="; check_hex(val, $FFFF); print ", "; @not 1 val; print "!1="; check_hex(val, $FFFE); print ", "; @not $F val; print "!$F="; check_hex(val, $FFF0); print ", "; @not $7FFF val; print "!$7FFF="; check_hex(val, $8000); print ", "; @not $8000 val; print "!$8000="; check_hex(val, $7FFF); print ", "; @not $FFFD val; print "!$FFFD="; check_hex(val, $2); print "^"; count_failures(); ]; TestClass ShiftTest with name 'shift', testfunc [ val res ix; print "Bit shifts:^^"; @log_shift $11 0 val; print "$11u<<0="; check_hex(val, $11); print ", "; @log_shift $11 1 val; print "$11u<<1="; check_hex(val, $22); print ", "; @log_shift $11 4 val; print "$11u<<4="; check_hex(val, $110); print ", "; @log_shift $11 10 val; print "$11u<<10="; check_hex(val, $4400); print ", "; @log_shift $11 15 val; print "$11u<<15="; check_hex(val, $8000); print ", "; @log_shift $11 16 val; print "$11u<<16="; check_hex_unspecified(val, 0); print ", "; @log_shift (-2) 0 val; print "-2u<<0="; check(val, -2); print ", "; @log_shift (-2) 1 val; print "-2u<<1="; check(val, -4); print ", "; @log_shift (-2) 7 val; print "-2u<<7="; check(val, -256); print ", "; @log_shift (-2) 15 val; print "-2u<<15="; check(val, 0); print "^"; testglobal = 1; res = 1; for (ix=0 : ix<16 : ix++) { @log_shift testglobal ix val; print "1u<<", ix, "="; check_hex(val, res); print ", "; res = res+res; } @log_shift testglobal ix val; print "1u<<", ix, "="; check_hex_unspecified(val, 0); print "^"; @log_shift $4001 (0) val; print "$4001u>>-0="; check_hex(val, $4001); print ", "; @log_shift $4001 (-1) val; print "$4001u>>-1="; check_hex(val, $2000); print ", "; @log_shift $4001 (-6) val; print "$4001u>>-6="; check_hex(val, $100); print ", "; @log_shift $4001 (-11) val; print "$4001u>>-11="; check_hex(val, $8); print ", "; @log_shift $4001 (-15) val; print "$4001u>>-15="; check_hex(val, $0); print ", "; @log_shift $4001 (-16) val; print "$4001u>>-16="; check_hex_unspecified(val, $0); print "^"; @log_shift $7FFF (0) val; print "$7FFFu>>-0="; check_hex(val, $7FFF); print ", "; @log_shift $7FFF (-1) val; print "$7FFFu>>-1="; check_hex(val, $3FFF); print ", "; @log_shift $7FFF (-2) val; print "$7FFFu>>-2="; check_hex(val, $1FFF); print ", "; @log_shift $7FFF (-6) val; print "$7FFFu>>-6="; check_hex(val, $1FF); print ", "; @log_shift $7FFF (-12) val; print "$7FFFu>>-12="; check_hex(val, $7); print ", "; @log_shift $7FFF (-15) val; print "$7FFFu>>-15="; check_hex(val, $0); print ", "; @log_shift $7FFF (-16) val; print "$7FFFu>>-16="; check_hex_unspecified(val, $0); print "^"; @log_shift (-1) (0) val; print "-1u>>-0="; check_hex(val, -1); print ", "; @log_shift (-1) (-1) val; print "-1u>>-1="; check_hex(val, $7FFF); print ", "; @log_shift (-1) (-2) val; print "-1u>>-2="; check_hex(val, $3FFF); print ", "; @log_shift (-1) (-6) val; print "-1u>>-6="; check_hex(val, $3FF); print ", "; @log_shift (-1) (-12) val; print "-1u>>-12="; check_hex(val, $F); print ", "; @log_shift (-1) (-13) val; print "-1u>>-13="; check_hex(val, $7); print ", "; @log_shift (-1) (-15) val; print "-1u>>-15="; check_hex(val, $1); print ", "; @log_shift (-1) (-16) val; print "-1u>>-16="; check_hex_unspecified(val, $0); print ", "; @log_shift (-1) (-17) val; print "-1u>>-17="; check_hex_unspecified(val, $0); print "^"; testglobal = -1; res = $7fff; for (ix=-1 : ix>-16 : ix--) { @log_shift testglobal ix val; print "-1u>>", ix, "="; check_hex(val, res); print ", "; res = res / 2; } @log_shift testglobal ix val; print "-1u>>", ix, "="; check_hex_unspecified(val, 0); print "^"; @art_shift $11 0 val; print "$11s<<0="; check_hex(val, $11); print ", "; @art_shift $11 1 val; print "$11s<<1="; check_hex(val, $22); print ", "; @art_shift $11 4 val; print "$11s<<4="; check_hex(val, $110); print ", "; @art_shift $11 10 val; print "$11s<<10="; check_hex(val, $4400); print ", "; @art_shift $11 15 val; print "$11s<<15="; check_hex(val, $8000); print ", "; @art_shift $11 16 val; print "$11s<<16="; check_hex_unspecified(val, 0); print ", "; @art_shift (-2) 0 val; print "-2s<<0="; check(val, -2); print ", "; @art_shift (-2) 1 val; print "-2s<<1="; check(val, -4); print ", "; @art_shift (-2) 7 val; print "-2s<<7="; check(val, -256); print ", "; @art_shift (-2) 15 val; print "-2s<<15="; check(val, 0); print "^"; testglobal = 1; res = 1; for (ix=0 : ix<16 : ix++) { @art_shift testglobal ix val; print "1s<<", ix, "="; check_hex(val, res); print ", "; res = res+res; } @art_shift testglobal ix val; print "1s<<", ix, "="; check_hex_unspecified(val, 0); print "^"; @art_shift $4001 (0) val; print "$4001s>>-0="; check_hex(val, $4001); print ", "; @art_shift $4001 (-1) val; print "$4001s>>-1="; check_hex(val, $2000); print ", "; @art_shift $4001 (-6) val; print "$4001s>>-6="; check_hex(val, $100); print ", "; @art_shift $4001 (-11) val; print "$4001s>>-11="; check_hex(val, $8); print ", "; @art_shift $4001 (-15) val; print "$4001s>>-15="; check_hex(val, $0); print ", "; @art_shift $4001 (-16) val; print "$4001s>>-16="; check_hex_unspecified(val, $0); print "^"; @art_shift $7FFF (0) val; print "$7FFFs>>-0="; check_hex(val, $7FFF); print ", "; @art_shift $7FFF (-1) val; print "$7FFFs>>-1="; check_hex(val, $3FFF); print ", "; @art_shift $7FFF (-2) val; print "$7FFFs>>-2="; check_hex(val, $1FFF); print ", "; @art_shift $7FFF (-6) val; print "$7FFFs>>-6="; check_hex(val, $1FF); print ", "; @art_shift $7FFF (-12) val; print "$7FFFs>>-12="; check_hex(val, $7); print ", "; @art_shift $7FFF (-13) val; print "$7FFFs>>-13="; check_hex(val, $3); print ", "; @art_shift $7FFF (-14) val; print "$7FFFs>>-14="; check_hex(val, $1); print ", "; @art_shift $7FFF (-15) val; print "$7FFFs>>-15="; check_hex(val, $0); print ", "; @art_shift $7FFF (-16) val; print "$7FFFs>>-16="; check_hex_unspecified(val, $0); print "^"; @art_shift (-1) (0) val; print "-1s>>-0="; check(val, -1); print ", "; @art_shift (-1) (-1) val; print "-1s>>-1="; check(val, -1); print ", "; @art_shift (-1) (-15) val; print "-1s>>-15="; check(val, -1); print ", "; @art_shift (-1) (-16) val; print "-1s>>-16="; check_hex_unspecified(val, -1); print ", "; @art_shift (-1) (-17) val; print "-1s>>-17="; check_hex_unspecified(val, -1); print "^"; @art_shift (-1000) (0) val; print "-1000s>>-0="; check(val, -1000); print ", "; @art_shift (-1000) (-1) val; print "-1000s>>-1="; check(val, -500); print ", "; @art_shift (-1000) (-2) val; print "-1000s>>-2="; check(val, -250); print ", "; @art_shift (-1000) (-4) val; print "-1000s>>-4="; check(val, -63); print ", "; @art_shift (-1000) (-6) val; print "-1000s>>-6="; check(val, -16); print ", "; @art_shift (-1000) (-9) val; print "-1000s>>-9="; check(val, -2); print ", "; @art_shift (-1000) (-15) val; print "-1000s>>-15="; check(val, -1); print ", "; @art_shift (-1000) (-16) val; print "-1000s>>-16="; check_hex_unspecified(val, -1); print ", "; @art_shift (-1000) (-17) val; print "-1000s>>-17="; check_hex_unspecified(val, -1); print "^"; testglobal = -1; for (ix=0 : ix>-16 : ix--) { @art_shift testglobal ix val; print "-1s>>", ix, "="; check(val, -1); print ", "; } @art_shift testglobal ix val; print "-1s>>", ix, "="; check_hex_unspecified(val, -1); print "^"; count_failures(); ]; TestClass IncrementTest with name 'inc' 'dec' 'increment' 'decrement', testfunc [ val; print "Increment/decrement:^^"; val = 0; @inc val; print "0++="; check(val, 1); print ", "; val = 1; @inc val; print "1++="; check(val, 2); print ", "; val = -1; @inc val; print "-1++="; check(val, 0); print ", "; val = -10; @inc val; print "-10++="; check(val, -9); print ", "; val = $7FFF; @inc val; print "$7FFF++="; check_hex(val, $8000); print ", "; val = $C000; @inc val; print "$C000++="; check_hex(val, $C001); print "^"; testglobal = 0; @inc testglobal; print "0++="; check(testglobal, 1); print ", "; testglobal = 1; @inc testglobal; print "1++="; check(testglobal, 2); print ", "; testglobal = -1; @inc testglobal; print "-1++="; check(testglobal, 0); print ", "; testglobal = -10; @inc testglobal; print "-10++="; check(testglobal, -9); print ", "; testglobal = $7FFF; @inc testglobal; print "$7FFF++="; check_hex(testglobal, $8000); print ", "; testglobal = $C000; @inc testglobal; print "$C000++="; check_hex(testglobal, $C001); print "^"; @push 0; @inc sp; @pull val; print "0++="; check(val, 1); print ", "; @push 1; @inc sp; @pull val; print "1++="; check(val, 2); print ", "; @push -1; @inc sp; @pull val; print "-1++="; check(val, 0); print ", "; @push -10; @inc sp; @pull val; print "-10++="; check(val, -9); print ", "; @push $7FFF; @inc sp; @pull val; print "$7FFF++="; check_hex(val, $8000); print ", "; @push $C000; @inc sp; @pull val; print "$C000++="; check_hex(val, $C001); print "^"; val = 0; @dec val; print "0--="; check(val, -1); print ", "; val = 1; @dec val; print "1--="; check(val, 0); print ", "; val = -1; @dec val; print "-1--="; check(val, -2); print ", "; val = 10; @dec val; print "10--="; check(val, 9); print ", "; val = $8000; @dec val; print "$8000--="; check_hex(val, $7FFF); print ", "; val = $C000; @dec val; print "$C000--="; check_hex(val, $BFFF); print "^"; testglobal = 0; @dec testglobal; print "0--="; check(testglobal, -1); print ", "; testglobal = 1; @dec testglobal; print "1--="; check(testglobal, 0); print ", "; testglobal = -1; @dec testglobal; print "-1--="; check(testglobal, -2); print ", "; testglobal = 10; @dec testglobal; print "10--="; check(testglobal, 9); print ", "; testglobal = $8000; @dec testglobal; print "$8000--="; check_hex(testglobal, $7FFF); print ", "; testglobal = $C000; @dec testglobal; print "$C000--="; check_hex(testglobal, $BFFF); print "^"; @push 0; @dec sp; @pull val; print "0--="; check(val, -1); print ", "; @push 1; @dec sp; @pull val; print "1--="; check(val, 0); print ", "; @push -1; @dec sp; @pull val; print "-1--="; check(val, -2); print ", "; @push 10; @dec sp; @pull val; print "10--="; check(val, 9); print ", "; @push $8000; @dec sp; @pull val; print "$8000--="; check_hex(val, $7FFF); print ", "; @push $C000; @dec sp; @pull val; print "$C000--="; check_hex(val, $BFFF); print "^"; count_failures(); ]; TestClass IncrementBranchTest with name 'incchk' 'decchk' 'inccheck' 'deccheck', testfunc [ val res; print "Increment/decrement and branch:^^"; res = 0; val = 1; @inc_chk res 0 ?jump1a; val = 0; .jump1a; print "++0="; check(res, 1); print ","; check(val, 1); print ", "; res = 1; val = 1; @inc_chk res 0 ?jump1b; val = 0; .jump1b; print "++1="; check(res, 2); print ","; check(val, 1); print ", "; res = -1; val = 1; @inc_chk res 0 ?jump1c; val = 0; .jump1c; print "++-1="; check(res, 0); print ","; check(val, 0); print ", "; res = 100; val = 1; @inc_chk res 0 ?jump1d; val = 0; .jump1d; print "++100="; check(res, 101); print ","; check(val, 1); print ", "; res = -10; val = 1; @inc_chk res 0 ?jump1e; val = 0; .jump1e; print "++-10="; check(res, -9); print ","; check(val, 0); print ", "; res = $7FFF; val = 1; @inc_chk res 0 ?jump1f; val = 0; .jump1f; print "++$7FFF="; check_hex(res, $8000); print ","; check(val, 0); print ", "; res = $C000; val = 1; @inc_chk res 0 ?jump1g; val = 0; .jump1g; print "++$C000="; check_hex(res, $C001); print ","; check(val, 0); print "^"; testglobal2 = 0; testglobal = 1; @inc_chk testglobal2 0 ?jump2a; testglobal = 0; .jump2a; print "++0="; check(testglobal2, 1); print ","; check(testglobal, 1); print ", "; testglobal2 = 1; testglobal = 1; @inc_chk testglobal2 0 ?jump2b; testglobal = 0; .jump2b; print "++1="; check(testglobal2, 2); print ","; check(testglobal, 1); print ", "; testglobal2 = -1; testglobal = 1; @inc_chk testglobal2 0 ?jump2c; testglobal = 0; .jump2c; print "++-1="; check(testglobal2, 0); print ","; check(testglobal, 0); print ", "; testglobal2 = 100; testglobal = 1; @inc_chk testglobal2 0 ?jump2d; testglobal = 0; .jump2d; print "++100="; check(testglobal2, 101); print ","; check(testglobal, 1); print ", "; testglobal2 = -10; testglobal = 1; @inc_chk testglobal2 0 ?jump2e; testglobal = 0; .jump2e; print "++-10="; check(testglobal2, -9); print ","; check(testglobal, 0); print ", "; testglobal2 = $7FFF; testglobal = 1; @inc_chk testglobal2 0 ?jump2f; testglobal = 0; .jump2f; print "++$7FFF="; check_hex(testglobal2, $8000); print ","; check(testglobal, 0); print ", "; testglobal2 = $C000; testglobal = 1; @inc_chk testglobal2 0 ?jump2g; testglobal = 0; .jump2g; print "++$C000="; check_hex(testglobal2, $C001); print ","; check(testglobal, 0); print "^"; @push 0; val = 1; @inc_chk sp 0 ?jump3a; val = 0; .jump3a; @pull res; print "++0="; check(res, 1); print ","; check(val, 1); print ", "; @push 1; val = 1; @inc_chk sp 0 ?jump3b; val = 0; .jump3b; @pull res; print "++1="; check(res, 2); print ","; check(val, 1); print ", "; @push -1; val = 1; @inc_chk sp 0 ?jump3c; val = 0; .jump3c; @pull res; print "++-1="; check(res, 0); print ","; check(val, 0); print ", "; @push 100; val = 1; @inc_chk sp 0 ?jump3d; val = 0; .jump3d; @pull res; print "++100="; check(res, 101); print ","; check(val, 1); print ", "; @push -10; val = 1; @inc_chk sp 0 ?jump3e; val = 0; .jump3e; @pull res; print "++-10="; check(res, -9); print ","; check(val, 0); print ", "; @push $7FFF; val = 1; @inc_chk sp 0 ?jump3f; val = 0; .jump3f; @pull res; print "++$7FFF="; check_hex(res, $8000); print ","; check(val, 0); print ", "; @push $C000; val = 1; @inc_chk sp 0 ?jump3g; val = 0; .jump3g; @pull res; print "++$C000="; check_hex(res, $C001); print ","; check(val, 0); print "^"; res = 0; val = 1; @dec_chk res 0 ?jump4a; val = 0; .jump4a; print "--0="; check(res, -1); print ","; check(val, 1); print ", "; res = 1; val = 1; @dec_chk res 0 ?jump4b; val = 0; .jump4b; print "--1="; check(res, 0); print ","; check(val, 0); print ", "; res = -1; val = 1; @dec_chk res 0 ?jump4c; val = 0; .jump4c; print "---1="; check(res, -2); print ","; check(val, 1); print ", "; res = 100; val = 1; @dec_chk res 0 ?jump4d; val = 0; .jump4d; print "--100="; check(res, 99); print ","; check(val, 0); print ", "; res = -10; val = 1; @dec_chk res 0 ?jump4e; val = 0; .jump4e; print "---10="; check(res, -11); print ","; check(val, 1); print ", "; res = $8000; val = 1; @dec_chk res 0 ?jump4f; val = 0; .jump4f; print "--$8000="; check_hex(res, $7FFF); print ","; check(val, 0); print ", "; res = $C000; val = 1; @dec_chk res 0 ?jump4g; val = 0; .jump4g; print "--$C000="; check_hex(res, $BFFF); print ","; check(val, 1); print "^"; testglobal2 = 0; testglobal = 1; @dec_chk testglobal2 0 ?jump5a; testglobal = 0; .jump5a; print "--0="; check(testglobal2, -1); print ","; check(testglobal, 1); print ", "; testglobal2 = 1; testglobal = 1; @dec_chk testglobal2 0 ?jump5b; testglobal = 0; .jump5b; print "--1="; check(testglobal2, 0); print ","; check(testglobal, 0); print ", "; testglobal2 = -1; testglobal = 1; @dec_chk testglobal2 0 ?jump5c; testglobal = 0; .jump5c; print "---1="; check(testglobal2, -2); print ","; check(testglobal, 1); print ", "; testglobal2 = 100; testglobal = 1; @dec_chk testglobal2 0 ?jump5d; testglobal = 0; .jump5d; print "--100="; check(testglobal2, 99); print ","; check(testglobal, 0); print ", "; testglobal2 = -10; testglobal = 1; @dec_chk testglobal2 0 ?jump5e; testglobal = 0; .jump5e; print "---10="; check(testglobal2, -11); print ","; check(testglobal, 1); print ", "; testglobal2 = $8000; testglobal = 1; @dec_chk testglobal2 0 ?jump5f; testglobal = 0; .jump5f; print "--$8000="; check_hex(testglobal2, $7FFF); print ","; check(testglobal, 0); print ", "; testglobal2 = $C000; testglobal = 1; @dec_chk testglobal2 0 ?jump5g; testglobal = 0; .jump5g; print "--$C000="; check_hex(testglobal2, $BFFF); print ","; check(testglobal, 1); print "^"; @push 0; val = 1; @dec_chk sp 0 ?jump6a; val = 0; .jump6a; @pull res; print "--0="; check(res, -1); print ","; check(val, 1); print ", "; @push 1; val = 1; @dec_chk sp 0 ?jump6b; val = 0; .jump6b; @pull res; print "--1="; check(res, 0); print ","; check(val, 0); print ", "; @push -1; val = 1; @dec_chk sp 0 ?jump6c; val = 0; .jump6c; @pull res; print "---1="; check(res, -2); print ","; check(val, 1); print ", "; @push 100; val = 1; @dec_chk sp 0 ?jump6d; val = 0; .jump6d; @pull res; print "--100="; check(res, 99); print ","; check(val, 0); print ", "; @push -10; val = 1; @dec_chk sp 0 ?jump6e; val = 0; .jump6e; @pull res; print "---10="; check(res, -11); print ","; check(val, 1); print ", "; @push $8000; val = 1; @dec_chk sp 0 ?jump6f; val = 0; .jump6f; @pull res; print "--$8000="; check_hex(res, $7FFF); print ","; check(val, 0); print ", "; @push $C000; val = 1; @dec_chk sp 0 ?jump6g; val = 0; .jump6g; @pull res; print "--$C000="; check_hex(res, $BFFF); print ","; check(val, 1); print "^"; res = 50; val = 1; @inc_chk res 60 ?jumpxa; val = 0; .jumpxa; print "++50="; check(res, 51); print ","; check(val, 0); print ", "; res = 70; val = 1; @inc_chk res 60 ?jumpxb; val = 0; .jumpxb; print "++70="; check(res, 71); print ","; check(val, 1); print ", "; res = -50; val = 1; @inc_chk res (-60) ?jumpxc; val = 0; .jumpxc; print "++-50="; check(res, -49); print ","; check(val, 1); print ", "; res = -70; val = 1; @inc_chk res (-60) ?jumpxd; val = 0; .jumpxd; print "++-70="; check(res, -69); print ","; check(val, 0); print ", "; res = -50; val = 1; @inc_chk res 60 ?jumpxe; val = 0; .jumpxe; print "++-50="; check(res, -49); print ","; check(val, 0); print ", "; res = 50; val = 1; @inc_chk res (-60) ?jumpxf; val = 0; .jumpxf; print "++50="; check(res, 51); print ","; check(val, 1); print "^"; res = 50; val = 1; @dec_chk res 60 ?jumpya; val = 0; .jumpya; print "--50="; check(res, 49); print ","; check(val, 1); print ", "; res = 70; val = 1; @dec_chk res 60 ?jumpyb; val = 0; .jumpyb; print "--70="; check(res, 69); print ","; check(val, 0); print ", "; res = -50; val = 1; @dec_chk res (-60) ?jumpyc; val = 0; .jumpyc; print "---50="; check(res, -51); print ","; check(val, 0); print ", "; res = -70; val = 1; @dec_chk res (-60) ?jumpyd; val = 0; .jumpyd; print "---70="; check(res, -71); print ","; check(val, 1); print ", "; res = -50; val = 1; @dec_chk res 60 ?jumpye; val = 0; .jumpye; print "---50="; check(res, -51); print ","; check(val, 1); print ", "; res = 50; val = 1; @dec_chk res (-60) ?jumpyf; val = 0; .jumpyf; print "--50="; check(res, 49); print ","; check(val, 0); print "^"; count_failures(); ]; Array array1 --> $1357 $FDB9 $0011 $FFEE; Array array2 --> 4; TestClass ArrayTest with name 'array' 'loadw' 'loadb' 'storew' 'storeb', testfunc [ val ix addr; print "Array loads and stores:^^"; addr = array1; @loadw array1 0 -> val; print "a-->0="; check_hex(val, $1357); print ", "; @loadw addr 0 -> val; print "a-->0="; check_hex(val, $1357); print ", "; ix = 1; @loadw array1 ix -> val; print "a-->1="; check_hex(val, $FDB9); print ", "; @loadw addr ix -> val; print "a-->1="; check_hex(val, $FDB9); print ", "; testglobal = 2; @loadw array1 testglobal -> val; print "a-->2="; check_hex(val, $0011); print ", "; @loadw addr testglobal -> val; print "a-->2="; check_hex(val, $0011); print ", "; @push 3; @loadw array1 sp -> val; print "a-->3="; check_hex(val, $FFEE); print ", "; @push 3; @loadw addr sp -> val; print "a-->3="; check_hex(val, $FFEE); print "^"; addr = array1+3; @loadw addr (-1) -> val; print "a+3-->-1="; check_hex(val, $57FD); print ", "; @loadw addr 0 -> val; print "a+3-->0="; check_hex(val, $B900); print ", "; @loadw addr 1 -> val; print "a+3-->1="; check_hex(val, $11FF); print ", "; testglobal = array1+3; @loadw testglobal (-1) -> val; print "a+3-->-1="; check_hex(val, $57FD); print ", "; @loadw testglobal 0 -> val; print "a+3-->0="; check_hex(val, $B900); print ", "; @loadw testglobal 1 -> val; print "a+3-->1="; check_hex(val, $11FF); print "^"; addr = array1; @loadb array1 0 -> val; print "a->0="; check_hex(val, $13); print ", "; @loadb addr 0 -> val; print "a->0="; check_hex(val, $13); print ", "; ix = 1; @loadb array1 ix -> val; print "a->1="; check_hex(val, $57); print ", "; @loadb addr ix -> val; print "a->1="; check_hex(val, $57); print ", "; testglobal = 2; @loadb array1 testglobal -> val; print "a->2="; check_hex(val, $FD); print ", "; @loadb addr testglobal -> val; print "a->2="; check_hex(val, $FD); print ", "; @push 3; @loadb array1 sp -> val; print "a->3="; check_hex(val, $B9); print ", "; @push 3; @loadb addr sp -> val; print "a->3="; check_hex(val, $B9); print "^"; addr = array1+3; @loadb addr (-1) -> val; print "a+3->-1="; check_hex(val, $FD); print ", "; @loadb addr 0 -> val; print "a+3->0="; check_hex(val, $B9); print ", "; @loadb addr 1 -> val; print "a+3->1="; check_hex(val, $00); print ", "; testglobal = array1+3; @loadb testglobal (-1) -> val; print "a+3->-1="; check_hex(val, $FD); print ", "; @loadb testglobal 0 -> val; print "a+3->0="; check_hex(val, $B9); print ", "; @loadb testglobal 1 -> val; print "a+3->1="; check_hex(val, $00); print "^"; addr = array2; @storew array2 0 $1201; @loadw array2 0 -> val; print "a-->0="; check_hex(val, $1201); print ", "; @storew addr 0 $2302; @loadw array2 0 -> val; print "a-->0="; check_hex(val, $2302); print ", "; ix = 1; @storew array2 ix $3403; @loadw array2 1 -> val; print "a-->1="; check_hex(val, $3403); print ", "; @storew addr ix $4504; @loadw array2 1 -> val; print "a-->1="; check_hex(val, $4504); print ", "; testglobal = 2; @storew array2 testglobal $5605; @loadw array2 2 -> val; print "a-->2="; check_hex(val, $5605); print ", "; @storew addr testglobal $6706; @loadw array2 2 -> val; print "a-->2="; check_hex(val, $6706); print ", "; @push 3; @storew array2 sp $7807; @loadw array2 3 -> val; print "a-->3="; check_hex(val, $7807); print ", "; @push 3; @storew addr sp $8908; @loadw array2 3 -> val; print "a-->3="; check_hex(val, $8908); print "^"; addr = array2+4; @storew addr (-1) $AB0A; @loadw array2 1 -> val; print "a-->-1="; check_hex(val, $AB0A); print ", "; @storew addr 0 $BC0B; @loadw array2 2 -> val; print "a-->0="; check_hex(val, $BC0B); print ", "; @storew addr 1 $CD0C; @loadw array2 3 -> val; print "a-->1="; check_hex(val, $CD0C); print ", "; testglobal = array2+4; @storew testglobal (-1) $BA1B; @loadw array2 1 -> val; print "a-->-1="; check_hex(val, $BA1B); print ", "; @storew testglobal 0 $CB1C; @loadw array2 2 -> val; print "a-->0="; check_hex(val, $CB1C); print ", "; @storew testglobal 1 $DC1D; @loadw array2 3 -> val; print "a-->1="; check_hex(val, $DC1D); print "^"; addr = array2; @storeb array2 0 $12; @loadb array2 0 -> val; print "a->0="; check_hex(val, $12); print ", "; @storeb addr 0 $23; @loadb array2 0 -> val; print "a->0="; check_hex(val, $23); print ", "; ix = 1; @storeb array2 ix $34; @loadb array2 1 -> val; print "a->1="; check_hex(val, $34); print ", "; @storeb addr ix $45; @loadb array2 1 -> val; print "a->1="; check_hex(val, $45); print ", "; testglobal = 2; @storeb array2 testglobal $56; @loadb array2 2 -> val; print "a->2="; check_hex(val, $56); print ", "; @storeb addr testglobal $67; @loadb array2 2 -> val; print "a->2="; check_hex(val, $67); print ", "; @push 3; @storeb array2 sp $78; @loadb array2 3 -> val; print "a->3="; check_hex(val, $78); print ", "; @push 3; @storeb addr sp $89; @loadb array2 3 -> val; print "a->3="; check_hex(val, $89); print "^"; addr = array2+4; @storeb addr (-1) $AB; @loadb array2 3 -> val; print "a->-1="; check_hex(val, $AB); print ", "; @storeb addr 0 $BC; @loadb array2 4 -> val; print "a->0="; check_hex(val, $BC); print ", "; @storeb addr 1 $CD; @loadb array2 5 -> val; print "a->1="; check_hex(val, $CD); print ", "; testglobal = array2+4; @storeb testglobal (-1) $BA; @loadb array2 3 -> val; print "a->-1="; check_hex(val, $BA); print ", "; @storeb testglobal 0 $CB; @loadb array2 4 -> val; print "a->0="; check_hex(val, $CB); print ", "; @storeb testglobal 1 $DC; @loadb array2 5 -> val; print "a->1="; check_hex(val, $DC); print "^"; ix = $F1; @storeb array2 0 ix; ix = $E2; @storeb array2 1 ix; @loadw array2 0 -> val; print "$F1 concat $E2 = "; check_hex(val, $F1E2); print "^"; ix = $9876; @storew array2 1 ix; @loadb array2 2 -> val; print "$9876 = "; check_hex(val, $98); print " "; @loadb array2 3 -> val; print "concat "; check_hex(val, $76); print "^"; count_failures(); ]; TestClass UndoTest with name 'undo', testfunc [ val loc; print "Undo:^^"; val = HDR_GAMEFLAGS-->0; ! "Flags 2" byte if (val & 16) print "Interpreter claims to support undo.^^"; else print "Interpreter claims to not support undo. (Continuing test anyway...)^^"; print "Using a local variable for @@64save_undo result:^"; loc = 99; testglobal = 999; @save_undo val; if (val == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (val == 0) { print "@@64save_undo failed!^"; failures++; count_failures(); return; } if (val == 1) { print "Undo saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; failures++; print "Restoring undo...^"; @restore_undo val; if (val == 0) { print "@@64restore_undo failed (value 0)!^"; } else { print "@@64restore_undo failed with unknown return value: ", val, "^"; } failures++; count_failures(); return; } else if (val ~= 2) { print "Unknown @@64save_undo return value: ", val, "^"; failures++; count_failures(); return; } print "Undo succeeded, return value "; check(val, 2); print ".^"; print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print "^"; print "Using a global variable for @@64save_undo result:^"; loc = 98; testglobal = 998; @save_undo testglobal2; if (testglobal2 == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (testglobal2 == 0) { print "@@64save_undo failed!^"; failures++; count_failures(); return; } if (testglobal2 == 1) { print "Undo saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; failures++; print "Restoring undo...^"; @restore_undo testglobal2; if (testglobal2 == 0) { print "@@64restore_undo failed (value 0)!^"; } else { print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; } failures++; count_failures(); return; } else if (testglobal2 ~= 2) { print "Unknown @@64save_undo return value: ", testglobal2, "^"; failures++; count_failures(); return; } print "Undo succeeded, return value "; check(testglobal2, 2); print ".^"; print "loc="; check(loc, 98); print " glob="; check(testglobal, 998); print "^"; print "Calling @@64save_undo within a function or two:^"; loc = 97; testglobal = 997; val = undo_depth_check(); if (val == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (val == 0) { print "@@64save_undo failed!^"; failures++; count_failures(); return; } if (val == 1) { print "Undo saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; failures++; print "Restoring undo...^"; @restore_undo val; if (val == 0) { print "@@64restore_undo failed (value 0)!^"; } else { print "@@64restore_undo failed with unknown return value: ", val, "^"; } failures++; count_failures(); return; } else if (val ~= 2) { print "Unknown @@64save_undo return value: ", val, "^"; failures++; count_failures(); return; } print "Undo succeeded, return value "; check(val, 2); print ".^"; print "loc="; check(loc, 97); print " glob="; check(testglobal, 997); print "^"; @check_arg_count 3 ?~ok; print "Error: test method wrongly got argument 3!^"; failures++; .ok; print "Using the stack for @@64save_undo result:^"; loc = 98; testglobal = 998; testglobal2 = -99; @save_undo sp; @pull testglobal2; if (testglobal2 == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (testglobal2 == 0) { print "@@64save_undo failed!^"; failures++; count_failures(); return; } if (testglobal2 == 1) { print "Undo saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; testglobal2 = -99; failures++; print "Restoring undo...^"; @restore_undo sp; @pull testglobal2; if (testglobal2 == 0) { print "@@64restore_undo failed (value 0)!^"; } else { print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; } failures++; count_failures(); return; } else if (testglobal2 ~= 2) { print "Unknown @@64save_undo return value: ", testglobal2, "^"; failures++; count_failures(); return; } print "Undo succeeded, return value "; check(testglobal2, 2); print ".^"; print "loc="; check(loc, 98); print " glob="; check(testglobal, 998); print "^"; print "Checking @@64save_undo saves the stack correctly:^"; @push 9; loc = 99; testglobal = 999; testglobal2 = -999; @save_undo val; if (val == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (val == 0) { print "@@64save_undo failed!^"; failures++; count_failures(); return; } if (val == 1) { print "Undo saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; testglobal2 = -777; @pull val; print "guard="; check(val, 9); print "^"; val = 7; failures++; print "Restoring undo...^"; @restore_undo testglobal2; if (testglobal2 == 0) { print "@@64restore_undo failed (value 0)!^"; } else { print "@@64restore_undo failed with unknown return value: ", testglobal2, "^"; } failures++; count_failures(); return; } else if (val ~= 2) { print "Unknown @@64save_undo return value: ", val, "^"; failures++; count_failures(); return; } print "Undo succeeded, return value "; check(val, 2); print ".^"; print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print " glob2="; check(testglobal2, -999); print "^"; @pull val; print "guard="; check(val, 9); print "^"; count_failures(); ]; [ undo_depth_check; return undo_depth_check2(11, 22, 33); ]; [ undo_depth_check2 foo bar baz val; bar = 1; foo = bar; baz = foo; @save_undo val; @check_arg_count 3 ?ok; print "Error: undo_depth_check2 did not get argument 3!^"; failures++; .ok; return val; ]; TestClass MultiUndoTest with name 'multiundo', testfunc [ val loc; print "Multi-level undo:^(Note: this capability is not required by the spec.)^^"; val = HDR_GAMEFLAGS-->0; ! "Flags 2" byte if (val & 16) print "Interpreter claims to support undo.^^"; else print "Interpreter claims to not support undo. (Continuing test anyway...)^^"; loc = 99; testglobal = 999; @save_undo val; if (val == -1) { print "Undo is not available on this interpreter.^"; count_failures(); return; } if (val == 0) { print "First @@64save_undo failed!^"; failures++; count_failures(); return; } if (val == 1) { print "Undo 1 saved...^"; ! The following changes will be undone. loc = 77; testglobal = 777; failures++; @save_undo val; if (val == -1) { print "Undo returned ~unavailable~, even though it was available the first time.^"; count_failures(); return; } if (val == 0) { print "Second @@64save_undo failed! This interpreter apparently doesn't support multi-level undo. This should not be considered a bug.^"; failures--; ! cancel the previous failure count_failures(); return; } if (val == 1) { print "Undo 2 saved...^"; ! The following changes will be undone. loc = 55; testglobal = 555; failures++; print "Restoring undo 2...^"; @restore_undo val; if (val == 0) { print "Second @@64restore_undo failed (value 0)!^"; } else { print "Second @@64restore_undo failed with unknown return value: ", val, "^"; } failures++; count_failures(); return; } else if (val ~= 2) { print "Unknown @@64save_undo return value: ", val, "^"; failures++; count_failures(); return; } print "Undo 2 succeeded, return value "; check(val, 2); print ".^"; print "loc="; check(loc, 77); print " glob="; check(testglobal, 777); print "^"; print "Restoring undo 1...^"; @restore_undo val; if (val == 0) { print "First @@64restore_undo failed (value 0)!^"; } else { print "First @@64restore_undo failed with unknown return value: ", val, "^"; } failures++; count_failures(); return; } else if (val ~= 2) { print "Unknown @@64save_undo return value: ", val, "^"; failures++; count_failures(); return; } print "Undo 1 succeeded, return value "; check(val, 2); print ".^"; print "loc="; check(loc, 99); print " glob="; check(testglobal, 999); print "^"; count_failures(); ]; ! The Indirect test is copied more-or-less whole from czech.inf ! (as of Oct 1 2010). Comments copied also: ! ! Indirect-able opcodes: inc, dec, inc_chk, dec_chk, store, pull, load ! Spec Version 1.1 (draft7): "an indirect reference to the stack ! pointer does not push or pull the top item of the stack - it is read ! or written in place." ! Based on my tests (see rec.arts.int-fiction 20031028), this seems to mean ! that, e.g., for load, you NEVER pop the stack, for all cases ! (a) load sp; (b) load [sp]; (c) i=0; load [i]; (d) sp=0; load [sp]; ! ! Overall rules: ! - Do NOT push/pop for "foo sp": write in place ! - DO pop for "foo [sp]". However, if top of stack is 0, only pop ONCE. ! - "bar = 0; foo [bar]" yields EXACTLY the same results as "foo sp" ! ("push 0; foo [sp] is also identical to "foo sp".) ! TestClass IndirectTest with name 'indirect', testfunc [ ix; print "Indirect opcodes:^^"; for (ix = 0: ix < 100: ix++) { do_indirect_test(ix); } count_failures(); ]; [ do_indirect_test which result local2 spointer lpointer rpointer top_of_stack which_str expectr expect1 expect2; ! First, set up everything we're going to need. local2 = 51; ! Gtemp = 61; result = 71; spointer = 0; ! stack rpointer = 2; ! points to 'result' lpointer = 3; ! local2 ! gpointer = 21; ! '21' means 6th global, which is (hopefully!) Gtemp expectr = 999; ! don't test 'result' unless we change this value @push 41; @push 42; @push 43; @push 44; @push 45; switch (which) { ! load -> result 0: @load sp -> result; ! compiles as 'load 0 -> result' expectr = 45; expect1 = 45; expect2 = 44; which_str = "load sp -> result"; 1: @load [spointer] -> result; expectr = 45; expect1 = 45; expect2 = 44; which_str = "load [spointer] -> result"; 2: @push lpointer; @load [sp] -> result; expectr = 51; expect1 = 45; expect2 = 44; which_str = "load [sp=lpointer] -> result"; 3: @push spointer; @load [sp] -> result; expectr = 45; expect1 = 45; expect2 = 44; which_str = "load [sp=spointer] -> result"; ! load -> sp 4: @load sp -> sp; expect1 = 45; expect2 = 45; which_str = "load sp -> sp"; 5: @push lpointer; @load [sp] -> sp; expect1 = 51; expect2 = 45; which_str = "load [sp=lpointer] -> sp"; 6: @push spointer; @load [sp] -> sp; expect1 = 45; expect2 = 45; which_str = "load [sp=spointer] -> sp"; ! store 10: @store sp 83; expect1 = 83; expect2 = 44; which_str = "store sp 83"; 11: @store [spointer] 83; expect1 = 83; expect2 = 44; which_str = "store [spointer] 83"; 12: @push spointer; @store [sp] 83; expect1 = 83; expect2 = 44; which_str = "store [sp=spointer] 83"; 13: @store [rpointer] 83; expectr = 83; expect1 = 45; expect2 = 44; which_str = "store [rpointer] 83"; 14: @push rpointer; @store [sp] 83; expectr = 83; expect1 = 45; expect2 = 44; which_str = "store [sp=rpointer] 83"; 15: @store result sp; expectr = 45; expect1 = 44; expect2 = 43; which_str = "store result sp"; 16: @store sp sp; expect1 = 45; expect2 = 43; which_str = "store sp sp"; 17: @push spointer; @store [sp] sp; expect1 = 45; expect2 = 43; which_str = "store [sp=spointer] sp"; 18: @store [rpointer] sp; expectr = 45; expect1 = 44; expect2 = 43; which_str = "store [rpointer] sp"; 19: @push rpointer; @store [sp] sp; expectr = 45; expect1 = 44; expect2 = 43; which_str = "store [sp=rpointer] sp"; ! pull 20: @pull result; expectr = 45; expect1 = 44; expect2 = 43; which_str = "pull result"; 21: @pull [rpointer]; expectr = 45; expect1 = 44; expect2 = 43; which_str = "pull [rpointer]"; 22: @push rpointer; @pull [sp]; expectr = 45; expect1 = 44; expect2 = 43; which_str = "pull [sp=rpointer]"; 23: @pull sp; expect1 = 45; expect2 = 43; which_str = "pull sp"; 24: @push spointer; @pull [sp]; expect1 = 45; expect2 = 43; which_str = "pull [sp=spointer]"; 25: @pull [spointer]; expect1 = 45; expect2 = 43; which_str = "pull [spointer]"; ! inc 30: @inc result; expectr = 72; expect1 = 45; expect2 = 44; which_str = "inc result"; 31: @inc [rpointer]; expectr = 72; expect1 = 45; expect2 = 44; which_str = "inc [rpointer]"; 32: @push rpointer; @inc [sp]; expectr = 72; expect1 = 45; expect2 = 44; which_str = "inc [sp=rpointer]"; 33: @inc sp; expect1 = 46; expect2 = 44; which_str = "inc sp"; 34: @inc [spointer]; expect1 = 46; expect2 = 44; which_str = "inc [spointer]"; 35: @push spointer; @inc [sp]; expect1 = 46; expect2 = 44; which_str = "inc [sp=spointer]"; ! dec 40: @dec result; expectr = 70; expect1 = 45; expect2 = 44; which_str = "dec result"; 41: @dec [rpointer]; expectr = 70; expect1 = 45; expect2 = 44; which_str = "dec [rpointer]"; 42: @push rpointer; @dec [sp]; expectr = 70; expect1 = 45; expect2 = 44; which_str = "dec [sp=rpointer]"; 43: @dec sp; expect1 = 44; expect2 = 44; which_str = "dec sp"; 44: @dec [spointer]; expect1 = 44; expect2 = 44; which_str = "dec [spointer]"; 45: @push spointer; @dec [sp]; expect1 = 44; expect2 = 44; which_str = "dec [sp=spointer]"; ! inc_chk 50: which_str = "inc_chk result"; @inc_chk result 72 ?bad_indirect_inc; expectr = 72; expect1 = 45; expect2 = 44; 51: which_str = "inc_chk [rpointer]"; @inc_chk [rpointer] 72 ?bad_indirect_inc; expectr = 72; expect1 = 45; expect2 = 44; 52: which_str = "inc_chk [sp=rpointer]"; @push rpointer; @inc_chk [sp] 72 ?bad_indirect_inc; expectr = 72; expect1 = 45; expect2 = 44; 53: which_str = "inc_chk sp"; @inc_chk sp 46 ?bad_indirect_inc; expect1 = 46; expect2 = 44; 54: which_str = "inc_chk [spointer]"; @inc_chk [spointer] 46 ?bad_indirect_inc; expect1 = 46; expect2 = 44; 55: which_str = "inc_chk [sp=spointer]"; @push spointer; @inc_chk [sp] 46 ?bad_indirect_inc; expect1 = 46; expect2 = 44; ! dec_chk 60: which_str = "dec_chk result"; @dec_chk result 70 ?bad_indirect_inc; expectr = 70; expect1 = 45; expect2 = 44; 61: which_str = "dec_chk [rpointer]"; @dec_chk [rpointer] 70 ?bad_indirect_inc; expectr = 70; expect1 = 45; expect2 = 44; 62: which_str = "dec_chk [sp=rpointer]"; @push rpointer; @dec_chk [sp] 70 ?bad_indirect_inc; expectr = 70; expect1 = 45; expect2 = 44; 63: which_str = "dec_chk sp"; @dec_chk sp 44 ?bad_indirect_inc; expect1 = 44; expect2 = 44; 64: which_str = "dec_chk [spointer]"; @dec_chk [spointer] 44 ?bad_indirect_inc; expect1 = 44; expect2 = 44; 65: which_str = "dec_chk [sp=spointer]"; @push spointer; @dec_chk [sp] 44 ?bad_indirect_inc; expect1 = 44; expect2 = 44; default: rfalse; ! no test here; do nothing. } ! Test results print (string) which_str, ": "; @je expectr 999 ?skip_expectr; check(result, expectr); print ", "; .skip_expectr; @pull top_of_stack; check(top_of_stack, expect1); print ", "; @pull top_of_stack; check(top_of_stack, expect2); new_line; rtrue; ! If you got here, inc_chk/dec_chk broke .bad_indirect_inc; print (string) which_str, ": "; check(result, 123); new_line; rfalse; ]; ! The lengths here must exceed the number of characters printed (below) ! by at least 3. Array streambuf -> 170; Array streambufcmp -> 170; ! The StreamTrip test sends every legal, printable ZSCII character to ! a memory stream, and then reads them back. They should all survive ! the journey unscathed. ! ! Note that character 9 (tab) and 10 (unix newline) are not legal for ! output. (Despite the fact that Zork 1 uses tabs for indenting ! the temple book's text.) (Tab is legal in V6, but this test is for ! v5/8.) ! ! Printing character 0 is legal, but doesn't generate output. It should ! not count towards the stream count either. (See 3.8.2.1.) ! TestClass StreamTripTest with name 'streamtrip', short_name "streamtrip", testfunc [ ix len pos; print "Memory stream round-trip:^^"; @output_stream 3 streambuf; pos = 0; @print_char 13; ! newline streambufcmp->pos = 13; pos++; for (ix=32 : ix <= 126 : ix++) { streambufcmp->pos = ix; pos++; @print_char ix; } for (ix=155 : ix <= 223 : ix++) { streambufcmp->pos = ix; pos++; @print_char ix; } ! no streambufcmp output for the no-op @print_char 0; ! no-op @print_char 64; ! @-sign streambufcmp->pos = 64; pos++; @output_stream -3; ix = streambuf; len = ix-->0; print "Number of characters written: "; check(pos, 166); new_line; print "Number of characters read: "; check(len, 166); new_line; check_array( streambuf+2, streambufcmp, len, Streamtripprint ); count_failures(); ]; [ Streamtripprint ch; print "Mismatch for ", ch, " '"; @print_char ch; print "': "; ]; TestClass StreamOpTest with name 'streamop', short_name "streamop", testfunc [ len; print "Memory stream opcodes:^^"; @output_stream 3 streambuf; @print_paddr "abc"; @output_stream -3; len = (streambuf+0)-->0; print "@@64print_paddr: "; check(len, 3); print " characters written: "; check_arr_3(streambuf+2, 'a', 'b', 'c'); new_line; @output_stream 3 streambuf; @print_num 789; @output_stream -3; len = (streambuf+0)-->0; print "@@64print_num: "; check(len, 3); print " characters written: "; check_arr_3(streambuf+2, '7', '8', '9'); new_line; @output_stream 3 streambuf; @print_char 'x'; @output_stream -3; len = (streambuf+0)-->0; print "@@64print_char: "; check(len, 1); print " characters written: "; check_arr_3(streambuf+2, 'x', '8', '9'); new_line; count_failures(); ]; TestClass Throwcatch with name 'throwcatch' 'throw' 'catch', short_name "throwcatch", testfunc [ val; print "@@64throw/@@64catch:^^"; testglobal = 0; testglobal2 = 0; val = Throwfunc1(); print "The function with @@64catch will be returned with the value of @@64throw: "; check(val, 1); print "^"; print "Intermediate functions should not set their storers.^testglobal="; check(testglobal, 0); print "^"; print "testglobal2="; check(testglobal2, 0); print "^"; count_failures(); ]; [ Throwfunc1 val; print "Throwfunc1^"; val = Throwfunc2(); print "Returning from Throwfunc1^^"; return val; ]; [ Throwfunc2 val; print "Throwfunc2^"; @catch -> val; val = Throwfunc3(val); print "Returning from Throwfunc2^"; return 2; ]; [ Throwfunc3 val; print "Throwfunc3^"; testglobal = Throwfunc4(val); print "Returning from Throwfunc3^"; return 3; ]; [ Throwfunc4 val; print "Throwfunc4^"; testglobal2 = Throwfunc5(val); print "Returning from Throwfunc4^"; return 4; ]; [ Throwfunc5 val; print "Throwfunc5^About to @@64throw - should then return from Throwfunc1^"; @throw 1 val; print "Returning from Throwfunc5^"; return 5; ]; Array tables_data -> 256; Array copy_table_reference -> $00 $01 $02 $03 $04 $05 $06 $07 $08 $09 $0a $0b $0c $0d $0e $0f $00 $01 $02 $03 $04 $05 $06 $07 $18 $19 $1a $1b $1c $1d $1e $1f $30 $31 $32 $33 $34 $35 $36 $37 $28 $29 $2a $2b $2c $2d $2e $2f $30 $31 $32 $33 $34 $35 $36 $37 $38 $39 $3a $3b $3c $3d $3e $3f $40 $41 $42 $43 $40 $41 $42 $43 $44 $45 $46 $47 $4c $4d $4e $4f $54 $55 $56 $57 $58 $59 $5a $5b $58 $59 $5a $5b $5c $5d $5e $5f $60 $61 $62 $63 $60 $61 $62 $63 $60 $61 $62 $63 $6c $6d $6e $6f $00 $00 $00 $00 $00 $00 $00 $00 $78 $79 $7a $7b $7c $7d $7e $7f; TestClass Tables with name 'tables' 'table', testfunc [ val val2 ix; print "*_table tests:^^"; for (ix=0 : ix<256 : ix++) { tables_data->ix = ix; } print "@@64print_table - should print the alphabet in upper then lower case:^"; val = tables_data + $41; @print_table val 26 2 6; print "^^@@64scan_table:"; print "^Default form, first word: "; @scan_table $0001 tables_data 128 -> val ?~bad_scan_table; check(val, tables_data); print "^Default form, another word: "; @scan_table $8081 tables_data 128 -> val ?~bad_scan_table; check(val, tables_data + $80); print "^Manually specified default form: "; @scan_table $8081 tables_data 128 $82 -> val ?~bad_scan_table; check(val, tables_data + $80); print "^Default form, nonexistent word: "; @scan_table $0102 tables_data 128 -> val ?bad_scan_table; check(val, 0); print "^Byte form, first byte: "; @scan_table $00 tables_data 256 $01 -> val ?~bad_scan_table; check(val, tables_data); print "^Byte form, another byte: "; @scan_table $80 tables_data 256 $01 -> val ?~bad_scan_table; check(val, tables_data + $80); print "^Byte form, nonexistent byte: "; @scan_table $100 tables_data 256 $01 -> val ?bad_scan_table; check(val, 0); print "^Longer form, first word: "; @scan_table $0001 tables_data 64 $84 -> val ?~bad_scan_table; check(val, tables_data); print "^Longer form, another word: "; @scan_table $8081 tables_data 64 $84 -> val ?~bad_scan_table; check(val, tables_data + $80); print "^Longer form, a word which will be skipped: "; @scan_table $0203 tables_data 64 $84 -> val ?bad_scan_table; check(val, 0); print "^Longer byte form, first byte: "; @scan_table $00 tables_data 64 $04 -> val ?~bad_scan_table; check(val, tables_data); print "^Longer byte form, another byte: "; @scan_table $80 tables_data 64 $04 -> val ?~bad_scan_table; check(val, tables_data + $80); print "^Longer byte form, a byte which will be skipped: "; @scan_table $02 tables_data 64 $04 -> val ?bad_scan_table; check(val, 0); print "^Default form, word after length of table: "; @scan_table $8081 tables_data 63 -> val ?bad_scan_table; check(val, 0); print "^Longer form, word after length of table: "; @scan_table $8081 tables_data 31 $84 -> val ?bad_scan_table; check(val, 0); .copy_table; print "^^@@64copy_table:^"; print "Copying forward, non-overlapping.^"; val = tables_data + $10; @copy_table tables_data val 8; val2 = copy_table_reference + $10; check_array( val, val2, 16, Copytableprint ); print "Copying backwards, non-overlapping.^"; val = tables_data + $20; val2 = tables_data + $30; @copy_table val2 val 8; val2 = copy_table_reference + $20; check_array( val, val2, 16, Copytableprint ); print "Copying forward, overlapping, non-corrupting.^"; val = tables_data + $40; val2 = tables_data + $44; @copy_table val val2 8; val2 = copy_table_reference + $40; check_array( val, val2, 16, Copytableprint ); print "Copying backward, overlapping, non-corrupting.^"; val = tables_data + $50; val2 = tables_data + $54; @copy_table val2 val 8; val2 = copy_table_reference + $50; check_array( val, val2, 16, Copytableprint ); print "Copying forward, overlapping, corrupting.^"; val = tables_data + $60; val2 = tables_data + $64; @copy_table val val2 (-8); val2 = copy_table_reference + $60; check_array( val, val2, 16, Copytableprint ); print "Using @@64copy_table to zero out an array.^"; val = tables_data + $70; @copy_table val 0 8; val2 = copy_table_reference + $70; check_array( val, val2, 16, Copytableprint ); val = failures; print "Checking final table (failures are not counted twice).^"; check_array( tables_data, copy_table_reference, 128, Copytableprint ); failures = val; count_failures(); return; .bad_scan_table; print "^Bad @@64scan_table branch."; failures++; jump copy_table; ]; [ Copytableprint ch ix; print "Mismatch for index ", ix, ": "; ]; TestClass specfixes with name 'specfixes' 'fixes', testfunc [ val ; print "Z-Machine 1.1 Updates/Clarifications:^^"; ! Operand evalution ! Opcode operands are always evaluated from first to last print "Operand evalution: "; @push 2; @push 4; @sub sp sp -> val; print "4-2="; check(val, 2); print "^"; ! Indirect variable references ! An indirect reference to the stack pointer does not push or pull the top item of the stack - it is read or written in place. print "Indirect variable references:^"; @push 9; @push 5; @dec sp; @pull val; @pull val; print "@@64dec: guard="; check(val, 9); print "^"; @push 9; @push 7; @dec_chk sp 2 ?jumpfail; @pull val; @pull val; print "@@64dec_chk: guard="; check(val, 9); print "^"; @push 9; @push 5; @inc sp; @pull val; @pull val; print "@@64inc: guard="; check(val, 9); print "^"; @push 9; @push 2; @inc_chk sp 7 ?jumpfail; @pull val; @pull val; print "@@64inc_chk: guard="; check(val, 9); print "^"; ! Push an extra value in case @load fails - we don't want a stack underflow @push 1; @push 9; @load sp -> val; @pull val; print "@@64load: guard="; check(val, 9); print "^"; @push 9; @pull sp; @pull val; print "@@64pull: guard="; check(val, 9); print "^"; @push 9; @push 1; @store sp 2; @pull val; @pull val; print "@@64store: guard="; check(val, 9); print "^"; ! @je ! @je can take between 2 and 4 operands. print "@@64je operands: "; val = 1; @je 1 0 1 ?je1; val = 0; .je1; print "3: "; check(val, 1); val = 1; @je 1 0 0 1 ?je2; val = 0; .je2; print ", 4: "; check(val, 1); print "^"; ! @get_prop_len ! @get_prop_len 0 must return 0. val = 1; print "@@64get_prop_len 0: "; @get_prop_len 0 -> val; check(val, 0); print "^"; !### @set_cursor !### @output_stream !### Mouse !### Sound count_failures(); return; .jumpfail; failures++; count_failures(); ]; Array basic_color_set --> $0000 $001D $0340 $03BD $59A0 $7C1F $77A0 $7FFF $5AD6 $4631 $2D6B; Array rainbow_set --> $001f $007f $00bf $00ff $013f $019f $01df $023f $027f $02bf $02ff $035f $039f $03df $03fd $03fb $03f9 $03f6 $03f4 $03f2 $03ef $03ed $03eb $03e8 $03e6 $03e4 $03e1 $07e0 $0fe0 $1be0 $23e0 $2be0 $33e0 $3fe0 $47e0 $53e0 $5be0 $63e0 $6be0 $77e0 $7fe0 $7f80 $7f40 $7f00 $7ec0 $7e60 $7e20 $7dc0 $7d80 $7d40 $7d00 $7ca0 $7c60 $7c00 $7c01 $7c04 $7c06 $7c09 $7c0b $7c0d $7c0f $7c12 $7c14 $7c17 $7c19 $7c1b $7c1d $781f $701f $641f $5c1f $541f $4c1f $401f $381f $2c1f $241f $1c1f $141f $081f; TestClass spec11 with name 'spec11', testfunc [ i val; print "Z-Machine 1.1 tests:^^"; ! Check we're in a 1.1 version interpreter val = HDR_SPECREVISION-->0; if (val < $0101) { print "Stopping, interpreter is only version "; Version(); print ".^"; return; } print "Ok, interpreter is version "; Version(); print ".^^"; ! Test @set_true_colour by printing a rainbow print "Checking @@64set_true_colour by printing a pretty rainbow (ultimate prettiness of rainbow depends on the observer's tastes):^^"; @set_text_style 8; for (i=0 : i<80 : i++) { val = rainbow_set-->i; @"EXT:13" -1 val; print " "; } @set_colour 1 1; @set_text_style 0; print "^^"; ! Check the recommended colour set print "Checking if the basic colour set uses the recommended true colours:^^"; @set_text_style 8; print "Recommended: "; for (i=0 : i<11 : i++) { val = basic_color_set-->i; @"EXT:13" -1 val; print " "; } @set_colour 1 1; print "^Interpreter: "; for (i=2 : i<13 : i++) { @set_colour 1 i; print " "; } @set_colour 1 1; @set_text_style 0; print "^"; !count_failures(); return; ]; TestClass gestalt with name 'spec12' 'gestalt', testfunc [ val ; print "Z-Machine 1.2 (@@64gestalt):^^"; ! Check we're in a 1.2 version interpreter val = HDR_SPECREVISION-->0; if (val < $0102) { print "Stopping, interpreter is only version "; Version(); print ".^"; return; } print "Ok, interpreter is version "; Version(); print ".^^"; ! Checking non-existant selector @"EXT:30S" 0 0 -> val; print "Selector 0 (non-existant): 0="; check(val, 0); print "^"; ! Checking Standard Revision selector @"EXT:30S" 1 0 -> val; print "Selector 1 (Standard Revision): $0102<= "; check_hex_min(val, $0102); print "^"; count_failures(); return; ];