diff options
| author | hachem <im@hachem.wtf> | 2026-08-30 21:21:53 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-08-30 21:21:53 +0200 |
| commit | 294777178f9203283364f3e672569becb4dd1e7c (patch) | |
| tree | b97447843d06f8f63a01505c85e6e9f9e804b797 | |
| parent | 13704a1df5c15af7163cc7764b0aeebc81ad2bdd (diff) | |
test: add automated docker testing for the whole test suite
| -rw-r--r-- | README.md | 10 | ||||
| -rw-r--r-- | examples/arithmetic.hdass | 13 | ||||
| -rw-r--r-- | examples/branch.hdass | 17 | ||||
| -rw-r--r-- | examples/call.hdass | 13 | ||||
| -rw-r--r-- | examples/exit_code.hdass | 9 | ||||
| -rw-r--r-- | examples/greet.hdass | 20 | ||||
| -rw-r--r-- | examples/loop_sum.hdass | 18 | ||||
| -rwxr-xr-x | scripts/docker_test.sh | 18 | ||||
| -rwxr-xr-x | scripts/test_examples.sh | 76 |
9 files changed, 194 insertions, 0 deletions
@@ -64,6 +64,16 @@ ld hello.o -o hello ./hello ``` +To transpile, assemble, link and run every program in [examples/](examples/) and check its output, use the end-to-end test script (also from inside the container): +```bash +make config=debug && ./scripts/test_examples.sh +``` + +Or, from the host, run the whole suite (unit tests plus the example tests) in one shot, bringing the container up if needed: +```bash +./scripts/docker_test.sh +``` + When you're finished, stop and remove the container: ```bash docker compose down diff --git a/examples/arithmetic.hdass b/examples/arithmetic.hdass new file mode 100644 index 0000000..359653e --- /dev/null +++ b/examples/arithmetic.hdass @@ -0,0 +1,13 @@ +// Computes (5 + 3) * 2 - 1 = 15 and returns it as the exit status. +const SYS_EXIT = 60 + +proc main +{ + rdi = 5 + rdi += 3 + rdi *= 2 + rdi -= 1 + + rax = SYS_EXIT + syscall +} diff --git a/examples/branch.hdass b/examples/branch.hdass new file mode 100644 index 0000000..1218773 --- /dev/null +++ b/examples/branch.hdass @@ -0,0 +1,17 @@ +// Returns the larger of two values (max(3, 8) = 8) as the exit status. +const SYS_EXIT = 60 + +proc main +{ + rbx = 3 + rcx = 8 + + rdi = rbx + if rcx <= rbx + goto done + rdi = rcx + +done: + rax = SYS_EXIT + syscall +} diff --git a/examples/call.hdass b/examples/call.hdass new file mode 100644 index 0000000..239a26b --- /dev/null +++ b/examples/call.hdass @@ -0,0 +1,13 @@ +// Passes an argument through a proc parameter, which exits with that value. +const SYS_EXIT = 60 + +proc exit_with(code: rdi) +{ + rax = SYS_EXIT + syscall +} + +proc main +{ + exit_with(21) +} diff --git a/examples/exit_code.hdass b/examples/exit_code.hdass new file mode 100644 index 0000000..7c44df9 --- /dev/null +++ b/examples/exit_code.hdass @@ -0,0 +1,9 @@ +// Exits with status 42 and no output. +const SYS_EXIT = 60 + +proc main +{ + rax = SYS_EXIT + rdi = 42 + syscall +} diff --git a/examples/greet.hdass b/examples/greet.hdass new file mode 100644 index 0000000..a253b5e --- /dev/null +++ b/examples/greet.hdass @@ -0,0 +1,20 @@ +// Writes a fixed string to stdout, then exits cleanly. +const SYS_WRITE = 1 +const SYS_EXIT = 60 + +const STDOUT = 1 + +data greeting = "hdass works!\n" + +proc main +{ + rax = SYS_WRITE + rdi = STDOUT + rsi = greeting + rdx = greeting.len + syscall + + rax = SYS_EXIT + rdi = 0 + syscall +} diff --git a/examples/loop_sum.hdass b/examples/loop_sum.hdass new file mode 100644 index 0000000..bb8d115 --- /dev/null +++ b/examples/loop_sum.hdass @@ -0,0 +1,18 @@ +// Sums 5 + 4 + 3 + 2 + 1 = 15 with a countdown loop, returns it as the status. +const SYS_EXIT = 60 + +proc main +{ + rbx = 0 // running total + rcx = 5 // counter + +loop: + rbx += rcx + rcx -= 1 + if rcx != 0 + goto loop + + rdi = rbx + rax = SYS_EXIT + syscall +} diff --git a/scripts/docker_test.sh b/scripts/docker_test.sh new file mode 100755 index 0000000..93f0bca --- /dev/null +++ b/scripts/docker_test.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Convenience wrapper: build hdass and run the full test suite (unit tests plus +# the end-to-end example tests) inside the amd64 Linux Docker environment. +# Run this from the host; it brings the container up if it is not already. +set -euo pipefail + +root="$(cd "$(dirname "$0")/.." && pwd)" +cd "$root" + +docker compose up -d + +docker compose exec -T hdass bash -c ' + set -e + premake5 gmake + make config=debug + ./bin/debug-linux/tests + ./scripts/test_examples.sh +' diff --git a/scripts/test_examples.sh b/scripts/test_examples.sh new file mode 100755 index 0000000..2fb4e5f --- /dev/null +++ b/scripts/test_examples.sh @@ -0,0 +1,76 @@ +#!/usr/bin/env bash +# End-to-end example tests: transpile each program with hdass, assemble it with +# nasm, link it with ld, run it, and compare its stdout and exit status against +# the expected values below. +# +# The generated programs use Linux x86-64 syscalls, so this must run in the +# amd64 Linux environment (see the Docker setup in the README), not on macOS. +set -u + +root="$(cd "$(dirname "$0")/.." && pwd)" +cd "$root" + +hdass="${HDASS:-./bin/debug-linux/hdass}" +if [ ! -x "$hdass" ]; then + echo "error: '$hdass' not found; build it first with:" >&2 + echo " premake5 gmake && make config=debug" >&2 + exit 1 +fi + +for tool in nasm ld; do + if ! command -v "$tool" >/dev/null 2>&1; then + echo "error: '$tool' not found; run this inside the Docker environment" >&2 + exit 1 + fi +done + +work="$(mktemp -d)" +trap 'rm -rf "$work"' EXIT + +pass=0 +fail=0 + +# check <name> <source> <expected_exit> <expected_stdout> +# expected_stdout is compared after trailing newlines are stripped (as $() does). +check() +{ + local name="$1" source="$2" expected_exit="$3" expected_stdout="$4" + local asm="$work/$name.asm" obj="$work/$name.o" bin="$work/$name" + + if ! "$hdass" "$source" -o "$asm" 2>"$work/err"; then + echo "FAIL $name (transpile)"; cat "$work/err"; fail=$((fail + 1)); return + fi + if ! nasm -f elf64 "$asm" -o "$obj" 2>"$work/err"; then + echo "FAIL $name (assemble)"; cat "$work/err"; fail=$((fail + 1)); return + fi + if ! ld "$obj" -o "$bin" 2>"$work/err"; then + echo "FAIL $name (link)"; cat "$work/err"; fail=$((fail + 1)); return + fi + + local actual_stdout actual_exit + actual_stdout="$("$bin")" + actual_exit=$? + + if [ "$actual_exit" != "$expected_exit" ] || [ "$actual_stdout" != "$expected_stdout" ]; then + echo "FAIL $name" + echo " expected: exit=$expected_exit stdout=$(printf '%q' "$expected_stdout")" + echo " actual: exit=$actual_exit stdout=$(printf '%q' "$actual_stdout")" + fail=$((fail + 1)) + return + fi + + echo "PASS $name" + pass=$((pass + 1)) +} + +check hello_world examples/hello_world.hdass 0 "Hello, World!" +check greet examples/greet.hdass 0 "hdass works!" +check exit_code examples/exit_code.hdass 42 "" +check arithmetic examples/arithmetic.hdass 15 "" +check loop_sum examples/loop_sum.hdass 15 "" +check branch examples/branch.hdass 8 "" +check call examples/call.hdass 21 "" + +echo +echo "$pass passed, $fail failed" +[ "$fail" -eq 0 ] |
