Skip to content

Commit 6e88ca2

Browse files
committed
Add a utility to assist in manually testing an exercise
Instead of having to manually enable tests, copy the examples, and clean up, this script automates all that. - Take optional exercise path argument - Express all paths in terms of exercise path - Pass further arguments through to cargo - Use arrays to simplify file/dir preservation and reset - Use trap to ensure reset occurs on ctrl-c - Express check-exercises.sh in terms of bin/test-exercise - Add debug tests to check-exercises in case of remote execution failure - Move $![deny(warnings)] insertion into test-exercise. - Give the feature to people testing the exercise on its own - Clean up properly after - Return the bitwise OR of individual exercises' return values That last one wants some commenting. If a bunch of values fail in different ways, this is of limited utility; your return code won't be 0, and Travis will fail, but you won't get the info you expected from the return codes. However, this does have some useful properties: - if a bunch of things fail in the same way, or only one thing fails, you get Cargo's return code back directly - you discard less overall information than the naïve implementation ( if [ $? != 0 ]; then return_code=1; fi ) - always returns zero or non-zero appropriately without branching
1 parent 822eb17 commit 6e88ca2

File tree

2 files changed

+120
-54
lines changed

2 files changed

+120
-54
lines changed

_test/check-exercises.sh

Lines changed: 36 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,55 @@
11
#!/bin/bash
22

3+
# test for existence and executability of the test-exercise script
4+
# this depends on that
5+
if [ ! -f "./bin/test-exercise" ]; then
6+
echo "bin/test-exercise does not exist"
7+
exit 1
8+
fi
9+
if [ ! -x "./bin/test-exercise" ]; then
10+
echo "bin/test-exercise does not have its executable bit set"
11+
exit 1
12+
fi
13+
314
# In DENYWARNINGS mode, do not set -e so that we run all tests.
415
# This allows us to see all warnings.
516
if [ -z "$DENYWARNINGS" ]; then
617
set -e
718
fi
819

20+
# can't benchmark with a stable compiler; to bench, use
21+
# $ BENCHMARK=1 rustup run nightly _test/check-exercises.sh
922
if [ -n "$BENCHMARK" ]; then
1023
files=exercises/*/benches
1124
else
1225
files=exercises/*/tests
1326
fi
1427

