Skip to content

Commit 5eef956

Browse files
Add script to test against test-runner image (#951)
This script is useful for testing against a test runner image. We remove the affine-cipher solution's dependence on GMP.
1 parent 3ee8b43 commit 5eef956

2 files changed

Lines changed: 116 additions & 1 deletion

File tree

bin/verify-exercises-in-docker

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env bash
2+
3+
# Synopsis:
4+
# Verify that each exercise's example/exemplar solution passes the tests
5+
# using the track's test runner Docker image.
6+
# You can either verify all exercises or a single exercise.
7+
8+
# Example: verify all exercises in Docker
9+
# bin/verify-exercises-in-docker
10+
11+
# Example: verify single exercise in Docker
12+
# bin/verify-exercises-in-docker two-fer
13+
14+
# Example: verify all exercises against specified test runner
15+
# bin/verify-exercises-in-docker -i my-local-image
16+
17+
set -e
18+
shopt -s nullglob
19+
20+
die() {
21+
echo "$*" >&2
22+
exit 1
23+
}
24+
25+
required_tool() {
26+
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."
27+
}
28+
29+
copy_example_or_exemplar_to_solution() {
30+
local dir="${1}"
31+
jq -r '[.files.solution, .files.exemplar // .files.example] | transpose | map(select(.[0] and .[1]))[][]' "${dir}/.meta/config.json" \
32+
| while read -r dst; read -r src; do
33+
cp "${dir}/${src}" "${dir}/${dst}"
34+
done
35+
}
36+
37+
run_tests() {
38+
local slug="${1}" dir="${2}"
39+
local -a docker_args
40+
41+
docker_args+=( --rm --network none )
42+
docker_args+=( --mount "type=bind,src=${dir},dst=/solution" )
43+
# /tmp needs to be a proper volume to run the compiled executable; tmpfs is not executable.
44+
docker_args+=( --mount "type=volume,dst=/tmp" )
45+
46+
# /solution is used both as the location to read the code from and as a destination for the results.json file.
47+
docker run "${docker_args[@]}" "${image}" "${slug}" /solution /solution
48+
jq -e '.status == "pass"' "${dir}/results.json" >/dev/null 2>&1
49+
}
50+
51+
verify_exercise() {
52+
local dir slug tmpdir
53+
dir="${1%/}"
54+
slug="${dir##*/}"
55+
tmpdir="$(mktemp -d -t "exercism-verify-${slug}-XXXXX")"
56+
57+
echo "Verifying ${slug} exercise..."
58+
(
59+
trap 'rm -rf "${tmpdir}"' EXIT # remove tempdir when subshell ends
60+
cp -r "${dir}/." "${tmpdir}" || exit
61+
copy_example_or_exemplar_to_solution "${tmpdir}"
62+
run_tests "${slug}" "${tmpdir}" || { cat "${tmpdir}/results.json"; exit 1; }
63+
)
64+
}
65+
66+
verify_exercises() {
67+
local -a exercises
68+
local parent path
69+
if (( $# )); then
70+
for slug; do
71+
for parent in concept practice; do
72+
path="./exercises/${parent}/${slug}"
73+
[[ -d "${path}" ]] && exercises+=( "${path}" )
74+
done
75+
done
76+
else
77+
exercises=( ./exercises/{concept,practice}/*/ )
78+
fi
79+
(( ${#exercises[@]} )) || die "No matching exercises found"
80+
81+
rc=0
82+
for exercise_dir in "${exercises[@]}"; do
83+
verify_exercise "${exercise_dir}" || rc=$?
84+
done
85+
return "$rc"
86+
}
87+
88+
89+
required_tool docker
90+
required_tool jq
91+
92+
image=''
93+
while getopts i: opt; do
94+
case "${opt}" in
95+
i) image="${OPTARG}" ;;
96+
?) die "Unknown option: -$OPTARG" ;;
97+
esac
98+
done
99+
shift "$((OPTIND - 1))"
100+
101+
if [[ -z "${image}" ]]; then
102+
image="exercism/php-test-runner"
103+
docker pull "${image}" ||
104+
die "docker pull ${image} failed. Check the test runner docs at https://exercism.org/docs/building/tooling/test-runners for more information."
105+
fi
106+
107+
verify_exercises "$@"

exercises/practice/affine-cipher/.meta/example.php

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,17 @@ function ($l) use ($a, $b, $alphabet) {
3434
);
3535
}
3636

37+
function gcd($a, $b)
38+
{
39+
while ($b !== 0) {
40+
[$a, $b] = [$b, $a % $b];
41+
}
42+
return $a;
43+
}
44+
3745
function coprimeCheck($a)
3846
{
39-
if (gmp_intval(gmp_gcd($a, 26)) !== 1) {
47+
if (gcd($a, 26) !== 1) {
4048
throw new Exception();
4149
}
4250
}

0 commit comments

Comments
 (0)