#!/bin/bash
#
# Runs every test_api_* binary in one go and prints a summary.
#
# The api tests are separate binaries because their gtest suite names overlap
# across files, so they cannot be linked into a single binary. This wrapper
# gives the "run everything" behaviour without that constraint.
#
# Usage:
#   libsessiond-test [options] [name ...]
#
#   name          run only the listed tests; a bare name is matched against
#                 test_api_<name> as well, so `switchprofile` works
#   -a, --account only the account-category tests
#   -p, --profile only the profile-category tests
#   -k, --skip-wait
#                 skip the tests that need subsession_event_wait_done(), which
#                 fails with NOT_SUPPORTED unless the platform feature
#                 http://tizen.org/feature/subsession is present
#   -x, --exclude PATTERN
#                 skip tests whose name matches PATTERN (repeatable)
#   -f, --gtest-filter FILTER
#                 passed through to each binary as --gtest_filter
#   -o, --output DIR
#                 also write per-test logs and gtest xml into DIR
#   -l, --list    list what would run and exit
#   -h, --help    this text
#
# Exit status is the number of failed tests, capped at 125.

set -u

readonly BINDIR="$(dirname "$(readlink -f "$0")")"

# Tests that call subsession_event_wait_done(). libsessiond gates that call on
# the subsession platform feature, so without it they fail for reasons that
# have nothing to do with the code under test.
readonly WAIT_TESTS=(
	test_api_adduserwait
	test_api_addprofilewait
	test_api_removeuserwait
	test_api_removeprofilewait
	test_api_switch_user_wait
	test_api_switch_profile_wait
	test_api_switch_user_completion
	test_api_switch_profile_completion
)

only_account=
only_profile=
skip_wait=
list_only=
gtest_filter=
outdir=
excludes=()
wanted=()

usage() { sed -n '2,/^$/p' "$0" | sed 's/^# \{0,1\}//'; }

while [ $# -gt 0 ]; do
	case "$1" in
	-a|--account)      only_account=1; shift;;
	-p|--profile)      only_profile=1; shift;;
	-k|--skip-wait)    skip_wait=1; shift;;
	-l|--list)         list_only=1; shift;;
	-x|--exclude)      excludes+=("$2"); shift 2;;
	-f|--gtest-filter) gtest_filter="$2"; shift 2;;
	-o|--output)       outdir="$2"; shift 2;;
	-h|--help)         usage; exit 0;;
	-*)                echo "unknown option: $1" >&2; usage >&2; exit 64;;
	*)                 wanted+=("$1"); shift;;
	esac
done

is_wait_test() {
	local t
	for t in "${WAIT_TESTS[@]}"; do
		[ "$t" = "$1" ] && return 0
	done
	return 1
}

feature_present() {
	# system-info-tool is not on every image; treat "cannot tell" as present so
	# we do not silently skip tests on a machine that would have run them.
	command -v system-info-tool >/dev/null 2>&1 || return 0

	local out
	out="$(system-info-tool -g tizen.org/feature/subsession 2>&1)"

	# Two ways to not have it: the key is absent, or it is present and false.
	echo "$out" | grep -qi "not found" && return 1
	echo "$out" | grep -qiE "value[[:space:]]*=[[:space:]]*(0|false)" && return 1
	return 0
}

# Collect the binaries. Explicitly named tests win over the category filters.
tests=()
if [ ${#wanted[@]} -gt 0 ]; then
	for name in "${wanted[@]}"; do
		if [ -x "$BINDIR/$name" ]; then
			tests+=("$name")
		elif [ -x "$BINDIR/test_api_$name" ]; then
			tests+=("test_api_$name")
		else
			echo "no such test: $name" >&2
			exit 66
		fi
	done
else
	for path in "$BINDIR"/test_api_*; do
		[ -x "$path" ] || continue
		name="$(basename "$path")"
		[ "$name" = "$(basename "$0")" ] && continue

		[ -n "$only_account" ] && [[ "$name" == *profile* ]] && continue
		[ -n "$only_profile" ] && [[ "$name" != *profile* && "$name" != *mixed* ]] && continue
		[ -n "$skip_wait" ] && is_wait_test "$name" && continue

		skip=
		for pat in ${excludes[@]+"${excludes[@]}"}; do
			[[ "$name" == *$pat* ]] && skip=1 && break
		done
		[ -n "$skip" ] && continue

		tests+=("$name")
	done
fi

if [ ${#tests[@]} -eq 0 ]; then
	echo "nothing to run" >&2
	exit 65
fi

if [ -n "$list_only" ]; then
	printf '%s\n' "${tests[@]}"
	exit 0
fi

if ! feature_present; then
	echo "WARNING: http://tizen.org/feature/subsession is not registered on this image."
	echo "         subsession_event_wait_done() returns NOT_SUPPORTED, so the wait and"
	echo "         completion tests will fail regardless of the code under test."
	echo "         Re-run with --skip-wait to leave them out."
	echo
fi

[ -n "$outdir" ] && mkdir -p "$outdir"

passed=()
failed=()
started=$(date +%s)

for name in "${tests[@]}"; do
	printf '=== %s\n' "$name"

	args=()
	[ -n "$gtest_filter" ] && args+=("--gtest_filter=$gtest_filter")
	[ -n "$outdir" ] && args+=("--gtest_output=xml:$outdir/$name.xml")

	if [ -n "$outdir" ]; then
		"$BINDIR/$name" ${args[@]+"${args[@]}"} 2>&1 | tee "$outdir/$name.log"
		rc=${PIPESTATUS[0]}
	else
		"$BINDIR/$name" ${args[@]+"${args[@]}"}
		rc=$?
	fi

	if [ "$rc" -eq 0 ]; then
		passed+=("$name")
	else
		failed+=("$name (rc=$rc)")
	fi
	echo
done

elapsed=$(( $(date +%s) - started ))

echo "==================== summary ===================="
printf 'ran %d test(s) in %ds\n' "${#tests[@]}" "$elapsed"
printf 'passed: %d\n' "${#passed[@]}"
printf 'failed: %d\n' "${#failed[@]}"
for f in ${failed[@]+"${failed[@]}"}; do
	printf '  %s\n' "$f"
done
[ -n "$outdir" ] && printf 'logs: %s\n' "$outdir"

[ ${#failed[@]} -gt 125 ] && exit 125
exit ${#failed[@]}
