#!/usr/bin/env bash # run-el-test.sh — compile and run one El test program from tests/. # # WHY THIS EXISTS (2026-08-07, issue #129): # tests/ has held 14 test programs for months with no way to run them. CI does # not run them. The convention printed in their own headers # (`elc soul.el && ./soul --test tests/x.el`) refers to a --test flag the El # runtime does not implement. So the tests were documentation, not gates — # which is how a P0 safety regression shipped with a test directory present. # # THE RECIPE, AND WHY IT IS THIS SHAPE: # Same discovery as gen-soul-amalgam.sh — `elc --target=c` emits only an extern # prototype for any module that has a .elh header next to it, and inlines the # module's bodies when it does not. A test that imports ../chat.el therefore # compiles to a 18 KB unit full of unresolved externs unless the headers are # out of the way. So: copy the sources into a scratch tree, delete every .elh # on the import chain, and compile the test there. # # Scratch copy on purpose: the worktree is shared with other terminals and # deleting headers in place would be a shared-tree mutation with no owner. # # EXIT STATUS IS THE GATE: non-zero if the binary fails to build, crashes, or if # its output contains a FAIL line or reports a non-zero failed count. Do not # "improve" this into something that only checks the exit code of the test # binary — these El tests print failures and still exit 0. # # usage: scripts/run-el-test.sh tests/test_history_amplification.el set -euo pipefail TEST_REL="${1:?usage: run-el-test.sh tests/.el}" SRC="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TEST_NAME="$(basename "$TEST_REL" .el)" ELC="${ELC:-$HOME/neuron-dev-stack/src/el/lang/dist/platform/elc}" [ -x "$ELC" ] || ELC="$HOME/el-sdk/elc" [ -x "$ELC" ] || { echo "[run-el-test] FAIL: no elc found (set ELC=)"; exit 1; } RTC="${RTC:-$SRC/vendor/el-runtime/v1.0.0-20260501/el_runtime.c}" [ -f "$RTC" ] || RTC="$HOME/el-sdk/el_runtime.c" [ -f "$RTC" ] || { echo "[run-el-test] FAIL: no el_runtime.c found (set RTC=)"; exit 1; } RTDIR="$(dirname "$RTC")" EL_REPO="${EL_REPO:-$HOME/Development/neuron-technologies/el}" SSL="${SSL_PREFIX:-/opt/homebrew/opt/openssl@3}" GEN="$(mktemp -d "${TMPDIR:-/tmp}/el-test.XXXXXX")" trap 'rm -rf "$GEN"' EXIT mkdir -p "$GEN/neuron/tests" "$GEN/foundation/el/elp/src" cp "$SRC"/*.el "$GEN/neuron/" cp "$SRC"/tests/*.el "$GEN/neuron/tests/" 2>/dev/null || true [ -d "$EL_REPO/elp/src" ] && cp "$EL_REPO"/elp/src/*.el "$GEN/foundation/el/elp/src/" 2>/dev/null || true # The whole recipe depends on there being no headers to short-circuit inlining. find "$GEN" -name '*.elh' -delete echo "[run-el-test] compiling $TEST_REL" ( cd "$GEN/neuron" && "$ELC" --target=c "tests/${TEST_NAME}.el" ) > "$GEN/${TEST_NAME}.c" BODIES=$(grep -c '^el_val_t .*) {$' "$GEN/${TEST_NAME}.c" || true) echo "[run-el-test] $(wc -c < "$GEN/${TEST_NAME}.c" | tr -d ' ') bytes, ${BODIES} inlined function bodies" # A test that imports ../chat.el pulls in the bulk of the engine. A tiny body # count means an import was read from a header instead of inlined, and the test # would be exercising extern stubs rather than the real code. if [ "$BODIES" -lt 100 ]; then echo "[run-el-test] FAIL: only $BODIES inlined bodies — an import was not inlined" exit 1 fi cc -O2 -DHAVE_CURL \ -I"$RTDIR" -I"$SSL/include" -L"$SSL/lib" \ "$GEN/${TEST_NAME}.c" "$RTC" \ -lssl -lcrypto -lcurl -lpthread -lm \ -o "$GEN/${TEST_NAME}" 2> "$GEN/cc.log" || { echo "[run-el-test] FAIL: compile error"; tail -30 "$GEN/cc.log"; exit 1; } # arm64 pointer-truncation guard (cc-brain.sh's rule): an implicit declaration of # a runtime symbol truncates its returned pointer to 32 bits. if grep -E 'implicit.*(engram_|el_)' "$GEN/cc.log"; then echo "[run-el-test] FAIL: implicit declarations of runtime symbols"; exit 1; fi # Throwaway HOME so a test can never read or write the live engram at ~/.neuron. TEST_HOME="$GEN/home" mkdir -p "$TEST_HOME" echo "[run-el-test] running $TEST_NAME" set +e HOME="$TEST_HOME" NEURON_HOME="$TEST_HOME/.neuron" "$GEN/${TEST_NAME}" 2>&1 | tee "$GEN/out.txt" RC=${PIPESTATUS[0]} set -e if [ "$RC" -ne 0 ]; then echo "[run-el-test] FAIL: $TEST_NAME exited $RC (crash or abort)" exit 1 fi if grep -q " FAIL:" "$GEN/out.txt"; then echo "[run-el-test] FAIL: $TEST_NAME reported failing assertions" exit 1 fi if grep -qE '[1-9][0-9]* failed' "$GEN/out.txt"; then echo "[run-el-test] FAIL: $TEST_NAME reported a non-zero failed count" exit 1 fi if ! grep -q "PASS:" "$GEN/out.txt"; then echo "[run-el-test] FAIL: $TEST_NAME produced no assertions at all" exit 1 fi echo "[run-el-test] PASS: $TEST_NAME"