tests: factor out common shell code to functions

Factor out shell code used in several tests to common functions.

* tests/fanotify_mark.expected: New file.
* tests/ioctl.expected: New file.
* tests/net-fd.expected: New file.
* tests/net.expected: New file.
* tests/statfs.expected: New file.
* tests/sun_path.expected: New file.
* tests/uio.expected: New file.
* tests/ipc.sh: New file.
* tests/Makefile.am (EXTRA_DIST): Add them.
* tests/init.sh (dump_log_and_fail_with, run_prog,
run_prog_skip_if_failed, run_strace, run_strace_merge,
match_awk, match_diff, match_grep): New functions.
* tests/*.test: Use them.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index ff5e136..7f9a11e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -87,15 +87,23 @@
 EXTRA_DIST = init.sh run.sh \
 	     caps.awk \
 	     dumpio.expected \
+	     fanotify_mark.expected \
 	     getdents.awk \
 	     getdents.out \
 	     getrandom.awk \
+	     ioctl.expected \
+	     ipc.sh \
 	     mmsg.expected \
+	     net.expected \
+	     net-fd.expected \
 	     net-yy-accept.awk \
 	     net-yy-connect.awk \
 	     select.awk \
 	     sigaction.awk \
+	     statfs.expected \
+	     sun_path.expected \
 	     uid.awk \
+	     uio.expected \
 	     unix-yy-accept.awk \
 	     unix-yy-connect.awk \
 	     $(TESTS)
diff --git a/tests/bexecve.test b/tests/bexecve.test
index 9064399..c49f08b 100755
--- a/tests/bexecve.test
+++ b/tests/bexecve.test
@@ -4,35 +4,26 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-args='-enone'
-what="$STRACE $args sh -c 'exec false'"
-
-$STRACE $args sh -c 'exec false' 2> "$LOG"
-if [ $? -ne 1 ]; then
-	cat "$LOG"
-	fail_ "$what: unexpected exit status"
-fi
-
-args='-bexecve -enone'
-what="$STRACE $args sh -c 'exec false'"
-
-$STRACE $args sh -c 'exec false' 2> "$LOG" || {
-	cat "$LOG"
-	fail_ "$what: unexpected exit status"
+run_strace_redir()
+{
+	args="$*"
+	$STRACE "$@" 2> "$LOG"
 }
 
+run_strace_redir -enone sh -c 'exec false'
+[ $? -eq 1 ] ||
+	dump_log_and_fail_with "$STRACE $args: unexpected exit status"
+
+run_strace_redir -bexecve -enone sh -c 'exec false' ||
+	dump_log_and_fail_with "$STRACE $args: unexpected exit status"
+
 pattern='Process [1-9][0-9]* detached'
 
-LC_ALL=C grep -x "$pattern" "$LOG" > /dev/null || {
-	cat "$LOG"
-	fail_ "$what: unexpected output"
-}
+LC_ALL=C grep -x "$pattern" "$LOG" > /dev/null ||
+	dump_log_and_fail_with "$STRACE $args: output mismatch"
 
 if LC_ALL=C grep -v -x "$pattern" "$LOG" > /dev/null; then
-	cat "$LOG"
-	fail_ "$what: unexpected output"
+	dump_log_and_fail_with "$STRACE $args: unexpected output"
 fi
 
 exit 0
diff --git a/tests/caps.test b/tests/caps.test
index ac0a85d..9437a4b 100755
--- a/tests/caps.test
+++ b/tests/caps.test
@@ -4,23 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog awk
-
-./caps || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'capget/capset syscalls do not behave as expected'
-	else
-		fail_ 'caps failed'
-	fi
-}
-
-args="-e trace=capget,capset ./caps"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-awk -f "$srcdir"/caps.awk "$LOG" ||
-	{ cat "$LOG"; fail_ 'unexpected output'; }
+run_prog
+run_strace -e trace=capget,capset $args
+match_awk
 
 exit 0
diff --git a/tests/count.test b/tests/count.test
index b94eeba..9c53fe2 100755
--- a/tests/count.test
+++ b/tests/count.test
@@ -7,38 +7,25 @@
 check_prog grep
 check_prog sleep
 
-make_log()
-{
-	$STRACE $args > $LOG 2>&1 || {
-		cat $LOG
-		fail_ "$STRACE $args failed"
-	}
-}
-
 grep_log()
 {
-	LC_ALL=C grep -E -x -e "$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "unexpected output from $STRACE $args"
+	local pattern="$1"; shift
+
+	run_strace "$@"
+
+	grep nanosleep "$LOG" > /dev/null ||
+		framework_skip_ 'sleep does not use nanosleep'
+
+	LC_ALL=C grep -E -x -e "$pattern" "$LOG" > /dev/null || {
+		echo "Pattern of expected output: $pattern"
+		echo 'Actual output:'
+		dump_log_and_fail_with "$STRACE $args output mismatch"
 	}
 }
 
-args='-c sleep 1'
-make_log
-grep nanosleep $LOG > /dev/null ||
-	skip_ 'sleep does not use nanosleep'
-grep_log ' *[^ ]+ +0\.0[^n]*nanosleep'
-
-args='-c -enanosleep sleep 1'
-make_log
-grep_log ' *[^ ]+ +0\.0[^n]*nanosleep'
-
-args='-cw sleep 1'
-make_log
-grep_log ' *[^ ]+ +(1\.0|0\.99)[^n]*nanosleep'
-
-args='-cw -enanosleep sleep 1'
-make_log
-grep_log '100\.00 +(1\.0|0\.99)[^n]*nanosleep'
+grep_log ' *[^ ]+ +0\.0[^n]*nanosleep'		-c sleep 1
+grep_log ' *[^ ]+ +0\.0[^n]*nanosleep'		-c -enanosleep sleep 1
+grep_log ' *[^ ]+ +(1\.0|0\.99)[^n]*nanosleep'	-cw sleep 1
+grep_log '100\.00 +(1\.0|0\.99)[^n]*nanosleep'	-cw -enanosleep sleep 1
 
 exit 0
diff --git a/tests/detach-running.test b/tests/detach-running.test
index 70e5208..595a505 100755
--- a/tests/detach-running.test
+++ b/tests/detach-running.test
@@ -4,17 +4,16 @@
 
 . "${srcdir=.}/init.sh"
 
-kill -0 $$ ||
-	framework_skip_ 'kill -0 does not work'
+run_prog_skip_if_failed \
+	kill -0 $$
 
-check_prog grep
 check_prog sleep
 
 set -e
 
 ./set_ptracer_any sh -c "echo > $LOG; while :; do :; done" > /dev/null &
 
-while ! [ -s $LOG ]; do
+while ! [ -s "$LOG" ]; do
 	kill -0 $! 2> /dev/null ||
 		fail_ 'set_ptracer_any sh failed'
 	$SLEEP_A_BIT
@@ -30,30 +29,35 @@
 	return 0
 }
 
-rm -f $LOG
-$STRACE -p $tracee_pid 2> $LOG &
+rm -f "$LOG"
+$STRACE -p $tracee_pid 2> "$LOG" &
 
-while ! grep -F "Process $tracee_pid attached" $LOG > /dev/null; do
-	kill -0 $! 2> /dev/null ||
-		{ cat $LOG; cleanup; fail_ 'strace -p does not work'; }
+while ! grep -F "Process $tracee_pid attached" "$LOG" > /dev/null; do
+	kill -0 $! 2> /dev/null || {
+		cleanup
+		dump_log_and_fail_with "$STRACE -p failed to attach"
+	}
 	$SLEEP_A_BIT
 done
 
 kill -INT $!
 wait $!
 
-grep -F "Process $tracee_pid detached" $LOG > /dev/null ||
-	{ cat $LOG; cleanup; fail_ 'strace -p failed to detach'; }
+grep -F "Process $tracee_pid detached" "$LOG" > /dev/null || {
+		cleanup
+		dump_log_and_fail_with "$STRACE -p failed to detach"
+	}
 
 if [ -f /proc/self/status ]; then
 	$SLEEP_A_BIT
-	test -d /proc/$tracee_pid ||
-		{ cat $LOG; cleanup; fail_ 'tracee died after detach'; }
+	test -d /proc/$tracee_pid || {
+		cleanup
+		dump_log_and_fail_with 'tracee died after detach'
+	}
 	grep '^State:.*R (running)' < /proc/$tracee_pid/status > /dev/null || {
-		cat $LOG
 		grep '^State:' < /proc/$tracee_pid/status
 		cleanup
-		fail_ 'tracee is not running after detach'
+		dump_log_and_fail_with 'tracee is not running after detach'
 	}
 fi
 
diff --git a/tests/detach-sleeping.test b/tests/detach-sleeping.test
index 6588d4f..345d7d0 100755
--- a/tests/detach-sleeping.test
+++ b/tests/detach-sleeping.test
@@ -4,18 +4,17 @@
 
 . "${srcdir=.}/init.sh"
 
-kill -0 $$ ||
-	framework_skip_ 'kill -0 does not work'
+run_prog_skip_if_failed \
+	kill -0 $$
 
-check_prog grep
 check_prog sleep
 
 set -e
 
-rm -f $LOG
-./set_ptracer_any sleep $((2*$TIMEOUT_DURATION)) > $LOG &
+rm -f "$LOG"
+./set_ptracer_any sleep $((2*$TIMEOUT_DURATION)) > "$LOG" &
 
-while ! [ -s $LOG ]; do
+while ! [ -s "$LOG" ]; do
 	kill -0 $! 2> /dev/null ||
 		fail_ 'set_ptracer_any sleep failed'
 	$SLEEP_A_BIT
@@ -31,30 +30,35 @@
 	return 0
 }
 
-rm -f $LOG
-$STRACE -p $tracee_pid 2> $LOG &
+rm -f "$LOG"
+$STRACE -p $tracee_pid 2> "$LOG" &
 
-while ! grep -F "Process $tracee_pid attached" $LOG > /dev/null; do
-	kill -0 $! 2> /dev/null ||
-		{ cat $LOG; cleanup; fail_ 'strace -p does not work'; }
+while ! grep -F "Process $tracee_pid attached" "$LOG" > /dev/null; do
+	kill -0 $! 2> /dev/null || {
+		cleanup
+		dump_log_and_fail_with "$STRACE -p failed to attach"
+	}
 	$SLEEP_A_BIT
 done
 
 kill -INT $!
 wait $!
 
-grep -F "Process $tracee_pid detached" $LOG > /dev/null ||
-	{ cat $LOG; cleanup; fail_ 'strace -p failed to detach'; }
+grep -F "Process $tracee_pid detached" "$LOG" > /dev/null || {
+	cleanup
+	dump_log_and_fail_with "$STRACE -p failed to detach"
+}
 
 if [ -f /proc/self/status ]; then
 	$SLEEP_A_BIT
-	test -d /proc/$tracee_pid ||
-		{ cat $LOG; cleanup; fail_ 'tracee died after detach'; }
+	test -d /proc/$tracee_pid || {
+		cleanup
+		dump_log_and_fail_with 'tracee died after detach'
+	}
 	grep '^State:.*S (sleeping)' < /proc/$tracee_pid/status > /dev/null || {
-		cat $LOG
 		grep '^State:' < /proc/$tracee_pid/status
 		cleanup
-		fail_ 'tracee is not sleeping after detach'
+		dump_log_and_fail_with 'tracee is not sleeping after detach'
 	}
 fi
 
diff --git a/tests/detach-stopped.test b/tests/detach-stopped.test
index 871a157..3d1c67e 100755
--- a/tests/detach-stopped.test
+++ b/tests/detach-stopped.test
@@ -4,23 +4,22 @@
 
 . "${srcdir=.}/init.sh"
 
-kill -0 $$ ||
-	framework_skip_ 'kill -0 does not work'
+run_prog_skip_if_failed \
+	kill -0 $$
 
-check_prog grep
 check_prog sleep
 
-$STRACE -d -enone / > /dev/null 2> $LOG
-if grep -F -x "PTRACE_SEIZE doesn't work" $LOG > /dev/null; then
+$STRACE -d -enone / > /dev/null 2> "$LOG"
+if grep -F -x "PTRACE_SEIZE doesn't work" "$LOG" > /dev/null; then
 	skip_ "PTRACE_SEIZE doesn't work"
 fi
 
 set -e
 
-rm -f $LOG
-./set_ptracer_any sleep $((2*$TIMEOUT_DURATION)) > $LOG &
+rm -f "$LOG"
+./set_ptracer_any sleep $((2*$TIMEOUT_DURATION)) > "$LOG" &
 
-while ! [ -s $LOG ]; do
+while ! [ -s "$LOG" ]; do
 	kill -0 $! 2> /dev/null ||
 		fail_ 'set_ptracer_any sleep failed'
 	$SLEEP_A_BIT
@@ -38,36 +37,43 @@
 	return 0
 }
 
-rm -f $LOG
-$STRACE -p $tracee_pid 2> $LOG &
+rm -f "$LOG"
+$STRACE -p $tracee_pid 2> "$LOG" &
 
-while ! grep -F "Process $tracee_pid attached" $LOG > /dev/null; do
-	kill -0 $! 2> /dev/null ||
-		{ cat $LOG; cleanup; fail_ 'strace -p does not work'; }
+while ! grep -F "Process $tracee_pid attached" "$LOG" > /dev/null; do
+	kill -0 $! 2> /dev/null || {
+		cleanup
+		dump_log_and_fail_with "$STRACE -p failed to attach"
+	}
 	$SLEEP_A_BIT
 done
 
-while ! grep -F -e '--- stopped by ' $LOG > /dev/null; do
-	kill -0 $! 2> /dev/null ||
-		{ cat $LOG; cleanup; fail_ 'strace -p does not work'; }
+while ! grep -F -e '--- stopped by ' "$LOG" > /dev/null; do
+	kill -0 $! 2> /dev/null || {
+		cleanup
+		dump_log_and_fail_with "$STRACE -p missed stop notifications"
+	}
 	$SLEEP_A_BIT
 done
 
 kill -INT $!
 wait $!
 
-grep -F "Process $tracee_pid detached" $LOG > /dev/null ||
-	{ cat $LOG; cleanup; fail_ 'strace -p failed to detach'; }
+grep -F "Process $tracee_pid detached" "$LOG" > /dev/null || {
+	cleanup
+	dump_log_and_fail_with "$STRACE -p failed to detach"
+}
 
 if [ -f /proc/self/status ]; then
 	$SLEEP_A_BIT
-	test -d /proc/$tracee_pid ||
-		{ cat $LOG; cleanup; fail_ 'tracee died after detach'; }
+	test -d /proc/$tracee_pid || {
+		cleanup
+		dump_log_and_fail_with 'tracee died after detach'
+	}
 	grep '^State:.*T (stopped)' < /proc/$tracee_pid/status > /dev/null || {
-		cat $LOG
 		grep '^State:' < /proc/$tracee_pid/status
 		cleanup
-		fail_ 'tracee is not group-stopped after detach'
+		dump_log_and_fail_with 'tracee is not group-stopped after detach'
 	}
 fi
 
diff --git a/tests/dumpio.test b/tests/dumpio.test
index ef3792d..8d272fc 100755
--- a/tests/dumpio.test
+++ b/tests/dumpio.test
@@ -4,23 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-dumpio_expected="${srcdir=.}/dumpio.expected"
-cat "$dumpio_expected" > /dev/null ||
-	fail_ "$dumpio_expected is not available"
-
-check_prog diff
-
-args='./unix-pair-send-recv abcdefghijklmnopqrstuvwxyz'
-$args ||
-	fail_ "$args failed"
-
-args="-esignal=none -esendto,recvfrom -eread=0 -ewrite=0 $args"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-diff "$dumpio_expected" "$LOG" ||
-	fail_ "$STRACE $args failed to dump i/o properly"
+run_prog ./unix-pair-send-recv abcdefghijklmnopqrstuvwxyz
+run_strace -esignal=none -esendto,recvfrom -eread=0 -ewrite=0 $args
+match_diff
 
 exit 0
diff --git a/tests/fanotify_mark.expected b/tests/fanotify_mark.expected
new file mode 100755
index 0000000..d2bb336
--- /dev/null
+++ b/tests/fanotify_mark.expected
@@ -0,0 +1 @@
+fanotify_mark\(-1, FAN_MARK_ADD, FAN_MODIFY\|FAN_ONDIR, AT_FDCWD, "\."\) += -1.*
diff --git a/tests/fanotify_mark.test b/tests/fanotify_mark.test
index c5eb4eb..4b7749a 100755
--- a/tests/fanotify_mark.test
+++ b/tests/fanotify_mark.test
@@ -4,32 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-./fanotify_mark || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'fanotify_mark is not available'
-	else
-		fail_ 'fanotify_mark failed'
-	fi
-}
-
-args="-efanotify_mark ./fanotify_mark"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-grep_log()
-{
-	local syscall="$1"; shift
-
-	LC_ALL=C grep -E -x "$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log fanotify_mark '\(-1, FAN_MARK_ADD, FAN_MODIFY\|FAN_ONDIR, AT_FDCWD, "\."\) += -1.*'
+run_prog
+run_strace -efanotify_mark $args
+match_grep
 
 exit 0
diff --git a/tests/getdents.test b/tests/getdents.test
index 5200c0b..5be3e83 100755
--- a/tests/getdents.test
+++ b/tests/getdents.test
@@ -15,29 +15,19 @@
 check_prog touch
 
 dir="$LOG.dir"
+rm -rf -- "$dir"
 mkdir -- "$dir" ||
 	framework_skip_ 'failed to create a directory'
 
 touch -- "$dir/$(for i in $(seq 1 127); do echo A; done; echo Z)" ||
 	framework_skip_ 'failed to create a file'
 
-ls -- "$dir" > /dev/null || {
-	rm -rf -- "$dir"
+ls -- "$dir" > /dev/null ||
 	framework_skip_ 'failed to list a directory'
-}
 
-args='-vegetdents,getdents64'
-$STRACE -o "$LOG" $args ls -- "$dir" > /dev/null
-rc=$?
+run_strace -vegetdents,getdents64 ls -- "$dir" > /dev/null
+match_awk
+
 rm -rf -- "$dir"
-[ $rc -eq 0 ] || {
-	cat "$LOG"
-	fail_ "strace $args failed"
-}
-
-awk -f "$srcdir"/getdents.awk "$LOG" || {
-	cat "$LOG"
-	fail_ "strace $args failed to trace getdents/getdents64 properly"
-}
 
 exit 0
diff --git a/tests/getrandom.test b/tests/getrandom.test
index 9117038..3dd76f2 100755
--- a/tests/getrandom.test
+++ b/tests/getrandom.test
@@ -4,20 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog awk
-
-./getrandom ||
-	framework_skip_ 'getrandom is not available'
-
-args="-e getrandom -xx -s3 ./getrandom"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-awk -f "$srcdir"/getrandom.awk "$LOG" || {
-	cat "$LOG"
-	fail_ 'unexpected output'
-}
+run_prog
+run_strace -e getrandom -xx -s3 $args
+match_awk
 
 exit 0
diff --git a/tests/init.sh b/tests/init.sh
index 418272b..a3ccd1f 100644
--- a/tests/init.sh
+++ b/tests/init.sh
@@ -14,6 +14,150 @@
 		framework_skip_ "$* is not available"
 }
 
+dump_log_and_fail_with()
+{
+	cat < "$LOG"
+	fail_ "$*"
+}
+
+run_prog()
+{
+	if [ $# -eq 0 ]; then
+		set -- "./${ME_%.test}"
+	fi
+	args="$*"
+	"$@" || {
+		if [ $? -eq 77 ]; then
+			skip_ "$args exited with code 77"
+		else
+			fail_ "$args failed"
+		fi
+	}
+}
+
+
+run_prog_skip_if_failed()
+{
+	args="$*"
+	"$@" || framework_skip_ "$args failed"
+}
+
+run_strace()
+{
+	> "$LOG" || fail_ "failed to write $LOG"
+	args="$*"
+	$STRACE -o "$LOG" "$@" ||
+		dump_log_and_fail_with "$STRACE $args failed"
+}
+
+run_strace_merge()
+{
+	rm -f -- "$LOG".[0-9]*
+	run_strace -ff -tt "$@"
+	"$srcdir"/../strace-log-merge "$LOG" > "$LOG" ||
+		dump_log_and_fail_with 'strace-log-merge failed'
+	rm -f -- "$LOG".[0-9]*
+}
+
+# Usage: [FILE_TO_CHECK [AWK_PROGRAM [ERROR_MESSAGE [EXTRA_AWK_OPTIONS...]]]]
+# Check whether all patterns listed in AWK_PROGRAM
+# match FILE_TO_CHECK using egrep.
+# If at least one of these patterns does not match,
+# dump both files and fail with ERROR_MESSAGE.
+match_awk()
+{
+	local output program error awk
+	if [ $# -eq 0 ]; then
+		output="$LOG"
+	else
+		output="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		program="$srcdir/${ME_%.test}.awk"
+	else
+		program="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		error="$STRACE $args output mismatch"
+	else
+		error="$1"; shift
+	fi
+	awk=${AWK:-awk}
+
+	check_prog "$awk"
+
+	"$awk" -f "$program" "$@" < "$output" || {
+		cat < "$output"
+		fail_ "$error"
+	}
+}
+
+# Usage: [FILE_TO_CHECK [FILE_TO_COMPATE_WITH [ERROR_MESSAGE]]]
+# Check whether FILE_TO_CHECK differs from FILE_TO_COMPATE_WITH.
+# If it does, dump the difference and fail with ERROR_MESSAGE.
+match_diff()
+{
+	local output expected error
+	if [ $# -eq 0 ]; then
+		output="$LOG"
+	else
+		output="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		expected="$srcdir/${ME_%.test}.expected"
+	else
+		expected="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		error="$STRACE $args output mismatch"
+	else
+		error="$1"; shift
+	fi
+
+	check_prog diff
+
+	diff -- "$expected" "$output" ||
+		fail_ "$error"
+}
+
+# Usage: [FILE_TO_CHECK [FILE_WITH_PATTERNS [ERROR_MESSAGE]]]
+# Check whether all patterns listed in FILE_WITH_PATTERNS
+# match FILE_TO_CHECK using egrep.
+# If at least one of these patterns does not match,
+# dump both files and fail with ERROR_MESSAGE.
+match_grep()
+{
+	local output patterns error expected matched
+	if [ $# -eq 0 ]; then
+		output="$LOG"
+	else
+		output="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		patterns="$srcdir/${ME_%.test}.expected"
+	else
+		patterns="$1"; shift
+	fi
+	if [ $# -eq 0 ]; then
+		error="$STRACE $args output mismatch"
+	else
+		error="$1"; shift
+	fi
+
+	check_prog wc
+	check_prog grep
+
+	expected=$(wc -l < "$patterns") &&
+	matched=$(LC_ALL=C grep -c -E -x -f "$patterns" < "$output") &&
+	test "$expected" -eq "$matched" || {
+		echo 'Patterns of expected output:'
+		cat < "$patterns"
+		echo 'Actual output:'
+		cat < "$output"
+		fail_ "$error"
+	}
+}
+
 check_prog cat
 check_prog rm
 
diff --git a/tests/ioctl.expected b/tests/ioctl.expected
new file mode 100755
index 0000000..b8e4a29
--- /dev/null
+++ b/tests/ioctl.expected
@@ -0,0 +1,6 @@
+ioctl\(-1, TCGETS, 0x[0-9a-f]+\) += -1 EBADF .*
+ioctl\(-1, MMTIMER_GETRES, 0x[0-9a-f]+\) += -1 EBADF .*
+ioctl\(-1, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x[0-9a-f]+\) += -1 EBADF .*
+ioctl\(-1, HIDIOCGPHYS\(8\), 0x[0-9a-f]+\) += -1 EBADF .*
+ioctl\(-1, EVIOCGBIT\(EV_KEY, 8\), 0x[0-9a-f]+\) += -1 EBADF .*
+ioctl\(-1, _IOC\(_IOC_READ, 0xde, 0xad, 0x08\), 0x[0-9a-f]+\) += -1 EBADF .*
diff --git a/tests/ioctl.test b/tests/ioctl.test
index bdcaa50..8c2a9ba 100755
--- a/tests/ioctl.test
+++ b/tests/ioctl.test
@@ -4,37 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-./ioctl || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'ioctl does not behave as expected'
-	else
-		fail_ 'ioctl failed'
-	fi
-}
-
-args="-e ioctl ./ioctl"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-grep_log()
-{
-	local syscall="$1"; shift
-
-	LC_ALL=C grep -E -x "$syscall$*" "$LOG" > /dev/null || {
-		cat "$LOG"
-		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log ioctl '\(-1, TCGETS, 0x[0-9a-f]+\) += -1 EBADF .*'
-grep_log ioctl '\(-1, MMTIMER_GETRES, 0x[0-9a-f]+\) += -1 EBADF .*'
-grep_log ioctl '\(-1, HIDIOCGRDESCSIZE or HIDIOCGVERSION, 0x[0-9a-f]+\) += -1 EBADF .*'
-grep_log ioctl '\(-1, HIDIOCGPHYS\(8\), 0x[0-9a-f]+\) += -1 EBADF .*'
-grep_log ioctl '\(-1, EVIOCGBIT\(EV_KEY, 8\), 0x[0-9a-f]+\) += -1 EBADF .*'
-grep_log ioctl '\(-1, _IOC\(_IOC_READ, 0xde, 0xad, 0x08\), 0x[0-9a-f]+\) += -1 EBADF .*'
+run_prog
+run_strace -e ioctl $args
+match_grep
 
 exit 0
diff --git a/tests/ipc.sh b/tests/ipc.sh
new file mode 100644
index 0000000..32ef423
--- /dev/null
+++ b/tests/ipc.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# Check decoding of ipc syscalls
+
+. "${srcdir=.}/init.sh"
+
+OUT="$LOG.out"
+
+run_prog > /dev/null
+run_strace -eipc $args > "$OUT"
+match_grep "$LOG" "$OUT"
+
+rm -f "$OUT"
+
+exit 0
diff --git a/tests/ipc_msg.test b/tests/ipc_msg.test
index e0d27ed..177495b 100755
--- a/tests/ipc_msg.test
+++ b/tests/ipc_msg.test
@@ -2,29 +2,4 @@
 
 # Check decoding of ipc msgget/msgctl syscalls
 
-. "${srcdir=.}/init.sh"
-
-check_prog grep
-
-OUT="$LOG.out"
-
-./ipc_msg > /dev/null || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'ipc msgget/msgctl syscalls do not behave as expected'
-	else
-		fail_ 'ipc_msg failed'
-	fi
-}
-
-args="-eipc ./ipc_msg"
-$STRACE -o "$LOG" $args > "$OUT" &&
-exp_lines=$(wc -l < "$OUT") &&
-matched_lines=$(LC_ALL=C grep -c -E -x -f "$OUT" "$LOG") &&
-test $exp_lines -eq $matched_lines || {
-	cat "$OUT" "$LOG"
-	fail_ "$STRACE $args output mismatch"
-}
-
-rm -f "$OUT"
-
-exit 0
+. "${srcdir=.}/ipc.sh"
diff --git a/tests/ipc_sem.test b/tests/ipc_sem.test
index ef957c3..cc93d07 100755
--- a/tests/ipc_sem.test
+++ b/tests/ipc_sem.test
@@ -2,29 +2,4 @@
 
 # Check decoding of ipc semget/semctl syscalls
 
-. "${srcdir=.}/init.sh"
-
-check_prog grep
-
-OUT="$LOG.out"
-
-./ipc_sem > /dev/null || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'ipc semget/semctl syscalls do not behave as expected'
-	else
-		fail_ 'ipc_sem failed'
-	fi
-}
-
-args='-eipc ./ipc_sem'
-$STRACE -o "$LOG" $args > "$OUT" &&
-exp_lines=$(wc -l < "$OUT") &&
-matched_lines=$(LC_ALL=C grep -c -E -x -f "$OUT" "$LOG") &&
-test $exp_lines -eq $matched_lines || {
-	cat "$OUT" "$LOG"
-	fail_ "$STRACE $args output mismatch"
-}
-
-rm -f "$OUT"
-
-exit 0
+. "${srcdir=.}/ipc.sh"
diff --git a/tests/ipc_shm.test b/tests/ipc_shm.test
index de8b47c..a67ea29 100755
--- a/tests/ipc_shm.test
+++ b/tests/ipc_shm.test
@@ -2,29 +2,4 @@
 
 # Check decoding of ipc shmget/shmctl syscalls
 
-. "${srcdir=.}/init.sh"
-
-check_prog grep
-
-OUT="$LOG.out"
-
-./ipc_shm > /dev/null || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'ipc shmget/shmctl syscalls do not behave as expected'
-	else
-		fail_ 'ipc_shm failed'
-	fi
-}
-
-args="-eipc ./ipc_shm"
-$STRACE -o "$LOG" $args > "$OUT" &&
-exp_lines=$(wc -l < "$OUT") &&
-matched_lines=$(LC_ALL=C grep -c -E -x -f "$OUT" "$LOG") &&
-test $exp_lines -eq $matched_lines || {
-	cat "$OUT" "$LOG"
-	fail_ "$STRACE $args output mismatch"
-}
-
-rm -f "$OUT"
-
-exit 0
+. "${srcdir=.}/ipc.sh"
diff --git a/tests/mmsg.test b/tests/mmsg.test
index ad5c659..0237df8 100755
--- a/tests/mmsg.test
+++ b/tests/mmsg.test
@@ -4,28 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-mmsg_expected="${srcdir=.}/mmsg.expected"
-
-check_prog diff
-
-cat "$mmsg_expected" > /dev/null ||
-	fail_ "$mmsg_expected is not available"
-
-./mmsg || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'sendmmsg/recvmmsg syscalls are not available'
-	else
-		fail_ 'mmsg failed'
-	fi
-}
-
-args="-e trace=recvmmsg,sendmmsg -e read=0 -e write=1 -o $LOG ./mmsg"
-$STRACE $args || {
-	cat $LOG
-	fail_ "$STRACE $args failed"
-}
-
-diff "$mmsg_expected" $LOG ||
-	fail_ "$STRACE $args failed to decode mmsghdr properly"
+run_prog
+run_strace -e trace=recvmmsg,sendmmsg -e read=0 -e write=1 $args
+match_diff
 
 exit 0
diff --git a/tests/net-fd.expected b/tests/net-fd.expected
new file mode 100755
index 0000000..49b6992
--- /dev/null
+++ b/tests/net-fd.expected
@@ -0,0 +1,5 @@
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +bind\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-fd-local-stream"\}, 22\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +listen\(0<socket:\[[0-9]+\]>, 5\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +getsockname\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-fd-local-stream"\}, \[22\]\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +accept\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), NULL\}, \[2\]\) += 1<socket:\[[0-9]+\]>
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +connect\(1<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-fd-local-stream"\}, 22\) += 0
diff --git a/tests/net-fd.test b/tests/net-fd.test
index 4c24efd..ddef8fc 100755
--- a/tests/net-fd.test
+++ b/tests/net-fd.test
@@ -8,40 +8,9 @@
 [ -d /proc/self/fd/ ] ||
 	framework_skip_ '/proc/self/fd/ is not available'
 
-check_prog grep
-
-rm -f $LOG.*
-
-addr=net-fd-local-stream
-./net-accept-connect $addr ||
-	fail_ 'net-accept-connect failed'
-
+run_prog ./net-accept-connect net-fd-local-stream
 # using -y to test socket descriptors 'paths' decoding
-args="-tt -ff -y -enetwork ./net-accept-connect $addr"
-$STRACE -o "$LOG" $args ||
-	fail_ "$STRACE $args failed"
-
-"$srcdir"/../strace-log-merge $LOG > $LOG || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-
-rm -f $LOG.*
-
-grep_log()
-{
-	local syscall="$1"; shift
-	local prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
-
-	LC_ALL=C grep -E -x "$prefix$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "strace -enetwork failed to trace \"$syscall\" properly"
-	}
-}
-grep_log bind '\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 22\) += 0'
-grep_log listen '\(0<socket:\[[0-9]+\]>, 5\) += 0'
-grep_log getsockname '\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, \[22\]\) += 0'
-grep_log accept '\(0<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), NULL\}, \[2\]\) += 1<socket:\[[0-9]+\]>'
-grep_log connect '\(1<socket:\[[0-9]+\]>, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 22\) += 0'
+run_strace_merge -y -enetwork $args
+match_grep
 
 exit 0
diff --git a/tests/net-yy.test b/tests/net-yy.test
index 47e3767..2a2c0f7 100755
--- a/tests/net-yy.test
+++ b/tests/net-yy.test
@@ -8,57 +8,22 @@
 [ -d /proc/self/fd/ ] ||
 	framework_skip_ '/proc/self/fd/ is not available'
 
-check_prog awk
 check_prog sed
 
-rm -f $LOG.* $LOG-*
+run_prog ./netlink_inet_diag
+run_prog ./inet-accept-connect-send-recv
+run_strace_merge -yy -eclose,network $args
 
-./inet-accept-connect-send-recv || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'PF_INET SOCK_STREAM (CONFIG_INET_TCP_DIAG) is not available'
-	else
-		fail_ 'inet-accept-connect-send-recv failed'
-	fi
-}
+child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' "$LOG")"
+[ -n "$child" ] ||
+	dump_log_and_fail_with 'failed to find pid of child process'
 
-./netlink_inet_diag || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'NETLINK_INET_DIAG is not available'
-	else
-		fail_ 'netlink_inet_diag failed'
-	fi
-}
+rm -f "$LOG"-*
+sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' "$LOG" > "$LOG"-connect &&
+sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' "$LOG" > "$LOG"-accept ||
+	dump_log_and_fail_with 'failed to separate logs'
 
-args="-tt -ff -yy -o $LOG -eclose,network ./inet-accept-connect-send-recv"
-$STRACE $args ||
-	fail_ "strace $args failed"
-
-"$srcdir"/../strace-log-merge $LOG > $LOG || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-rm -f $LOG.*
-
-child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' $LOG)"
-[ -n "$child" ] || {
-	cat $LOG
-	fail_ 'failed to find pid of child process'
-}
-
-sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-connect &&
-sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-accept || {
-	cat $LOG
-	fail_ 'failed to separate logs'
-}
-
-awk -f "$srcdir"/net-yy-connect.awk $LOG-connect || {
-	cat $LOG-connect
-	fail_ "strace $args failed to decode socket descriptors properly"
-}
-
-awk -f "$srcdir"/net-yy-accept.awk $LOG-accept || {
-	cat $LOG-accept
-	fail_ "strace $args failed to decode socket descriptors properly"
-}
+match_awk "$LOG-connect" "$srcdir"/net-yy-connect.awk "$STRACE $args connect output mismatch"
+match_awk "$LOG-accept" "$srcdir"/net-yy-accept.awk "$STRACE $args accept output mismatch"
 
 exit 0
diff --git a/tests/net.expected b/tests/net.expected
new file mode 100755
index 0000000..af92922
--- /dev/null
+++ b/tests/net.expected
@@ -0,0 +1,7 @@
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +socket\(PF_(LOCAL|UNIX|FILE), SOCK_STREAM, 0\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +socket\(PF_(LOCAL|UNIX|FILE), SOCK_STREAM, 0\) += 1
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +bind\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-local-stream"\}, 19\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +listen\(0, 5\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +getsockname\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-local-stream"\}, \[19\]\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +accept\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), NULL\}, \[2\]\) += 1
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +connect\(1, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="net-local-stream"\}, 19\) += 0
diff --git a/tests/net.test b/tests/net.test
index c007271..cf943ff 100755
--- a/tests/net.test
+++ b/tests/net.test
@@ -4,42 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-rm -f $LOG.*
-
-addr=net-local-stream
-./net-accept-connect $addr ||
-	fail_ 'net-accept-connect failed'
-
-args="-tt -ff -enetwork ./net-accept-connect $addr"
-$STRACE -o "$LOG" $args ||
-	fail_ "$STRACE $args failed"
-
-"$srcdir"/../strace-log-merge $LOG > $LOG || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-
-rm -f $LOG.*
-
-grep_log()
-{
-	local syscall="$1"; shift
-	local prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
-
-	LC_ALL=C grep -E -x "$prefix$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "strace -enetwork failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log socket '\(PF_(LOCAL|UNIX|FILE), SOCK_STREAM, 0\) += 0'
-grep_log socket '\(PF_(LOCAL|UNIX|FILE), SOCK_STREAM, 0\) += 1'
-grep_log bind '\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 19\) += 0'
-grep_log listen '\(0, 5\) += 0'
-grep_log getsockname '\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, \[19\]\) += 0'
-grep_log accept '\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), NULL\}, \[2\]\) += 1'
-grep_log connect '\(1, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 19\) += 0'
+run_prog ./net-accept-connect net-local-stream
+run_strace_merge -enetwork $args
+match_grep
 
 exit 0
diff --git a/tests/pc.test b/tests/pc.test
index a8537a2..022dacc 100755
--- a/tests/pc.test
+++ b/tests/pc.test
@@ -4,18 +4,13 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
+check_prog sed
 
-OUT="$LOG.out"
+run_prog > /dev/null
 
-./pc > /dev/null ||
-	framework_skip_ 'munmap/fork/wait do not behave as expected'
-
-args="-if ./pc"
-$STRACE $args > "$OUT" 2> "$LOG" || {
-	cat "$LOG"
-	fail_ "$STRACE $args does not work"
-}
+args="-if $args"
+$STRACE $args 2> "$LOG" ||
+	dump_log_and_fail_with "$STRACE $args failed"
 
 len="$(sed -n 's/^\[[[:xdigit:]]\+\] write(-1, NULL, \([[:digit:]]\{1,2\}\))[[:space:]]\+= -1 .*/\1/p' "$LOG")" &&
 [ -n "$len" ] &&
