#!/usr/bin/env bash

PROGNAME="${BASH_SOURCE[0]}"
HERE="$(cd "$(dirname "$PROGNAME")" &>/dev/null && pwd)"
ROOT=$(cd $HERE/.. && pwd)
RED=$'\033[0;31m'
LIGHTRED=$'\033[1;31m'
NOCOLOR=$'\033[0m'

cd $HERE

#----------------------------------------------------------------------------------------------

valgrind_check() {
	echo -n "${NOCOLOR}"
	if grep -l "$1" $logdir/*.valgrind.log &> /dev/null; then
		echo
		echo "${LIGHTRED}### Valgrind: ${TYPE} detected:${RED}"
		grep -l "$1" $logdir/*.valgrind.log
		echo -n "${NOCOLOR}"
		E=1
	fi
}

valgrind_summary() {
	local logdir="$ROOT/tests/$DIR/logs"

	local leaks_head=0
	for file in $(ls $logdir/*.valgrind.log 2>/dev/null); do
		# If the last "definitely lost: " line of a logfile has a nonzero value, print the file name
		if tac "$file" | grep -a -m 1 "definitely lost: " | grep "definitely lost: [1-9][0-9,]* bytes" &> /dev/null; then
			if [[ $leaks_head == 0 ]]; then
				echo
				echo "${LIGHTRED}### Valgrind: leaks detected:${RED}"
				leaks_head=1
			fi
			echo "$file"
			E=1
		fi
	done

	TYPE="invalid reads" valgrind_check "Invalid read"
	TYPE="invalid writes" valgrind_check "Invalid write"
}

#----------------------------------------------------------------------------------------------

sanitizer_check() {
	if grep -l "$1" $logdir/*.asan.log* &> /dev/null; then
		echo
		echo "${LIGHTRED}### Sanitizer: ${TYPE} detected:${RED}"
		grep -l "$1" $logdir/*.asan.log*
		echo "${NOCOLOR}"
		E=1
	fi
}

sanitizer_summary() {
	local logdir="$ROOT/tests/$DIR/logs"
	# Every leak report opens with "ERROR: LeakSanitizer", whether the leaks are
	# direct or only indirect — one grep covers both.
	TYPE="leaks" sanitizer_check "ERROR: LeakSanitizer"
	# Every ASan report opens with an "ERROR: AddressSanitizer" header line,
	# whatever the report type — matching that catches all of them
	# (heap-buffer-overflow, use-after-free, SEGV, ...) instead of a per-type
	# whitelist that goes stale.
	TYPE="memory errors" sanitizer_check "ERROR: AddressSanitizer"
	TYPE="signal 11" sanitizer_check "caught signal 11"
}

# RLTest has the sanitizer write each process's reports to its own log instead of
# stdout/stderr, so a report does not fail the test that triggered it. Startup
# leaks are suppressed and the tests with known leaks skip themselves, so any
# report is unexpected, whatever its kind, including one cut short because the
# process was killed while writing it.
sanitizer_flow_summary() {
	local logdir="$ROOT/tests/$DIR/logs"
	local logs
	logs=$(find "$logdir" -name '*.asan.log*' -type f -size +0 2> /dev/null | sort)
	if [[ -n $logs ]]; then
		echo
		echo "${LIGHTRED}### Sanitizer: reports detected:${RED}"
		for log in $logs; do
			echo "$log"
			head -n 100 "$log"
		done
		echo "${NOCOLOR}"
		E=1
	fi
}

#----------------------------------------------------------------------------------------------

E=0

DIRS=
if [[ $UNIT == 1 ]]; then
	DIRS+=" ."
fi
if [[ $FLOW == 1 ]]; then
	DIRS+=" pytests"
fi

if [[ $VG == 1 ]]; then
	for dir in $DIRS; do
		DIR="$dir" valgrind_summary
	done
elif [[ -n $SAN ]]; then
	for dir in $DIRS; do
		if [[ $dir == pytests ]]; then
			DIR="$dir" sanitizer_flow_summary
		else
			DIR="$dir" sanitizer_summary
		fi
	done
fi

if [[ $E == 0 ]]; then
	echo "# No leaks detected"
fi

exit $E