15-
tmp=${TMPDIR:-/tmp/}
16-
mkdir "${tmp}exercises"
17-
18-
exitcode=0
19-
28+
return_code=0
2029
# An exercise worth testing is defined here as any top level directory with
2130
# a 'tests' directory
2231
for exercise in $files; do
23-
# This assumes that exercises are only one directory deep
24-
# and that the primary module is named the same as the directory
25-
directory=$(dirname "${exercise}");
26-
27-
workdir=$(mktemp -d "${tmp}${directory}.XXXXXXXXXX")
28-
29-
cp -R -T $directory $workdir
30-
31-
# Run in subshell to change workdir without affecting current workdir.
32-
(
33-
cd $workdir
34-
35-
cp example.rs src/lib.rs
36-
37-
# Overwrite empty Cargo.toml if an example specific file exists
38-
if [ -f Cargo-example.toml ]; then
39-
cp Cargo-example.toml Cargo.toml
40-
fi
41-
42-
# Forcibly strip all "ignore" statements from the testing files
43-
for test in tests/*.rs; do
44-
sed -i '/\[ignore\]/d' $test
45-
done
46-
47-
# Run benchmarks instead of tests when enabled.
48-
if [ -n "$BENCHMARK" ]; then
49-
cargo bench
50-
elif [ -n "$DENYWARNINGS" ]; then
51-
sed -i -e '1i #![deny(warnings)]' src/lib.rs
52-
53-
# No-run mode so we see no test output.
54-
# Quiet mode so we see no compile output
55-
# (such as "Compiling"/"Downloading").
56-
# Compiler errors will still be shown though.
57-
# Both flags are necessary to keep things quiet.
58-
cargo test --quiet --no-run
59-
else
60-
# Run the test and get the status
61-
cargo test
62-
fi
63-
)
64-
65-
status=$?
66-
67-
if [ $status -ne 0 ]
68-
then
69-
exitcode=1
70-
fi
32+
# This assumes that exercises are only one directory deep
33+
# and that the primary module is named the same as the directory
34+
directory=$(dirname "${exercise}");
35+
36+
if [ -n "$DENYWARNINGS" ]; then
37+
# No-run mode so we see no test output.
38+
# Quiet mode so we see no compile output
39+
# (such as "Compiling"/"Downloading").
40+
# Compiler errors will still be shown though.
41+
# Both flags are necessary to keep things quiet.
42+
./bin/test-exercise $directory --quiet --no-run
43+
return_code=$(($return_code | $?))
44+
else
45+
# Run the test and get the status
46+
# We use release mode here because, while it somewhat increases
47+
# the compile time for all exercises, it substantially improves
48+
# the runtime for certain exercises such as alphametics.
49+
# Overall this should be an improvement.
50+
./bin/test-exercise $directory
51+
return_code=$(($return_code | $?))
52+
fi
7153
done
7254

73-
exit $exitcode
55+
exit $return_code

bin/test-exercise

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/bash
2+
# Test an exercise
3+
4+
# which exercise are we testing right now?
5+
# if we were passed an argument, that should be the
6+
# exercise directory. Otherwise, assume we're in
7+
# it currently.
8+
if [ $# -ge 1 ]; then
9+
exercise=$1
10+
# if this script is called with arguments, it will pass through
11+
# any beyond the first to cargo. Note that we can only get a
12+
# free default argument if no arguments at all were passed,
13+
# so if you are in the exercise directory and want to pass any
14+
# arguments to cargo, you need to include the local path first.
15+
# I.e. to test in release mode:
16+
# $ test-exercise . --release
17+
shift 1
18+
else
19+
exercise='.'
20+
fi
21+
22+
# what cargo command will we use?
23+
if [ -n "$BENCHMARK" ]; then
24+
command="bench"
25+
else
26+
command="test"
27+
fi
28+
29+
declare -a preserve_files=("src/lib.rs" "Cargo.toml" "Cargo.lock")
30+
declare -a preserve_dirs=("tests")
31+
32+
# reset instructions
33+
reset () {
34+
for file in ${preserve_files[@]}; do
35+
if [ -f "$exercise/$file.orig" ]; then
36+
mv -f "$exercise/$file.orig" "$exercise/$file"
37+
fi
38+
done
39+
for dir in ${preserve_dirs[@]}; do
40+
if [ -d "$exercise/$dir.orig" ]; then
41+
rm -rf "$exercise/$dir"
42+
mv "$exercise/$dir.orig" "$exercise/$dir"
43+
fi
44+
done
45+
}
46+
47+
# cause the reset to execute when the script exits normally or is killed
48+
trap reset EXIT INT TERM
49+
50+
# preserve the files and directories we care about
51+
for file in ${preserve_files[@]}; do
52+
if [ -f "$exercise/$file" ]; then
53+
cp "$exercise/$file" "$exercise/$file.orig"
54+
fi
55+
done
56+
for dir in ${preserve_dirs[@]}; do
57+
if [ -d "$exercise/$dir" ]; then
58+
cp -r "$exercise/$dir" "$exercise/$dir.orig"
59+
fi
60+
done
61+
62+
# Move example files to where Cargo expects them
63+
cp -f "$exercise/example.rs" "$exercise/src/lib.rs"
64+
if [ -f "$exercise/Cargo-example.toml" ]; then
65+
cp -f "$exercise/Cargo-example.toml" "$exercise/Cargo.toml"
66+
fi
67+
68+
# If deny warnings, insert a deny warnings compiler directive in the header
69+
if [ -n "$DENYWARNINGS" ]; then
70+
sed -i -e '1i #![deny(warnings)]' "$exercise/src/lib.rs"
71+
fi
72+
73+
# eliminate #[ignore] lines from tests
74+
for test in "$exercise/tests/*.rs"; do
75+
sed -i '/\[ignore\]/d' $test
76+
done
77+
78+
# run tests from within exercise directory
79+
# (use subshell so we auto-reset to current pwd after)
80+
(
81+
cd $exercise
82+
# this is the last command; its exit code is what's passed on
83+
cargo $command "$@"
84+
)

0 commit comments

Comments
 (0)