diff --git a/rules.mak b/rules.mak index bff91d3..b01b740 100644 --- a/rules.mak +++ b/rules.mak @@ -43,6 +43,19 @@ clean: $(Q)rm -f $(TESTS_ATB) $(Q)rm -f $(TESTS_LBL) $(Q)rm -f $(TESTS_STAMP) + $(Q)if [ -d build/tests ]; then \ + for manifest in build/tests/.fbtest-manifest-*; do \ + [ -f "$$manifest" ] || continue; \ + while read -r kind path; do \ + case "$$kind" in \ + F) rm -f "$$path" ;; \ + D) rmdir "$$path" 2>/dev/null || true ;; \ + esac; \ + done < "$$manifest"; \ + rm -f "$$manifest"; \ + done; \ + fi + $(Q)rmdir build/tests 2>/dev/null || true $(Q)rm -f $(RUNTEST_OBJS) $(RUNTEST) $(RUNTEST_OBJS:.o=.d) .PHONY: distclean diff --git a/tests.mak b/tests.mak index 94870ce..031d8e0 100644 --- a/tests.mak +++ b/tests.mak @@ -26,6 +26,7 @@ MINI65_SRC=\ atari.c\ ataridos.c\ atcio.c\ + atedit.c\ atsio.c\ dosfname.c\ hw.c\ @@ -37,6 +38,8 @@ TESTS := $(sort $(wildcard testsuite/tests/*.chk)) # The tests need to be rerun if any of this files change: TESTS_DEPS=\ + build/bin/fb.xex\ + build/bin/fbi.xex\ build/bin/fbc.xex\ build/bin/fbci.xex\ build/bin/fastbasic$(HOST_EXT)\ @@ -58,7 +61,10 @@ RUNTEST_OBJS=build/obj/tests/fbtest.o $(MINI65_SRC:%.c=build/obj/tests/%.o) .PHONY: test test: $(TESTS_STAMP) $(RUNTEST) -build/tests/%.stamp: testsuite/tests/%.chk testsuite/tests/%.bas $(RUNTEST) $(TESTS_DEPS) | build/tests +.SECONDEXPANSION: +build/tests/%.stamp: testsuite/tests/%.chk $$(wildcard testsuite/tests/$$*.bas) \ + $(wildcard testsuite/tests/fixtures/*) \ + $(RUNTEST) $(TESTS_DEPS) | build/tests $(Q)$(RUNTEST) $< @touch $@ diff --git a/testsuite/README.md b/testsuite/README.md index b1122a5..94c027f 100644 --- a/testsuite/README.md +++ b/testsuite/README.md @@ -1,6 +1,262 @@ FastBasic test suite --------------------- +==================== -To run the testsuite, you need "git" to download the 6502 simulator and type -`make test` from the parent directory. +To run the testsuite, you need `git` to download the 6502 simulator and type +`make test` from the parent directory. To run a single test: + build/bin/fbtest testsuite/tests/.chk + + +File format +----------- + +Normal tests are a pair of files: `tests/.chk` (the test definition) +and `tests/.bas` (the source program). + +Editor tests (`Test: editor`) are different: the `.chk` file is +self-contained and **no `.bas` file is needed**. The initial editor buffer is +declared explicitly with the `Document:` key, so the same `.bas` file is never +silently used as both program source and editor buffer. + +The `.chk` file is a sequence of `Key: value` lines, followed by multi-line +sections terminated by a line containing only `.`. Lines starting with `#` in +the header are comments. Recognised keys: + +| Key | Value | +|:----------------|:---------------------------------------------------------------| +| `Name:` | Human-readable test name (shown in pass/fail output). | +| `Test:` | comma/space/hyphen separated list of test modifiers (below). | +| `Max-cycles:` | Cycle limit for the simulator (default 20 000 000). | +| `Error:` | Expected compiler error message (for `error` tests). | +| `Error-pos:` | Expected error location as `line : column`. | +| `Document:` | Editor tests only: initial document (see below). | +| `Input:` | Keystrokes fed to the running program (section, terminated by `.`). | +| `Output:` | Expected captured output stream (rest of file, exact match). | +| `Screen:` | Expected screen state, up to 24 lines of up to 40 chars (section). | +| `Cursor:` | Expected cursor position as `row,col` (editor tests, from ROWCRS/COLCRS). | +| `Expect-out:` | Substring that must appear in the captured output. | +| `Exists:` | Filename that must exist after the run (in the test's DOS root).| +| `Check :` | Section with expected content of a file written during the run.| +| `Files:` | Filenames to copy into the DOS root before the run (section). | + +### Test modifiers (`Test:`) + +| Modifier | Meaning | +|:----------|:--------------------------------------------------------------| +| `run` | Compile as XEX and run under mini65 (default for most tests). | +| `fp` | Use the floating-point compiler (default). | +| `int` | Use the integer compiler. | +| `cross` | Cross-compile (build/bin/fastbasic). | +| `native` | Native compile (build/bin/fbc / fbci). | +| `compile` | Compile only, do not run. | +| `error` | Expect a compile error; `Error:` gives the message. | +| `editor` | Run the IDE (fb.xex) with a keystroke script. Implies `fp`. | + +Multiple modifiers can be combined: `Test: run, int` runs the integer +compiler, `Test: cross, compile` cross-compiles without running. + +When neither `cross` nor `native` is given, both are used. When neither `fp` +nor `int` is given, both are used. A single test may be compiled and run up to +six ways: native FP/INT and cross FP/INT, each as XEX and cart ROM. + + +Input notation +-------------- + +The `Input:` section supports readable notation for control and special +characters. All other bytes pass through literally (newlines in the file are +converted to ATASCII EOL `$9B`). + +| Notation | Maps to | +|:-------------|:------------------------------------------------------| +| `^A` .. `^Z` | Ctrl-A (`$01`) .. Ctrl-Z (`$1A`). Case-insensitive. | +| `` | Escape (`$1B`). | +| `` | Cursor up (`$1C`). | +| `` | Cursor down (`$1D`). | +| `` | Cursor left (`$1E`). | +| `` | Cursor right (`$1F`). | +| `` | Return / ATASCII EOL (`$9B`). | +| `` | Clear screen (`$7D`). | +| `` | Backspace (`$7E`). | +| `` | Tab (`$7F`). | +| `` | Delete line (`$9C`). | +| `` | Insert line (`$9D`). | +| `` | Clear tab stop (`$9E`). | +| `` | Set tab stop (`$9F`). | +| `` | Bell (`$FD`). | +| `` | Delete character at cursor (`$FE`). | +| `` | Insert character at cursor (`$FF`). | +| `\xHH` | Explicit hex byte (e.g. `\x9B` for ATASCII EOL). | +| UTF-8 chars | Multi-byte UTF-8 sequences from the ATASCII character set (e.g. `⇱` for CLS, `▄` for block graphic, `𝗔` for inverse A). | + +Example — the following types "HELLO", runs the program, saves as +`T2.XEX` and quits: + + Input: + HELLO + ^R ^WT2.XEX + ^Q^C + . + +For normal (non-editor) tests, every line break in `Input:` is passed to the +program. In editor tests, the line break immediately before the terminating +`.` is treated as a section separator, not as a RETURN key press. Use an +`` or an empty line before `.` when the script needs a final +RETURN. + + +Editor tests +------------ + +Editor tests (`Test: editor`) run the FastBasic IDE (`fb.xex`) under the +mini65 simulator with a scripted keystroke sequence. + +### Initial document + +The IDE opens `D:HELP.TXT` on startup, and that file is the initial editor +buffer. The `Document:` key describes how to create it: + + Document: none + +creates an empty `HELP.TXT`. This is the default when `Document:` is omitted. + + Document: + ' split test + . + +uses the lines between `Document:` and `.` as the initial document. Lines +are converted from LF to ATASCII EOL. The newline before the final `.` is not +part of the document; add an empty line before `.` if the document must end +with an EOL. + + Document: fixtures/lines33.txt + +copies an ASCII fixture from the test directory, converting LF to ATASCII. +Fixtures are read-only and are never modified by a test. + +`Document:` is only valid for editor tests. + +### Per-test DOS root + +Every editor test runs with its own emulated `D:` root: + + build/tests// + +`HELP.TXT`, files from `Files:`, files written by the IDE, and the targets of +`Check:` and `Exists:` all live in that directory. The harness creates the +directory and removes known output files before each run, so `Exists:` cannot +pass because of a file left by an earlier run. + +All generated files stay under `build/`. Tests never write into +`testsuite/tests/`. + +### EOF termination + +When the `Input:` feeder is exhausted, `str_get_char()` returns EOF and the +simulator's cycle limit is set to 1, causing it to stop on the next cycle +check. This avoids wasting cycles waiting for more input when the editor is +idle. This only applies to editor tests (the `str_stop_on_eof` flag); regular +tests are not affected. + + +Screen assertions +----------------- + +The `Screen:` section allows editor tests to check the final state of the +emulated 24×40 text screen. It contains up to 24 lines, each up to 40 +characters, terminated by a line with only `.`. + +Trailing spaces on each line are trimmed before comparison. The screen is +read after the simulation ends and compared byte-exactly against the expected +content — the ATASCII inverse bit (`$80`) and all control characters are +preserved. Notation is expanded in expected lines, so you can use `\x92` for +inverse space, `` for `$7D`, UTF-8 characters like `𝗔` for inverse A, etc. + +When a comparison fails, the actual screen row is also printed using UTF-8 +characters with ANSI inverse-video escapes, so you can visually see what the +Atari screen looks like. + +A `Cursor: row,col` line asserts the cursor position after the run; coordinates +are zero-based and are read from the emulated `ROWCRS` and `COLCRS` OS +variables. This complements the cursor glyph in `Screen:` and is useful for +navigation tests. + +The simulation is terminated when the input feeder reaches EOF, so the screen +snapshot captures the state at that point. + +### Cursor rendering + +The real Atari OS renders the cursor by XOR'ing `$80` at the cursor position +(`CRSINH`/`OLDCHR` mechanism). The mini65 screen accessor includes the visible +cursor glyph, so the test harness reads the screen buffer directly and does +**not** invert the cursor cell again. Goldens must account for the cursor +glyph — e.g., a normal space (`$20`) at the cursor position becomes inverse +space (`$A0`). + +### Last-column and wrap markers + +The editor writes continuation markers in the last column of a wrapped +logical line. Tests must not write to (23, 39) unless they intend to trigger +a scroll, and screen goldens must include these marker cells when a line +overflows. + +### Screen state after quit + +If the editor quits (Ctrl-Q Ctrl-C), the screen is typically cleared. +`Screen:` assertions are meaningful only while the editor is still running +(e.g. after typing text or running a program). Do not assert the post-quit +screen. + + +Debugging +--------- + +Set environment variables before running `make test` or `build/bin/fbtest`: + +| Variable | Effect | +|:-----------------|:-------------------------------------------------------------| +| `FBTEST_DEBUG` | Enable sim65 debug messages (CIO activity, device I/O). | +| `FB_DUMP_SCREEN` | Write the final 24×40 screen as raw ATASCII bytes to `build/tests/.screen`. | +| `FB_DUMP_OUTPUT` | Write the captured output stream to `build/tests/.output`. | + +Example: + + FBTEST_DEBUG=1 FB_DUMP_SCREEN=1 \ + build/bin/fbtest testsuite/tests/ed-assert.chk + +Both dump variables are switches; the files are always written under +`build/tests/`. + + +Cleanup +------- + +Each test writes a cleanup manifest derived from its `.chk` declarations: + + build/tests/.fbtest-manifest- + +For editor tests the manifest contains `HELP.TXT` (from `Document:`), every +`Files:` copy, every `Check:` and `Exists:` file, and the test directory. For +normal tests it contains the `Check:` and `Exists:` files. The opt-in +`.screen` / `.output` debug dumps are also listed. + +`make clean` reads those manifests and removes only the listed files. +Editor test directories are removed with `rmdir`, so a directory that still +contains user files is left in place. Manifests are written in binary mode so +the same cleanup works on Windows with the MSYS shell tools used by the rest of +the Makefile. + +Every file written by a test must therefore be declared with `Document:`, +`Files:`, `Check:`, or `Exists:`. + + +Architecture +------------ + +- `testsuite/src/fbtest.c` — the test harness (compilation, execution, + output comparison, screen assertions, notation expansion). +- `testsuite/mini65/` — the mini65 6502 simulator with Atari BIOS + emulation (submodule). +- `testsuite/tests/*.chk` — test definitions. +- `testsuite/tests/*.bas` — source programs for non-editor tests. +- `testsuite/tests/fixtures/` — shared read-only editor documents. diff --git a/testsuite/mini65 b/testsuite/mini65 index 30b85d1..8d20189 160000 --- a/testsuite/mini65 +++ b/testsuite/mini65 @@ -1 +1 @@ -Subproject commit 30b85d1ee940b546ca7b5737be371ff6c7f99ed1 +Subproject commit 8d20189a87e9e23b70b2a991adbfecfa723f2e79 diff --git a/testsuite/src/fbtest.c b/testsuite/src/fbtest.c index 2e49031..2a9cf50 100644 --- a/testsuite/src/fbtest.c +++ b/testsuite/src/fbtest.c @@ -21,30 +21,44 @@ #define _GNU_SOURCE // for asprintf #include "atari.h" #include "sim65.h" +#include "atcio.h" #include #include #include #include +#include #include #ifdef _WIN32 +# include +# define MKDIR(path) _mkdir(path) # define PATH_SEP "\\" -// Implement missing "strndup" -static char *strndup(const char *s, size_t n) -{ - char *ret = malloc(n + 1); - strncpy(ret, s, n); - ret[n] = 0; - return ret; -}; #else +# define MKDIR(path) mkdir(path, 0777) # define PATH_SEP "/" #endif +// Private strndup replacement: avoid conflicting with libc/POSIX strndup, +// which newer MinGW headers now declare. +static char *xstrndup(const char *s, size_t n) +{ + size_t len = 0; + while (len < n && s[len]) + len++; + char *ret = malloc(len + 1); + if (!ret) + return NULL; + memcpy(ret, s, len); + ret[len] = 0; + return ret; +} + // Flags static int verbose; static const char *fb_atari_comp_int = "build/bin/fbci.xex"; static const char *fb_atari_comp_fp = "build/bin/fbc.xex"; +static const char *fb_atari_ide_int = "build/bin/fbi.xex"; +static const char *fb_atari_ide_fp = "build/bin/fb.xex"; static const char *fb_compiler = "build" PATH_SEP "bin" PATH_SEP "fastbasic"; static const char *ca65_path = "build" PATH_SEP "bin" PATH_SEP "ca65"; static const char *ld65_path = "build" PATH_SEP "bin" PATH_SEP "ld65"; @@ -69,6 +83,9 @@ static const char *output_dir = "build/tests"; static size_t str_out_pos, str_out_len, str_in_pos, str_in_len; static char *str_out; static const char *str_in; +static sim65 str_s; +static int str_stop_on_eof; +static int input_eof; static void str_put_char(int c) { if (c == 0x9b) @@ -83,14 +100,76 @@ static int str_get_char(void) { if (str_in_pos < str_in_len) return 0xFF & str_in[str_in_pos++]; - else - return EOF; + // Input exhausted + input_eof = 1; + if (str_stop_on_eof) + sim65_set_cycle_limit(str_s, 1); + return EOF; +} + +// ATASCII→UTF-8 table for visual screen diagnostics. +// Adapted from conv-atascii-utf8.c — indexed by ATASCII byte value. +static const char *const atascii_utf8[256] = { + "♥", "├", "🮇", "┘", "┤", "┐", "╱", "╲", + "◢", "▗", "◣", "▝", "▘", "🮂", "▂", "▖", + "♣", "┌", "─", "┼", "●", "▄", "▎", "┬", + "┴", "▌", "└", "␛", "↑", "↓", "←", "→", + " ", "!", "\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "0", "1", "2", "3", "4", "5", "6", "7", + "8", "9", ":", ";", "<", "=", ">", "?", + "@", "A", "B", "C", "D", "E", "F", "G", + "H", "I", "J", "K", "L", "M", "N", "O", + "P", "Q", "R", "S", "T", "U", "V", "W", + "X", "Y", "Z", "[", "\\", "]", "^", "_", + "♦", "a", "b", "c", "d", "e", "f", "g", + "h", "i", "j", "k", "l", "m", "n", "o", + "p", "q", "r", "s", "t", "u", "v", "w", + "x", "y", "z", "♠", "|", "⇱", "◀", "▶", + "♥", "┣", "▊", "┛", "┫", "┓", "╱", "╲", + "◤", "▛", "◥", "▙", "▟", "▆", "🮅", "▜", + "♣", "┏", "━", "╋", "●", "▀", "🮊", "┳", + "┻", "▐", "┗", "\n", "⇑", "⇓", "⇐", "⇒", + "█", "!", "\"", "#", "$", "%", "&", "'", + "(", ")", "*", "+", ",", "-", ".", "/", + "𝟬", "𝟭", "𝟮", "𝟯", "𝟰", "𝟱", "𝟲", "𝟳", + "𝟴", "𝟵", ":", ";", "<", "=", ">", "?", + "@", "𝗔", "𝗕", "𝗖", "𝗗", "𝗘", "𝗙", "𝗚", + "𝗛", "𝗜", "𝗝", "𝗞", "𝗟", "𝗠", "𝗡", "𝗢", + "𝗣", "𝗤", "𝗥", "𝗦", "𝗧", "𝗨", "𝗩", "𝗪", + "𝗫", "𝗬", "𝗭", "[", "\\", "]", "^", "_", + "♦", "𝗮", "𝗯", "𝗰", "𝗱", "𝗲", "𝗳", "𝗴", + "𝗵", "𝗶", "𝗷", "𝗸", "𝗹", "𝗺", "𝗻", "𝗼", + "𝗽", "𝗾", "𝗿", "𝘀", "𝘁", "𝘂", "𝘃", "𝘄", + "𝘅", "𝘆", "𝘇", "♠", "|", "⇱", "◀", "▶" +}; + +// Print one screen row as UTF-8 with ANSI inverse-video escapes. +// atari_screen_get() already contains the visible cursor glyph, so the +// character must not be inverted again here. +static void print_screen_row_utf8(FILE *fp, int row) +{ + int inv = 0; + for (int c = 0; c < 40; c++) + { + int ch = atari_screen_get(row, c); + int is_inv = ch & 0x80; + if (is_inv != inv) + { + fputs(inv ? "\033[27m" : "\033[7m", fp); + inv = is_inv; + } + fputs(atascii_utf8[ch & 0x7F], fp); + } + if (inv) + fputs("\033[27m", fp); } // Runs atari XEX file capturing the output static int run_atari_prog(const char *progname, char *output, size_t *output_len, const char *input, size_t input_len, uint64_t max_cycles, - int is_rom, const char *cmdline) + int is_rom, const char *cmdline, int fix_margins, + const char *dos_root, int *out_row, int *out_col) { // Init input/output str_in = input; @@ -100,11 +179,17 @@ static int run_atari_prog(const char *progname, char *output, size_t *output_len str_out_pos = 0; str_out_len = *output_len - 1; memset(str_out, 0, *output_len); + input_eof = 0; // Init emulator sim65 s = sim65_new(); if (!s) return -1; + // NOTE: never enable full instruction tracing here, a single run can + // log billions of lines and fill the disk. // sim65_set_debug(s, sim65_debug_trace); + if (getenv("FBTEST_DEBUG")) + // Log CIO and device activity, useful to debug editor scripts + sim65_set_debug(s, sim65_debug_messages); emu_options opts = { .get_char = str_get_char, .put_char = str_put_char, .flags = atari_opt_cycletime }; @@ -114,18 +199,27 @@ static int run_atari_prog(const char *progname, char *output, size_t *output_len if (cmdline) atari_dos_add_cmdline(s, cmdline); // Set DOS path - atari_dos_set_root(s, output_dir); - // Use 0 as left-margin value, to normalize results - unsigned char val = 0; - sim65_add_data_ram(s, 0x52, &val, 1); // LMARGN - sim65_add_data_ram(s, 0x55, &val, 1); // COLCRS + atari_dos_set_root(s, dos_root ? dos_root : output_dir); + // Use 0 as left-margin value, to normalize results. This is not + // done when running the IDE, that expects the default margins. + if (fix_margins) + { + unsigned char val = 0; + sim65_add_data_ram(s, 0x52, &val, 1); // LMARGN + sim65_add_data_ram(s, 0x55, &val, 1); // COLCRS + } sim65_set_cycle_limit(s, max_cycles); + str_s = s; enum sim65_error e; if( is_rom ) e = atari_rom_load(s, 0xA000, progname); else e = atari_xex_load(s, progname, 1); + str_s = NULL; + // Cycle limit hit after input exhausted is the normal editor exit path + if (e == sim65_err_cycle_limit && str_stop_on_eof && input_eof) + e = sim65_err_none; if (e == sim65_err_user) { fprintf(stderr, "%s: error reading XEX/ROM file\n", progname); @@ -144,6 +238,12 @@ static int run_atari_prog(const char *progname, char *output, size_t *output_len // TODO: this should depend on actual compiled value, we currently expect the // value to be constant. int x = 0x28 != (sim65_get_byte(s, 0x8E) & 0xFF); + // Read the OS cursor variables before freeing the simulator. + if (out_row) + *out_row = sim65_get_byte(s, ROWCRS); + if (out_col) + *out_col = sim65_get_byte(s, COLCRS) | + (sim65_get_byte(s, COLCRS + 1) << 8); // Update output length *output_len = str_out_pos; free(s); @@ -153,6 +253,30 @@ static int run_atari_prog(const char *progname, char *output, size_t *output_len return x; } +// Checks that the captured output matches the expected output +static int check_output(const char *fname, const char *expected_out, const char *out) +{ + if (!strcmp(expected_out, out)) + return 0; + size_t l = 0; + for (l = 0; out[l] == expected_out[l] && out[l]; l++); + + size_t l1 = l > 20 ? l - 20 : 0; + size_t l2 = l + 20; + fprintf(stderr, "%s: output does not match:\n", fname); + fprintf(stderr, "expected: "); + for(const char *x = expected_out + l1; x<(expected_out+l2) && *x; x++) + putc(*x > 31 && *x < 127 ? *x : '.', stderr); + fprintf(stderr, "\ngot: "); + for(const char *x = out + l1; x<(out+l2) && *x; x++) + putc(*x > 31 && *x < 127 ? *x : '.', stderr); + fprintf(stderr, "\n "); + for(size_t x = l1; x 20 ? l - 20 : 0; - size_t l2 = l + 20; - fprintf(stderr, "%s: output does not match:\n", fname); - fprintf(stderr, "expected: "); - for(const char *x = expected_out + l1; x<(expected_out+l2) && *x; x++) - putc(*x > 31 && *x < 127 ? *x : '.', stderr); - fprintf(stderr, "\ngot: "); - for(const char *x = out + l1; x<(out+l2) && *x; x++) - putc(*x > 31 && *x < 127 ? *x : '.', stderr); - fprintf(stderr, "\n "); - for(size_t x = l1; x 0) fprintf(stderr,"%s: unexpected stack value.\n", fname); @@ -193,6 +298,154 @@ int run_test_xex(const char *fname, const char *input, const char *expected_out, return e; } +// Copies a file from the test directory into a DOS root, converting to +// ATASCII. The destination is always under build/. +static int atascii_convert(const char *infile, const char *outfile); +static int copy_fixture_to(const char *srcdir, const char *name, const char *dst) +{ + char *src; + if (asprintf(&src, "%s/%s", srcdir, name) < 0) + return -1; + int e = atascii_convert(src, dst); + free(src); + return e; +} + +static int dos_copy_file(const char *srcdir, const char *name, const char *dstdir) +{ + char *dst; + if (asprintf(&dst, "%s/%s", dstdir, name) < 0) + return -1; + int e = copy_fixture_to(srcdir, name, dst); + free(dst); + return e; +} + +// Removes a file from a directory, ignoring errors. +static void unlink_in(const char *dir, const char *name) +{ + char *path; + if (asprintf(&path, "%s/%s", dir, name) >= 0) + { + unlink(path); + free(path); + } +} + +// A manifest lists the paths created by one test. make clean reads these +// manifests and removes only the listed files; directories are removed with +// rmdir, so user files left in a test directory are preserved. +static FILE *manifest_open(const char *tag_name) +{ + char *path; + if (asprintf(&path, "%s/.fbtest-manifest-%s", output_dir, tag_name) < 0) + return NULL; + FILE *f = fopen(path, "wb"); + free(path); + return f; +} + +static void manifest_add(FILE *f, char kind, const char *path) +{ + fprintf(f, "%c %s\n", kind, path); +} + +static void manifest_add_file(FILE *f, const char *dir, const char *name) +{ + char *path; + if (asprintf(&path, "%s/%s", dir, name) >= 0) + { + manifest_add(f, 'F', path); + free(path); + } +} + +// Debug dumps use fixed names derived from the test tag. +static void manifest_add_debug(FILE *f, const char *tag_name) +{ + char *path; + if (asprintf(&path, "%s/%s.screen", output_dir, tag_name) >= 0) + { + manifest_add(f, 'F', path); + free(path); + } + if (asprintf(&path, "%s/%s.output", output_dir, tag_name) >= 0) + { + manifest_add(f, 'F', path); + free(path); + } +} + +struct file_check +{ + char *name; + char *data; + size_t len; +}; + +// Checks Check:/Exists: files in the given DOS root. +static int check_test_files(const char *fname, const char *dir, + const struct file_check *checks, int nchecks, + char **exists, int nexists) +{ + for (int i = 0; i < nchecks; i++) + { + char *path; + if (asprintf(&path, "%s/%s", dir, checks[i].name) < 0) + exit(1); + FILE *fc = fopen(path, "rb"); + free(path); + char *got = 0; + size_t rlen = 0; + if (fc) + { + fseek(fc, 0, SEEK_END); + long sz = ftell(fc); + fseek(fc, 0, SEEK_SET); + got = calloc(sz + 1, 1); + rlen = fread(got, 1, sz, fc); + fclose(fc); + } + if (!got) + { + fprintf(stderr, "%s: can't open checked file '%s'.\n", + fname, checks[i].name); + return -1; + } + else if (rlen != checks[i].len || memcmp(got, checks[i].data, rlen)) + { + size_t d = 0; + while (d < rlen && d < checks[i].len && + got[d] == checks[i].data[d]) + d++; + fprintf(stderr, + "%s: file '%s' does not match: %lu bytes vs %lu " + "expected, first difference at byte %lu.\n", + fname, checks[i].name, (unsigned long)rlen, + (unsigned long)checks[i].len, (unsigned long)d); + free(got); + return -1; + } + free(got); + } + + for (int i = 0; i < nexists; i++) + { + char *path; + if (asprintf(&path, "%s/%s", dir, exists[i]) < 0) + exit(1); + FILE *fx = fopen(path, "rb"); + free(path); + if (!fx) + { + fprintf(stderr, "%s: file '%s' not created.\n", fname, exists[i]); + return -1; + } + fclose(fx); + } + return 0; +} + // Converts ASCII file to ATASCII static int atascii_convert(const char *infile, const char *outfile) { @@ -237,7 +490,7 @@ static int compile_native(const char *atbname, const char *xexname, const char * sprintf(cmd, "%s %s", atbname, xexname); else sprintf(cmd, "%s %s", atbname + l, xexname + l); - int e = run_atari_prog(compiler, out, &len, 0, 0, MAX_FPC_CYCLES, 0, cmd); + int e = run_atari_prog(compiler, out, &len, 0, 0, MAX_FPC_CYCLES, 0, cmd, 1, NULL, NULL, NULL); if (e) fprintf(stderr, "%s: can't execute compiler.\n", compiler); @@ -429,9 +682,158 @@ enum tests { test_int = 4, test_cross = 8, test_native = 16, - test_compile_error = 32 + test_compile_error = 32, + test_editor = 64 +}; + +// Initial document specification for editor tests. +enum document_kind { + doc_default = 0, // no Document: key, start with an empty file + doc_none, + doc_inline, + doc_file }; +// Expands control-key, named-key, and UTF-8 notation in an input buffer. +// ^X (0x41-0x5A) -> Ctrl-A..Z ($01-$1A) +// -> single byte from the Atari special-character table +// \xHH -> hex byte +// UTF-8 multi-byte sequences -> ATASCII byte from atascii_utf8 table +// All other bytes pass through literally. +// Returns a malloc'ed buffer; caller must free the original. +static char *expand_notation(char *input, size_t *len_out) +{ + static const struct { const char *name; int code; } keys[] = { + { "ESC", 0x1B }, { "UP", 0x1C }, { "DOWN", 0x1D }, + { "LEFT", 0x1E }, { "RIGHT", 0x1F }, { "RETURN", 0x9B }, + { "CLS", 0x7D }, + { "BACKSP", 0x7E }, { "TAB", 0x7F }, { "DELLN", 0x9C }, + { "INSLN", 0x9D }, { "DELTAB", 0x9E }, { "SETTAB", 0x9F }, + { "BELL", 0xFD }, { "DEL", 0xFE }, { "INS", 0xFF }, + { NULL, 0 } + }; + size_t in_len = strlen(input); + char *out = malloc(in_len + 1); + size_t oi = 0; + for (size_t i = 0; i < in_len; ) + { + unsigned char c = (unsigned char)input[i]; + if (c == '^' && i + 1 < in_len) + { + unsigned char next = (unsigned char)input[i + 1]; + if (next >= 'A' && next <= 'Z') + { + out[oi++] = next - 'A' + 1; + i += 2; + continue; + } + if (next >= 'a' && next <= 'z') + { + out[oi++] = next - 'a' + 1; + i += 2; + continue; + } + } + if (c == '<') + { + size_t j = i + 1; + while (j < in_len && input[j] != '>') + j++; + if (j < in_len) + { + size_t nlen = j - i - 1; + for (int k = 0; keys[k].name; k++) + { + if (strlen(keys[k].name) == nlen && + !strncasecmp(input + i + 1, keys[k].name, nlen)) + { + out[oi++] = (unsigned char)keys[k].code; + i = j + 1; + goto next; + } + } + } + } + if (c == '\\' && i + 3 < in_len && input[i + 1] == 'x') + { + int hi = -1, lo = -1; + unsigned char h = (unsigned char)input[i + 2]; + unsigned char l = (unsigned char)input[i + 3]; + if (h >= '0' && h <= '9') hi = h - '0'; + else if (h >= 'A' && h <= 'F') hi = h - 'A' + 10; + else if (h >= 'a' && h <= 'f') hi = h - 'a' + 10; + if (l >= '0' && l <= '9') lo = l - '0'; + else if (l >= 'A' && l <= 'F') lo = l - 'A' + 10; + else if (l >= 'a' && l <= 'f') lo = l - 'a' + 10; + if (hi >= 0 && lo >= 0) + { + out[oi++] = (unsigned char)(hi * 16 + lo); + i += 4; + continue; + } + } + // UTF-8: scan atascii_utf8 table for a match at current position. + if (c >= 0xC0) + { + for (int k = 0; k < 256; k++) + { + size_t ulen = strlen(atascii_utf8[k]); + if (i + ulen <= in_len && + !memcmp(input + i, atascii_utf8[k], ulen)) + { + out[oi++] = (unsigned char)k; + i += ulen; + goto next; + } + } + } + out[oi++] = c; + i++; + next:; + } + out[oi] = 0; + *len_out = oi; + free(input); + return out; +} + +// Reads a section of lines, terminated by a lone ".", converting newlines +// to ATASCII EOL. Returns a malloc'ed buffer and its size, or NULL if the +// section is unterminated. +static char *read_section(FILE *f, int *line, size_t *len_out) +{ + size_t cap = 4096, size = 0; + char *buf = calloc(cap, 1), lbuf[256]; + while (fgets(lbuf, sizeof(lbuf)-1, f)) + { + (*line)++; + if (!strcmp(lbuf, ".") || !strcmp(lbuf, ".\n")) + { + buf[size] = 0; + *len_out = size; + return buf; + } + size_t l = strlen(lbuf); + if (l && lbuf[l-1] == '\n') + lbuf[l-1] = 0x9B; + while (size + l + 1 > cap) + { + cap *= 2; + char *nb = realloc(buf, cap); + if (!nb) + { + free(buf); + return NULL; + } + buf = nb; + } + memcpy(buf + size, lbuf, l); + size += l; + } + free(buf); + return NULL; +} + // Runs one test from the test-file int fbtest(const char *fname) { @@ -454,6 +856,27 @@ int fbtest(const char *fname) * The expected output, up to the end of the file. */ char *name = 0, *expected_out = 0, *input_buf = 0, *error_data = 0; + char *files[16]; + int nfiles = 0; + // Initial editor document + int doc_kind = doc_default, doc_set = 0; + char *doc_filename = 0, *doc_data = 0; + size_t doc_len = 0; + size_t input_len = 0; + // Expected content of files written during the run + struct file_check checks[16]; + int nchecks = 0; + // Names of files that must exist after the run + char *exists[16]; + int nexists = 0; + // Substrings that must appear in the captured output stream + char *expects[8]; + int nexpects = 0; + // Expected screen content (24 rows of up to 40 cols) + char *expected_screen[24]; + int screen_lines = 0; + // Expected cursor position, read from ROWCRS/COLCRS after the run + int cursor_set = 0, cursor_row = 0, cursor_col = 0; int error_pos_line = 0, error_pos_column = 0; int test = 0, n = 0, line = 0; uint64_t max_cycles = 20000000; @@ -463,8 +886,11 @@ int fbtest(const char *fname) line ++; if ( !*lbuf || *lbuf == '\n' ) continue; + // Header comments + if (lbuf[0] == '#') + continue; - char key[16], buf[256]; + char key[48], buf[256]; n = sscanf(lbuf, "%15[^:]: %255[^\n\r]", key, buf); if (n < 1) { @@ -490,6 +916,9 @@ int fbtest(const char *fname) test = test & ~test_cross; else if (!strcasecmp(tok, "compile")) test = test_cross | test_native | test_fp | test_int; + else if (!strcasecmp(tok, "editor")) + // Runs the IDE; the initial buffer comes from Document: + test = test_editor | test_fp; else if (!strcasecmp(tok, "error")) test |= test_compile_error; else @@ -522,6 +951,167 @@ int fbtest(const char *fname) return -1; } } + else if (!strcasecmp(key, "cursor")) + { + if (cursor_set) + { + fprintf(stderr, "%s:%d: more than one CURSOR entry.\n", fname, line); + return -1; + } + if (2 != sscanf(buf, " %i , %i", &cursor_row, &cursor_col) || + cursor_row < 0 || cursor_row >= 24 || + cursor_col < 0 || cursor_col >= 40) + { + fprintf(stderr, "%s:%d: error, invalid value for CURSOR '%s'\n", + fname, line, buf); + return -1; + } + cursor_set = 1; + } + else if (!strcasecmp(key, "document")) + { + // Initial editor document, only valid for editor tests. + // Document: none start with an empty HELP.TXT + // Document: install an ASCII fixture + // Document: read the inline section below + if (doc_set) + { + fprintf(stderr, "%s:%d: more than one DOCUMENT entry.\n", fname, line); + return -1; + } + doc_set = 1; + if (n < 2 || !*buf) + { + doc_kind = doc_inline; + doc_data = read_section(f, &line, &doc_len); + if (!doc_data) + { + fprintf(stderr, "%s:%d: unfinished DOCUMENT section.\n", fname, line); + return -1; + } + } + else if (!strcasecmp(buf, "none")) + doc_kind = doc_none; + else + { + doc_kind = doc_file; + doc_filename = strdup(buf); + } + } + else if (!strcasecmp(key, "files")) + { + // Files to copy into the DOS root before the run + while ( 0 != fgets(lbuf, sizeof(lbuf)-1, f) ) + { + line ++; + size_t l = strlen(lbuf); + while (l && (lbuf[l-1] == '\n' || lbuf[l-1] == ' ' || lbuf[l-1] == '\t')) + lbuf[--l] = 0; + if (!strcmp(lbuf, ".")) + break; + if (!l || nfiles >= 16) + { + fprintf(stderr, "%s:%d: error, invalid FILES entry\n", fname, line); + return -1; + } + files[nfiles++] = strdup(lbuf); + } + if (feof(f)) + { + fprintf(stderr, "%s:%d: unfinished FILES section.\n", fname, line); + return -1; + } + } + else if (!strcasecmp(key, "check")) + { + // Compare a file written during the session against this content + if (n < 2 || !*buf) + { + fprintf(stderr, "%s:%d: error, missing file name in CHECK\n", fname, line); + return -1; + } + if (nchecks >= 16) + { + fprintf(stderr, "%s:%d: error, too many CHECK sections.\n", fname, line); + return -1; + } + checks[nchecks].name = strdup(buf); + checks[nchecks].data = read_section(f, &line, &checks[nchecks].len); + if (!checks[nchecks].data) + { + fprintf(stderr, "%s:%d: unfinished CHECK section.\n", fname, line); + return -1; + } + nchecks++; + } + else if (!strcasecmp(key, "exists")) + { + if (n < 2 || !*buf) + { + fprintf(stderr, "%s:%d: error, missing file name in EXISTS\n", fname, line); + return -1; + } + if (nexists >= 16) + { + fprintf(stderr, "%s:%d: error, too many EXISTS entries.\n", fname, line); + return -1; + } + exists[nexists++] = strdup(buf); + } + else if (!strcasecmp(key, "expect-out")) + { + if (n < 2 || !*buf) + { + fprintf(stderr, "%s:%d: error, missing text in EXPECT-OUT\n", fname, line); + return -1; + } + if (nexpects >= 8) + { + fprintf(stderr, "%s:%d: error, too many EXPECT-OUT entries.\n", fname, line); + return -1; + } + expects[nexpects++] = strdup(buf); + } + else if (!strcasecmp(key, "screen")) + { + if (screen_lines) + { + fprintf(stderr, "%s:%d: more than one SCREEN section.\n", fname, line); + return -1; + } + if (n > 1 && *buf) + { + fprintf(stderr, "%s:%d: error, extra characters in SCREEN '%s'\n", fname, line, buf); + return -1; + } + while ( 0 != fgets(lbuf, sizeof(lbuf)-1, f) ) + { + line++; + if ( !strcmp(lbuf, ".") || !strcmp(lbuf, ".\n") ) + break; + if (screen_lines >= 24) + { + fprintf(stderr, "%s:%d: error, too many SCREEN lines (max 24).\n", fname, line); + return -1; + } + size_t l = strlen(lbuf); + // Trim trailing newline + if (l && lbuf[l-1] == '\n') + lbuf[--l] = 0; + // Trim trailing spaces + while (l && lbuf[l-1] == ' ') + lbuf[--l] = 0; + // Expand notation + size_t elen; + char *line_buf = expand_notation(strdup(lbuf), &elen); + expected_screen[screen_lines++] = line_buf; + } + if (feof(f)) + { + fprintf(stderr, "%s:%d: unfinished SCREEN section.\n", fname, line); + return -1; + } + } else if (!strcasecmp(key, "input")) { size_t input_size = 0; @@ -557,6 +1147,7 @@ int fbtest(const char *fname) input_size += l; } input_buf[input_size] = 0; + input_len = input_size; if (feof(f)) { fprintf(stderr, "%s:%d: unfinished INPUT section.\n", fname, line); @@ -581,7 +1172,8 @@ int fbtest(const char *fname) free(input_buf); return -1; } - else if(len < 1) + // Editor tests compare the screen and files, not the output + else if (len < 1 && !(test & test_editor)) { fprintf(stderr, "%s: error, no output.\n", fname); free(input_buf); @@ -606,10 +1198,34 @@ int fbtest(const char *fname) } if (!name) name = "unnamed"; + if (doc_set && !(test & test_editor)) + { + fprintf(stderr, "%s: error, DOCUMENT is only valid for editor tests\n", fname); + return -1; + } + if (cursor_set && !(test & test_editor)) + { + fprintf(stderr, "%s: error, CURSOR is only valid for editor tests\n", fname); + return -1; + } if (!expected_out) expected_out = strdup(""); if (!input_buf) + { input_buf = strdup(""); + input_len = 0; + } + // Expand ^X, , \xHH notation after the whole file is parsed, so + // header keys may appear in any order. In editor tests, the final EOL + // of the Input section is a section separator, not a RETURN keystroke. + { + size_t expanded_len; + input_buf = expand_notation(input_buf, &expanded_len); + input_len = expanded_len; + } + if ((test & test_editor) && input_len && + (unsigned char)input_buf[input_len - 1] == 0x9B) + input_len--; if (error_data && !(test & test_compile_error)) { fprintf(stderr, "%s: error data but no compile error expected\n", fname); @@ -624,7 +1240,7 @@ int fbtest(const char *fname) ext = fname + strlen(fname); // base_name: file name without extension - char *base_name = strndup(fname, ext - fname); + char *base_name = xstrndup(fname, ext - fname); // tag_name: file name without directory and extension char *tag_name = strrchr(base_name, '/'); @@ -633,6 +1249,10 @@ int fbtest(const char *fname) else tag_name = tag_name + 1; + // srcdir: directory containing the test files + char *srcdir = (tag_name != base_name) ? + xstrndup(fname, tag_name - base_name - 1) : strdup("."); + // basname: input basic file name char *basname = source_fname(base_name, "bas"); // atbname: BASIC file converted to ATASCII @@ -648,15 +1268,234 @@ int fbtest(const char *fname) // objname: Object file name char *objname = build_fname(tag_name, "o"); - // Generate ATASCII file - atascii_convert(basname, atbname); + // Generate ATASCII file for normal (non-editor) tests. Editor tests + // use the Document: section instead of the paired .bas file. + if (!(test & test_editor)) + atascii_convert(basname, atbname); // Ok, do tests int test_ok = 0; char *cmd_out = calloc(65536, 1); + // Write the cleanup manifest from the declarations in the .chk file. + if (!(test & test_editor)) + { + FILE *manifest = manifest_open(tag_name); + if (manifest) + { + for (int i = 0; i < nchecks; i++) + manifest_add_file(manifest, output_dir, checks[i].name); + for (int i = 0; i < nexists; i++) + manifest_add_file(manifest, output_dir, exists[i]); + manifest_add_debug(manifest, tag_name); + fclose(manifest); + } + } + do { + if (0 != (test & test_editor)) + { + const char *ide = (test & test_int) ? fb_atari_ide_int : fb_atari_ide_fp; + if (verbose) + fprintf(stderr, "%s: run editor '%s'\n", fname, ide); + + // Each editor test gets its own DOS root, always under build/. + MKDIR(output_dir); + char *test_root; + if (asprintf(&test_root, "%s/%s", output_dir, tag_name) < 0) + exit(1); + MKDIR(test_root); + char *help_txt; + if (asprintf(&help_txt, "%s/HELP.TXT", test_root) < 0) + exit(1); + + // Write the cleanup manifest from the declarations in the .chk + // file, before running anything. + FILE *manifest = manifest_open(tag_name); + if (manifest) + { + manifest_add(manifest, 'F', help_txt); + for (int i = 0; i < nfiles; i++) + manifest_add_file(manifest, test_root, files[i]); + for (int i = 0; i < nchecks; i++) + manifest_add_file(manifest, test_root, checks[i].name); + for (int i = 0; i < nexists; i++) + manifest_add_file(manifest, test_root, exists[i]); + manifest_add_debug(manifest, tag_name); + manifest_add(manifest, 'D', test_root); + fclose(manifest); + } + + // Setup the initial document and extra files in the DOS root. + int e = 0; + unlink(help_txt); + for (int i = 0; i < nfiles; i++) + unlink_in(test_root, files[i]); + for (int i = 0; i < nchecks; i++) + unlink_in(test_root, checks[i].name); + for (int i = 0; i < nexists; i++) + unlink_in(test_root, exists[i]); + + if (doc_kind == doc_file) + { + if (copy_fixture_to(srcdir, doc_filename, help_txt)) + { + fprintf(stderr, "%s: can't install document '%s'.\n", + fname, doc_filename); + e = -1; + } + } + else + { + FILE *fh = fopen(help_txt, "wb"); + if (!fh) + { + fprintf(stderr, "%s: can't create '%s'.\n", fname, help_txt); + e = -1; + } + else + { + if (doc_kind == doc_inline && doc_len) + { + // The newline before the section terminator is not + // part of the document. Add an empty line before the + // terminator to keep a trailing EOL. + size_t len = doc_len; + if ((unsigned char)doc_data[len - 1] == 0x9B) + len--; + if (fwrite(doc_data, 1, len, fh) != len) + e = -1; + } + fclose(fh); + } + } + for (int i = 0; !e && i < nfiles; i++) + { + unlink_in(test_root, files[i]); + if (dos_copy_file(srcdir, files[i], test_root)) + { + fprintf(stderr, "%s: can't install file '%s'.\n", + fname, files[i]); + e = -1; + } + } + + // Run the IDE with the keystroke script + size_t len = 65536; + char *out = calloc(len + 1, 1); + int cur_row = 0, cur_col = 0; + if (!e) + { + str_stop_on_eof = 1; + e = run_atari_prog(ide, out, &len, input_buf, input_len, + max_cycles, 0, 0, 0, test_root, + &cur_row, &cur_col); + str_stop_on_eof = 0; + } + // Cursor state from ROWCRS/COLCRS is used for Cursor: checks and + // diagnostics. The screen accessor already includes the visible + // cursor glyph, so it must not be XORed again. + + // Dump final E: screen state as raw ATASCII bytes for hex analysis. + if (getenv("FB_DUMP_SCREEN")) + { + char *dump; + if (asprintf(&dump, "%s/%s.screen", output_dir, tag_name) >= 0) + { + FILE *fd = fopen(dump, "wb"); + if (fd) + { + for (int r = 0; r < 24; r++) + { + for (int c = 0; c < 40; c++) + putc(atari_screen_get(r, c), fd); + putc('\n', fd); + } + fclose(fd); + } + free(dump); + } + } + if (!e && screen_lines) + { + // Compare expected screen against the actual screen buffer. + // atari_screen_get() includes the cursor glyph, so it must + // not be XORed again here. + for (int r = 0; !e && r < screen_lines; r++) + { + char actual[41]; + for (int c = 0; c < 40; c++) + actual[c] = atari_screen_get(r, c); + actual[40] = 0; + int alen = 40; + while (alen > 0 && actual[alen - 1] == ' ') + alen--; + actual[alen] = 0; + if (strcmp(expected_screen[r], actual)) + { + fprintf(stderr, "%s: SCREEN row %d mismatch:\n", fname, r); + fprintf(stderr, " expected: '%s'\n", expected_screen[r]); + fprintf(stderr, " actual: '%s'\n", actual); + fprintf(stderr, " cursor: %d,%d\n", cur_row, cur_col); + fprintf(stderr, " screen: "); + print_screen_row_utf8(stderr, r); + fprintf(stderr, "\n"); + e = -1; + } + } + } + if (!e && cursor_set && + (cur_row != cursor_row || cur_col != cursor_col)) + { + fprintf(stderr, "%s: CURSOR mismatch: expected %d,%d, got %d,%d\n", + fname, cursor_row, cursor_col, cur_row, cur_col); + e = -1; + } + if (!e && *expected_out) + e = check_output(fname, expected_out, out); + + // Dump captured output stream, to debug editor test scripts. + if (getenv("FB_DUMP_OUTPUT")) + { + char *dumpo; + if (asprintf(&dumpo, "%s/%s.output", output_dir, tag_name) >= 0) + { + FILE *fd = fopen(dumpo, "wb"); + if (fd) + { + fwrite(out, 1, strlen(out), fd); + fclose(fd); + } + free(dumpo); + } + } + // Check expected substrings of the captured output stream + for (int i = 0; !e && i < nexpects; i++) + { + if (!strstr(out, expects[i])) + { + fprintf(stderr, "%s: '%s' not found on output.\n", + fname, expects[i]); + e = -1; + } + } + + if (!e) + e = check_test_files(fname, test_root, checks, nchecks, + exists, nexists); + + if (e > 0) + fprintf(stderr, "%s: unexpected stack value.\n", fname); + else if (e < 0) + fprintf(stderr, "%s: error on editor execution.\n", fname); + + free(out); + free(help_txt); + free(test_root); + if (e) + break; + } if (0 != (test & test_native) && 0 != (test & test_fp)) { if (verbose) @@ -672,6 +1511,8 @@ int fbtest(const char *fname) // Now, runs and checks XEX if (run_test_xex(comname, input_buf, expected_out, max_cycles, 0)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } } if (0 != (test & test_native) && 0 != (test & test_int)) @@ -689,6 +1530,8 @@ int fbtest(const char *fname) // Now, runs and checks XEX if (run_test_xex(comname, input_buf, expected_out, max_cycles, 0)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } } if (0 != (test & test_fp) && 0 != (test & test_cross)) @@ -709,6 +1552,8 @@ int fbtest(const char *fname) // Now, runs and checks XEX if (run_test_xex(xexname, input_buf, expected_out, max_cycles, 0)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } // CARTRIDGE version: @@ -727,6 +1572,8 @@ int fbtest(const char *fname) // Now, runs and checks ROM if (run_test_xex(romname, input_buf, expected_out, max_cycles, 1)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } } if (0 != (test & test_int) && 0 != (test & test_cross)) @@ -747,6 +1594,8 @@ int fbtest(const char *fname) // Now, runs and checks XEX if (run_test_xex(xexname, input_buf, expected_out, max_cycles, 0)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } // CARTRIDGE version: @@ -765,6 +1614,8 @@ int fbtest(const char *fname) // Now, runs and checks ROM if (run_test_xex(romname, input_buf, expected_out, max_cycles, 1)) break; + if (check_test_files(fname, output_dir, checks, nchecks, exists, nexists)) + break; } } @@ -779,6 +1630,8 @@ int fbtest(const char *fname) free(input_buf); free(expected_out); free(name); + free(doc_filename); + free(doc_data); free(basname); free(atbname); free(romname); @@ -786,6 +1639,20 @@ int fbtest(const char *fname) free(asmname); free(objname); free(base_name); + free(srcdir); + for (int i = 0; i < nfiles; i++) + free(files[i]); + for (int i = 0; i < nchecks; i++) + { + free(checks[i].name); + free(checks[i].data); + } + for (int i = 0; i < nexists; i++) + free(exists[i]); + for (int i = 0; i < nexpects; i++) + free(expects[i]); + for (int i = 0; i < screen_lines; i++) + free(expected_screen[i]); return !test_ok; } diff --git a/testsuite/tests/diskio.chk b/testsuite/tests/diskio.chk index c7acccd..427f81e 100644 --- a/testsuite/tests/diskio.chk +++ b/testsuite/tests/diskio.chk @@ -1,5 +1,9 @@ Name: Check D: input/output Test: run +Check: XXX +Big 1: +Big 2: +. Output: Start 1 diff --git a/testsuite/tests/ed-assert.chk b/testsuite/tests/ed-assert.chk new file mode 100644 index 0000000..f22e6c1 --- /dev/null +++ b/testsuite/tests/ed-assert.chk @@ -0,0 +1,15 @@ +Name: assert plumbing +Test: editor +Max-cycles: 800000000 +Document: +' assert-plumbing help document + +. +Input: +? "MARKERXYZ" +^R ^WT2.XEX +^Q^C +. +Expect-out: Parsing +Expect-out: MARKERXYZ +Exists: T2.XEX diff --git a/testsuite/tests/ed-backspace-nop.chk b/testsuite/tests/ed-backspace-nop.chk new file mode 100644 index 0000000..67b3d33 --- /dev/null +++ b/testsuite/tests/ed-backspace-nop.chk @@ -0,0 +1,35 @@ +Name: ed backspace nop +Test: editor +Max-cycles: 800000000 +Document: +simple test for editor +. +Input: + +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xf3imple test for editor +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-backspace.chk b/testsuite/tests/ed-backspace.chk new file mode 100644 index 0000000..3adb3e0 --- /dev/null +++ b/testsuite/tests/ed-backspace.chk @@ -0,0 +1,36 @@ +Name: ed-backspace +Test: editor +Max-cycles: 800000000 +Document: +abcdef +. +Input: + +. +Cursor: 1,2 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +ab\xe4ef +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-copy-before-mark.chk b/testsuite/tests/ed-copy-before-mark.chk new file mode 100644 index 0000000..d692cc1 --- /dev/null +++ b/testsuite/tests/ed-copy-before-mark.chk @@ -0,0 +1,39 @@ +Name: ed-copy-before-mark +Test: editor +Max-cycles: 800000000 +Document: +A +B +C +D +. +Input: +^G3^C^G1^V +. +Cursor: 2,0 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 +A +\xc3 +B +C +D +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-copy-paste.chk b/testsuite/tests/ed-copy-paste.chk new file mode 100644 index 0000000..56f1218 --- /dev/null +++ b/testsuite/tests/ed-copy-paste.chk @@ -0,0 +1,36 @@ +Name: ed copy paste +Test: editor +Max-cycles: 800000000 +Document: +abc +def +. +Input: +^C^V^V +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb4\x92\x92\x92\x92\x92\x92\x92 +abc +def +abc +\xe4ef +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-cursor-down-scroll.chk b/testsuite/tests/ed-cursor-down-scroll.chk new file mode 100644 index 0000000..7857630 --- /dev/null +++ b/testsuite/tests/ed-cursor-down-scroll.chk @@ -0,0 +1,34 @@ +Name: ed-cursor-down-scroll +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G1^I +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\xb4\x92\x92\x92\x92\x92\x92 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +\xecine 24 +. +Cursor: 23,0 diff --git a/testsuite/tests/ed-cursor-up-scroll.chk b/testsuite/tests/ed-cursor-up-scroll.chk new file mode 100644 index 0000000..0c142a0 --- /dev/null +++ b/testsuite/tests/ed-cursor-up-scroll.chk @@ -0,0 +1,34 @@ +Name: ed-cursor-up-scroll +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G10 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb9\x92\x92\x92\x92\x92\x92\x92 +\xecine 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +line 25 +line 26 +line 27 +line 28 +line 29 +line 30 +line 31 +. +Cursor: 1,0 diff --git a/testsuite/tests/ed-del-char.chk b/testsuite/tests/ed-del-char.chk new file mode 100644 index 0000000..8d897fa --- /dev/null +++ b/testsuite/tests/ed-del-char.chk @@ -0,0 +1,36 @@ +Name: ed-del-char +Test: editor +Max-cycles: 800000000 +Document: +abcdef +. +Input: + +. +Cursor: 1,3 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +abc\xe5f +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-del-eof.chk b/testsuite/tests/ed-del-eof.chk new file mode 100644 index 0000000..7765b94 --- /dev/null +++ b/testsuite/tests/ed-del-eof.chk @@ -0,0 +1,36 @@ +# DEL at EOF must not crash. The screen is intentionally unchanged. +Name: ed del eof +Test: editor +Max-cycles: 800000000 +Document: +simple test for editor +. +Input: + +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +simple test for editor\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-del-line-first.chk b/testsuite/tests/ed-del-line-first.chk new file mode 100644 index 0000000..ddaebdb --- /dev/null +++ b/testsuite/tests/ed-del-line-first.chk @@ -0,0 +1,38 @@ +Name: ed-del-line-first +Test: editor +Max-cycles: 800000000 +Document: +abc +def +ghi +. +Input: + +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xe4ef +ghi +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-del-line-last.chk b/testsuite/tests/ed-del-line-last.chk new file mode 100644 index 0000000..18e236f --- /dev/null +++ b/testsuite/tests/ed-del-line-last.chk @@ -0,0 +1,38 @@ +Name: ed-del-line-last +Test: editor +Max-cycles: 800000000 +Document: +abc +def +ghi +. +Input: +^G3 +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 +\xe4ef +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-del-line-only.chk b/testsuite/tests/ed-del-line-only.chk new file mode 100644 index 0000000..f47a564 --- /dev/null +++ b/testsuite/tests/ed-del-line-only.chk @@ -0,0 +1,36 @@ +Name: ed-del-line-only +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: + +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-del-line.chk b/testsuite/tests/ed-del-line.chk new file mode 100644 index 0000000..e68bbfe --- /dev/null +++ b/testsuite/tests/ed-del-line.chk @@ -0,0 +1,36 @@ +Name: ed del line +Test: editor +Max-cycles: 800000000 +Document: +abc +def +. +Input: + +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-end-empty.chk b/testsuite/tests/ed-end-empty.chk new file mode 100644 index 0000000..32ff4af --- /dev/null +++ b/testsuite/tests/ed-end-empty.chk @@ -0,0 +1,33 @@ +Name: ed end empty +Test: editor +Max-cycles: 800000000 +Document: none +Input: +^E +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-end.chk b/testsuite/tests/ed-end.chk new file mode 100644 index 0000000..76552f5 --- /dev/null +++ b/testsuite/tests/ed-end.chk @@ -0,0 +1,36 @@ +Name: ed-end +Test: editor +Max-cycles: 800000000 +Document: +abcdef +. +Input: +^E +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +abcdef\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Cursor: 1,6 diff --git a/testsuite/tests/ed-escape.chk b/testsuite/tests/ed-escape.chk new file mode 100644 index 0000000..8ed4d44 --- /dev/null +++ b/testsuite/tests/ed-escape.chk @@ -0,0 +1,36 @@ +Name: ed-escape +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^A +. +Cursor: 1,1 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\x01\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-filename-edit.chk b/testsuite/tests/ed-filename-edit.chk new file mode 100644 index 0000000..7d06876 --- /dev/null +++ b/testsuite/tests/ed-filename-edit.chk @@ -0,0 +1,39 @@ +Name: ed filename edit +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^ST.BAXS +. +Cursor: 1,0 +Check: T.BAS +abc +. +Screen: +\x92\x92\xc4\xba\xd4\xae\xc2\xc1\xd3\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92 +\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-goto0.chk b/testsuite/tests/ed-goto0.chk new file mode 100644 index 0000000..823d097 --- /dev/null +++ b/testsuite/tests/ed-goto0.chk @@ -0,0 +1,36 @@ +# TODO: Ctrl-G 0 currently lands on line 02 because of abs(topLine - 1). +# Expected is line 01; keep this test documenting the bug for now. +Name: ed goto 0 +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G0 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 +\xecine 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +. +Cursor: 1,0 diff --git a/testsuite/tests/ed-goto1.chk b/testsuite/tests/ed-goto1.chk new file mode 100644 index 0000000..072bf98 --- /dev/null +++ b/testsuite/tests/ed-goto1.chk @@ -0,0 +1,33 @@ +Name: ed goto 1 +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G1 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xecine 01 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +. diff --git a/testsuite/tests/ed-goto30.chk b/testsuite/tests/ed-goto30.chk new file mode 100644 index 0000000..e68017d --- /dev/null +++ b/testsuite/tests/ed-goto30.chk @@ -0,0 +1,33 @@ +Name: ed goto 30 +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G30 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb3\xb0\x92\x92\x92\x92\x92\x92 +\xecine 30 +line 31 +line 32 +line 33 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-goto5.chk b/testsuite/tests/ed-goto5.chk new file mode 100644 index 0000000..781d5ec --- /dev/null +++ b/testsuite/tests/ed-goto5.chk @@ -0,0 +1,33 @@ +Name: ed goto 5 +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G5 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb5\x92\x92\x92\x92\x92\x92\x92 +\xecine 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +line 25 +line 26 +line 27 +. diff --git a/testsuite/tests/ed-goto99.chk b/testsuite/tests/ed-goto99.chk new file mode 100644 index 0000000..d803528 --- /dev/null +++ b/testsuite/tests/ed-goto99.chk @@ -0,0 +1,33 @@ +Name: ed goto 99 +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G99 +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb3\xb3\x92\x92\x92\x92\x92\x92 +\xecine 33 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-home.chk b/testsuite/tests/ed-home.chk new file mode 100644 index 0000000..8e7c5c9 --- /dev/null +++ b/testsuite/tests/ed-home.chk @@ -0,0 +1,36 @@ +Name: ed-home +Test: editor +Max-cycles: 800000000 +Document: +abcdef +. +Input: +^A +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xe1bcdef +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Cursor: 1,0 diff --git a/testsuite/tests/ed-hscroll-back.chk b/testsuite/tests/ed-hscroll-back.chk new file mode 100644 index 0000000..ad4a414 --- /dev/null +++ b/testsuite/tests/ed-hscroll-back.chk @@ -0,0 +1,36 @@ +Name: ed-hscroll-back +Test: editor +Max-cycles: 800000000 +Document: +AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE +. +Input: +^E^A +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xc1AAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDD\x9f +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-insert-inverse.chk b/testsuite/tests/ed-insert-inverse.chk new file mode 100644 index 0000000..f6166f4 --- /dev/null +++ b/testsuite/tests/ed-insert-inverse.chk @@ -0,0 +1,36 @@ +Name: ed-insert-inverse +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +𝗔 +. +Cursor: 1,1 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xc1\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-join-long.chk b/testsuite/tests/ed-join-long.chk new file mode 100644 index 0000000..5da8ce3 --- /dev/null +++ b/testsuite/tests/ed-join-long.chk @@ -0,0 +1,39 @@ +Name: ed join long +Test: editor +Max-cycles: 800000000 +Document: +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB +. +Input: +^G1^E^ST.BAS +. +Screen: +\x92\x92\xc4\xba\xd4\xae\xc2\xc1\xd3\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92 +\x9eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xc2BBBBB\x9f +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +check: T.BAS +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB +. diff --git a/testsuite/tests/ed-join.chk b/testsuite/tests/ed-join.chk new file mode 100644 index 0000000..aefe44b --- /dev/null +++ b/testsuite/tests/ed-join.chk @@ -0,0 +1,39 @@ +Name: ed join +Test: editor +Max-cycles: 800000000 +Document: +abcde +fghij +klmno +pqrst +uvwxy +. +Input: +^E^E +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +abcde\xa0 +fghij +klmnopqrstuvwxy +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-left-right-boundary.chk b/testsuite/tests/ed-left-right-boundary.chk new file mode 100644 index 0000000..4435492 --- /dev/null +++ b/testsuite/tests/ed-left-right-boundary.chk @@ -0,0 +1,36 @@ +Name: ed-left-right-boundary +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: + +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +abc\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Cursor: 1,3 diff --git a/testsuite/tests/ed-load-error.chk b/testsuite/tests/ed-load-error.chk new file mode 100644 index 0000000..da0bf50 --- /dev/null +++ b/testsuite/tests/ed-load-error.chk @@ -0,0 +1,37 @@ +Name: ed load error +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^Lmissing +. +Cursor: 1,0 +Expect-out: I/O ERROR! +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-load.chk b/testsuite/tests/ed-load.chk new file mode 100644 index 0000000..23f7d31 --- /dev/null +++ b/testsuite/tests/ed-load.chk @@ -0,0 +1,37 @@ +Name: ed load +Test: editor +Max-cycles: 800000000 +Document: none +Files: +load.txt +. +Input: +^Lload.txt +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\xec\xef\xe1\xe4\xae\xf4\xf8\xf4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xecoaded line 1 +loaded line 2 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-new-discard.chk b/testsuite/tests/ed-new-discard.chk new file mode 100644 index 0000000..fcd02eb --- /dev/null +++ b/testsuite/tests/ed-new-discard.chk @@ -0,0 +1,36 @@ +Name: ed new discard +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +X^N^C +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-new.chk b/testsuite/tests/ed-new.chk new file mode 100644 index 0000000..5943232 --- /dev/null +++ b/testsuite/tests/ed-new.chk @@ -0,0 +1,36 @@ +Name: ed new +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^N +. +Cursor: 1,0 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-page-down.chk b/testsuite/tests/ed-page-down.chk new file mode 100644 index 0000000..e04c51c --- /dev/null +++ b/testsuite/tests/ed-page-down.chk @@ -0,0 +1,35 @@ +# Current code moves 20 lines; manual.md says 19. Document current behavior. +Name: ed-page-down +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines40.txt +Input: +^I +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\xb1\x92\x92\x92\x92\x92\x92 +line 01 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +\xecine 21 +line 22 +line 23 +. +Cursor: 21,0 diff --git a/testsuite/tests/ed-page-up.chk b/testsuite/tests/ed-page-up.chk new file mode 100644 index 0000000..d48a335 --- /dev/null +++ b/testsuite/tests/ed-page-up.chk @@ -0,0 +1,35 @@ +# Current code moves 20 lines; manual.md says 19. Document current behavior. +Name: ed-page-up +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines40.txt +Input: +^G30^U +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\xb0\x92\x92\x92\x92\x92\x92 +\xecine 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +line 25 +line 26 +line 27 +line 28 +line 29 +line 30 +line 31 +line 32 +. +Cursor: 1,0 diff --git a/testsuite/tests/ed-quit-prompt.chk b/testsuite/tests/ed-quit-prompt.chk new file mode 100644 index 0000000..f356b20 --- /dev/null +++ b/testsuite/tests/ed-quit-prompt.chk @@ -0,0 +1,36 @@ +Name: ed quit prompt +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +X^Q +. +Expect-out: Save +Screen: +Save? D:\xa0 +Xabc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-return-end.chk b/testsuite/tests/ed-return-end.chk new file mode 100644 index 0000000..9483a11 --- /dev/null +++ b/testsuite/tests/ed-return-end.chk @@ -0,0 +1,36 @@ +Name: ed-return-end +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^E +. +Cursor: 2,0 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 +abc +\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-return-last-row.chk b/testsuite/tests/ed-return-last-row.chk new file mode 100644 index 0000000..7208b74 --- /dev/null +++ b/testsuite/tests/ed-return-last-row.chk @@ -0,0 +1,34 @@ +Name: ed-return-last-row +Test: editor +Max-cycles: 800000000 +Document: fixtures/lines33.txt +Input: +^G1^I +. +Cursor: 23,0 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\xb4\x92\x92\x92\x92\x92\x92 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 + +\xecine 23 +. diff --git a/testsuite/tests/ed-return-start.chk b/testsuite/tests/ed-return-start.chk new file mode 100644 index 0000000..894ea14 --- /dev/null +++ b/testsuite/tests/ed-return-start.chk @@ -0,0 +1,36 @@ +Name: ed-return-start +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: + +. +Cursor: 2,0 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 + +\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-save-source.chk b/testsuite/tests/ed-save-source.chk new file mode 100644 index 0000000..64b4c61 --- /dev/null +++ b/testsuite/tests/ed-save-source.chk @@ -0,0 +1,39 @@ +Name: ed save source +Test: editor +Max-cycles: 800000000 +Document: +abc +. +Input: +^ST.BAS +. +Cursor: 1,0 +Check: T.BAS +abc +. +Screen: +\x92\x92\xc4\xba\xd4\xae\xc2\xc1\xd3\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92 +\xe1bc +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-scroll.chk b/testsuite/tests/ed-scroll.chk new file mode 100644 index 0000000..2ea09d2 --- /dev/null +++ b/testsuite/tests/ed-scroll.chk @@ -0,0 +1,35 @@ +Name: ed scroll +Test: editor +Max-cycles: 800000000 +Document: +AAAAAAAAAABBBBBBBBBBCCCCCCCCCCDDDDDDDDDDEEEEEEEEEE +. +Input: +^E +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\x9eBBBBCCCCCCCCCCDDDDDDDDDDEEEEE\xc5EEEE +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-split.chk b/testsuite/tests/ed-split.chk new file mode 100644 index 0000000..ab9808c --- /dev/null +++ b/testsuite/tests/ed-split.chk @@ -0,0 +1,36 @@ +Name: ed split +Test: editor +Max-cycles: 800000000 +Document: +' split test +. +Input: +abcdefghij +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\x92\x92\x92\x92\x92\x92\x92 +abcdefg +\xe8ij' split test +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Cursor: 2,0 diff --git a/testsuite/tests/ed-syntax-error.chk b/testsuite/tests/ed-syntax-error.chk new file mode 100644 index 0000000..8ef940c --- /dev/null +++ b/testsuite/tests/ed-syntax-error.chk @@ -0,0 +1,64 @@ +Name: ed syntax error +Test: editor +Max-cycles: 800000000 +Document: +PRINT "LINE 01" +PRINT "LINE 02" +PRINT "LINE 03" +PRINT "LINE 04" +PRINT "LINE 05" +PRINT "LINE 06" +PRINT "LINE 07" +PRINT "LINE 08" +PRINT "LINE 09" +PRINT "LINE 10" +PRINT "LINE 11" +PRINT "LINE 12" +PRINT "LINE 13" +PRINT "LINE 14" +PRINT "LINE 15" +PRINT "LINE 16" +PRINT "LINE 17" +PRINT "LINE 18" +PRINT "LINE 19" +? B +PRINT "LINE 21" +PRINT "LINE 22" +PRINT "LINE 23" +PRINT "LINE 24" +PRINT "LINE 25" +PRINT "LINE 26" +PRINT "LINE 27" +PRINT "LINE 28" +PRINT "LINE 29" +PRINT "LINE 30" +. +Input: +^R +. +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb2\xb0\x92\x92\x92\x92\x92\x92 +PRINT "LINE 10" +PRINT "LINE 11" +PRINT "LINE 12" +PRINT "LINE 13" +PRINT "LINE 14" +PRINT "LINE 15" +PRINT "LINE 16" +PRINT "LINE 17" +PRINT "LINE 18" +PRINT "LINE 19" +? B\xa0 +PRINT "LINE 21" +PRINT "LINE 22" +PRINT "LINE 23" +PRINT "LINE 24" +PRINT "LINE 25" +PRINT "LINE 26" +PRINT "LINE 27" +PRINT "LINE 28" +PRINT "LINE 29" +PRINT "LINE 30" +\xfd +\xfd +. diff --git a/testsuite/tests/ed-syntax-line1.chk b/testsuite/tests/ed-syntax-line1.chk new file mode 100644 index 0000000..821b750 --- /dev/null +++ b/testsuite/tests/ed-syntax-line1.chk @@ -0,0 +1,37 @@ +Name: ed-syntax-line1 +Test: editor +Max-cycles: 800000000 +Document: +? B +. +Input: +^R +. +Cursor: 1,3 +Screen: +\x92\x92\xc4\xba\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +? B\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Expect-out: Parsing diff --git a/testsuite/tests/ed-syntax-msg.chk b/testsuite/tests/ed-syntax-msg.chk new file mode 100644 index 0000000..f49e2de --- /dev/null +++ b/testsuite/tests/ed-syntax-msg.chk @@ -0,0 +1,36 @@ +Name: ed syntax msg +Test: editor +Max-cycles: 800000000 +Document: +A = 1 +? B +. +Input: +^R +. +Screen: +Parsing: parse error\xa0 +A = 1 +? B +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-typing-254.chk b/testsuite/tests/ed-typing-254.chk new file mode 100644 index 0000000..553d97a --- /dev/null +++ b/testsuite/tests/ed-typing-254.chk @@ -0,0 +1,36 @@ +Name: ed-typing-254 +Test: editor +Max-cycles: 800000000 +Document: +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +. +Input: +Y +. +Cursor: 1,1 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +Y\xd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x9f +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-typing-at-255.chk b/testsuite/tests/ed-typing-at-255.chk new file mode 100644 index 0000000..50e8b17 --- /dev/null +++ b/testsuite/tests/ed-typing-at-255.chk @@ -0,0 +1,35 @@ +Name: ed typing at 255 +Test: editor +Max-cycles: 800000000 +Document: +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +. +Input: +Y +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xd8XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x9f +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-undo-delete.chk b/testsuite/tests/ed-undo-delete.chk new file mode 100644 index 0000000..2aeff02 --- /dev/null +++ b/testsuite/tests/ed-undo-delete.chk @@ -0,0 +1,36 @@ +Name: ed-undo-delete +Test: editor +Max-cycles: 800000000 +Document: +abcdef +. +Input: +^Z +. +Cursor: 1,3 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +abc\xe4ef +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-undo.chk b/testsuite/tests/ed-undo.chk new file mode 100644 index 0000000..972be58 --- /dev/null +++ b/testsuite/tests/ed-undo.chk @@ -0,0 +1,36 @@ +Name: ed undo +Test: editor +Max-cycles: 800000000 +Document: +' undo test + +. +Input: +XXXX^Z^EYYYY +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +' undo testYYYY\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/ed-wrap-80.chk b/testsuite/tests/ed-wrap-80.chk new file mode 100644 index 0000000..0adc960 --- /dev/null +++ b/testsuite/tests/ed-wrap-80.chk @@ -0,0 +1,36 @@ +Name: ed-wrap-80 +Test: editor +Max-cycles: 800000000 +Document: +AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA +. +Input: +^E +. +Cursor: 1,33 +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\x9eAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\xa0 +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/fixtures/.gitattributes b/testsuite/tests/fixtures/.gitattributes new file mode 100644 index 0000000..fa1385d --- /dev/null +++ b/testsuite/tests/fixtures/.gitattributes @@ -0,0 +1 @@ +* -text diff --git a/testsuite/tests/fixtures/lines33.txt b/testsuite/tests/fixtures/lines33.txt new file mode 100644 index 0000000..dea6e12 --- /dev/null +++ b/testsuite/tests/fixtures/lines33.txt @@ -0,0 +1,33 @@ +line 01 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +line 25 +line 26 +line 27 +line 28 +line 29 +line 30 +line 31 +line 32 +line 33 diff --git a/testsuite/tests/fixtures/lines40.txt b/testsuite/tests/fixtures/lines40.txt new file mode 100644 index 0000000..f8a8ac7 --- /dev/null +++ b/testsuite/tests/fixtures/lines40.txt @@ -0,0 +1,40 @@ +line 01 +line 02 +line 03 +line 04 +line 05 +line 06 +line 07 +line 08 +line 09 +line 10 +line 11 +line 12 +line 13 +line 14 +line 15 +line 16 +line 17 +line 18 +line 19 +line 20 +line 21 +line 22 +line 23 +line 24 +line 25 +line 26 +line 27 +line 28 +line 29 +line 30 +line 31 +line 32 +line 33 +line 34 +line 35 +line 36 +line 37 +line 38 +line 39 +line 40 diff --git a/testsuite/tests/fp-input.chk b/testsuite/tests/fp-input.chk index 1bae856..f3df58c 100644 --- a/testsuite/tests/fp-input.chk +++ b/testsuite/tests/fp-input.chk @@ -6,6 +6,6 @@ Input: . Output: Start -?1 1 +?1 1 1 2 ?18 diff --git a/testsuite/tests/load.txt b/testsuite/tests/load.txt new file mode 100644 index 0000000..73d01e0 --- /dev/null +++ b/testsuite/tests/load.txt @@ -0,0 +1,2 @@ +loaded line 1 +loaded line 2 diff --git a/testsuite/tests/screen-basic.chk b/testsuite/tests/screen-basic.chk new file mode 100644 index 0000000..748cfdf --- /dev/null +++ b/testsuite/tests/screen-basic.chk @@ -0,0 +1,36 @@ +Name: screen basic +Test: editor +Max-cycles: 800000000 +Document: +' screen test + +. +Input: +HELLO WORLD +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +HELLO WORLD\xa7 screen test +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. diff --git a/testsuite/tests/screen-initial.chk b/testsuite/tests/screen-initial.chk new file mode 100644 index 0000000..98ad5a8 --- /dev/null +++ b/testsuite/tests/screen-initial.chk @@ -0,0 +1,35 @@ +Name: screen initial +Test: editor +Max-cycles: 800000000 +Document: +screen initial test +. +Input: +. +Screen: +\x92\x92\xc4\xba\xc8\xc5\xcc\xd0\xae\xd4\xd8\xd4\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\x92\xb1\x92\x92\x92\x92\x92\x92\x92 +\xf3creen initial test +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +\xfd +. +Cursor: 1,0 diff --git a/testsuite/tests/stmt-cls.chk b/testsuite/tests/stmt-cls.chk index 08f6f4c..c38c20e 100644 --- a/testsuite/tests/stmt-cls.chk +++ b/testsuite/tests/stmt-cls.chk @@ -3,5 +3,5 @@ Test: run Output: Start SCREEN: set graphics 1 with text window -}SCREEN: plot 1,1 color 125 +}SCREEN: plot 0,0 color 125 Ok diff --git a/testsuite/tests/stmt-input.chk b/testsuite/tests/stmt-input.chk index 722fa4f..1db502f 100644 --- a/testsuite/tests/stmt-input.chk +++ b/testsuite/tests/stmt-input.chk @@ -11,11 +11,11 @@ hello . Output: Start -?1 1234 +?1 1234 1 2345 Prompt: 1 3456 -?18 0 -?1 -1 -?18 0 -?1 hello +?18 0 +?1 -1 +?18 0 +?1 hello ?136