@@ -24,24 +19,18 @@
 ip="$(sed -n 's/^\[pid \+'"$pid"'\] \[\([[:xdigit:]]\{'"$len"'\}\)] --- SIGSEGV {.*} ---$/\1/p' "$LOG")" &&
 [ -n "$ip" ] &&
 addr="$(echo "$ip" |sed 's/^0\+//')" &&
-[ -n "$addr" ] || {
-	cat "$OUT" "$LOG"
-	fail_ "$STRACE $args output mismatch"
-}
+[ -n "$addr" ] ||
+	dump_log_and_fail_with
 
-grep_log()
-{
-	LC_ALL=C grep -x -e "$*" < "$LOG" > /dev/null || {
-		cat "$OUT" "$LOG"
-		fail_ "$STRACE $args output mismatch"
-	}
-}
+EXPECTED="$LOG.expected"
+cat > "$EXPECTED" << __EOF__
+\\[[[:xdigit:]]{$len}\\] munmap\\(0x[[:xdigit:]]+, 0\\) += -1 .*
+\\[pid +$pid\\] \\[$ip\\] --- SIGSEGV \\{si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x$addr\\} ---
+\\[pid +$pid\\] \\[\\?{$len}\\] \\+\\+\\+ killed by SIGSEGV( \\(core dumped\\))? \\+\\+\\+
+\\[\\?{$len}\\] \\+\\+\\+ exited with 0 \\+\\+\\+
+__EOF__
 
