all repos — xyw @ ed455f994f4497b3b389df581489c0bf91ec0b0a

A minimal virtual machine and assembler for terminals.

Implemented simple test script.
h3rald h3rald@h3rald.com
Mon, 02 Feb 2026 15:40:07 +0100
commit

ed455f994f4497b3b389df581489c0bf91ec0b0a

parent

0cf83a858b968240d81b1a3dcffafac4184d6e29

1 files changed, 167 insertions(+), 0 deletions(-)

jump to
A test.sh

@@ -0,0 +1,167 @@

+#!/usr/bin/env bash +set -euo pipefail + +### Test cases +TEST_CASES=( + "run_test helloworld.xyw assert_output_equals \$'Hello, World!\\n'" + "run_test d6.xyw assert_output_in_range 1 6" +) + +### Helper functions + +ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +EXAMPLES_DIR="$ROOT_DIR/examples" + +fail() { + echo "ERROR: $*" >&2 + exit 1 +} + +need_file() { + local path="$1" + [[ -f "$path" ]] || fail "Missing file: $path" +} + +build_xyw() { + if command -v make >/dev/null 2>&1; then + (cd "$ROOT_DIR" && make xyw) + else + echo "WARN: 'make' not found; using existing xyw binary if present." >&2 + fi +} + +find_xyw_bin() { + if [[ -x "$ROOT_DIR/xyw" ]]; then + echo "$ROOT_DIR/xyw" + return 0 + fi + if [[ -x "$ROOT_DIR/xyw.exe" ]]; then + echo "$ROOT_DIR/xyw.exe" + return 0 + fi + fail "Could not find executable xyw binary (expected $ROOT_DIR/xyw or $ROOT_DIR/xyw.exe)." +} + +assemble_in_examples_dir() { + local xyw_bin="$1" + local src_basename="$2" # e.g. helloworld.xyw + + need_file "$EXAMPLES_DIR/$src_basename" + + (cd "$EXAMPLES_DIR" && "$xyw_bin" "$src_basename" >/dev/null) + + local img_basename="${src_basename%.xyw}.xim" + need_file "$EXAMPLES_DIR/$img_basename" + echo "$img_basename" +} + +run_image_capture_stdout() { + local xyw_bin="$1" + local img_basename="$2" # e.g. helloworld.xim + local out_file="$3" + + need_file "$EXAMPLES_DIR/$img_basename" + + (cd "$EXAMPLES_DIR" && "$xyw_bin" "$img_basename" >"$out_file") +} + +normalize_crlf() { + local in_file="$1" + local out_file="$2" + + tr -d '\r' <"$in_file" >"$out_file" +} + +### Assertion functions + +assert_file_equals() { + local actual_file="$1" + local expected_file="$2" + + if ! cmp -s "$actual_file" "$expected_file"; then + echo "--- Expected (cat -v) ---" >&2 + cat -v "$expected_file" >&2 || true + echo "--- Actual (cat -v) ---" >&2 + cat -v "$actual_file" >&2 || true + fail "Output did not match expectation." + fi +} + +assert_output_equals() { + local stdout_file="$1" + local expected_string="$2" + + local expected_file + expected_file="$TMPDIR/expected.$$.${RANDOM}.txt" + printf '%s' "$expected_string" >"$expected_file" + assert_file_equals "$stdout_file" "$expected_file" + rm -f "$expected_file" +} + +assert_output_in_range() { + local stdout_file="$1" + local min_value="$2" + local max_value="$3" + + local value + value="$(tr -d '\n\t ' <"$stdout_file")" + + if [[ ! "$value" =~ ^-?[0-9]+$ ]]; then + echo "--- Actual (cat -v) ---" >&2 + cat -v "$stdout_file" >&2 || true + fail "Output is not an integer: '$value'" + fi + + if (( value < min_value || value > max_value )); then + echo "--- Actual (cat -v) ---" >&2 + cat -v "$stdout_file" >&2 || true + fail "Output out of range (expected ${min_value}..${max_value}): $value" + fi +} + +### Test runner + +run_test() { + local src_basename="$1" + local assert_fn="$2" + shift 2 + + if ! declare -F "$assert_fn" >/dev/null 2>&1; then + fail "Assertion function not found: $assert_fn" + fi + + need_file "$EXAMPLES_DIR/$src_basename" + + local img_basename + img_basename="$(assemble_in_examples_dir "$XYW_BIN" "$src_basename")" + + local raw_out="$TMPDIR/${src_basename%.xyw}.raw" + local norm_out="$TMPDIR/${src_basename%.xyw}.norm" + + run_image_capture_stdout "$XYW_BIN" "$img_basename" "$raw_out" + normalize_crlf "$raw_out" "$norm_out" + + "$assert_fn" "$norm_out" "$@" + echo "PASS: $src_basename" +} + +### Main + +main() { + need_file "$ROOT_DIR/Makefile" + + build_xyw + + TMPDIR="$(mktemp -d 2>/dev/null || mktemp -d -t xywtest)" + trap "rm -rf \"$TMPDIR\"" EXIT + + XYW_BIN="$(find_xyw_bin)" + + for tc in "${TEST_CASES[@]}"; do + eval "$tc" + done + + echo "All tests passed." +} + +main "$@"