xref: /linux/tools/objtool/tests/run-tests.sh (revision 317cec905af82e9ccca93cec661e88b1d3968a43)
1#!/bin/bash
2# SPDX-License-Identifier: GPL-2.0
3#
4# Run the objtool klp tests.  Each test-*.sh prints one TAP result line.
5#
6# Tests live in generic/ and in a directory per architecture.  A run executes
7# generic/ plus the one matching this architecture, so a test which cannot
8# apply here is not run rather than reporting a skip; what was left out is
9# reported once, as a comment, so differing coverage is still visible.
10#
11# A run covers one compiler and one architecture; CI runs the combinations.
12# The harness checks the environment once up front and fails the run if the
13# suite cannot execute, rather than letting every test skip and exit 0.
14
15set -u
16
17# Determinism: the order test-*.sh expands in, and how grep's character ranges
18# and sort's collation behave inside the tests, are all locale-dependent.  A
19# suite whose results depend on the invoking shell's locale is a suite whose
20# failures cannot be reproduced.
21export LC_ALL=C
22
23usage()
24{
25	cat <<EOF
26usage: $(basename "$0") [test...]
27
28Run the objtool klp tests for this architecture: everything in generic/, plus
29everything in the directory named for it.  With no arguments, runs all of them.
30A test may be named with or without its "test-" prefix and ".sh" suffix, and is
31looked for in both directories.
32
33Environment:
34    OBJTOOL       objtool binary to test (default ../objtool)
35    CC            compiler used to build fixtures (default gcc)
36    ARCH          architecture the tests are for (default: uname -m)
37
38A test which needs something of its own says so in its skip message.
39EOF
40	exit "${1:-0}"
41}
42
43cd "$(dirname "$0")" || exit 1
44
45while [ $# -gt 0 ]; do
46	case "$1" in
47	-h|--help)	usage ;;
48	--)		shift; break ;;
49	-*)		echo "unknown option: $1" >&2; usage 1 ;;
50	*)		break ;;
51	esac
52done
53
54echo "TAP version 13"
55
56# Sourcing the harness runs its preflight, which decides which architecture
57# this run is for -- so the test list cannot be built before it has, and the
58# tests inherit the answers rather than working them out again.
59. ./lib.sh
60
61dirs=( generic )
62[ -d "$KLP_TEST_ARCH" ] && dirs+=( "$KLP_TEST_ARCH" )
63
64if [ $# -gt 0 ]; then
65	tests=()
66	for arg in "$@"; do
67		name="test-${arg#test-}"; name="${name%.sh}.sh"
68		found=
69		for d in "${dirs[@]}"; do
70			[ -f "$d/$name" ] || continue
71			[ -x "$d/$name" ] ||
72				{ echo "not executable: $d/$name" >&2; exit 1; }
73			tests+=( "$d/$name" ); found=y
74		done
75		[ -n "$found" ] ||
76			{ echo "no such test for $KLP_TEST_ARCH: $arg" >&2; exit 1; }
77	done
78else
79	tests=()
80	for d in "${dirs[@]}"; do
81		for t in "$d"/test-*.sh; do
82			[ -f "$t" ] && tests+=( "$t" )
83		done
84	done
85	[ "${#tests[@]}" -gt 0 ] ||
86		{ echo "1..0 # SKIP no tests found"; exit 0; }
87
88	# Tests for another architecture are absent from this run entirely.  Say
89	# how many, so a run which covers less than the tree holds does not look
90	# like one that covers all of it.
91	for d in */; do
92		d="${d%/}"
93		case "$d" in generic|"$KLP_TEST_ARCH") continue ;; esac
94		n=$(ls "$d"/test-*.sh 2>/dev/null | wc -l)
95		[ "$n" -gt 0 ] || continue
96		echo "# not run: $n test$( [ "$n" = 1 ] || echo s ) in $d/" \
97		     "(this run is $KLP_TEST_ARCH)"
98	done
99fi
100
101echo "1..${#tests[@]}"
102
103pass=0 fail=0 static_skip=0 probe_skip=0 xfail=0 xpass=0
104
105for t in "${tests[@]}"; do
106	out="$(./"$t" 2>&1)"
107	rc=$?
108
109	# A test prints one result line, but it is not necessarily the only
110	# thing it prints: objtool warns on stderr, and the runner captures
111	# that.  Classify the result line itself rather than the whole of the
112	# output, or a stray line ahead of it makes every pattern below miss and
113	# the exit status decide -- which would count an expected failure, which
114	# exits 0, as a pass.
115	result="$(printf '%s\n' "$out" | grep -E '^(ok|not ok)' | tail -1)"
116	rest="$(printf '%s\n' "$out" | grep -Ev '^(ok|not ok)')"
117
118	# Classify from the result line, not the exit status: a skip and a pass
119	# both exit 0, and telling them apart is the point of counting.
120	#
121	# The two skip kinds differ in what they promise.  A static skip was
122	# declared before the test ran ("clang does not do this"), so it is
123	# expected indefinitely.  A probe skip means the construct did not turn
124	# up this time, which is weaker and worth watching: one that becomes
125	# permanent is a fixture that quietly stopped testing anything.
126	case "$result" in
127	*"# SKIP (declared)"*)	static_skip=$((static_skip + 1)) ;;
128	*"# SKIP (probe)"*)	probe_skip=$((probe_skip + 1)) ;;
129	*"# SKIP"*)
130		# An undeclared skip: the test gave up for a reason it never
131		# said it might.  That is a hole, not an expected outcome.
132		#
133		# Replace the line rather than adding one.  Every test owes the
134		# plan exactly one result, and a consumer counting them is
135		# entitled to say so when the totals disagree.
136		rest="$rest${rest:+$'\n'}was: $result"
137		result="not ok - $(basename "$t" .sh): undeclared skip"
138		result="$result (use gcc_only/clang_only or require_input_*)"
139		fail=$((fail + 1)) ;;
140	"not ok"*"# TODO"*)	xfail=$((xfail + 1)) ;;
141	"ok"*"# TODO"*)		xpass=$((xpass + 1)) ;;
142	"not ok"*)		fail=$((fail + 1)) ;;
143	"ok"*)			pass=$((pass + 1)) ;;
144	*)
145		# No result line at all: the test died before reporting.
146		rest="$rest${rest:+$'\n'}exited $rc without a result line"
147		result="not ok - $(basename "$t" .sh): no TAP result"
148		fail=$((fail + 1)) ;;
149	esac
150
151	echo "$result"
152	[ -n "$rest" ] && printf '%s\n' "$rest" | sed 's/^[^#]/# &/'
153
154done
155
156echo "# pass:$pass fail:$fail static-skip:$static_skip" \
157     "probe-skip:$probe_skip xfail:$xfail xpass:$xpass"
158
159[ "$fail" = 0 ] && [ "$xpass" = 0 ]
160