-grep_log '\[[[:xdigit:]]\{'"$len"'\}\] munmap(0x[[:xdigit:]]\+, 0)[[:space:]]\+= -1 .*'
-grep_log '\[pid \+'"$pid"'\] \['"$ip"'\] --- SIGSEGV {si_signo=SIGSEGV, si_code=SEGV_MAPERR, si_addr=0x'"$addr"'} ---'
-grep_log '\[pid \+'"$pid"'\] \[?\{'"$len"'\}\] +++ killed by SIGSEGV\( (core dumped)\)\? +++'
-grep_log '\[?\{'"$len"'\}\] +++ exited with 0 +++'
-
-rm -f "$OUT"
+match_grep "$LOG" "$EXPECTED"
+rm -f "$EXPECTED"
 
 exit 0
diff --git a/tests/qual_syscall.test b/tests/qual_syscall.test
index 652fcdb..1aff1cc 100755
--- a/tests/qual_syscall.test
+++ b/tests/qual_syscall.test
@@ -5,21 +5,21 @@
 . "${srcdir=.}/init.sh"
 
 check_prog ls
-check_prog grep
+run_strace -e execve ls
 
-$STRACE -e execve ls > /dev/null 2> $LOG &&
-grep '^execve(' $LOG > /dev/null ||
-	{ cat $LOG; fail_ 'strace -e execve does not work'; }
+grep '^execve(' "$LOG" > /dev/null ||
+	dump_log_and_fail_with "$STRACE $args output mismatch"
 
