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