boot2

Playing with the boostrap
git clone https://git.ryansepassi.com/git/boot2.git
Log | Files | Refs | README

run-tests.sh (9666B)


      1 #!/bin/sh
      2 ## run-tests.sh — unified test runner for the m1pp, p1, and scheme1 suites.
      3 ##
      4 ## Each suite is a directory of `<name>.<ext>` fixtures with sibling
      5 ## `<name>.expected` files. The runner builds each fixture, runs it inside
      6 ## the matching busybox container (`boot2-busybox:<arch>`), and diffs
      7 ## actual against expected output. Filenames starting with `_` are skipped
      8 ## (parked, ad-hoc debugging).
      9 ##
     10 ## Suites:
     11 ##   m1pp     tests/M1pp/<name>.M1     — P1 program built via build-p1.sh
     12 ##                                       for each requested arch, run in
     13 ##                                       container, stdout diffed.
     14 ##            tests/M1pp/<name>.M1pp   — m1pp expander parity test: per-arch
     15 ##                                       m1pp binary consumes the fixture
     16 ##                                       and writes <out>; diffed.
     17 ##   p1       tests/P1/<name>.P1pp     — P1pp program built via build-p1pp.sh
     18 ##                                       for each requested arch, run in
     19 ##                                       container, stdout diffed.
     20 ##   scheme1  tests/scheme1/<name>.scm — Scheme source run by the per-arch
     21 ##                                       scheme1 binary. stdout diffed
     22 ##                                       against <name>.expected (default
     23 ##                                       empty); exit code diffed against
     24 ##                                       <name>.expected-exit (default 0).
     25 ##
     26 ## All three arches by default; --arch restricts to one.
     27 ##
     28 ## Usage: scripts/run-tests.sh --suite <m1pp|p1|scheme1> [--arch ARCH] [name ...]
     29 
     30 set -eu
     31 
     32 SUITE=
     33 ARCH=
     34 NAMES=
     35 
     36 while [ "$#" -gt 0 ]; do
     37     case "$1" in
     38         --suite)   shift; SUITE=$1 ;;
     39         --suite=*) SUITE=${1#--suite=} ;;
     40         --arch)    shift; ARCH=$1 ;;
     41         --arch=*)  ARCH=${1#--arch=} ;;
     42         --) shift; while [ "$#" -gt 0 ]; do NAMES="$NAMES $1"; shift; done; break ;;
     43         -*) echo "$0: unknown flag '$1'" >&2; exit 2 ;;
     44         *) NAMES="$NAMES $1" ;;
     45     esac
     46     shift
     47 done
     48 
     49 case "$SUITE" in
     50     m1pp|p1|scheme1) ;;
     51     "") echo "$0: --suite required (m1pp | p1 | scheme1)" >&2; exit 2 ;;
     52     *) echo "$0: unknown suite '$SUITE'" >&2; exit 2 ;;
     53 esac
     54 
     55 REPO=$(cd "$(dirname "$0")/.." && pwd)
     56 cd "$REPO"
     57 
     58 platform_of() {
     59     case "$1" in
     60         aarch64) echo linux/arm64 ;;
     61         amd64)   echo linux/amd64 ;;
     62         riscv64) echo linux/riscv64 ;;
     63         *) echo "$0: unknown arch '$1'" >&2; return 1 ;;
     64     esac
     65 }
     66 
     67 run_in_container() {
     68     arch=$1; shift
     69     podman run --rm --pull=never --platform "$(platform_of "$arch")" \
     70         --tmpfs /tmp:size=512M \
     71         -e "ARCH=$arch" \
     72         -v "$REPO":/work -w /work \
     73         "boot2-busybox:$arch" "$@"
     74 }
     75 
     76 discover() {
     77     dir=$1; ext=$2
     78     ls "$dir" 2>/dev/null \
     79         | sed -n "s/^\\([^_][^.]*\\)\\.$ext\$/\\1/p" \
     80         | sort -u
     81 }
     82 
     83 PASS=0
     84 FAIL=0
     85 
     86 report() {
     87     label=$1; status=$2
     88     case "$status" in
     89         PASS) PASS=$((PASS + 1));;
     90         FAIL) FAIL=$((FAIL + 1));;
     91     esac
     92     echo "  $status $label"
     93 }
     94 
     95 show_diff() {
     96     expected=$1; actual=$2
     97     echo "    --- expected ---"
     98     printf '%s\n' "$expected" | sed 's/^/    /'
     99     echo "    --- actual ---"
    100     printf '%s\n' "$actual"   | sed 's/^/    /'
    101 }
    102 
    103 ## --- m1pp suite ---------------------------------------------------------
    104 ##
    105 ## Caller (Make) ensures build/<arch>/m1pp expanders, build/<arch>/tools/M0,
    106 ## the per-arch image, and P1/P1-<arch>.M1 tables exist before this runs.
    107 ## .M1 fixtures are still built per-fixture inline via boot-build-p1.sh
    108 ## (per-fixture build is test work, not infrastructure).
    109 
    110 run_m1pp_suite() {
    111     if [ -z "$ARCH" ]; then
    112         ARCHES="aarch64 amd64 riscv64"
    113     else
    114         ARCHES=$ARCH
    115     fi
    116     if [ -z "$NAMES" ]; then
    117         m1=$(discover tests/M1pp M1)
    118         m1pp=$(discover tests/M1pp M1pp)
    119         NAMES=$(printf '%s\n%s\n' "$m1" "$m1pp" | sort -u | tr '\n' ' ')
    120     fi
    121     for name in $NAMES; do
    122         expected=tests/M1pp/$name.expected
    123         m1_src=tests/M1pp/$name.M1
    124         m1pp_src=tests/M1pp/$name.M1pp
    125 
    126         if [ ! -e "$expected" ]; then
    127             echo "  SKIP $name (no .expected)"
    128             continue
    129         fi
    130         expected_content=$(cat "$expected")
    131 
    132         for arch in $ARCHES; do
    133             label="[$arch] $name"
    134             if [ -e "$m1pp_src" ]; then
    135                 outfile=build/$arch/m1pp-out/$name
    136                 mkdir -p "$(dirname "$outfile")"
    137                 rm -f "$outfile"
    138                 run_in_container "$arch" "./build/$arch/m1pp" "$m1pp_src" "$outfile" \
    139                     >/dev/null 2>&1 || true
    140                 actual=$([ -e "$outfile" ] && cat "$outfile" || echo "")
    141             elif [ -e "$m1_src" ]; then
    142                 bin=build/$arch/m1pp-tests/$name
    143                 if ! ARCH=$arch sh scripts/lint.sh "$m1_src" >/dev/null 2>&1 \
    144                   || ! run_in_container "$arch" sh scripts/boot-build-p1.sh "$m1_src" "$bin" \
    145                        >/dev/null 2>&1; then
    146                     report "$label" FAIL
    147                     ARCH=$arch sh scripts/lint.sh "$m1_src" 2>&1 | sed 's/^/    /' >&2 || true
    148                     run_in_container "$arch" sh scripts/boot-build-p1.sh "$m1_src" "$bin" \
    149                         2>&1 | sed 's/^/    /' >&2 || true
    150                     continue
    151                 fi
    152                 actual=$(run_in_container "$arch" "./$bin" 2>&1 || true)
    153             else
    154                 echo "  SKIP $name (no .M1 or .M1pp)"
    155                 break
    156             fi
    157 
    158             if [ "$actual" = "$expected_content" ]; then
    159                 report "$label" PASS
    160             else
    161                 report "$label" FAIL
    162                 show_diff "$expected_content" "$actual"
    163             fi
    164         done
    165     done
    166 }
    167 
    168 ## --- p1 suite -----------------------------------------------------------
    169 
    170 run_p1_suite() {
    171     if [ -z "$ARCH" ]; then
    172         ARCHES="aarch64 amd64 riscv64"
    173     else
    174         ARCHES=$ARCH
    175     fi
    176     if [ -z "$NAMES" ]; then
    177         NAMES=$(discover tests/P1 P1pp)
    178     fi
    179     for name in $NAMES; do
    180         fixture=tests/P1/$name.P1pp
    181         expected=tests/P1/$name.expected
    182         if [ ! -e "$fixture" ]; then
    183             echo "  SKIP $name (no .P1pp)"; continue
    184         fi
    185         if [ ! -e "$expected" ]; then
    186             echo "  SKIP $name (no .expected)"; continue
    187         fi
    188         expected_content=$(cat "$expected")
    189 
    190         for arch in $ARCHES; do
    191             label="[$arch] $name"
    192             bin=build/$arch/p1-tests/$name
    193             if ! run_in_container "$arch" sh scripts/boot-build-p1pp.sh "$fixture" "$bin" \
    194                  >/dev/null 2>&1; then
    195                 report "$label" FAIL
    196                 run_in_container "$arch" sh scripts/boot-build-p1pp.sh "$fixture" "$bin" \
    197                     2>&1 | sed 's/^/    /' >&2 || true
    198                 continue
    199             fi
    200             actual=$(run_in_container "$arch" "./$bin" 2>&1 || true)
    201             if [ "$actual" = "$expected_content" ]; then
    202                 report "$label" PASS
    203             else
    204                 report "$label" FAIL
    205                 show_diff "$expected_content" "$actual"
    206             fi
    207         done
    208     done
    209 }
    210 
    211 ## --- scheme1 suite ------------------------------------------------------
    212 ##
    213 ## Caller (Make) ensures build/<arch>/scheme1 already exists. The runner
    214 ## just invokes that binary against each .scm fixture, capturing stdout
    215 ## and the exit status. stdout is diffed against <name>.expected (defaults
    216 ## to empty if absent); the exit status is diffed against
    217 ## <name>.expected-exit (defaults to 0 if absent).
    218 
    219 run_scheme1_suite() {
    220     if [ -z "$ARCH" ]; then
    221         ARCHES="aarch64 amd64 riscv64"
    222     else
    223         ARCHES=$ARCH
    224     fi
    225     if [ -z "$NAMES" ]; then
    226         NAMES=$(discover tests/scheme1 scm)
    227     fi
    228     for name in $NAMES; do
    229         fixture=tests/scheme1/$name.scm
    230         expected_stdout_file=tests/scheme1/$name.expected
    231         expected_exit_file=tests/scheme1/$name.expected-exit
    232 
    233         if [ ! -e "$fixture" ]; then
    234             echo "  SKIP $name (no .scm)"; continue
    235         fi
    236         if [ -e "$expected_stdout_file" ]; then
    237             expected_stdout=$(cat "$expected_stdout_file")
    238         else
    239             expected_stdout=
    240         fi
    241         if [ -e "$expected_exit_file" ]; then
    242             expected_exit=$(cat "$expected_exit_file")
    243         else
    244             expected_exit=0
    245         fi
    246 
    247         for arch in $ARCHES; do
    248             label="[$arch] $name"
    249             bin=build/$arch/scheme1
    250             if [ ! -x "$bin" ]; then
    251                 report "$label" FAIL
    252                 echo "    (missing $bin -- run 'make scheme1 ARCH=$arch')" >&2
    253                 continue
    254             fi
    255 
    256             tmp_stdout=$(mktemp)
    257             if run_in_container "$arch" "./$bin" "$fixture" >"$tmp_stdout" 2>&1; then
    258                 actual_exit=0
    259             else
    260                 actual_exit=$?
    261             fi
    262             actual_stdout=$(cat "$tmp_stdout")
    263             rm -f "$tmp_stdout"
    264 
    265             if [ "$actual_stdout" = "$expected_stdout" ] \
    266                && [ "$actual_exit" = "$expected_exit" ]; then
    267                 report "$label" PASS
    268             else
    269                 report "$label" FAIL
    270                 if [ "$actual_stdout" != "$expected_stdout" ]; then
    271                     show_diff "$expected_stdout" "$actual_stdout"
    272                 fi
    273                 if [ "$actual_exit" != "$expected_exit" ]; then
    274                     echo "    exit: expected $expected_exit, got $actual_exit"
    275                 fi
    276             fi
    277         done
    278     done
    279 }
    280 
    281 case "$SUITE" in
    282     m1pp)    run_m1pp_suite ;;
    283     p1)      run_p1_suite ;;
    284     scheme1) run_scheme1_suite ;;
    285 esac
    286 
    287 echo "$PASS passed, $FAIL failed"
    288 [ "$FAIL" -eq 0 ]