-grep -v '^execve(' $LOG |
+grep -v '^execve(' "$LOG" |
 LC_ALL=C grep '^[[:alnum:]_]*(' > /dev/null &&
-	{ cat $LOG; fail_ 'strace -e execve does not work properly'; }
+	dump_log_and_fail_with "$STRACE $args unexpected output"
 
-$STRACE -e trace=process ls > /dev/null 2> $LOG &&
-grep '^execve(' $LOG > /dev/null ||
-	{ cat $LOG; fail_ 'strace -e trace=process does not work'; }
+run_strace -e trace=process ls
 
-grep '^open' $LOG > /dev/null &&
-	{ cat $LOG; fail_ 'strace -e trace=process does not work properly'; }
+grep '^execve(' "$LOG" > /dev/null ||
+	dump_log_and_fail_with "$STRACE $args output mismatch"
+
+grep '^open' "$LOG" > /dev/null &&
+	dump_log_and_fail_with "$STRACE $args unexpected output"
 
 exit 0
diff --git a/tests/scm_rights-fd.test b/tests/scm_rights-fd.test
index 1974e0d..62e7c0d 100755
--- a/tests/scm_rights-fd.test
+++ b/tests/scm_rights-fd.test
@@ -8,15 +8,13 @@
 [ -d /proc/self/fd/ ] ||
 	framework_skip_ '/proc/self/fd/ is not available'
 
