A framework for test-driving assembly code for the Sinclair ZX Spectrum 48k.
Usage
The framework has been written with the Pasmo assembler. Simply grab the source in src and include zx-spec.asm to write tests:
include src/zx-spec.asm spec_init describe 'ld a,n' it 'sets A register to value' ld a,5 assert_a_equal 5 spec_end
Names and Groupings
You can optionally name a set of asserts using the it macro. This groups the asserts into a single test. In addition to it, you can use the describe macro to group one or more tests. Nested describe or it macros are not permitted.
Verbose Output
By default test descriptions are not output for tests that pass. You can output test descriptions even for passing tests by defining zxspec_config_verbose_output as non-zero either on the command-line of Pasmo (--equ zxspec_config_verbose_output), or in code before you call spec_init:
zxspec_config_verbose_output equ $FF
This can be used to generate a form of living documentation for your project.
Hexadecimals
By default, expected and actual values are displayed as decimals. You can switch to hexadecimal by defining zxspec_config_display_numbers_as_hex as non-zero either on the command-line of Pasmo (--equ zxspec_config_display_numbers_as_hex), or in code before you call spec_init:
zxspec_config_display_numbers_as_hex equ $FF
See test/test-hex.asm for example usage. Note that assert_bytes_equal always displays expected/actual bytes as a comma-seperated list of hexadecimal pairs, regardless of this setting.
Assertions
See test/test-passes.asm for examples.
You can immediately pass or fail a test by using:
assert_passassert_fail
Registers
These assertions will preserve register values.
8-bit
assert_a_equalassert_a_not_equalassert_b_equalassert_b_not_equalassert_c_equalassert_c_not_equalassert_d_equalassert_d_not_equalassert_e_equalassert_e_not_equalassert_h_equalassert_h_not_equalassert_l_equalassert_l_not_equalassert_a_is_zeroassert_a_is_not_zero
16-bit
assert_bc_equalassert_bc_not_equalassert_de_equalassert_de_not_equalassert_hl_equalassert_hl_not_equalassert_ix_equalassert_ix_not_equal
IY
Asserting on the IY register value is not currently supported. The IY register is used by Spectrum ROM routines as a index to system variables and is not generally recommended to be used in custom routines due to the added complexity of ensuring its use does not interfere with normal operation.
Flags
assert_z_setassert_z_resetassert_carry_setassert_carry_resetassert_s_setassert_s_resetassert_p_v_setassert_p_v_reset
Memory
Be warned that these assertions will not preserve register values.
Single-Byte
assert_byte_equalassert_byte_not_equal
Double-Byte Word
assert_word_equalassert_word_not_equal
Strings
assert_str_equalassert_str_not_equal
Multiple Bytes
assert_bytes_equalassert_bytes_not_equal
Dependencies
-
Python 3 (for running ZX Spec tests)
-
Docker (for running Pasmo)
-
Fuse Emulator
Linux
$ sudo apt-get install fuse-emulator-common spectrum-roms
macOS
$ brew install homebrew/games/fuse-emulator
You can also run Fuse with Docker by setting the
FUSEenvironment variable accordingly:$ export "FUSE=docker run -v /tmp/.X11-unix:/tmp/.X11-unix --privileged -e DISPLAY=unix$DISPLAY -it rhargreaves/fuse-emulator"
Tests
ZX Spec can be tested by running:
Two sets of automated tests will run. One set results in all tests passing, and the other set results in all tests failing. The results are sent to an emulated ZX Printer (rather than sent to the display) which is then output by the emulator to a text file. This file is then validated to ensure the framework is working correctly.
Unfortunately, the speed of the ZX Printer is also emulated resulting in the tests taking a few minutes to complete. I don't currently know of a way to speed this up!
Demos
You can run a couple of example demos:
When all tests pass...
When all tests fail...
When there's a mixture...
Example Kata
I had a go at completing part of the Checkout Kata using this framework.
Credits
- This project was inspired by 64spec - a Commodore 64 Testing Framework



