Skip to content

Commit ab932a3

Browse files
committed
add tests
Signed-off-by: Harmen Stoppels <me@harmenstoppels.nl>
1 parent 469c2ff commit ab932a3

3 files changed

Lines changed: 295 additions & 2 deletions

File tree

.github/workflows/shellcheck.yml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
1313
- name: Run shellcheck
14-
run: shellcheck cc.sh test/run.sh
14+
run: shellcheck cc.sh test/run.sh test/test_list_ops.sh
1515
- name: Run tests
16-
run: sh test/run.sh
16+
run: |
17+
sh test/run.sh
18+
sh test/test_list_ops.sh

cc.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
# other separators, we set and reset it.
2525
unset IFS
2626

27+
# BEGIN list functions
28+
2729
# Separator for lists whose names end with `_list`.
2830
# We pick the alarm bell character, which is highly unlikely to
2931
# conflict with anything. This is a literal bell character (which
@@ -205,6 +207,8 @@ preextend() {
205207
fi
206208
}
207209

210+
# END list functions
211+
208212
execute() {
209213
# dump the full command if the caller supplies SPACK_TEST_COMMAND=dump-args
210214
if [ -n "${SPACK_TEST_COMMAND=}" ]; then

test/test_list_ops.sh

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,287 @@
1+
#!/bin/sh
2+
# shellcheck disable=SC2034 # vars are passed by name to functions sourced from cc.sh
3+
# shellcheck disable=SC2154 # lsep/sep are defined by the sourced cc.sh block
4+
#
5+
# Copyright Spack Project Developers. See COPYRIGHT file for details.
6+
#
7+
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
8+
#
9+
# Unit tests for the list-manipulation primitives in cc.sh (empty, setsep,
10+
# append, extend, preextend). The block between '# BEGIN list functions' and
11+
# '# END list functions' in cc.sh is extracted and sourced, so we can call
12+
# the functions directly without running the rest of the wrapper.
13+
14+
SCRIPT_DIR=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
15+
REPO_DIR=$(CDPATH='' cd -- "$SCRIPT_DIR/.." && pwd)
16+
CC_SH="$REPO_DIR/cc.sh"
17+
18+
if [ ! -f "$CC_SH" ]; then
19+
echo "Cannot find cc.sh at $CC_SH" >&2
20+
exit 1
21+
fi
22+
23+
FUNCS_SH=$(mktemp)
24+
trap 'rm -f "$FUNCS_SH"' EXIT INT TERM
25+
26+
awk '/^# BEGIN list functions$/{flag=1; next} /^# END list functions$/{flag=0} flag' \
27+
"$CC_SH" > "$FUNCS_SH"
28+
29+
# shellcheck disable=SC1090
30+
. "$FUNCS_SH"
31+
32+
# ---------------------------------------------------------------------------
33+
# Test harness
34+
# ---------------------------------------------------------------------------
35+
36+
PASS_COUNT=0
37+
FAIL_COUNT=0
38+
CURRENT_TEST=""
39+
CURRENT_FAILED=0
40+
41+
start_test() {
42+
CURRENT_TEST="$1"
43+
CURRENT_FAILED=0
44+
}
45+
46+
end_test() {
47+
if [ "$CURRENT_FAILED" -eq 0 ]; then
48+
PASS_COUNT=$((PASS_COUNT + 1))
49+
printf 'PASS %s\n' "$CURRENT_TEST"
50+
else
51+
FAIL_COUNT=$((FAIL_COUNT + 1))
52+
printf 'FAIL %s (%d sub-check(s) failed)\n' "$CURRENT_TEST" "$CURRENT_FAILED"
53+
fi
54+
}
55+
56+
fail() {
57+
CURRENT_FAILED=$((CURRENT_FAILED + 1))
58+
printf ' [%s] %s\n' "$CURRENT_TEST" "$1" >&2
59+
}
60+
61+
# expect_eq LABEL ACTUAL EXPECTED
62+
expect_eq() {
63+
if [ "$2" != "$3" ]; then
64+
# Render the bell separator visibly in error output.
65+
_exp=$(printf '%s' "$3" | tr "$lsep" '|')
66+
_act=$(printf '%s' "$2" | tr "$lsep" '|')
67+
fail "$1: expected '$_exp', got '$_act'"
68+
fi
69+
}
70+
71+
# expect_true LABEL CMD...
72+
expect_true() {
73+
_label="$1"; shift
74+
if ! "$@"; then
75+
fail "$_label: expected success, got failure"
76+
fi
77+
}
78+
79+
# expect_false LABEL CMD...
80+
expect_false() {
81+
_label="$1"; shift
82+
if "$@"; then
83+
fail "$_label: expected failure, got success"
84+
fi
85+
}
86+
87+
# ---------------------------------------------------------------------------
88+
# Tests
89+
# ---------------------------------------------------------------------------
90+
91+
test_empty() {
92+
unset tvar || true
93+
expect_true empty_unset empty tvar
94+
tvar=''
95+
expect_true empty_empty empty tvar
96+
tvar='x'
97+
expect_false empty_nonempty empty tvar
98+
tvar=' '
99+
expect_false empty_space empty tvar
100+
unset tvar
101+
}
102+
103+
test_setsep() {
104+
setsep foo_dirs; expect_eq setsep_dirs "$sep" ':'
105+
setsep FOO_DIRS; expect_eq setsep_DIRS "$sep" ':'
106+
setsep MYPATH; expect_eq setsep_PATH "$sep" ':'
107+
setsep MYPATHS; expect_eq setsep_PATHS "$sep" ':'
108+
setsep foo_list; expect_eq setsep_list "$sep" "$lsep"
109+
setsep whatever; expect_eq setsep_other "$sep" ' '
110+
}
111+
112+
test_append() {
113+
# _list (lsep separator)
114+
tgt_list=''
115+
append tgt_list a
116+
expect_eq append_list_empty "$tgt_list" "a"
117+
append tgt_list b
118+
expect_eq append_list_two "$tgt_list" "a${lsep}b"
119+
append tgt_list c
120+
expect_eq append_list_three "$tgt_list" "a${lsep}b${lsep}c"
121+
122+
# _dirs (colon separator)
123+
tgt_dirs=''
124+
append tgt_dirs /a
125+
append tgt_dirs /b
126+
expect_eq append_dirs "$tgt_dirs" "/a:/b"
127+
128+
# default (space separator)
129+
tgt_other=''
130+
append tgt_other x
131+
append tgt_other y
132+
expect_eq append_default "$tgt_other" "x y"
133+
}
134+
135+
test_extend_empty_source() {
136+
src_list=''
137+
tgt_list='existing'
138+
extend tgt_list src_list
139+
expect_eq extend_empty_src "$tgt_list" 'existing'
140+
}
141+
142+
test_extend_single_into_empty() {
143+
src_list='a'
144+
tgt_list=''
145+
extend tgt_list src_list
146+
expect_eq extend_single "$tgt_list" 'a'
147+
}
148+
149+
test_extend_multi_into_empty() {
150+
src_list="a${lsep}b${lsep}c"
151+
tgt_list=''
152+
extend tgt_list src_list
153+
expect_eq extend_multi_empty "$tgt_list" "a${lsep}b${lsep}c"
154+
}
155+
156+
test_extend_multi_into_nonempty() {
157+
src_list="b${lsep}c"
158+
tgt_list='a'
159+
extend tgt_list src_list
160+
expect_eq extend_multi_nonempty "$tgt_list" "a${lsep}b${lsep}c"
161+
}
162+
163+
test_extend_prefix() {
164+
src_list="b${lsep}c"
165+
tgt_list='a'
166+
extend tgt_list src_list '-I'
167+
expect_eq extend_prefix "$tgt_list" "a${lsep}-Ib${lsep}-Ic"
168+
}
169+
170+
test_extend_cross_separator() {
171+
# Source uses ':' (dirs), target uses lsep (list).
172+
src_dirs='a:b:c'
173+
tgt_list=''
174+
extend tgt_list src_dirs
175+
expect_eq extend_dirs_to_list_empty "$tgt_list" "a${lsep}b${lsep}c"
176+
177+
tgt_list='x'
178+
extend tgt_list src_dirs '-L'
179+
expect_eq extend_dirs_to_list_nonempty "$tgt_list" "x${lsep}-La${lsep}-Lb${lsep}-Lc"
180+
}
181+
182+
test_extend_default_separator() {
183+
src_other='a b c'
184+
tgt_other='x'
185+
extend tgt_other src_other
186+
expect_eq extend_default_sep "$tgt_other" 'x a b c'
187+
}
188+
189+
test_preextend_empty_source() {
190+
src_list=''
191+
tgt_list='existing'
192+
preextend tgt_list src_list
193+
expect_eq preextend_empty_src "$tgt_list" 'existing'
194+
}
195+
196+
test_preextend_single_into_empty() {
197+
src_list='a'
198+
tgt_list=''
199+
preextend tgt_list src_list
200+
expect_eq preextend_single "$tgt_list" 'a'
201+
}
202+
203+
test_preextend_multi_into_empty() {
204+
# The original reversed-prepend logic existed to preserve source order.
205+
src_list="a${lsep}b${lsep}c"
206+
tgt_list=''
207+
preextend tgt_list src_list
208+
expect_eq preextend_multi_empty "$tgt_list" "a${lsep}b${lsep}c"
209+
}
210+
211+
test_preextend_multi_into_nonempty() {
212+
src_list="a${lsep}b"
213+
tgt_list="c${lsep}d"
214+
preextend tgt_list src_list
215+
expect_eq preextend_multi_nonempty "$tgt_list" "a${lsep}b${lsep}c${lsep}d"
216+
}
217+
218+
test_preextend_prefix() {
219+
src_list="a${lsep}b"
220+
tgt_list='c'
221+
preextend tgt_list src_list '-I'
222+
expect_eq preextend_prefix "$tgt_list" "-Ia${lsep}-Ib${lsep}c"
223+
}
224+
225+
test_preextend_cross_separator() {
226+
src_dirs='a:b:c'
227+
tgt_list='x'
228+
preextend tgt_list src_dirs
229+
expect_eq preextend_dirs_to_list "$tgt_list" "a${lsep}b${lsep}c${lsep}x"
230+
}
231+
232+
test_lsep_prepend_pattern() {
233+
# The inline replacement for the old prepend helper, as used at
234+
# 'full_command_list="${SPACK_CCACHE_BINARY}${lsep}${full_command_list}"'.
235+
tgt_list=''
236+
append tgt_list compiler
237+
append tgt_list -O2
238+
tgt_list="ccache${lsep}${tgt_list}"
239+
240+
IFS="$lsep"
241+
# shellcheck disable=SC2086
242+
set -- $tgt_list
243+
unset IFS
244+
expect_eq prepend_pattern_count "$#" 3
245+
expect_eq prepend_pattern_first "$1" 'ccache'
246+
expect_eq prepend_pattern_mid "$2" 'compiler'
247+
expect_eq prepend_pattern_last "$3" '-O2'
248+
}
249+
250+
# ---------------------------------------------------------------------------
251+
# Runner
252+
# ---------------------------------------------------------------------------
253+
254+
all_tests='
255+
test_empty
256+
test_setsep
257+
test_append
258+
test_extend_empty_source
259+
test_extend_single_into_empty
260+
test_extend_multi_into_empty
261+
test_extend_multi_into_nonempty
262+
test_extend_prefix
263+
test_extend_cross_separator
264+
test_extend_default_separator
265+
test_preextend_empty_source
266+
test_preextend_single_into_empty
267+
test_preextend_multi_into_empty
268+
test_preextend_multi_into_nonempty
269+
test_preextend_prefix
270+
test_preextend_cross_separator
271+
test_lsep_prepend_pattern
272+
'
273+
274+
if [ $# -gt 0 ]; then
275+
tests_to_run="$*"
276+
else
277+
tests_to_run="$all_tests"
278+
fi
279+
280+
for t in $tests_to_run; do
281+
start_test "$t"
282+
"$t"
283+
end_test
284+
done
285+
286+
printf '\n%d passed, %d failed\n' "$PASS_COUNT" "$FAIL_COUNT"
287+
[ "$FAIL_COUNT" -eq 0 ]

0 commit comments

Comments
 (0)