-check_prog grep
 check_prog mkdir
 check_prog rm
 check_prog seq
 check_prog touch
 
-rm -rf -- "$LOG".*
-
 dir="$LOG.dir"
+rm -rf -- "$dir"
 mkdir -- "$dir" ||
 	framework_skip_ 'failed to create a directory'
 
@@ -25,36 +23,23 @@
 touch -- "$file" ||
 	framework_skip_ 'failed to create a file'
 
-./scm_rights /dev/zero ||
-	fail_ 'scm_rights failed'
-
-args="-tt -ff -y -x -enetwork ./scm_rights /dev/zero"
-$STRACE -o "$LOG" $args "$file" ||
-	fail_ "$STRACE $args failed"
-
-"$srcdir"/../strace-log-merge "$LOG" > "$LOG" || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-
-rm -rf -- "$LOG".*
-
-grep_log()
-{
-	local syscall="$1"; shift
-	local prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
-
-	LC_ALL=C grep -E -x "$prefix$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
-	}
-}
+run_prog ./scm_rights /dev/zero
+run_strace_merge -y -x -enetwork $args "$file"
 
 n='[1-9][0-9]*'
 msg='\{msg_name\(0\)=NULL, msg_iov\(1\)=\[\{"\\x00\\x00\\x00\\x00[^"]*", '"$n"'\}\], msg_controllen='"$n"
 rights='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_RIGHTS, \[3</dev/null>, 4</dev/zero>, 5</[^}>]*/(A\\n){127}Z>\]\}'
 creds='\{cmsg_len='"$n"', cmsg_level=SOL_SOCKET, cmsg_type=SCM_CREDENTIALS, \{pid='"$n"', uid=[0-9]+, gid=[0-9]+\}\}'
