Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup tests #26

Merged
merged 13 commits into from
Jan 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ jobs:
steps:
- name: Check out repository code
uses: actions/checkout@v4
- name: shellcheck
run: shellcheck *.sh **/*.sh
- name: build challenge
run: ./create_challenge.sh --verbose
- name: create tarball
Expand Down
3 changes: 3 additions & 0 deletions .shellcheckrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Don't warn about expressions not being expanded in single quotes
# We use faaaar to many strings which are `eval`d and should only then capture the variables
disable=SC2016
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ To run the tests you simply need to execute:
```sh
./test.sh
```
WARNING: It will build the challenge for you, since it basically only ever makes sense to run this on a freshly built dir
It has two levels of debugging, so by default it just prints the test cases, but if run with `-v` it will also output every expect. If run with `-v -v` it will additionally print every output of the commands it executed.

WARNING: It will build the challenge for you, since it has to reset the state inbetween to check incompatible "paths" (test with triggering the LocalCodeExecution trap, or not). That means it does not matter into which state you bring the challenge directory before the run - it will be deleted and replaced by a fresh build before the first test is run.

There is a small testing library roughly mimicking `jest` in its usage.
15 changes: 8 additions & 7 deletions create_challenge.sh
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ git init --initial-branch="$initial_branch" challenge
cd challenge
reproducibility_setup

# Create an empty commit and delete it, so that our own nuggits "branch" can reference the empty tree
# TODO: figure out how to create a tree object without interacting with the index
commit --allow-empty -m "RootOfAllNuggits
# Create an empty commit for our own nuggits "branch"
# don't use `git commit`, since that would find itself in the reflog
# the `printf "" | git mktree` simulates an empty tree
# (so basically: since there was no commit before, this is an empty commit)
git commit-tree "$(printf "" | git mktree)" -m "RootOfAllNuggits

Have a free nuggit!"
# pretend this was done in our manually managed nuggits "branch" instead
mv ".git/refs/heads/$initial_branch" ".git/nuggits"
Have a free nuggit!" > .git/nuggits

cp -r "$DOCDIR/01_init/"* .
git add .
Expand Down Expand Up @@ -162,7 +162,8 @@ create_chapter hooks
# hooks (should be installed last, since they are self-mutating and would be called e.g. by `git commit`)
rm .git/hooks/*

for file in $(ls "$DOCDIR/hooks"); do
for filep in "$DOCDIR/hooks/"*; do
file="$(basename "$filep")"
replace_placeholders "$DOCDIR/hooks/$file" > ".git/hooks/$file.orig"
chmod +x ".git/hooks/$file.orig"
done
Expand Down
2 changes: 1 addition & 1 deletion src/redeem.nuggit
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ else
commit_nuggit() { # Manage our own little "branch" manually
local tree
# get the tree object from the last commit in nuggits
tree="$(git show --format="%T" nuggits)"
tree="$(git rev-parse "nuggits^{tree}")"
# add an empty commit with the parent being nuggits and "reset nuggits to that new commit"
git commit-tree "$tree" -p "$(cat .git/nuggits)" -m "$1" > .git/nuggits.bak
# We can't directly pipe it into the file, because it will empty it before we read it...
Expand Down
6 changes: 3 additions & 3 deletions test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
set -e

test_verbose=0
create_challenge_flags=
create_challenge_flags=("--force")
while [ $# -gt 0 ]; do
opt="$1"; shift
case "$opt" in
-v|--verbose)
test_verbose=$((test_verbose + 1))
create_challenge_flags="$create_challenge_flags -v"
create_challenge_flags+=("-v")
;;
*)
echo "ERROR! Unknown option '$opt'. Useage: $0 [-v|--verbose] [-f|--force|--delete-existing-challenge]" >&2
Expand All @@ -21,7 +21,7 @@ done
. ./test_helpers/lib-test.sh
build_challenge() {
echo "Building challenge..."
./create_challenge.sh $create_challenge_flags
./create_challenge.sh "${create_challenge_flags[@]}"
}
build_challenge
cd challenge
Expand Down
36 changes: 22 additions & 14 deletions test_helpers/lib-test.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#!/usr/bin/env bash

# Make sure to set a default value for verbosity
: "${test_verbose:=0}"

success() {
# use \r to overwrite the line saying "running" => add spaces to the end to cover the longer line
printf "\r✅ \e[32m%s\e[0m \n" "$1"
Expand Down Expand Up @@ -42,64 +45,68 @@ trap - EXIT # Remove the trap handler, so that it does not fire at the end of th
success "$testname"
}

string_contains() { [ -z "${1##*"$2"*}" ] && [ -n "$1" ]; }

# Assertion
expect() {
local not result error
local invert_result failed error
expect_err() {
echo >&2
echo "$1" >&2
exit 1
}
if [ "$test_verbose" -ge 1 ]; then
if [ "$test_verbose" -lt 2 ]; then printf " "; fi # make room for checkbox/exclamation mark in the beginning of the line
printf "\e[34mexpect %s\e[0m " "$(pretty_escape "$@")"
fi
command="$1"; shift
if [ "$1" = not ]; then
not="not "
invert_result=true
shift
fi
to="$1"; shift # For readability only
if [ "$to" != to ]; then
expect_err "ERROR: usage of \`expect\` requires 'to', e.g.:
expect \"echo hi\" ${not}to <action> [<argument of action>]"
expect \"echo hi\" ${invert_result+not }to <action> [<argument of action>]"
else
action="$1"; shift
case "$action" in
contain)
if [ $# -ne 1 ]; then
expect_err "\
usage: expect <command> ${not}to contain <string>
usage: expect <command> ${invert_result+not }to contain <string>
E.g.:
expect \"echo hi\" ${not}to contain '${not}hi'
expect \"echo hi\" ${invert_result+not }to contain '${invert_result+not }hi'
but got:
expect $(pretty_escape "$command" ${not} to contain "$@")"
expect $(pretty_escape "$command" ${invert_result+not }to contain "$@")"
fi
string="$1"
output="$(eval "$command")"

[[ $output =~ "$string" ]] || result=1
string_contains "$output" "$string" || failed=true
error="> $command
${not}Expected: $string
${invert_result+Not }Expected: $string
Received: $output"
;;
succeed)
output=$(eval "$command") || result=1
error="> $command should ${not}succeed
output=$(eval "$command") || failed=true
error="> $command should ${invert_result+not }succeed
Output: $output"
;;
*)
expect_err "ERROR: unknown action '$action' in \`expect ${not}to $(pretty_escape action) ...\`"
expect_err "ERROR: unknown action '$action' in \`expect ${invert_result+not }to $(pretty_escape action) ...\`"
;;
esac
fi
if [ "$test_verbose" -ge 2 ]; then printf "\n%s\n" "$output"; fi
if { [ -n "$not" ] && [ -z "$result" ]; } || { [ -z "$not" ] && [ -n "$result" ]; }; then
if [ "$test_verbose" -ge 1 ]; then printf "❗️\n"; fi
if { [ "$invert_result" = true ] && [ "$failed" != true ]; } || { [ "$invert_result" != true ] && [ "$failed" = true ]; }; then
if [ "$test_verbose" -ge 1 ]; then printf "\r❗️\n"; fi
expect_err "$error"
fi
if [ "$test_verbose" -ge 1 ]; then printf "☑️\n"; fi
if [ "$test_verbose" -ge 1 ]; then printf "\r☑️\n"; fi
}

# WARNING! Contrary to it's name it just tries its best to escape shell characters, but it probably does not catch all special characters, so be careful with the output!
pretty_escape() {
while [ $# -gt 0 ]; do
if ! [[ "$(printf "%q" "$1")" == *\\* ]]; then # No special characters to escape, so print raw
Expand All @@ -113,6 +120,7 @@ pretty_escape() {
if [ "$num_single_quote_escapes" -gt "$num_double_quote_escapes" ]; then
printf '"%s"' "$(sed -r 's/([$`"\!])/\\\1/g' <<< "$1")"
else
# shellcheck disable=SC1003
printf "'%s'" "$(sed -r "s/'/'"'\\'"''/g" <<< "$1")"
fi
fi
Expand Down