Template
test: add end-to-end integration across dash/bash/zsh
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
# Makefile.in - integration-fixture template (plan todo 26).
|
||||
#
|
||||
# The substitution placeholders are filled by the generated ./configure
|
||||
# (they must stay literal here - never expand them in this file). CC and
|
||||
# CFLAGS come from the C language module's detection, LIBS from the feature
|
||||
# probes' link flags (-lpthread/-lm), prefix from the --prefix default or
|
||||
# override.
|
||||
#
|
||||
# NOTE: the substitution is LINE-BASED and runs on every line, comments
|
||||
# included - so no comment may contain a placeholder-shaped token (the
|
||||
# configure script would treat it as a variable to substitute).
|
||||
#
|
||||
# This file is NOT generated by stupidtools: the tool only substitutes
|
||||
# placeholders into it (Makefile generation is out of v1 scope by design).
|
||||
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@ -std=c23 -Wall -Wextra -Wpedantic
|
||||
LIBS = @LIBS@
|
||||
prefix = @prefix@
|
||||
|
||||
all: demo
|
||||
|
||||
demo: main.c demo.c demo.h
|
||||
$(CC) $(CFLAGS) main.c demo.c -o demo $(LIBS)
|
||||
|
||||
clean:
|
||||
rm -f demo
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* demo.c - second translation unit of the integration fixture.
|
||||
*
|
||||
* Gives the fixture a real multi-file shape (the header demo.h is part of
|
||||
* the deliverable "sources + headers"). Deliberately libm-free: the only
|
||||
* libm dependency lives in main.c (sin), so a broken -lm accumulation is
|
||||
* caught at LINK time there.
|
||||
*/
|
||||
|
||||
#include "demo.h"
|
||||
|
||||
int
|
||||
demo_compute(int x)
|
||||
{
|
||||
return x * 3 + 1;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* demo.h - fixture header, included by main.c and demo.c.
|
||||
*/
|
||||
|
||||
#ifndef HELLOTHREADS_DEMO_H
|
||||
#define HELLOTHREADS_DEMO_H
|
||||
|
||||
int demo_compute(int x);
|
||||
|
||||
#endif /* HELLOTHREADS_DEMO_H */
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* main.c - integration-fixture entry point (plan todo 26).
|
||||
*
|
||||
* A REAL C23 program exercising both fixture features end to end:
|
||||
* - pthread: pthread_create()/pthread_join() run a worker thread (guarded
|
||||
* by the HAVE_PTHREAD define the generated config.h wrote), printing a
|
||||
* grep-able marker the runner asserts on;
|
||||
* - math: sin(0.5) from libm, printed with a fixed format the runner
|
||||
* greps (the link would fail without -lm, so a successful run proves
|
||||
* the LIBS accumulation reached the Makefile).
|
||||
*
|
||||
* _POSIX_C_SOURCE must be defined BEFORE the first include: under strict
|
||||
* -std=c23 glibc sets __STRICT_ANSI__ and hides pthread_create's
|
||||
* declaration, which C23 turns into an implicit-declaration ERROR
|
||||
* (the same trap recorded for src/ in the project learnings).
|
||||
*/
|
||||
|
||||
#ifndef _POSIX_C_SOURCE
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include "demo.h"
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef HAVE_PTHREAD
|
||||
#include <pthread.h>
|
||||
|
||||
static void *
|
||||
worker(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
printf("worker thread ran\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
double s = sin(0.5);
|
||||
|
||||
printf("hellothreads demo: sin(0.5) = %.4f\n", s);
|
||||
printf("demo_compute(2) = %d\n", demo_compute(2));
|
||||
#ifdef HAVE_PTHREAD
|
||||
{
|
||||
pthread_t t;
|
||||
|
||||
if (pthread_create(&t, NULL, worker, NULL) != 0) {
|
||||
fprintf(stderr, "pthread_create failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if (pthread_join(t, NULL) != 0) {
|
||||
fprintf(stderr, "pthread_join failed\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/* project-fail.kdl - the FAILURE variant of project.kdl (plan todo 26).
|
||||
*
|
||||
* Same shape as project.kdl, but the pthread feature is replaced by a
|
||||
* feature checking a header that does not exist on any system:
|
||||
*
|
||||
* feature "nope" { header "nope_missing_xyz.h" }
|
||||
*
|
||||
* The generated ./configure must handle the failed probe CLEANLY under
|
||||
* every shell in the matrix: the failure is recorded (have_nope=no), the
|
||||
* check is named in config.log (the compiler's diagnostic), config.h gets
|
||||
* NO HAVE_NOPE define, and no shell reports a syntax error. A healthy
|
||||
* second feature ("posix", unistd.h) proves configure continues after a
|
||||
* failed check and the healthy feature still resolves.
|
||||
*
|
||||
* NOTE (deviation, tracked in .omo/notepads/stupidtools/issues.md): the
|
||||
* v1 generator (todos 16/17, frozen to todo 26) follows autoconf
|
||||
* semantics - a failed OPTIONAL check records have_<name>=no and
|
||||
* configure still exits 0; it does not abort. The plan/todo text expected
|
||||
* rc!=0 here. run.sh asserts the generator's REAL contract and exercises
|
||||
* the genuinely-non-zero configure-error path via an unrecognized option.
|
||||
*/
|
||||
|
||||
project "hellothreads-fail" version "1.0.0"
|
||||
|
||||
feature "nope" {
|
||||
header "nope_missing_xyz.h"
|
||||
}
|
||||
|
||||
feature "posix" {
|
||||
header "unistd.h"
|
||||
}
|
||||
|
||||
target "default" {
|
||||
src "main.c"
|
||||
feature "nope"
|
||||
feature "posix"
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
/* project.kdl - integration-fixture build file (plan todo 26).
|
||||
*
|
||||
* A small but REAL C project exercising the DSL the way a user would:
|
||||
* - feature "pthread": a header check (pthread.h) AND a library check
|
||||
* (pthread -> -lpthread), like the classic autoconf AC_CHECK_HEADER +
|
||||
* AC_CHECK_LIB pair;
|
||||
* - feature "math": an optional library check (m -> -lm). Not strictly
|
||||
* required by every build (an option maps to --enable-math/--disable
|
||||
* --math), but present so the generated Makefile accumulates -lm
|
||||
* when it resolves;
|
||||
* - target "default": the real source list of the fixture (descriptive
|
||||
* in v1 - the generated configure substitutes @VAR@ into Makefile.in,
|
||||
* it does not generate Makefiles);
|
||||
* - option "debug": an option node, proving the --enable-debug /
|
||||
* --disable-debug surface shows up in the generated --help.
|
||||
*
|
||||
* DSL grammar (src/kdl/schema.h): `project` first, then targets/features/
|
||||
* options; feature children are checks (header/library/... from the 8
|
||||
* registry kinds). */
|
||||
|
||||
project "hellothreads" version "1.0.0"
|
||||
|
||||
feature "pthread" {
|
||||
header "pthread.h"
|
||||
library "pthread"
|
||||
}
|
||||
|
||||
feature "math" {
|
||||
library "m"
|
||||
}
|
||||
|
||||
target "default" {
|
||||
src "main.c"
|
||||
src "demo.c"
|
||||
feature "pthread"
|
||||
feature "math"
|
||||
}
|
||||
|
||||
option "debug" default=#false
|
||||
Executable
+381
@@ -0,0 +1,381 @@
|
||||
#!/bin/sh
|
||||
# tests/integration/run.sh - end-to-end integration test (plan todo 26).
|
||||
#
|
||||
# Drives a REAL fixture C project (tests/integration/fixture/) through the
|
||||
# full stupidtools pipeline, once per shell in the portability matrix
|
||||
# (dash/bash/zsh; sh stands in for dash when dash is not installed):
|
||||
#
|
||||
# 1. the wired binary ($TOP_DIR/src/stupidtools) generates ./configure
|
||||
# from project.kdl into an isolated temp dir (one dir per shell);
|
||||
# 2. that ./configure runs UNDER THE SHELL (any non-POSIX emission dies
|
||||
# as a syntax error right here), writing Makefile/config.h/config.log/
|
||||
# config.status;
|
||||
# 3. make builds the fixture binary; assertions verify the build, the
|
||||
# substituted Makefile (CC/CFLAGS/LIBS/prefix), config.h defines,
|
||||
# config.log probe results and config.status --config.
|
||||
#
|
||||
# A second fixture (project-fail.kdl) checks a deliberately MISSING header:
|
||||
# the generated configure must handle the failed probe CLEANLY under every
|
||||
# shell - the failure is recorded (have_nope=no), the check is named in
|
||||
# config.log (the compiler's diagnostic), config.h gets NO HAVE_NOPE
|
||||
# define, and no shell may report a syntax error.
|
||||
#
|
||||
# NOTE (deviation, tracked in .omo/notepads/stupidtools/issues.md): the v1
|
||||
# generator (todos 16/17, frozen to todo 26) follows autoconf semantics -
|
||||
# a failed OPTIONAL check records have_<name>=no and configure still exits
|
||||
# 0; it does not abort. The plan/todo text expected rc!=0 for a missing
|
||||
# header. This runner asserts the generator's REAL contract (rc=0 + the
|
||||
# failure recorded), and additionally exercises the genuinely-non-zero
|
||||
# configure-error path (an unrecognized option exits 1 with a readable
|
||||
# message and no shell syntax error) so BOTH halves of "fails cleanly
|
||||
# (non-zero, readable message)" are covered by a real assertion.
|
||||
#
|
||||
# POSIX sh only (dash/bash/zsh safe): no [[ ]], arrays, local, ==, <<<, &>.
|
||||
# Exit 0 = every shell's happy case AND failure case passed.
|
||||
|
||||
TOP_DIR=$(cd "$(dirname "$0")/../.." && pwd) || {
|
||||
echo "FAIL: cannot resolve project root" >&2
|
||||
exit 1
|
||||
}
|
||||
BIN="$TOP_DIR/src/stupidtools"
|
||||
FIX="$TOP_DIR/tests/integration/fixture"
|
||||
|
||||
TESTS_RUN=0
|
||||
TESTS_FAILED=0
|
||||
|
||||
# temp dirs created by new_work() are recorded in a file list; the trap
|
||||
# cleans them on every exit path (a file list + $(cat ...) splits under
|
||||
# every POSIX shell AND native zsh, unlike an unquoted variable).
|
||||
WORK_LIST="${TMPDIR:-/tmp}/stupidtools-int-worklist.$$"
|
||||
: > "$WORK_LIST"
|
||||
cleanup_dirs() {
|
||||
[ -s "$WORK_LIST" ] && rm -rf $(cat "$WORK_LIST")
|
||||
rm -f "$WORK_LIST"
|
||||
}
|
||||
trap cleanup_dirs EXIT HUP INT TERM
|
||||
|
||||
pass() {
|
||||
TESTS_RUN=$((TESTS_RUN + 1))
|
||||
printf 'ok %d - %s\n' "$TESTS_RUN" "$1"
|
||||
}
|
||||
|
||||
fail() {
|
||||
TESTS_RUN=$((TESTS_RUN + 1))
|
||||
TESTS_FAILED=$((TESTS_FAILED + 1))
|
||||
printf 'not ok %d - %s\n' "$TESTS_RUN" "$1" >&2
|
||||
}
|
||||
|
||||
# new_work: mktemp an isolated dir and record it for trap cleanup.
|
||||
new_work() {
|
||||
WORK=$(mktemp -d "${TMPDIR:-/tmp}/stupidtools-int.XXXXXX") || {
|
||||
fail "cannot create temp dir"
|
||||
return 1
|
||||
}
|
||||
printf '%s\n' "$WORK" >> "$WORK_LIST"
|
||||
return 0
|
||||
}
|
||||
|
||||
# --- preconditions (fail honestly, never silently skip) ------------------
|
||||
if [ -x "$BIN" ]; then
|
||||
pass "binary exists and is executable: $BIN"
|
||||
else
|
||||
fail "binary missing: $BIN (run 'make' first)"
|
||||
fi
|
||||
|
||||
for f in project.kdl project-fail.kdl Makefile.in main.c demo.c demo.h; do
|
||||
if [ -f "$FIX/$f" ]; then
|
||||
pass "fixture file present: $f"
|
||||
else
|
||||
fail "fixture file missing: $FIX/$f"
|
||||
fi
|
||||
done
|
||||
|
||||
# --- the shell matrix -----------------------------------------------------
|
||||
# Built as positional parameters and iterated with "$@" - the one portable
|
||||
# multi-word construct that behaves identically under POSIX sh AND native
|
||||
# zsh (an unquoted variable is NOT word-split in native zsh). dash when
|
||||
# available (it now is on this host), else sh as stand-in; the runner
|
||||
# prints which one it used - never a silent substitution.
|
||||
set --
|
||||
if command -v dash >/dev/null 2>&1; then
|
||||
set -- "$@" dash
|
||||
DASH_USED=yes
|
||||
else
|
||||
set -- "$@" sh
|
||||
DASH_USED=no
|
||||
printf '# note: dash: unavailable - matrix uses sh instead of dash\n'
|
||||
fi
|
||||
for cand in bash zsh; do
|
||||
if command -v "$cand" >/dev/null 2>&1; then
|
||||
set -- "$@" "$cand"
|
||||
else
|
||||
fail "required shell not installed: $cand"
|
||||
fi
|
||||
done
|
||||
SHELLS="$*"
|
||||
printf '# shell matrix: %s (dash used: %s)\n' "$SHELLS" "$DASH_USED"
|
||||
|
||||
printf '# note: failed-check semantics per the frozen v1 generator: a failed\n'
|
||||
printf '# optional check records have_<name>=no and configure exits 0;\n'
|
||||
printf '# the non-zero configure-error path is asserted via an unknown\n'
|
||||
printf '# option instead (see header + issues.md).\n'
|
||||
|
||||
# --- happy case: one shell, one isolated dir ------------------------------
|
||||
run_happy() {
|
||||
shell=$1
|
||||
|
||||
new_work || return 1
|
||||
if cp "$FIX/project.kdl" "$FIX/Makefile.in" "$FIX/main.c" "$FIX/demo.c" \
|
||||
"$FIX/demo.h" "$WORK/" \
|
||||
&& (cd "$WORK" && XDG_DATA_HOME="$WORK/xdg" STUPIDTOOLS_EXT= \
|
||||
"$BIN" project.kdl >gen.log 2>&1) \
|
||||
&& [ -s "$WORK/configure" ]; then
|
||||
pass "$shell: stupidtools generated ./configure from project.kdl"
|
||||
else
|
||||
fail "$shell: configure generation failed: $(cat "$WORK/gen.log" 2>/dev/null)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# real dash is the strict oracle when it is in the matrix
|
||||
if [ "$shell" = "dash" ]; then
|
||||
if dash -n "$WORK/configure" 2>"$WORK/dashn.err"; then
|
||||
pass "dash: generated ./configure passes dash -n"
|
||||
else
|
||||
fail "dash: generated ./configure fails dash -n: $(cat "$WORK/dashn.err" 2>/dev/null)"
|
||||
fi
|
||||
fi
|
||||
|
||||
# run configure UNDER THE SHELL. CC/CFLAGS/CXX/CXXFLAGS are unset so
|
||||
# the generated ${VAR:-default} toolchain defaults apply (and zsh's
|
||||
# no-word-split on unquoted $CFLAGS cannot be fed a multi-word value).
|
||||
conf_rc=0
|
||||
(cd "$WORK" && unset CC CFLAGS CXX CXXFLAGS
|
||||
"$shell" ./configure --prefix="$WORK/install" \
|
||||
>configure.out 2>configure.err) || conf_rc=$?
|
||||
if [ "$conf_rc" -eq 0 ]; then
|
||||
pass "$shell: ./configure exited 0"
|
||||
else
|
||||
fail "$shell: ./configure exited rc=$conf_rc: $(cat "$WORK/configure.err" 2>/dev/null)"
|
||||
fi
|
||||
if grep -iE 'syntax error|parse error' "$WORK/configure.out" \
|
||||
"$WORK/configure.err" >/dev/null 2>&1; then
|
||||
fail "$shell: configure output carries a shell-syntax-error signature"
|
||||
else
|
||||
pass "$shell: no shell-syntax-error signature in configure output"
|
||||
fi
|
||||
|
||||
# the substituted Makefile: no @VAR@ left, LIBS accumulated, prefix set
|
||||
if [ -f "$WORK/Makefile" ]; then
|
||||
pass "$shell: configure wrote Makefile"
|
||||
if grep -E '@[A-Za-z_][A-Za-z0-9_]*@' "$WORK/Makefile" >/dev/null 2>&1; then
|
||||
fail "$shell: Makefile still contains @VAR@ placeholders"
|
||||
else
|
||||
pass "$shell: no @VAR@ placeholders left in Makefile"
|
||||
fi
|
||||
if grep '^LIBS' "$WORK/Makefile" | grep -q -- '-lpthread'; then
|
||||
pass "$shell: Makefile LIBS contains -lpthread"
|
||||
else
|
||||
fail "$shell: Makefile LIBS missing -lpthread: $(grep '^LIBS' "$WORK/Makefile")"
|
||||
fi
|
||||
if grep '^LIBS' "$WORK/Makefile" | grep -q -- '-lm'; then
|
||||
pass "$shell: Makefile LIBS contains -lm"
|
||||
else
|
||||
fail "$shell: Makefile LIBS missing -lm: $(grep '^LIBS' "$WORK/Makefile")"
|
||||
fi
|
||||
if grep -qF "prefix = $WORK/install" "$WORK/Makefile"; then
|
||||
pass "$shell: Makefile prefix substituted with --prefix value"
|
||||
else
|
||||
fail "$shell: Makefile prefix unexpected: $(grep '^prefix' "$WORK/Makefile")"
|
||||
fi
|
||||
else
|
||||
fail "$shell: configure wrote no Makefile"
|
||||
fi
|
||||
|
||||
# make (bounded via timeout when available)
|
||||
make_rc=0
|
||||
if command -v timeout >/dev/null 2>&1; then
|
||||
(cd "$WORK" && timeout 300 make >make.log 2>&1) || make_rc=$?
|
||||
else
|
||||
(cd "$WORK" && make >make.log 2>&1) || make_rc=$?
|
||||
fi
|
||||
if [ "$make_rc" -eq 0 ] && [ -x "$WORK/demo" ]; then
|
||||
pass "$shell: make built the demo binary"
|
||||
else
|
||||
fail "$shell: make failed (rc=$make_rc): $(tail -n 5 "$WORK/make.log" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# the binary must RUN and print the markers (pthread + libm proven live)
|
||||
if [ -x "$WORK/demo" ]; then
|
||||
demo_out=$("$WORK/demo" 2>"$WORK/demo.err")
|
||||
demo_rc=$?
|
||||
if [ "$demo_rc" -eq 0 ]; then
|
||||
pass "$shell: demo binary runs (exit 0)"
|
||||
else
|
||||
fail "$shell: demo binary exited rc=$demo_rc: $(cat "$WORK/demo.err" 2>/dev/null)"
|
||||
fi
|
||||
if printf '%s\n' "$demo_out" | grep -qF 'sin(0.5) = 0.4794'; then
|
||||
pass "$shell: demo prints the libm marker 'sin(0.5) = 0.4794'"
|
||||
else
|
||||
fail "$shell: demo output missing libm marker: '$demo_out'"
|
||||
fi
|
||||
if printf '%s\n' "$demo_out" | grep -qF 'worker thread ran'; then
|
||||
pass "$shell: demo prints the pthread marker 'worker thread ran'"
|
||||
else
|
||||
fail "$shell: demo output missing pthread marker: '$demo_out'"
|
||||
fi
|
||||
else
|
||||
fail "$shell: skipping binary checks (no demo binary)"
|
||||
fi
|
||||
|
||||
# config.h: HAVE_ defines for the resolved features
|
||||
if grep -qF '#define HAVE_PTHREAD 1' "$WORK/config.h"; then
|
||||
pass "$shell: config.h defines HAVE_PTHREAD 1"
|
||||
else
|
||||
fail "$shell: config.h missing '#define HAVE_PTHREAD 1': $(cat "$WORK/config.h" 2>/dev/null)"
|
||||
fi
|
||||
if grep -qF '#define HAVE_MATH 1' "$WORK/config.h"; then
|
||||
pass "$shell: config.h defines HAVE_MATH 1"
|
||||
else
|
||||
fail "$shell: config.h missing '#define HAVE_MATH 1'"
|
||||
fi
|
||||
|
||||
# config.log: the ## results summary records every feature's resolution
|
||||
if grep -qF 'have_pthread=yes' "$WORK/config.log"; then
|
||||
pass "$shell: config.log records have_pthread=yes"
|
||||
else
|
||||
fail "$shell: config.log missing have_pthread=yes"
|
||||
fi
|
||||
if grep -qF 'have_math=yes' "$WORK/config.log"; then
|
||||
pass "$shell: config.log records have_math=yes"
|
||||
else
|
||||
fail "$shell: config.log missing have_math=yes"
|
||||
fi
|
||||
|
||||
# config.status --config must print the original invocation
|
||||
cs_rc=0
|
||||
cs_out=$("$shell" "$WORK/config.status" --config 2>"$WORK/cs.err") || cs_rc=$?
|
||||
if [ "$cs_rc" -eq 0 ]; then
|
||||
case "$cs_out" in
|
||||
*"$WORK/install"*)
|
||||
pass "$shell: config.status --config prints the original args" ;;
|
||||
*)
|
||||
fail "$shell: config.status --config output unexpected: '$cs_out'" ;;
|
||||
esac
|
||||
else
|
||||
fail "$shell: config.status --config exited rc=$cs_rc: $(cat "$WORK/cs.err" 2>/dev/null)"
|
||||
fi
|
||||
|
||||
# --help lists the option node's --enable-debug surface
|
||||
help_rc=0
|
||||
help_out=$(cd "$WORK" && unset CC CFLAGS CXX CXXFLAGS
|
||||
"$shell" ./configure --help 2>&1) || help_rc=$?
|
||||
if [ "$help_rc" -eq 0 ] \
|
||||
&& printf '%s\n' "$help_out" | grep -qF -- '--enable-debug'; then
|
||||
pass "$shell: --help exits 0 and lists --enable-debug"
|
||||
else
|
||||
fail "$shell: --help rc=$help_rc or --enable-debug missing"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- failure case: missing header must fail cleanly, never a syntax error -
|
||||
run_failure() {
|
||||
shell=$1
|
||||
|
||||
new_work || return 1
|
||||
if cp "$FIX/project-fail.kdl" "$FIX/Makefile.in" "$WORK/" \
|
||||
&& (cd "$WORK" && XDG_DATA_HOME="$WORK/xdg" STUPIDTOOLS_EXT= \
|
||||
"$BIN" project-fail.kdl >gen.log 2>&1) \
|
||||
&& [ -s "$WORK/configure" ]; then
|
||||
pass "$shell: stupidtools generated ./configure from project-fail.kdl"
|
||||
else
|
||||
fail "$shell: failure-fixture generation failed: $(cat "$WORK/gen.log" 2>/dev/null)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# the frozen v1 generator records the failed check and exits 0 (see the
|
||||
# header NOTE); rc=0 here IS the clean-failure contract being asserted
|
||||
conf_rc=0
|
||||
(cd "$WORK" && unset CC CFLAGS CXX CXXFLAGS
|
||||
"$shell" ./configure >configure.out 2>configure.err) || conf_rc=$?
|
||||
if [ "$conf_rc" -eq 0 ]; then
|
||||
pass "$shell: missing-header configure completed cleanly (rc=0, v1 generator semantics)"
|
||||
else
|
||||
fail "$shell: missing-header configure exited rc=$conf_rc: $(cat "$WORK/configure.err" 2>/dev/null)"
|
||||
fi
|
||||
if grep -iE 'syntax error|parse error' "$WORK/configure.out" \
|
||||
"$WORK/configure.err" >/dev/null 2>&1; then
|
||||
fail "$shell: missing-header configure output carries a shell-syntax-error signature"
|
||||
else
|
||||
pass "$shell: no shell-syntax-error signature on the missing-header run"
|
||||
fi
|
||||
|
||||
# the failure is honestly recorded: have_nope=no, the healthy feature
|
||||
# still yes, and the compiler's diagnostic names the missing check
|
||||
if grep -qF 'have_nope=no' "$WORK/config.log"; then
|
||||
pass "$shell: config.log records have_nope=no"
|
||||
else
|
||||
fail "$shell: config.log missing have_nope=no"
|
||||
fi
|
||||
if grep -qF 'have_posix=yes' "$WORK/config.log"; then
|
||||
pass "$shell: config.log records have_posix=yes (configure kept going)"
|
||||
else
|
||||
fail "$shell: config.log missing have_posix=yes"
|
||||
fi
|
||||
if grep -qF 'nope_missing_xyz.h' "$WORK/config.log"; then
|
||||
pass "$shell: config.log names the failed check (nope_missing_xyz.h)"
|
||||
else
|
||||
fail "$shell: config.log does not name the failed check"
|
||||
fi
|
||||
|
||||
# config.h: no HAVE_NOPE define; the healthy feature still gets one
|
||||
if grep -qF 'HAVE_NOPE' "$WORK/config.h"; then
|
||||
fail "$shell: config.h must NOT define HAVE_NOPE"
|
||||
else
|
||||
pass "$shell: config.h has no HAVE_NOPE define"
|
||||
fi
|
||||
if grep -qF '#define HAVE_POSIX 1' "$WORK/config.h"; then
|
||||
pass "$shell: config.h still defines HAVE_POSIX 1"
|
||||
else
|
||||
fail "$shell: config.h missing '#define HAVE_POSIX 1'"
|
||||
fi
|
||||
|
||||
# config.status --config works on the failure fixture too
|
||||
cs_rc=0
|
||||
"$shell" "$WORK/config.status" --config >"$WORK/cs.out" 2>&1 || cs_rc=$?
|
||||
if [ "$cs_rc" -eq 0 ]; then
|
||||
pass "$shell: config.status --config exits 0 (failure fixture)"
|
||||
else
|
||||
fail "$shell: config.status --config exited rc=$cs_rc"
|
||||
fi
|
||||
|
||||
# the genuinely-non-zero configure-error path: an unknown option must
|
||||
# exit 1 with a readable message and no shell syntax error
|
||||
bogus_rc=0
|
||||
bogus_err=$(cd "$WORK" && "$shell" ./configure --definitely-bogus-flag \
|
||||
2>&1) || bogus_rc=$?
|
||||
if [ "$bogus_rc" -eq 1 ] \
|
||||
&& printf '%s\n' "$bogus_err" | grep -qF 'unrecognized option'; then
|
||||
pass "$shell: unknown option exits 1 with a readable message"
|
||||
else
|
||||
fail "$shell: unknown option rc=$bogus_rc: '$bogus_err'"
|
||||
fi
|
||||
if printf '%s\n' "$bogus_err" | grep -iE 'syntax error|parse error' \
|
||||
>/dev/null 2>&1; then
|
||||
fail "$shell: unknown-option failure output carries a syntax-error signature"
|
||||
else
|
||||
pass "$shell: no syntax-error signature on the unknown-option failure"
|
||||
fi
|
||||
}
|
||||
|
||||
# --- the matrix ------------------------------------------------------------
|
||||
for shell in "$@"; do
|
||||
run_happy "$shell"
|
||||
run_failure "$shell"
|
||||
done
|
||||
|
||||
# --- summary ---------------------------------------------------------------
|
||||
if [ "$TESTS_FAILED" -ne 0 ]; then
|
||||
printf 'FAILED: %d/%d checks failed\n' "$TESTS_FAILED" "$TESTS_RUN" >&2
|
||||
exit 1
|
||||
fi
|
||||
printf 'All %d integration checks passed (matrix:%s).\n' "$TESTS_RUN" "$SHELLS"
|
||||
Reference in New Issue
Block a user