-grep_log sendmsg '\(1<socket:\[[0-9]+\]>, '"$msg"', \['"$rights"'\], msg_flags=0\}, 0\) += '"$n"
-grep_log recvmsg '\(0<socket:\[[0-9]+\]>, '"$msg"', \['"$creds"', '"$rights"'\], msg_flags=0\}, 0\) += '"$n"
+prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
+EXPECTED="$LOG.expected"
+
+cat > "$EXPECTED" << __EOF__
+${prefix}sendmsg\\(1<socket:\\[[0-9]+\\]>, $msg, \\[$rights\\], msg_flags=0\\}, 0\\) += $n
+${prefix}recvmsg\\(0<socket:\\[[0-9]+\\]>, $msg, \\[$creds, $rights\\], msg_flags=0\\}, 0\\) += $n
+__EOF__
+
+match_grep "$LOG" "$EXPECTED"
+rm -f "$EXPECTED"
+rm -rf -- "$dir"
 
 exit 0
diff --git a/tests/select.test b/tests/select.test
index 5d5fe54..52b9f17 100755
--- a/tests/select.test
+++ b/tests/select.test
@@ -4,26 +4,14 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog awk
-
 syscall=
 $STRACE -epselect6 -h > /dev/null && syscall=$syscall,pselect6
 $STRACE -eselect -h > /dev/null && syscall=$syscall,select
 test -n "$syscall" ||
-	skip_ 'select syscall is not supported on this architecture'
+	fail_ 'neither select not pselect6 syscall is supported on this architecture'
 
-./select ||
-	framework_skip_ 'select syscall does not behave as expected'
-
-args="-e$syscall ./select"
-$STRACE -o "$LOG" $args || {
-	cat "$LOG"
-	fail_ "$STRACE $args failed"
-}
-
-awk -f "$srcdir"/select.awk "$LOG" || {
-	cat "$LOG"
-	fail_ 'unexpected output'
-}
+run_prog
+run_strace -e$syscall $args
+match_awk
 
 exit 0
diff --git a/tests/sigaction.test b/tests/sigaction.test
index 33732e0..fcde3ba 100755
--- a/tests/sigaction.test
+++ b/tests/sigaction.test
@@ -4,16 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog awk
-
-./sigaction ||
-	fail_ 'sigaction failed'
-
-args="-o $LOG -ert_sigaction ./sigaction"
-$STRACE $args ||
-	fail_ "strace $args failed"
-
-awk -f "$srcdir"/sigaction.awk $LOG ||
-	{ cat $LOG; fail_ 'unexpected output'; }
+run_prog
+run_strace -ert_sigaction $args
+match_awk
 
 exit 0
diff --git a/tests/sigreturn.test b/tests/sigreturn.test
index 1e96ede..8cf636a 100755
--- a/tests/sigreturn.test
+++ b/tests/sigreturn.test
@@ -4,28 +4,20 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-./sigreturn ||
-	fail_ 'sigreturn failed'
-
-args='-esignal ./sigreturn'
-$STRACE -o "$LOG" $args ||
-	fail_ "$STRACE $args does not work"
-
-grep_log()
-{
-	LC_ALL=C grep -E -x -e "$*" < "$LOG" > /dev/null || {
-		cat "$LOG"
-		fail_ "$STRACE $args output mismatch"
-	}
-}
+run_prog
+run_strace -esignal $args
 
 mask='\[(USR2 CHLD|CHLD USR2) RT_2 RT_3 RT_4 RT_26 RT_27\]'
 rt_sigprocmask='rt_sigprocmask\(SIG_SETMASK, '"$mask"', NULL, [[:digit:]]+\) += 0'
 osf_sigprocmask='osf_sigprocmask\(SIG_SETMASK, '"$mask"'\) += 0 +\(old mask \[[^]]*\]\)'
-grep_log "$rt_sigprocmask|$osf_sigprocmask"
-grep_log '(rt_)?sigreturn\((\{mask='"$mask"'\})?\) += 0'
+EXPECTED="$LOG.expected"
 
+cat > "$EXPECTED" << __EOF__
+$rt_sigprocmask|$osf_sigprocmask
+(rt_)?sigreturn\\((\\{mask=$mask\\})?\\) += 0
+__EOF__
+
+match_grep "$LOG" "$EXPECTED"
+rm -f "$EXPECTED"
 
 exit 0
diff --git a/tests/stat.test b/tests/stat.test
index ef57396..3e1790a 100755
--- a/tests/stat.test
+++ b/tests/stat.test
@@ -6,74 +6,56 @@
 
 check_prog dd
 check_prog find
-check_prog grep
 
-OUT="$LOG.out"
+EXPECTED="$LOG.expected"
 size=46118400000
 sample=stat_sample
 
 rm -f $sample
 umask 022
 
-truncate_cmd="dd seek=$size bs=1 count=0 if=/dev/null of=$sample"
-$truncate_cmd > "$OUT" 2>&1 || {
-	cat "$OUT"
-	framework_skip_ 'failed to create a large sparse file'
-}
-
-find_cmd="find $sample -quit"
-$find_cmd || framework_skip_ "$find_cmd failed"
-
-find_L_cmd="find -L $sample -quit"
-$find_L_cmd || framework_skip_ "$find_L_cmd failed"
-
-rm -f $sample
-
-$STRACE -o "$LOG" -edesc $truncate_cmd 2>&1 > "$OUT" 2>&1 || {
-	cat "$LOG" "$OUT"
-	fail_ "$STRACE -edesc $truncate_cmd failed"
-}
-
-rm -f "$OUT"
+run_prog_skip_if_failed \
+	dd seek=$size bs=1 count=0 if=/dev/null of=$sample
+run_strace -edesc $args
 
 r_ftruncate="ftruncate(64)?\\(1, $size\\) += 0"
-LC_ALL=C grep -E -x "$r_ftruncate" "$LOG" > /dev/null || {
-	cat "$LOG"
-	fail_ 'strace -edesc failed to trace ftruncate/ftruncate64 properly'
-}
-
 r_lseek="lseek\\(1, $size, SEEK_CUR\\) += $size"
 r_llseek="_llseek\\(1, $size, \\[$size\\], SEEK_CUR\\) += 0"
-LC_ALL=C grep -E -x "$r_lseek|$r_llseek" "$LOG" > /dev/null || {
-	cat "$LOG"
-	fail_ 'strace -edesc failed to trace lseek/_llseek properly'
-}
 
-$STRACE -o "$LOG" -efile $find_L_cmd || {
-	cat "$LOG"
-	fail_ "$STRACE -efile $find_L_cmd failed"
-}
+cat > "$EXPECTED" << __EOF__
+$r_ftruncate
+$r_lseek|$r_llseek
+__EOF__
+
+match_grep "$LOG" "$EXPECTED"
+
+run_prog_skip_if_failed \
+	find -L $sample -quit
+run_strace -efile $args
 
 stat="\\{st_mode=S_IFREG\\|0644, st_size=$size, \\.\\.\\.\\}"
 r_stat="stat(64)?\\(\"$sample\", $stat\\) += 0"
 r_fstatat="(new)?fstatat(64)?\\(AT_FDCWD, \"$sample\", $stat, 0\\) += 0"
-LC_ALL=C grep -E -x "$r_stat|$r_fstatat" "$LOG" > /dev/null || {
-	cat "$LOG"
-	fail_ 'strace -efile failed to trace stat/stat64 properly'
-}
 
