#!/bin/bash

set -eu
. /opt/fox_utils/crab_sys.sh

### --help Info:
### --help Usage: autotest [tag1][tag2] [--failstop] [--cover]
### --help Example:
[ "${1:-}" = "--help" ] && sys::usage "$@"

sys::arg_parse "$@"
declare DIRS ALL_TESTS_DIR ALL_FILES
SHORT_NAME="${0##*/}"
DIR="$(readlink -f ${0%/*})"
echo "start test in $DIR"
cd "$DIR"
if pidof -csxo %PPID "${0##*/}"; then
	echo "Already running" >&2
	exit 255
fi
if [ -x ./autotest_enabled ] \
	&& ! ./autotest_enabled; then
	echo "LOG_ERROR ./autotest_enabled not enabled"
	exit 255
fi
find_allfiles(){
	find . -type f \( \
		! -path '*/.git/*' -a ! -name '*.o' \
		-a ! -path '*/tests/*' -a ! -path '*/TODO*/*' \
		-a ! -path '*/man/*' -a ! -path '*/m4/*'\
		-a ! -path '*/doc/*' -a ! -path '*/po/*' \
		-a ! -path '*/todo*/*' -a ! -path '*/autotest*' \
		-a ! -path '*/build-aux/*' -a ! -path '*/.deps/*' \
		-a ! -path '*/examples/*' -a ! -path '*/docs/*' \
		-a ! -path '*/Documentation/*' -a ! -path '*/test/*'\
		\
		-a ! -name '.git*e' -a ! -name 'TODO*' -a ! -name 'README*' \
		-a ! -name '*.o.cmd' -a ! -name '*.ko.unsigned' -a ! -name 'Makefile*' \
		-a ! -name 'modules.order' -a ! -name 'MAKE*' \
		-a ! -name 'LICENSE*' -a ! -name 'AUTHORS*' -a ! -name 'configure*' \
		-a ! -name 'aclocal*' -a ! -name 'bootstrap*' -a ! -name 'configure*' \
		-a ! -name 'THANKS*' -a ! -name 'NEWS*' -a ! -name 'INSTALL' \
		-a ! -name 'ChangeLog*' -a ! -name 'COPYING*' -a ! -name 'GNUmakefile' \
		-a ! -name '*.diff' -a ! -name '.*' -a ! -name '*.mk' -a ! -name 'ABOUT*' \
		-a ! -name '*.out*' -a ! -name '*.gperf' ! -name '*.sin' -a !  -name '*.y' \
		-a ! -name '*.lo' -a ! -name '*.a' ! -name '*.lai' -a !  -name '*.am' \
		-a ! -name '*.log' -a ! -name '*.Plo' ! -name '*.la' -a !  -name '*.Kbuild' \
		-a ! -name 'Module.symvers' -a ! -name 'Kconfig' ! -name 'config.status' \
		-a ! -name '*.pc.in' -a ! -name '*.pc' ! -name '*.map' -a !  -name '*.la' \
		-a ! -name 'UPGRADE*' -a ! -name 'Kbuild' -a ! -name '*.mod'  -a ! -name 'libtool' \
		-a ! -name 'Kconfig.*' -a ! -name '*.in' -a ! -name 'CHANGES*' -a ! -name 'config.sub' \
		-a ! -name '*.test' -a ! -name '*.spec' -a ! -name 'config.guess' -a ! -name 'Doxyfile' \
		-a ! -name '*.mak' -a ! -name 'depcomp' -a ! -name 'LGPL-2.1' -a ! -name 'GPL-2.0' \
		-a ! -name '*.m4' -a ! -name '*.obj' -a ! -name '*.S' -a ! -name 'modules.builtin' \
		-a ! -name 'CHANGELOG' -a ! -path '*/.idea/*' -a ! -name 'NOTICE*' \) \
		| cut -f2- -d '.' >/tmp/autotest_allfiles.$$
	echo none >>/tmp/autotest_allfiles.$$
	ALL_FILES=$(cat /tmp/autotest_allfiles.$$ | wc -l)
	return 0
}
parse_test_files(){
	local tst tests
	ALL_TESTS_DIR=''
	DIRS=$( echo ./tests ./*/tests ./*/*/tests )
	for tst in $DIRS; do
		[ ! -x "$tst/test" ] && continue
		[[ "$tst" == *"TODO"* ]] && continue
		ALL_TESTS_DIR="$ALL_TESTS_DIR $tst"
	done
	for tests in $ALL_TESTS_DIR; do
		if ! grep -h -r "^### COVER_FILE" "$tests"; then
			echo "LOG_WARNING in $tests not found macro ### COVER_FILE [ FAIL ]" >&2
		fi
	done > /tmp/autotest_cover_files.$$
	return 0
}
check_cover(){
	local f
	COVER_ERROR=0
	while read -r f; do
		echo -n "### COVER_FILE $f - "
		if grep -qw "$f" /tmp/autotest_cover_files.$$; then
			echo "[ OK ]"
		else
			echo "[ FAIL ] - not cover"
			COVER_ERROR=$((COVER_ERROR+1))
		fi
	done < /tmp/autotest_allfiles.$$
	return 0
}
check_cover_trash(){
	local f
	while read -r f; do
		f="${f#*### COVER_FILE }"
		f="${f%% *}"
		if grep -qw "$f" /tmp/autotest_allfiles.$$; then
			# echo -n "### COVERED_FILE EXISTS $f - "
			# echo "[ OK ]"
			:
		else
			echo -n "### COVERED_FILE_EXISTS $f - "
			echo "[ FAIL ] - covered file not exists"
			COVER_ERROR=$((COVER_ERROR+1))
		fi
	done < /tmp/autotest_cover_files.$$
	return 0
}

do_test(){
	local d
	>/tmp/autotest.$$
	tail -qF --pid=$$ /tmp/autotest.$$ 2>/dev/null &
	for d in $DIRS; do
		[[ "$d" == *"TODO"* ]] && continue
		[ ! -x "$d/test" ] && continue
		echo "Report test: ########## Start $d/test"
		if ! $d/test "$@"; then
			TEST_ERROR=$((TEST_ERROR+1))
		fi
		[ "$TEST_ERROR" != 0 -a "${ARG_FAILSTOP:-}" = TRUE ] && exit $TEST_ERROR
	done >>/tmp/autotest.$$
	return 0
}
do_report(){
	echo
	echo "################# REPORT AUTOTEST ######################"
	if [ -s /tmp/autotest.$$ ]; then
		cat /tmp/autotest.$$ | grep 'Report test:' || true
		TEST_ERROR=$(cat /tmp/autotest.$$ | grep 'Report test:' | grep FAILED | wc -l )
	fi
	echo "ALL_FILES=$ALL_FILES COVER_ERROR=$COVER_ERROR(have not test)"
	echo "TEST_ERROR=$TEST_ERROR"
	echo "################# END REPORT ###########################"
	return 0
}

find_allfiles
parse_test_files
check_cover
check_cover_trash
rm -f /tmp/autotest_cover_files.$$
rm -f /tmp/autotest_allfiles.$$
TEST_ERROR=0
[ "${ARG_COVER:-}" != TRUE ] && do_test
do_report
rm -f /tmp/autotest.$$
[ "$COVER_ERROR" != 0 ] && exit 2
[ "$TEST_ERROR" != 0 ] && exit 1
exit 0
