TEST_DIRS := $(patsubst %/,%,$(wildcard */))

# Check root directory set
$(if $(ROOT),,$(error "Please run make from root directory!"))
# Get the OCaml path
$(if $(OCAML_PATH),,$(error "Cannot find OCaml path!"))

TEST_ROOT := $(shell pwd)

# Get the depth of the root path
ROOTPATH_DEPTH := $(words $(subst /, ,$(subst  ,,$(TEST_ROOT))))

CMD := $(ROOT)/$(MAIN_EXE)

.PHONY: all clean $(TEST_DIRS) process_test process_unit

all: $(TEST_DIRS)

$(TEST_DIRS):
	@TEST="$@" $(MAKE) --no-print-directory process_test

process_test:
	@echo "Processing $$TEST"
	@UNITS=$$(ls -d "$$TEST"/*/ | sort); \
	for UNIT in $$UNITS; do \
		UNIT=$${UNIT%/}; UNIT=$${UNIT##*/}; \
		echo -n "\tTest $$UNIT: "; \
		TEST_DIR="$$TEST/$$UNIT" $(MAKE) --no-print-directory process_unit; \
	done

remove_artifacts:
	@rm -f $(TEST_DIR)/*.patch
	@rm -f $(TEST_DIR)/*.log
	@rm -f $(TEST_DIR)/*.err

process_unit: remove_artifacts
	@BUILD_OUTPUT=$$($(MAKE) -C "$$TEST_DIR" --no-print-directory 2>&1); \
	EXIT_CODE=$$?; \
	if [ ! $$EXIT_CODE -eq 0 ]; then \
		echo "$$BUILD_OUTPUT" > "$$TEST_DIR/test.err"; \
		echo "Test build failed (exit code $$EXIT_CODE)"; \
	else \
		OCAML_INCLUDES=""; \
		if [ -r "$$TEST_DIR/ocaml-include" ]; then \
			while read INCLUDE || [ -n "$$INCLUDE" ] ; do \
				OCAML_INCLUDES="$$OCAML_INCLUDES -I \"$(OCAML_PATH)/$$INCLUDE\""; \
			done < "$$TEST_DIR/ocaml-include"; \
		fi; \
		PARAMS=""; if [ -r "$$TEST_DIR/params" ]; then PARAMS=$$(cat "$$TEST_DIR/params"); fi; \
		CMD_OUTPUT=$$("$(CMD)" -I "$$TEST_DIR" $$OCAML_INCLUDES -log-file="$$TEST_DIR/test.log" -d "$$TEST_DIR" -r $$TEST $$PARAMS 2>&1); \
		EXIT_CODE=$$?; \
		$(MAKE) -C "$$TEST_DIR" test-exit-code.$$EXIT_CODE >/dev/null 2>&1; \
		if [ ! $$? -eq 0 ]; then \
			if [ -n "$$CMD_OUTPUT" ]; then echo $$CMD_OUTPUT > "$$TEST_DIR/test.err"; fi; \
			echo "failed (tool returned unexpected exit code $$EXIT_CODE)"; \
		elif [ $$EXIT_CODE -eq 0 ]; then \
			echo "$$CMD_OUTPUT" > "$$TEST_DIR/test.patch"; \
			diff "$$TEST_DIR/test.patch" "$$TEST_DIR/test.expect" >/dev/null 2>&1; \
			if [ $$? -eq 0 ]; then \
				echo "passed"; \
			else \
				echo "failed (patch output different from expected)"; \
			fi; \
		else \
			echo "passed"; \
		fi; \
	fi

rename_val.%:
	@TEST="rename_val" TEST_DIR="rename_val/$*"  $(MAKE) --no-print-directory process_unit

CLEAN_DIRS := $(patsubst %,%.clean,$(TEST_DIRS))

clean: $(CLEAN_DIRS)

%.clean:
	@for UNIT in $*/*/; do \
		$(MAKE) -C $$UNIT --no-print-directory clean >/dev/null 2>&1; \
		TEST_DIR="$$UNIT" $(MAKE) --no-print-directory remove_artifacts; \
	done