-$STRACE -o "$LOG" -efile $find_cmd || {
-	cat "$LOG"
-	fail_ "$STRACE -efile $find_cmd failed"
-}
+cat > "$EXPECTED" << __EOF__
+$r_stat|$r_fstatat
+__EOF__
+
+match_grep "$LOG" "$EXPECTED"
+
+run_prog_skip_if_failed \
+	find $sample -quit
+run_strace -efile $args
 
 r_lstat="lstat(64)?\\(\"$sample\", $stat\\) += 0"
 r_lfstatat="(new)?fstatat(64)?\\(AT_FDCWD, \"$sample\", $stat, AT_SYMLINK_NOFOLLOW\\) += 0"
-LC_ALL=C grep -E -x "$r_lstat|$r_lfstatat" "$LOG" > /dev/null || {
-	cat "$LOG"
-	fail_ 'strace -efile failed to trace fstatat/fstatat64 properly'
-}
 
-rm -f $sample
+cat > "$EXPECTED" << __EOF__
+$r_lstat|$r_lfstatat
+__EOF__
+
+match_grep "$LOG" "$EXPECTED"
+
+rm -f "$EXPECTED" $sample
 
 exit 0
diff --git a/tests/stat32-v.test b/tests/stat32-v.test
index 67eb5ed..46e49f4 100755
--- a/tests/stat32-v.test
+++ b/tests/stat32-v.test
@@ -4,8 +4,9 @@
 
 . "${srcdir=.}/init.sh"
 
+run_prog ./stat32 . > /dev/null
+
 check_prog dd
-check_prog grep
 check_prog touch
 
 OUT="$LOG.out"
@@ -13,32 +14,15 @@
 sample=stat32_sample
 
 umask 022
-truncate_cmd="dd seek=$size bs=1 count=0 if=/dev/null of=$sample"
-$truncate_cmd > "$OUT" 2>&1 || {
-	cat "$OUT"
-	framework_skip_ 'failed to create a large sparse file'
-}
+run_prog_skip_if_failed \
+	dd seek=$size bs=1 count=0 if=/dev/null of=$sample
 
-./stat32 $sample > /dev/null || {
-	if [ $? -eq 77 ]; then
-		rm -f $sample "$OUT"
-		framework_skip_ '32-bit stat syscall is not available'
-	else
-		fail_ 'stat32 failed'
-	fi
-}
-
-touch -t 0102030405 $sample
+run_prog_skip_if_failed \
+	touch -t 0102030405 $sample
 
 for f in $sample . /dev/null; do
-	args="-v -efile ./stat32 $f"
-	$STRACE -o "$LOG" $args > "$OUT" &&
-	exp_lines=$(wc -l < "$OUT") &&
-	matched_lines=$(LC_ALL=C grep -c -E -x -f "$OUT" "$LOG") &&
-	test $exp_lines -eq $matched_lines || {
-		cat "$OUT" "$LOG"
-		fail_ "$STRACE $args output mismatch"
-	}
+	run_strace -v -efile ./stat32 $f > "$OUT"
+	match_grep "$LOG" "$OUT"
 done
 
 rm -f $sample "$OUT"
diff --git a/tests/stat64-v.test b/tests/stat64-v.test
index 785403d..a8122f0 100755
--- a/tests/stat64-v.test
+++ b/tests/stat64-v.test
@@ -4,8 +4,9 @@
 
 . "${srcdir=.}/init.sh"
 
+run_prog ./stat . > /dev/null
+
 check_prog dd
-check_prog grep
 check_prog touch
 
 OUT="$LOG.out"
@@ -13,26 +14,15 @@
 sample=stat64_sample
 
 umask 022
-truncate_cmd="dd seek=$size bs=1 count=0 if=/dev/null of=$sample"
-$truncate_cmd > "$OUT" 2>&1 || {
-	cat "$OUT"
-	framework_skip_ 'failed to create a large sparse file'
-}
+run_prog_skip_if_failed \
+	dd seek=$size bs=1 count=0 if=/dev/null of=$sample
 
-./stat $sample > /dev/null ||
-	fail_ 'stat failed'
-
-touch -d '1970-01-01 -42 seconds' $sample
+run_prog_skip_if_failed \
+	touch -d '1970-01-01 -42 seconds' $sample
 
 for f in $sample . /dev/null; do
-	args="-v -efile ./stat $f"
-	$STRACE -o "$LOG" $args > "$OUT" &&
-	exp_lines=$(wc -l < "$OUT") &&
-	matched_lines=$(LC_ALL=C grep -c -E -x -f "$OUT" "$LOG") &&
-	test $exp_lines -eq $matched_lines || {
-		cat "$OUT" "$LOG"
-		fail_ "$STRACE $args output mismatch"
-	}
+	run_strace -v -efile ./stat $f > "$OUT"
+	match_grep "$LOG" "$OUT"
 done
 
 rm -f $sample "$OUT"
diff --git a/tests/statfs.expected b/tests/statfs.expected
new file mode 100755
index 0000000..93e2b51
--- /dev/null
+++ b/tests/statfs.expected
@@ -0,0 +1 @@
+statfs(64)?\("/proc/self/status"(, [1-9][0-9]*)?, \{f_type="PROC_SUPER_MAGIC", f_bsize=[1-9][0-9]*, f_blocks=[0-9]+, f_bfree=[0-9]+, f_bavail=[0-9]+, f_files=[0-9]+, f_ffree=[0-9]+, f_fsid=\{[0-9]+, [0-9]+\}, f_namelen=[1-9][0-9]*(, f_frsize=[0-9]+)?(, f_flags=[0-9]+)?\}\) += 0
diff --git a/tests/statfs.test b/tests/statfs.test
index 5b8cc97..214d521 100755
--- a/tests/statfs.test
+++ b/tests/statfs.test
@@ -4,31 +4,12 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
 # this test probes /proc/self/status
 [ -f /proc/self/status ] ||
         framework_skip_ '/proc/self/status is not available'
 
