Overview
This appendix describes the plain text file formats used by riscos-tooltester. The runner is intentionally simple: test suites are line-oriented text files, expectations are ordinary text files, and optional replacement scripts normalise unstable output before comparison.
Suite format and command reference
Suite layout and defaults
The normal suite entry point is a file named tests.txt in the chosen test directory, though the runner can be pointed at a different file with -script. A suite directory commonly contains:
- one main script file, usually tests.txt;
- expected output files, often under expect/;
- replacement scripts used to normalise unstable output before comparison; and
- optional input data files, often under testdata/.
The script is read line by line. Blank lines and lines beginning with # are ignored.
Statement syntax
Each statement has one of these forms:
Keyword: value
Checker:parameter: value
-Keyword:
-Checker:parameter:
The two structural statements are:
| Statement | Meaning |
|---|---|
| Group: <name> | Begin a group. The group establishes default statements inherited by later tests in that group. |
| Test: <name> | Begin one individual test. It starts as a copy of the current group settings, then any following statements override or clear those inherited values. |
To clear an inherited value from the current group, write the same keyword with a leading minus and no value, such as -Expect: or -Creates:.
Core suite commands
The runner accepts the following built-in suite statements:
| Statement | Meaning |
|---|---|
| Include: <file> | Read another suite file inline at that point. This is commonly used to split a large suite into smaller files. |
| Suite: <name> | Set the suite name used in JUnit XML output. If omitted, the runner infers a name from the script filename where possible. |
| Command: <command> | Command line to execute for the test. The command may contain substitution variables such as $TOOL, $FILE, or $ARGS. |
| Capture: stdout|stderr|both | Select which output stream is captured for comparison. The default is both. |
| File: <path> | Source file value, available to substitutions as $FILE and $BASE. |
| Args: <arguments> | Arbitrary argument string, available as $ARGS and tokenised into $ARG1, $ARG2, and so on. |
| Expect: <file> | Expectation file containing the expected captured output. |
| Replace: <file> | Replacement script applied to captured output before comparison. |
| Creates: <file...> | One or more files that must be created by the command. The runner removes any pre-existing paths before the test and removes successful outputs afterwards. |
| CreatesDir: <dir...> | One or more directories that must be created by the command. These are also removed before and after the test. |
| Length: <n> | Expected file length in bytes for files named by Creates:. When more than one created file is named, they must all match this size. |
| Removes: <file> | File that the command is expected to delete. The runner creates an empty placeholder before the test so that removal can be checked. |
| Absent: <file> | File that must not exist after the command completes. |
| RC: <n> | Expected return code. The default is 0. |
| Input: <file> | File whose contents are supplied on standard input. |
| InputLine: <text> | One line of text supplied on standard input, with a trailing newline appended by the runner. |
| Env: <VAR>=<value> | Environment variable set only for this test execution. This statement may be repeated. |
| Disable: <reason> | Disable the current group or test, recording the given reason in the reported skip result. |
Substitution variables
Most statement values may contain substitution variables. The runner expands the following names:
| Variable | Meaning |
|---|---|
| $TOOL | Tool path supplied on the riscos-tooltester command line. |
| $FILE | Value supplied by the current File: statement. |
| $OFILE | Object-file path derived from $FILE using RISC OS build-directory conventions. |
| $SFILE | Assembler-file path derived from $FILE. |
| $CFILE | C-file path derived from $FILE. |
| $BASE | Leaf filename derived from $FILE. |
| $ARGS | Full argument string from Args:. |
| $ARG1 ... $ARG9 | Whitespace-tokenised arguments derived from Args:. Missing values expand to an empty string. |
Quoted argument text in Args: is preserved when the numbered $ARGn variables are extracted, so embedded spaces can still be treated as one argument.
Only $ARG1 through $ARG9 are ever defined; a tenth or later argument is simply not made available through a numbered variable. Writing $ARG10 in a command does not fall back to $ARG1 followed by a literal 0: the substitution logic greedily matches as many digits as possible when looking for a variable name, so it treats the whole of ARG10 as the candidate name, finds no such variable, and leaves $ARG10 in the command unsubstituted. A test needing a tenth or later argument should pass it through $ARGS instead and split it within the tested command.
Checker commands
Checker statements use the form <checker>:<parameter>: <value>. They attach extra validation rules to the current group or test and are typically used with one file named by Creates:. The runner currently supports the following checker families:
AOF checker
| Statement | Meaning |
|---|---|
| aof:totalareasize: <size> | Require the sum of all AOF area sizes to match the given value. |
ALF checker
| Statement | Meaning |
|---|---|
| alf:files: <count> | Require the library to contain the given number of files. |
ELF checker
| Statement | Meaning |
|---|---|
| elf:endianness: little|big | Expected ELF endianness. |
| elf:entry: <address> | Expected entry address. |
| elf:type: <type> | Expected ELF object type, checked as a plain numeric comparison against the file's e_type field with no restriction to particular values. The installed script's own comments only mention 1 (relocatable) and 2 (executable), but the standard ELF enumeration's other small values also work: 3 for a shared object and 4 for a core file. |
| elf:osabi: <value> | Expected OS/ABI value. |
| elf:phoff: <offset> | Expected program-header table offset. |
| elf:shoff: <offset> | Expected section-header table offset. |
| elf:ehsize: <size> | Expected ELF header size. |
| elf:flags: <flags> | Expected ELF flags field. |
| elf:phentsize: <size> | Expected size of each program-header entry. |
| elf:phnum: <count> | Expected number of program-header entries. |
| elf:shentsize: <size> | Expected size of each section-header entry. |
| elf:shnum: <count> | Expected number of section-header entries. |
| elf:shstrndx: <index> | Expected section-name string-table index. |
Text checker
| Statement | Meaning |
|---|---|
| text:matches: <file> | Compare the created file's textual content against the named file. |
| text:replace: <file> | Apply a replacement script before the textual comparison. |
Binary checker
| Statement | Meaning |
|---|---|
| binary:matches: <file> | Compare the created file byte-for-byte against the named file. |
| binary:checkfile: <file> | Validate specific offsets described by a separate checkfile. |
| binary:replace: <file> | Apply a replacement script before comparing the binary file rendered as text. |
The installed script comments describe the checkfile syntax as:
<offset> [word|byte|string]: <value>
The installed runner does not permit checker use with more than one created file in the same test. If you need checker validation for multiple outputs, split them into separate tests.
Replacement script language
Replacement scripts are miniature line-processing programs. They transform the captured output into a stable form before it is compared against the expectation file, which is useful when the tool prints variable data such as absolute paths, timestamps, branch names, or memory addresses.
The replacement file is read line by line:
- blank lines and comment lines beginning with # are ignored;
- directive lines begin with %;
- all other lines are rules made of zero or more conditions followed by one action.
Directives
The installed runner supports one directive:
| Directive | Meaning |
|---|---|
| %include <file> | Read another replacement file inline. Paths are resolved relative to the current replacement file. |
Conditions
Rules may be restricted by line number, by regular-expression match, or by both together.
| Condition form | Meaning |
|---|---|
| 5 | Apply only to line 5. |
| -5 | Apply only to lines 1 through 5. |
| 3-10 | Apply only to lines 3 through 10. |
| 10- | Apply only to line 10 onwards. |
| /pattern/ | Apply only when the line matches the regular expression. |
| /pattern/ ! | Negated regular-expression condition: apply only when the line does not match. |
The installed script also accepts negation on the numeric range condition by adding ! immediately after it. When both a range and a regular-expression condition are present, both must match for the action to run.
Actions
The supported actions are:
| Action | Meaning |
|---|---|
| s/from/to/ | Replace the first regular-expression match on the line. |
| s/from/to/g | Replace all matches on the line. |
| s/from/to/i | Case-insensitive single substitution. |
| s/from/to/gi | Case-insensitive global substitution. |
| p | Write the line to the output immediately and continue with the next input line. |
| d | Delete the line from the output. |
| q | Stop processing and end the output before the current line. |
If no rule takes an early action and the end of the rule list is reached, the current line is written to the output unchanged.
Replacement example
This example removes transient progress messages, normalises a test-data path, and rewrites hexadecimal addresses:
/^Processing:/ d
s!/[^ ]+/testdata!TESTDATA!g
s/0x[0-9a-f]{8}/0xXXXXXXXX/gi
Worked suite example
A compact suite for command help and version output can be written like this:
Group: Core behaviour
Command: $TOOL $ARGS
Replace: expect/shared_replacements
Test: Help text
Args: --help
Expect: expect/help
Test: Version text
Args: --version
Expect: expect/version
Test: Writes report
Args: --report out.txt
Creates: out.txt
text:matches: expect/report
That pattern keeps the command line and shared replacements at group level, leaving each test to describe only the inputs and checks that differ.