dev: errors: improve error test generation

This commit is contained in:
Simon Michael 2022-07-14 18:59:58 +01:00
parent 32c7f6300b
commit fc1621e647
2 changed files with 51 additions and 32 deletions

View File

@ -1,51 +1,28 @@
HLEDGER ?= hledger
ERRORSCRIPTS=*.j *.timeclock # *.timedot *.csv
# Check error messages of hledger in $PATH against current error tests.
test:
@printf "Running error message tests with hledger $$($(HLEDGER) --version | awk '{print $$2}'):\n"
shelltest -w $(HLEDGER) *.test
TESTJOURNALS=*.j
# Update error message tests and readme based on the latest test journals
# and error output of hledger in $PATH.
update: tests readme
tests:
@printf "Updating *.test with the error messages of hledger $$(hledger --version | awk '{print $$2}')\n"
@printf "(Re)generating *.test with the error messages of hledger $$($(HLEDGER) --version | awk '{print $$2}')\n"
@read -p "ok ? Press enter: "
for f in $(TESTJOURNALS); do make -s $$(basename $$f .j).test; done
@printf "\nNow please edit *.test and limit regexps to 300 chars to avoid shelltestrunner limitation\n\n"
@for f in $(ERRORSCRIPTS); do echo "HLEDGER=$(HLEDGER) ./hledger2shelltest $$f"; HLEDGER=$(HLEDGER) ./hledger2shelltest $$f; done
# Generate a shelltest. Run the test script/journal to generate the error message.
# Since the error will contain an absolute file path, we must:
# 1. remove most of the file path
# 2. test with a (multiline) regex rather than literal text
# 3. backslash-quote most forward slashes in error messages
# 4. neutralise any remaining problematic error text (eg in parseable-regexps.test)
%.test: %.j
head -1 $< | sed -E 's%#!/usr/bin/env -S (.*)%$$$$$$ \1 $<%' >$@
printf ">>>2 /" >>$@
-./$< 2>&1 | sed -E \
-e 's%(hledger: Error: ).*/\./(.*)%\1.*\2%' \
-e 's%/%\\/%g' \
-e 's/\^/\\^/g' \
-e 's/\$$/\\$$/g' \
-e 's/\(/\\(/g' \
-e 's/\)/\\)/g' \
-e 's/\|/\\|/g' \
>>$@
printf "/\n>>>= 1" >>$@
# -e 's%alias \\/\(\\/%alias \\/\\(\\/%' \
# -e 's%compiled: \(%compiled: \\(%' \
readme: $(TESTJOURNALS)
@printf "Updating README.md with the error messages of hledger $$(hledger --version | awk '{print $$2}')\n"
readme: $(ERRORSCRIPTS)
@printf "Updating README.md with the error messages of hledger $$($(HLEDGER) --version)\n"
@read -p "ok ? Press enter: "
sed '/<!-- GENERATED: -->/q' <README.md >README.md.tmp
echo "$$(hledger --version | cut -d, -f1) error messages:" >>README.md.tmp
for f in $(TESTJOURNALS); do \
printf '\n### %s\n```\n%s\n```\n\n' "$$(basename "$$f" .j)" "$$(./"$$f" 2>&1)"; \
echo "$$($(HLEDGER) --version | cut -d, -f1) error messages:" >>README.md.tmp
for f in $(ERRORSCRIPTS); do \
printf '\n### %s\n```\n%s\n```\n\n' "$$(echo "$$f" | sed -E 's/\.[^.]+$$//')" "$$(./"$$f" 2>&1)"; \
done >>README.md.tmp
mv README.md.tmp README.md

View File

@ -0,0 +1,42 @@
#!/usr/bin/env bash
# hledger2shelltest SCRIPT
#
# Speaking generally: given an executable hashbang script (beginning with #!/usr/bin/env),
# this generates a similarly-named shelltestrunner test that will repeatably
# run the same command as the script and test its (stderr) output.
# (Ideally, this would be built in to shelltestrunner.)
# More precisely, this generates a test expecting no stdout, the given stderr,
# and an error exit code, for scripts reproducing various hledger errors.
#
# The script is run once to capture its output, which is then adjusted
# for use in a shelltest regex matcher:
# - common regex metacharacters are escaped
# - file paths are simplified
# - any remaining problematic text is sanitised
# - the regex is trimmed to <= 300 chars, to avoid a shelltestrunner limitation.
SCRIPT="$1"
TEST=$(echo "$SCRIPT" | sed -E 's/\.[^.]+$//').test
{
head -1 "$SCRIPT" | sed -E "s%#!/usr/bin/env -S (.*)%\$\$\$ \1 $SCRIPT%"
printf ">>>2 /"
"./$SCRIPT" 2>&1 | sed -E \
-e 's%(hledger: Error: ).*/\./(.*)%\1.*\2%' \
-e 's%/%\\/%g' \
-e 's/\^/\\^/g' \
-e 's/\$/\\$/g' \
-e 's/\(/\\(/g' \
-e 's/\)/\\)/g' \
-e 's/\|/\\|/g' \
| head -c 300
printf "/\n>>>= 1\n"
} >"$TEST"
# -e 's%alias \\/\(\\/%alias \\/\\(\\/%' \
# -e 's%compiled: \(%compiled: \\(%' \
# gnused() { # GNU sed, called gsed on mac
# if hash gsed 2>/dev/null; then gsed "$@"; else sed "$@"; fi
# }