-./statfs ||
-	fail_ 'statfs failed'
-
-args="-efile ./statfs"
-$STRACE $args > $LOG 2>&1 || {
-	cat $LOG
-	fail_ "$STRACE $args failed"
-}
-
-grep_log()
-{
-	local syscall="$1"; shift
-
-	LC_ALL=C grep -E -x "$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log 'statfs(64)?' '\("/proc/self/status"(, [1-9][0-9]*)?, \{f_type="PROC_SUPER_MAGIC", f_bsize=[1-9][0-9]*, f_blocks=[0-9]+, f_bfree=[0-9]+, f_bavail=[0-9]+, f_files=[0-9]+, f_ffree=[0-9]+, f_fsid=\{[0-9]+, [0-9]+\}, f_namelen=[1-9][0-9]*(, f_frsize=[0-9]+)?(, f_flags=[0-9]+)?\}\) += 0'
+run_prog
+run_strace -efile $args
+match_grep
 
 exit 0
diff --git a/tests/strace-f.test b/tests/strace-f.test
index 0c4622c..7b5a6c2 100755
--- a/tests/strace-f.test
+++ b/tests/strace-f.test
@@ -6,6 +6,5 @@
 
 time=/usr/bin/time
 check_prog $time
-
-$STRACE -f $time /bin/ls > $LOG 2>&1 ||
-	{ cat $LOG; fail_ 'strace -f does not work'; }
+check_prog ls
+run_strace -f $time ls > /dev/null
diff --git a/tests/strace-k.test b/tests/strace-k.test
index f757fb9..90d56dc 100755
--- a/tests/strace-k.test
+++ b/tests/strace-k.test
@@ -4,6 +4,9 @@
 
 . "${srcdir=.}/init.sh"
 
+$STRACE -h | grep '^-k' > /dev/null ||
+	skip_ 'strace -k is not available'
+
 # strace -k is implemented using /proc/$pid/maps
 [ -f /proc/self/maps ] ||
 	framework_skip_ '/proc/self/maps is not available'
@@ -11,27 +14,17 @@
 check_prog sed
 check_prog tr
 
-./stack-fcall ||
-	fail_ 'stack-fcall failed'
-
-$STRACE -h | grep '^-k' > /dev/null ||
-	skip_ 'strace -k is not available'
-
-args="-e getpid -k ./stack-fcall"
-$STRACE $args > $LOG 2>&1 || {
-	cat $LOG
-	fail_ "$STRACE $args failed"
-}
+run_prog ./stack-fcall
+run_strace -e getpid -k $args
 
 expected='getpid f3 f2 f1 f0 main '
-result=$(sed -n '1,/(main+0x[a-f0-9]\+) .*/ s/^.*(\([^+]\+\)+0x[a-f0-9]\+) .*/\1/p' $LOG |
+result=$(sed -n '1,/(main+0x[a-f0-9]\+) .*/ s/^.*(\([^+]\+\)+0x[a-f0-9]\+) .*/\1/p' "$LOG" |
 	tr '\n' ' ')
 
 test "$result" = "$expected" || {
-	cat $LOG
 	echo "expected: \"$expected\""
 	echo "result: \"$result\""
-	fail_ "unexpected output from $STRACE $args"
+	dump_log_and_fail_with "$STRACE $args output mismatch"
 }
 
 exit 0
diff --git a/tests/sun_path.expected b/tests/sun_path.expected
new file mode 100755
index 0000000..4407686
--- /dev/null
+++ b/tests/sun_path.expected
@@ -0,0 +1,3 @@
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +bind\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"\}, 110\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +getsockname\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"\}, \[111\]\) += 0
+[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +connect\(1, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678"\}, 110\) += 0
diff --git a/tests/sun_path.test b/tests/sun_path.test
index 6ae67f4..728328a 100755
--- a/tests/sun_path.test
+++ b/tests/sun_path.test
@@ -4,38 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-rm -f $LOG.*
-
-addr=123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
-./net-accept-connect $addr ||
-	fail_ 'net-accept-connect failed'
-
-args="-tt -ff -ebind,connect,getsockname ./net-accept-connect $addr"
-$STRACE -o "$LOG" $args ||
-	fail_ "$STRACE $args failed"
-
-"$srcdir"/../strace-log-merge $LOG > $LOG || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-
-rm -f $LOG.*
-
-grep_log()
-{
-	local syscall="$1"; shift
-	local prefix='[1-9][0-9]* +[0-9]+:[0-9]+:[0-9]+\.[0-9]+ +'
-
-	LC_ALL=C grep -E -x "$prefix$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "strace -enetwork failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log bind '\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 110\) += 0'
-grep_log getsockname '\(0, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, \[111\]\) += 0'
-grep_log connect '\(1, \{sa_family=AF_(LOCAL|UNIX|FILE), sun_path="'$addr'"\}, 110\) += 0'
+run_prog ./net-accept-connect 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678
+run_strace_merge -ebind,connect,getsockname $args
+match_grep
 
 exit 0
diff --git a/tests/uid.test b/tests/uid.test
index d8b0261..7bbcca7 100755
--- a/tests/uid.test
+++ b/tests/uid.test
@@ -4,29 +4,15 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog gawk
-
 s="${uid_syscall_suffix-}"
 w="${uid_t_size-}"
-uid="uid$s$w"
-./"$uid" || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ "some uid$s or uid${w}_t syscalls are not available"
-	else
-		fail_ "$uid failed"
-	fi
-}
+
+run_prog ./uid$s$w
 
 syscalls="getuid$s,setuid$s,getresuid$s,setreuid$s,setresuid$s,fchown$s,getgroups$s"
-args="-e trace=$syscalls"
-$STRACE -o "$LOG" $args ./"$uid"|| {
-	cat "$LOG"
-	fail_ "$STRACE $args ./$uid failed"
-}
+run_strace -e trace="$syscalls" $args
 
-gawk -f "$srcdir"/uid.awk -v suffix="$s" "$LOG" || {
-	cat "$LOG"
-	fail_ 'unexpected output'
-}
+AWK=gawk
+match_awk "$LOG" "$srcdir"/uid.awk "$STRACE $args output mismatch" -v suffix="$s"
 
 exit 0
diff --git a/tests/uio.expected b/tests/uio.expected
new file mode 100755
index 0000000..999b88c
--- /dev/null
+++ b/tests/uio.expected
@@ -0,0 +1,4 @@
+pread(64)?\(3, "\\0\\0\\0\\0", 4, 1004211379570065135\) += 4
+preadv\(3, \[{"\\0\\0\\0\\0", 4}\], 1, 1004211379570065135\) += 4
+pwrite(64)?\(3, "\\0\\0\\0\\0", 4, 1004211379570065135\) += 4
+pwritev\(3, \[{"\\0\\0\\0\\0", 4}\], 1, 1004211379570065135\) += 4
diff --git a/tests/uio.test b/tests/uio.test
index 0e8b315..020b97e 100755
--- a/tests/uio.test
+++ b/tests/uio.test
@@ -4,35 +4,8 @@
 
 . "${srcdir=.}/init.sh"
 
-check_prog grep
-
-./uio || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'preadv/pwritev syscalls are not available'
-	else
-		fail_ 'uio failed'
-	fi
-}
-
-args="-edesc ./uio"
-$STRACE $args > $LOG 2>&1 || {
-	cat $LOG
-	fail_ "$STRACE $args failed"
-}
-
-grep_log()
-{
-	local syscall="$1"; shift
-
-	LC_ALL=C grep -E -x "$syscall$*" $LOG > /dev/null || {
-		cat $LOG
-		fail_ "$STRACE $args failed to trace \"$syscall\" properly"
-	}
-}
-
-grep_log 'pread(64)?' '\(3, "\\0\\0\\0\\0", 4, 1004211379570065135\) += 4'
-grep_log 'preadv' '\(3, \[{"\\0\\0\\0\\0", 4}\], 1, 1004211379570065135\) += 4'
-grep_log 'pwrite(64)?' '\(3, "\\0\\0\\0\\0", 4, 1004211379570065135\) += 4'
-grep_log 'pwritev' '\(3, \[{"\\0\\0\\0\\0", 4}\], 1, 1004211379570065135\) += 4'
+run_prog
+run_strace -edesc $args
+match_grep
 
 exit 0
diff --git a/tests/unix-yy.test b/tests/unix-yy.test
index 1845f55..640b477 100755
--- a/tests/unix-yy.test
+++ b/tests/unix-yy.test
@@ -9,53 +9,23 @@
 [ -d /proc/self/fd/ ] ||
 	framework_skip_ '/proc/self/fd/ is not available'
 
-check_prog awk
 check_prog sed
 
-rm -f $LOG.* $LOG-*
-
+run_prog ./netlink_unix_diag
 addr=unix-yy-local-stream
-./net-accept-connect $addr ||
-	fail_ 'net-accept-connect failed'
+run_prog ./net-accept-connect $addr
+run_strace_merge -yy -eclose,network $args
 
-./netlink_unix_diag || {
-	if [ $? -eq 77 ]; then
-		framework_skip_ 'NETLINK_SOCK_DIAG for unix domain sockets (CONFIG_UNIX_DIAG) is not available'
-	else
-		fail_ 'netlink_unix_diag failed'
-	fi
-}
+child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' "$LOG")"
+[ -n "$child" ] ||
+	dump_log_and_fail_with 'failed to find pid of child process'
 
-args="-tt -ff -yy -eclose,network ./net-accept-connect $addr"
-$STRACE -o "$LOG" $args ||
-	fail_ "$STRACE $args failed"
+rm -f "$LOG"-*
+sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' "$LOG" > "$LOG"-connect &&
+sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' "$LOG" > "$LOG"-accept ||
+	dump_log_and_fail_with 'failed to separate logs'
 
-"$srcdir"/../strace-log-merge $LOG > $LOG || {
-	cat $LOG
-	fail_ 'strace-log-merge failed'
-}
-rm -f $LOG.*
-
-child="$(sed -rn '/SIGCHLD/ s/^.*, si_pid=([1-9][0-9]*), .*/\1/p' $LOG)"
-[ -n "$child" ] || {
-	cat $LOG
-	fail_ 'failed to find pid of child process'
-}
-
-sed -rn "/^$child"' /!d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-connect &&
-sed -rn "/^$child"' /d; /SIGCHLD/d; / socket\(/,$ s/^[0-9]+ +[^ ]+ (.+)/\1/p' $LOG > $LOG-accept || {
-	cat $LOG
-	fail_ 'failed to separate logs'
-}
-
-awk -f "$srcdir"/unix-yy-connect.awk -v addr=$addr $LOG-connect || {
-	cat $LOG-connect
-	fail_ "strace $args failed to decode socket descriptors properly"
-}
-
-awk -f "$srcdir"/unix-yy-accept.awk -v addr=$addr $LOG-accept || {
-	cat $LOG-accept
-	fail_ "strace $args failed to decode socket descriptors properly"
-}
+match_awk "$LOG-connect" "$srcdir"/unix-yy-connect.awk "$STRACE $args connect output mismatch" -v addr=$addr
+match_awk "$LOG-accept" "$srcdir"/unix-yy-accept.awk "$STRACE $args accept output mismatch" -v addr=$addr
 
 exit 0