Introduce a DSL to replace the plain bash scripts
It's really important for `git-check-assertions` blocks to be 'obviously correct', so that we don't need to... test the tests that test the tests. Let's introduce a little DSL that is less error-prone than a plain bash script.
This commit is contained in:
parent
ad10b2cc4c
commit
4704cc088d
3 changed files with 130 additions and 127 deletions
|
|
@ -24,48 +24,6 @@
|
|||
|
||||
set -euo pipefail
|
||||
|
||||
# helper functions inspired by bats/bats-assert
|
||||
run() {
|
||||
set +e
|
||||
tmp_output="$(mktemp)"
|
||||
"$@" 2>&1 | tee "$tmp_output"
|
||||
status=${PIPESTATUS[0]}
|
||||
set -e
|
||||
output="$(cat "$tmp_output")"
|
||||
rm -f "$tmp_output"
|
||||
printf '%s\n' "$output"
|
||||
return 0
|
||||
}
|
||||
assert_success() {
|
||||
if [ "$status" -ne 0 ]; then
|
||||
echo "Expected command to succeed, but it failed."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
assert_failure() {
|
||||
if [ "$status" -eq 0 ]; then
|
||||
echo "Expected command to fail, but it succeeded."
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
assert_output() {
|
||||
if [ "${1:-}" = "--partial" ]; then
|
||||
local expected="$2"
|
||||
if [[ "$output" != *"$expected"* ]]; then
|
||||
echo "Expected output to contain: $expected"
|
||||
echo "Actual output: $output"
|
||||
exit 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
if [ "$output" != "$1" ]; then
|
||||
echo "Expected output to equal: $1"
|
||||
echo "Actual output: $output"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
export -f run assert_success assert_failure assert_output
|
||||
|
||||
# main flow
|
||||
if [ ! -z "$(git status --porcelain)" ]; then
|
||||
echo "Uncommitted changes. Refusing to run." >&2
|
||||
|
|
@ -121,8 +79,64 @@ for commit_hash in "${commits[@]}"; do
|
|||
check_assertions() {
|
||||
python3 - "$block" <<-EOF
|
||||
import sys
|
||||
import re
|
||||
import subprocess
|
||||
subprocess.run(sys.argv[1], shell=True, check=True)
|
||||
|
||||
block = sys.argv[1]
|
||||
steps = []
|
||||
current_step = None
|
||||
|
||||
for line_number, raw_line in enumerate(block.splitlines(), start=1):
|
||||
line = raw_line.rstrip("\\r")
|
||||
if not line.strip():
|
||||
continue
|
||||
|
||||
match = re.match(r"^\\[(success|failure)\\]\\s+(.+)$", line)
|
||||
if match:
|
||||
current_step = {
|
||||
"expects_success": match.group(1) == "success",
|
||||
"command": match.group(2),
|
||||
"assertions": [],
|
||||
}
|
||||
steps.append(current_step)
|
||||
continue
|
||||
|
||||
if current_step is None:
|
||||
print(
|
||||
f"DSL parse error on line {line_number}: "
|
||||
"assertion text must follow [success] or [failure]."
|
||||
)
|
||||
sys.exit(1)
|
||||
|
||||
current_step["assertions"].append(line)
|
||||
|
||||
for step in steps:
|
||||
completed = subprocess.run(
|
||||
["sh", "-lc", step["command"]],
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
text=True,
|
||||
)
|
||||
output = completed.stdout or ""
|
||||
|
||||
if output:
|
||||
sys.stdout.write(output)
|
||||
if not output.endswith("\\n"):
|
||||
sys.stdout.write("\\n")
|
||||
|
||||
if step["expects_success"]:
|
||||
if completed.returncode != 0:
|
||||
print("Expected command to succeed, but it failed.")
|
||||
sys.exit(1)
|
||||
elif completed.returncode == 0:
|
||||
print("Expected command to fail, but it succeeded.")
|
||||
sys.exit(1)
|
||||
|
||||
for expected in step["assertions"]:
|
||||
if expected not in output:
|
||||
print(f"Expected output to contain: {expected}")
|
||||
print(f"Actual output: {output}")
|
||||
sys.exit(1)
|
||||
EOF
|
||||
}
|
||||
if ! check_assertions; then
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue