#!/bin/bash
# NOTICE: this file was generated by https://github.com/khimaros/enc using the following invocation: ./enc test.en -o test.sh --context-files Makefile

set -e
set -o pipefail

# to update/test, the "tests" make target should be built (make -B)
TARGETS=("tests")
# goldens are stored in ./testdata/goldens/
GOLDEN_DIR="./testdata/goldens"
# temporary output for comparison is stored in ./testdata/output/
OUTPUT_DIR="./testdata/output"

# the test runner produces very detailed logging to stderr
log() {
	echo "test: $@" >&2
}

# usage: test <update|test|help>
usage() {
	echo "usage: $0 <update|test|help>" >&2
	exit 1
}

# the name of the golden output files should have "/" in target names replaced with "-"
target_to_filename() {
	echo "$1" | sed 's/\//-/g'
}

# output of the `make` command (lines beginning with `make: ` or `make[`) will be filtered out.
run_target() {
	local target="$1"
	log "building target: $target"
	make -B "$target" 2>&1 | grep -vE '^(make: |make\[)'
}

# all integers and floating point numbers are discarded when comparing to goldens
sanitize() {
	# this regex removes integers (e.g., 467) and floats (e.g., 0.001600)
	sed -E 's/[0-9]+\.?[0-9]*//g' "$1"
}

# on test, the same results are computed and compared to the goldens
compare_files() {
	local golden_path="$1"
	local output_path="$2"
	local target_name="$3"

	log "comparing $golden_path with $output_path"
	local sanitized_golden
	sanitized_golden=$(mktemp)
	local sanitized_output
	sanitized_output=$(mktemp)
	trap 'rm -f "$sanitized_golden" "$sanitized_output"' RETURN

	sanitize "$golden_path" >"$sanitized_golden"
	sanitize "$output_path" >"$sanitized_output"

	if diff -q "$sanitized_golden" "$sanitized_output" >/dev/null 2>&1; then
		log "PASS: $target_name"
		return 0
	else
		log "FAIL: $target_name"
		log "diff (ignoring numbers) follows:"
		diff -u "$golden_path" "$output_path" >&2 || true
		return 1
	fi
}

# on update the result of the build including all shell history is saved to goldens
run_update() {
	log "mode: update"
	# any directories needed to store the output are created before hand
	mkdir -p "$GOLDEN_DIR"
	for target in "${TARGETS[@]}"; do
		local filename
		filename=$(target_to_filename "$target")
		local golden_path="$GOLDEN_DIR/$filename.golden"
		log "updating golden for '$target' -> '$golden_path'"
		run_target "$target" >"$golden_path"
	done
	log "update complete"
}

# on test, the same results are computed and compared to the goldens
run_test() {
	log "mode: test"
	# any directories needed to store the output are created before hand
	mkdir -p "$OUTPUT_DIR"
	local failed_tests=0

	for target in "${TARGETS[@]}"; do
		local filename
		filename=$(target_to_filename "$target")
		local golden_path="$GOLDEN_DIR/$filename.golden"
		local output_path="$OUTPUT_DIR/$filename.output"

		if [ ! -f "$golden_path" ]; then
			log "FAIL: '$target' - golden file not found at '$golden_path'"
			failed_tests=$((failed_tests + 1))
			continue
		fi

		log "generating output for '$target' -> '$output_path'"
		run_target "$target" >"$output_path"

		if ! compare_files "$golden_path" "$output_path" "$target"; then
			failed_tests=$((failed_tests + 1))
		fi
	done

	if [ "$failed_tests" -eq 0 ]; then
		log "all tests passed"
		exit 0
	else
		log "$failed_tests test(s) failed"
		exit 1
	fi
}

main() {
	if [ "$#" -ne 1 ]; then
		usage
	fi

	case "$1" in
	update)
		run_update
		;;
	test)
		run_test
		;;
	help)
		usage
		;;
	*)
		log "error: unknown command '$1'"
		usage
		;;
	esac
}

main "$@"
