Skip to content

rhargreaves/zx-spec

Repository files navigation

ZX Spec Build Status

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_pass
  • assert_fail

Registers

These assertions will preserve register values.

8-bit

  • assert_a_equal
  • assert_a_not_equal
  • assert_b_equal
  • assert_b_not_equal
  • assert_c_equal
  • assert_c_not_equal
  • assert_d_equal
  • assert_d_not_equal
  • assert_e_equal
  • assert_e_not_equal
  • assert_h_equal
  • assert_h_not_equal
  • assert_l_equal
  • assert_l_not_equal
  • assert_a_is_zero
  • assert_a_is_not_zero

16-bit

  • assert_bc_equal
  • assert_bc_not_equal
  • assert_de_equal
  • assert_de_not_equal
  • assert_hl_equal
  • assert_hl_not_equal
  • assert_ix_equal
  • assert_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_set
  • assert_z_reset
  • assert_carry_set
  • assert_carry_reset
  • assert_s_set
  • assert_s_reset
  • assert_p_v_set
  • assert_p_v_reset

Memory

Be warned that these assertions will not preserve register values.

Single-Byte

  • assert_byte_equal
  • assert_byte_not_equal

Double-Byte Word

  • assert_word_equal
  • assert_word_not_equal

Strings

  • assert_str_equal
  • assert_str_not_equal

Multiple Bytes

  • assert_bytes_equal
  • assert_bytes_not_equal

Dependencies

  • Python 2.7 (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 FUSE environment 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:

$ make test

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...

$ make demo-green

When all tests fail...

$ make demo-red

When there's a mixture...

$ make demo-mix

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