Skip to content

Commit e8f651f

Browse files
committed
test(e2e): the check-stamp mechanism, on the platform it exists for
Every test of it declares `# requires: gcc`, so all of them skip on Windows -- and the whole justification for the engine writing a check's stamp is that the alternative, a wrapper script, cannot be written portably: an action's command is an argv with no shell assumed, and there is no `touch` on Windows. The feature's reason to exist was verified nowhere near the platform it exists for. This is the shape `# requires:` produces when nobody checks which runners actually satisfy the token, and this repository has been here before. 313 carries no `# requires:` line, so it runs wherever the suite runs. It can do that only because of the mechanism itself: the check's command is `mcpp --version` -- an executable present by construction, exiting 0 and writing nothing, which is exactly the shape of a real analyser. ⚠️ It asserts on the STAMP and on the check not re-running, not on the build's exit code. Measured: ninja does not fail when a declared output goes unproduced. It leaves the file absent and re-runs that edge on every build afterwards, so a build with no stamp mechanism at all stays green and merely redoes work. Seen red with the mechanism disabled, green with it.
1 parent f83dca1 commit e8f651f

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
#!/usr/bin/env bash
2+
# 313_check_stamp_on_every_platform.sh — a `role = "check"` whose command never
3+
# touches its stamp, on EVERY platform.
4+
#
5+
# ⚠️ WHY THIS EXISTS SEPARATELY FROM 188 AND 312.
6+
#
7+
# The engine writes a check's stamp so that an analyser -- which answers with an
8+
# exit code and writes nothing -- can be a check without a wrapper script. The
9+
# whole justification for doing it in the engine rather than in a script is that
10+
# an action's command is an argv with no shell assumed, so the wrapper cannot be
11+
# written portably: there is no `touch` on Windows.
12+
#
13+
# And every existing test of that mechanism declares `# requires: gcc`, so all
14+
# of them SKIP on Windows. The feature's reason to exist was verified nowhere
15+
# near the platform it exists for. This file carries no `# requires:` line at
16+
# all, so it runs wherever the suite runs.
17+
#
18+
# To do that it must avoid a POSIX shell entirely, which the new mechanism makes
19+
# possible: the check's command is `mcpp --version` -- an executable that is
20+
# present by construction, exits 0, and writes no stamp.
21+
set -e
22+
23+
source "$(dirname "$0")/_host_path.sh"
24+
25+
TMP=$(mktemp -d)
26+
trap "rm -rf $TMP" EXIT
27+
cd "$TMP"
28+
29+
mkdir -p src
30+
cat > mcpp.toml <<'EOF'
31+
[package]
32+
name = "stampprobe"
33+
version = "0.1.0"
34+
EOF
35+
cat > src/main.cpp <<'EOF'
36+
#include <cstdio>
37+
#ifndef CHECK_DECLARED
38+
#error "the build program never ran"
39+
#endif
40+
int main() { std::printf("STAMP_PROBE_OK\n"); }
41+
EOF
42+
43+
MCPP_HOST="$(host_path "$MCPP")"
44+
cat > build.mcpp <<EOF
45+
import std;
46+
import mcpp;
47+
int main() {
48+
mcpp::define("CHECK_DECLARED");
49+
mcpp::action a;
50+
a.id = "probe";
51+
a.role = "check";
52+
a.description = "a check whose command writes no stamp";
53+
// The engine itself: present on every platform this suite runs on, exits 0,
54+
// and touches nothing. That is exactly the shape of a real analyser.
55+
a.arg("$MCPP_HOST").arg("--version")
56+
.output((std::string(mcpp::out_dir()) + "/probe.stamp").c_str())
57+
.submit();
58+
}
59+
EOF
60+
61+
"$MCPP" build > b1.log 2>&1 || { cat b1.log; echo "FAIL: build failed"; exit 1; }
62+
out="$("$MCPP" run 2>&1 | tail -1)"
63+
[[ "$out" == *STAMP_PROBE_OK* ]] || {
64+
echo "FAIL: the program did not run: '$out'"; exit 1; }
65+
66+
# THE criterion. Not the build's exit code: measured, ninja does not fail when a
67+
# declared output goes unproduced -- it leaves the file absent and re-runs that
68+
# edge on every build afterwards, so a build with no stamp mechanism at all
69+
# stays green and merely redoes work.
70+
mapfile -t stamps < <(find target -name 'probe.stamp')
71+
(( ${#stamps[@]} == 1 )) || {
72+
printf ' %s\n' "${stamps[@]}"
73+
echo "FAIL: expected exactly one stamp written by the engine, found ${#stamps[@]}"
74+
exit 1; }
75+
76+
# And the other half: a satisfied edge is not re-run. Without the stamp this
77+
# would repeat forever, which is the symptom the exit code hides.
78+
"$MCPP" build > b2.log 2>&1 || { cat b2.log; echo "FAIL: no-op rebuild failed"; exit 1; }
79+
if grep -q 'CHECK' b2.log; then
80+
cat b2.log
81+
echo "FAIL: the check re-ran with nothing changed — its stamp is not satisfying the edge"
82+
exit 1
83+
fi
84+
85+
echo "OK"

0 commit comments

Comments
 (0)