diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 0295db5..cdf4e29 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -33,4 +33,4 @@ jobs: | match("exercises/practice/([^/]+)/") | .captures[0].string ) | unique[] - ' | xargs -r -L1 bin/test-one + ' | xargs -r -L1 bin/verify-exercises diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index afe6a13..56352bd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,4 +25,4 @@ jobs: - name: test run: | - bin/test-all + bin/verify-exercises diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 560641f..1d98189 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -92,7 +92,7 @@ 1. Test it with ```sh - bin/test-one ${slug_name} + bin/verify-exercises ${slug_name} ``` 1. When you're satisfied with the solution, create the stub file `${slug_name}.moon`. diff --git a/README.md b/README.md index 134442e..02ae276 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@ Exercism exercises in MoonScript. ## Testing -To test all exercises, run `./bin/test-all`. +To test all exercises, run `./bin/verify-exercises`. This command will iterate over all exercises and check to see if their exemplar/example implementation passes all the tests. -To test a single exercise, run `./bin/test-one `. +To test a single exercise, run `./bin/verify-exercises `. ### Using Docker diff --git a/bin/add-practice-exercise b/bin/add-practice-exercise index d097a86..66f284d 100755 --- a/bin/add-practice-exercise +++ b/bin/add-practice-exercise @@ -129,7 +129,7 @@ Your next steps are: 2. Create the example solution ==> $(jq -r '.example' <<< "${files}") -3. Verify the example solution passes the tests ==> $ bin/test-one ${slug} +3. Verify the example solution passes the tests ==> $ bin/verify-exercises ${slug} 4. Create the stub solution ==> $(jq -r '.solution' <<< "${files}") diff --git a/bin/test-all b/bin/test-all deleted file mode 100755 index f31d8c8..0000000 --- a/bin/test-all +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env bash - -start=$SECONDS - -unset CDPATH - -script_dir=$(realpath "$(dirname "$0")") - -cd "${script_dir}/../exercises/practice" || exit 4 -result=0 -count=0 - -for exercise in *; do - [[ -d $exercise ]] || continue - - "$script_dir"/test-one "$exercise" || (( ++result )) - (( ++count )) -done - -echo -echo "$count exercises tested in $(( SECONDS - start )) seconds." - -exit $result diff --git a/bin/test-one b/bin/test-one deleted file mode 100755 index e8ec430..0000000 --- a/bin/test-one +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -# -# shellcheck disable=SC2164 - -if [[ -z $1 ]]; then - echo "Usage: $0 exercise-slug" >&2 - exit 2 -fi - -unset CDPATH - -cd "$(realpath "$(dirname "$0")/..")" - -exercise=$1 -shift -exercise_dir=$(realpath "exercises/practice/$exercise") - -if [[ ! -d $exercise_dir ]]; then - echo "No such exercise: $exercise" >&2 - exit 3 -fi - -test_dir=$( mktemp -d ) -trap 'rm -rf "$test_dir"' EXIT - -cd "$test_dir" || exit 4 -(cd "$exercise_dir"; tar cf - .) | tar xf - - -echo >&2 -echo "Testing $exercise..." >&2 - -IFS=$'\t' read -r solution tests example < <( - jq -r '.files | [.solution[0], .test[0], .example[0]] | @tsv' .meta/config.json -) - -mv "$example" "$solution" -perl -i -pe 's/^\s+\Kpending\b/it/' "$tests" - -busted --verbose "$@" diff --git a/bin/verify-exercises b/bin/verify-exercises index 269a608..fc378b0 100755 --- a/bin/verify-exercises +++ b/bin/verify-exercises @@ -19,8 +19,6 @@ required_tool() { die "${1} is required but not installed. Please install it and make sure it's in your PATH." } -required_tool jq - copy_example_or_examplar_to_solution() { jq -c '[.files.solution, .files.exemplar // .files.example] | transpose | map({src: .[1], dst: .[0]}) | .[]' .meta/config.json \ | while read -r src_and_dst; do @@ -29,26 +27,13 @@ copy_example_or_examplar_to_solution() { } unskip_tests() { - jq -r '.files.test[]' .meta/config.json | while read -r test_file; do - noop # TODO: replace this with the command to unskip the tests. - # Note: this function runs from within an exercise directory. - # Note: the exercise directory is a temporary directory, so feel - # free to modify its (test) files as needed. - # Note: ignore this function if either: - # - skipping tests is not supported, or - # - skipping tests does not require modifying the test files. - # Example: sed -i 's/test.skip/test/g' "${test_file}" - done + local test_files + readarray -t test_files < <( jq -r '.files.test[]' .meta/config.json ) + perl -i -pe 's/^\s+\Kpending\b/it/' "${test_files[@]}" } run_tests() { - noop # TODO: replace this with the command to run the tests for the exercise. - # Note: this function runs from within an exercise directory. - # Note: the exercise directory is a temporary directory, so feel - # free to modify its files as needed. - # Note: return a zero exit code if all tests pass, otherwise non-zero. - # Example: `npm test` - # Example: `python3 -m pytest two_fer_test.py` + busted --verbose } verify_exercise() { @@ -89,5 +74,9 @@ verify_exercises() { ((count > 0)) || die 'no matching exercises found!' } +required_tool jq +required_tool perl +required_tool busted + exercise_slug="${1:-*}" verify_exercises "${exercise_slug}" diff --git a/bin/verify-exercises-in-docker b/bin/verify-exercises-in-docker index 6b238f2..584344e 100755 --- a/bin/verify-exercises-in-docker +++ b/bin/verify-exercises-in-docker @@ -11,17 +11,37 @@ # Example: verify single exercise in Docker # bin/verify-exercises-in-docker two-fer -set -eo pipefail +set -euo pipefail + +image="exercism/moonscript-test-runner" + +usage() { + echo "Run exercise tests in the $image docker image." + echo "Specify an exercise slug to test that one, otherwise test all." + echo + echo "usage: $(basename "$0") [-h] [-L] [exercise-slug]" + echo "where:" + echo " -L Use a locally built image; default is to pull from a docker registry." + echo " See https://github.com/$image" +} die() { echo "$*" >&2; exit 1; } +docker_local=false +while getopts ":hL" opt; do + case $opt in + h) usage; exit ;; + L) docker_local=true ;; + ?) die "Unknown option -$OPTARG" ;; + esac +done +shift $((OPTIND - 1)) + required_tool() { - command -v "${1}" >/dev/null 2>&1 || - die "${1} is required but not installed. Please install it and make sure it's in your PATH." + command -v "${1}" >/dev/null 2>&1 \ + || die "${1} is required but not installed. Please install it and make sure it's in your PATH." } -required_tool docker - copy_example_or_examplar_to_solution() { jq -c '[.files.solution, .files.exemplar // .files.example] | transpose | map({src: .[1], dst: .[0]}) | .[]' .meta/config.json \ | while read -r src_and_dst; do @@ -30,8 +50,15 @@ copy_example_or_examplar_to_solution() { } pull_docker_image() { - docker pull exercism/moonscript-test-runner || - die $'Could not find the `exercism/moonscript-test-runner` Docker image.\nCheck the test runner docs at https://exercism.org/docs/building/tooling/test-runners for more information.' + if $docker_local && docker image inspect "$image" >/dev/null 2>&1; then + echo "Using local image" + docker image ls "$image" + else + if ! docker pull "$image"; then + die "Could not find the '$image' Docker image. +Check the test runner docs at https://exercism.org/docs/building/tooling/test-runners for more information." + fi + fi } run_tests() { @@ -83,6 +110,9 @@ verify_exercises() { ((count > 0)) || die 'no matching exercises found!' } +required_tool docker +required_tool jq + pull_docker_image exercise_slug="${1:-*}"