1#!/bin/sh
2#
3# Copyright (c) 2011-2015 Dmitry V. Levin <ldv@altlinux.org>
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without
7# modification, are permitted provided that the following conditions
8# are met:
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11# 2. Redistributions in binary form must reproduce the above copyright
12#    notice, this list of conditions and the following disclaimer in the
13#    documentation and/or other materials provided with the distribution.
14# 3. The name of the author may not be used to endorse or promote products
15#    derived from this software without specific prior written permission.
16#
17# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28ME_="${0##*/}"
29
30warn_() { printf >&2 '%s\n' "$*"; }
31fail_() { warn_ "$ME_: failed test: $*"; exit 1; }
32skip_() { warn_ "$ME_: skipped test: $*"; exit 77; }
33framework_failure_() { warn_ "$ME_: framework failure: $*"; exit 99; }
34framework_skip_() { warn_ "$ME_: framework skip: $*"; exit 77; }
35
36check_prog()
37{
38	type "$@" > /dev/null 2>&1 ||
39		framework_skip_ "$* is not available"
40}
41
42dump_log_and_fail_with()
43{
44	cat < "$LOG"
45	fail_ "$*"
46}
47
48run_prog()
49{
50	if [ $# -eq 0 ]; then
51		set -- "./${ME_%.test}"
52	fi
53	args="$*"
54	"$@" || {
55		if [ $? -eq 77 ]; then
56			skip_ "$args exited with code 77"
57		else
58			fail_ "$args failed"
59		fi
60	}
61}
62
63
64run_prog_skip_if_failed()
65{
66	args="$*"
67	"$@" || framework_skip_ "$args failed"
68}
69
70run_strace()
71{
72	> "$LOG" || fail_ "failed to write $LOG"
73	args="$*"
74	$STRACE -o "$LOG" "$@" ||
75		dump_log_and_fail_with "$STRACE $args failed"
76}
77
78run_strace_merge()
79{
80	rm -f -- "$LOG".[0-9]*
81	run_strace -ff -tt "$@"
82	"$srcdir"/../strace-log-merge "$LOG" > "$LOG" ||
83		dump_log_and_fail_with 'strace-log-merge failed'
84	rm -f -- "$LOG".[0-9]*
85}
86
87check_gawk()
88{
89	check_prog gawk
90	check_prog grep
91
92	local program="$1"; shift
93	if grep '^@include[[:space:]]' < "$program" > /dev/null; then
94		gawk '@include "/dev/null"' < /dev/null ||
95			framework_skip_ 'gawk does not support @include'
96	fi
97}
98
99# Usage: [FILE_TO_CHECK [AWK_PROGRAM [ERROR_MESSAGE [EXTRA_AWK_OPTIONS...]]]]
100# Check whether AWK_PROGRAM matches FILE_TO_CHECK using gawk.
101# If it doesn't, dump FILE_TO_CHECK and fail with ERROR_MESSAGE.
102match_awk()
103{
104	local output program error
105	if [ $# -eq 0 ]; then
106		output="$LOG"
107	else
108		output="$1"; shift
109	fi
110	if [ $# -eq 0 ]; then
111		program="$srcdir/${ME_%.test}.awk"
112	else
113		program="$1"; shift
114	fi
115	if [ $# -eq 0 ]; then
116		error="$STRACE $args output mismatch"
117	else
118		error="$1"; shift
119	fi
120
121	check_gawk "$program"
122
123	AWKPATH="$srcdir" gawk -f "$program" "$@" < "$output" || {
124		cat < "$output"
125		fail_ "$error"
126	}
127}
128
129# Usage: [FILE_TO_CHECK [FILE_TO_COMPATE_WITH [ERROR_MESSAGE]]]
130# Check whether FILE_TO_CHECK differs from FILE_TO_COMPATE_WITH.
131# If it does, dump the difference and fail with ERROR_MESSAGE.
132match_diff()
133{
134	local output expected error
135	if [ $# -eq 0 ]; then
136		output="$LOG"
137	else
138		output="$1"; shift
139	fi
140	if [ $# -eq 0 ]; then
141		expected="$srcdir/${ME_%.test}.expected"
142	else
143		expected="$1"; shift
144	fi
145	if [ $# -eq 0 ]; then
146		error="$STRACE $args output mismatch"
147	else
148		error="$1"; shift
149	fi
150
151	check_prog diff
152
153	diff -- "$expected" "$output" ||
154		fail_ "$error"
155}
156
157# Usage: [FILE_TO_CHECK [FILE_WITH_PATTERNS [ERROR_MESSAGE]]]
158# Check whether all patterns listed in FILE_WITH_PATTERNS
159# match FILE_TO_CHECK using egrep.
160# If at least one of these patterns does not match,
161# dump both files and fail with ERROR_MESSAGE.
162match_grep()
163{
164	local output patterns error pattern failed=
165	if [ $# -eq 0 ]; then
166		output="$LOG"
167	else
168		output="$1"; shift
169	fi
170	if [ $# -eq 0 ]; then
171		patterns="$srcdir/${ME_%.test}.expected"
172	else
173		patterns="$1"; shift
174	fi
175	if [ $# -eq 0 ]; then
176		error="$STRACE $args output mismatch"
177	else
178		error="$1"; shift
179	fi
180
181	check_prog wc
182	check_prog grep
183
184	while read -r pattern; do
185		LC_ALL=C grep -E -x -e "$pattern" < "$output" > /dev/null || {
186			test -n "$failed" || {
187				echo 'Failed patterns of expected output:'
188				failed=1
189			}
190			printf '%s\n' "$pattern"
191		}
192	done < "$patterns"
193	test -z "$failed" || {
194		echo 'Actual output:'
195		cat < "$output"
196		fail_ "$error"
197	}
198}
199
200check_prog cat
201check_prog rm
202
203LOG="$ME_.tmp"
204rm -f "$LOG"
205
206: "${STRACE:=../strace}"
207: "${TIMEOUT_DURATION:=60}"
208: "${SLEEP_A_BIT:=sleep 1}"
209
210[ -z "${VERBOSE-}" ] ||
211	set -x
212