#
# LIBGTEST is the google test library
# GTEST_MAIN is the file that contains the google test
##
LIBGTEST = test/libgtest.a
GTEST_MAIN = $(GTEST)/src/gtest_main.cc
CFLAGS_GTEST += -I $(GTEST)/include -I $(GTEST)

##
# Build the google test library.
## 
$(LIBGTEST): $(LIBGTEST)(test/gtest.o)

test/gtest.o: $(GTEST)/src/gtest-all.cc
	@mkdir -p test
	$(COMPILE.c) -O$O $(CFLAGS_GTEST) $< $(OUTPUT_OPTION)

##
# Rule for building a test
##
test/%.o : src/test/%_test.cpp $(LIBGTEST) bin/libstan.a
	@mkdir -p $(dir $@)
	$(COMPILE.c) -O$O $(CFLAGS_GTEST) $< $(OUTPUT_OPTION)

##
# Rule for building a test executable
##
test/%$(EXE) : test/%.o bin/libstan.a
	@mkdir -p $(dir $@)
	$(LINK.c) -O$O $(GTEST_MAIN) $< $(CFLAGS_GTEST) $(OUTPUT_OPTION) $(LIBGTEST) $(LDLIBS)


##
# static rule to link in libstanc.
# needed by subset of unit tests that test stan compiler
# all these tests are under stan/test/unit/gm
##
STANC_TESTS_HEADERS := $(shell find src/test/unit/gm -type f -name '*_test.cpp')
STANC_TESTS_O := $(patsubst src/%_test.cpp,%.o,$(STANC_TESTS_HEADERS))
STANC_TESTS := $(patsubst src/%_test.cpp,%$(EXE),$(STANC_TESTS_HEADERS))

# $(STANC_TESTS) : test/%$(EXE) : test/%.o bin/libstan.a bin/libstanc.a
# 	@mkdir -p $(dir $@)
# 	$(LINK.c) -O$O $(GTEST_MAIN) $< $(CFLAGS_GTEST) $(OUTPUT_OPTION) $(LIBGTEST) $(LDLIBS) $(LDLIBS_STANC)

# add additional dependency to libstanc.a
##$(patsubst src/%_test.cpp,%.o,$(STANC_TEST_HEADERS)) : test/%.o : bin/libstanc.a
$(STANC_TESTS_O) : bin/libstanc.a
$(STANC_TESTS) : LDLIBS += $(LDLIBS_STANC)





##
# Rule for generating dependencies.
##
.PRECIOUS: test/%.d
test/%.d : src/test/%_test.cpp
	@mkdir -p $(dir $@)
	@set -e; \
	rm -f $@; \
	$(CC) $(CFLAGS) -O$O $(CFLAGS_GTEST) $(TARGET_ARCH) -MM $< > $@.$$$$; \
	sed -e 's,\($(notdir $*)\)\(_test\)\.o[ :]*,$(dir $@)\1\$(EXE) $@ : ,g' < $@.$$$$ > $@; \
	rm -f $@.$$$$

############################################################
##
# Target to verify header files within Stan has
# enough include calls
##
HEADER_TESTS := $(addsuffix -test,$(shell find src/stan -name '*.hpp' -type f)) 

ifeq ($(OS_TYPE),win) 
  DEV_NULL = nul
else
  DEV_NULL = /dev/null
endif

.PHONY: HEADER_TESTS
%.hpp-test : %.hpp test/dummy.cpp
	$(COMPILE.c) -O0 -include $< -o $(DEV_NULL) test/dummy.cpp

test/dummy.cpp:
	@mkdir -p test
	@touch $@
	@echo "int main() {return 0;}" >> $@

.PHONY: test-headers
test-headers: $(HEADER_TESTS)

############################################################
##
# Use the stanc compiler to generate C++ from Stan programs
##

.PRECIOUS: test/test-models/stanc$(EXE)
test/test-models/stanc$(EXE) : src/test/test-models/stanc.cpp bin/libstanc.a
	@mkdir -p $(dir $@)
	$(LINK.c) -O$(O_STANC) $(OUTPUT_OPTION) $< $(LDLIBS_STANC)

TEST_MODELS := $(shell find src/test/test-models -type f -name '*.stan')
$(patsubst %.stan,%.cpp,$(TEST_MODELS)) : %.cpp : %.stan test/test-models/stanc$(EXE)
	$(WINE) test/test-models/stanc$(EXE) --o=$@ $<

##
# Explicitly specify dependencies for tests that depend on the generated C++ of Stan programs.
##
src/test/unit/io/mcmc_writer_test.cpp: src/test/test-models/no-main/io_example.cpp
src/test/unit/gm/generator_test.cpp: src/test/test-models/no-main/gm/test_lp.cpp
src/test/unit/gm/parser_generator_test.cpp: $(patsubst %.stan,%.cpp,$(shell find src/test/test-models/syntax-only/parser-generator -type f -name '*.stan'))

src/test/unit/model/util_test.cpp: src/test/test-models/no-main/model/valid.cpp src/test/test-models/no-main/model/domain_fail.cpp

src/test/unit/mcmc/hmc/hamiltonians/base_hamiltonian_test.cpp: src/test/test-models/no-main/mcmc/hmc/hamiltonians/funnel.cpp
src/test/unit/mcmc/hmc/hamiltonians/unit_e_metric_test.cpp: src/test/test-models/no-main/mcmc/hmc/hamiltonians/funnel.cpp
src/test/unit/mcmc/hmc/hamiltonians/diag_e_metric_test.cpp: src/test/test-models/no-main/mcmc/hmc/hamiltonians/funnel.cpp
src/test/unit/mcmc/hmc/hamiltonians/dense_e_metric_test.cpp: src/test/test-models/no-main/mcmc/hmc/hamiltonians/funnel.cpp
src/test/unit/mcmc/hmc/integrators/expl_leapfrog_test.cpp: src/test/test-models/no-main/mcmc/hmc/integrators/command.cpp 
src/test/unit/mcmc/hmc/integrators/expl_leapfrog2_test.cpp: src/test/test-models/no-main/mcmc/hmc/integrators/gauss.cpp

src/test/unit/common/do_bfgs_optimize_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp
src/test/unit/optimization/bfgs_linesearch_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp
src/test/unit/optimization/bfgs_minimizer_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp
src/test/unit/optimization/bfgs_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp
src/test/unit/optimization/bfgs_update_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp
src/test/unit/optimization/lbfgs_update_test.cpp: src/test/test-models/no-main/optimization/rosenbrock.cpp

src/test/unit/common/command_init_test.cpp: src/test/test-models/no-main/common/test_lp.cpp
src/test/unit/common/run_markov_chain_test.cpp: src/test/test-models/no-main/common/test_lp.cpp
src/test/unit/common/sample_test.cpp: src/test/test-models/no-main/common/test_lp.cpp
src/test/unit/common/warmup_test.cpp: src/test/test-models/no-main/common/test_lp.cpp
src/test/unit/common/write_iteration_test.cpp: src/test/test-models/no-main/common/test_lp.cpp

src/test/unit/gm/reject/reject_mult_args_test.cpp: src/test/test-models/no-main/gm/reject_mult_args.cpp

src/test/unit/gm/reject/reject_model_test.cpp: src/test/test-models/no-main/gm/reject_model.cpp
src/test/unit/gm/reject/reject_func_call_model_test.cpp: src/test/test-models/no-main/gm/reject_func_call_model.cpp

src/test/unit/gm/reject/reject_transformed_data_test.cpp: src/test/test-models/no-main/gm/reject_transformed_data.cpp
src/test/unit/gm/reject/reject_func_call_transformed_data_test.cpp: src/test/test-models/no-main/gm/reject_func_call_transformed_data.cpp

src/test/unit/gm/reject/reject_transformed_parameters_test.cpp: src/test/test-models/no-main/gm/reject_transformed_parameters.cpp
src/test/unit/gm/reject/reject_func_call_transformed_parameters_test.cpp: src/test/test-models/no-main/gm/reject_func_call_transformed_parameters.cpp

src/test/unit/gm/reject/reject_generated_quantities_test.cpp: src/test/test-models/no-main/gm/reject_generated_quantities.cpp
src/test/unit/gm/reject/reject_func_call_generated_quantities_test.cpp: src/test/test-models/no-main/gm/reject_func_call_generated_quantities.cpp

##
# Target to verify code generated Stan programs
# (.stan -> .cpp) are compilable
##
.PHONY: %.cpp-test
%.cpp-test : %.cpp
	$(COMPILE.c) -fsyntax-only -O$O $< 


##
# Compile models depends on every model within
# src/test/test-models/syntax-only/*.stan being able to
# be code-generated to a *.cpp, then passed through
# the compiler using the -fsyntax-only flag
##
test/integration/compile_models$(EXE) : $(patsubst %.stan,%.cpp-test,$(shell find src/test/test-models/syntax-only -type f -name '*.stan'))


############################################################
##
# Test generator for distribution tests
##
test/unit-distribution/generate_tests$(EXE) : src/test/unit-distribution/generate_tests.cpp
	@mkdir -p $(dir $@)
	$(LINK.c) -O$(O_STANC) $(CFLAGS) $< $(OUTPUT_OPTION)


test_name = $(shell echo $(1) | sed 's,_[0-9]\{5\},_test.hpp,g')
.SECONDEXPANSION:
src/test/unit-distribution/%_generated_test.cpp : src/test/unit-distribution/$$(call test_name,$$*) test/unit-distribution/generate_tests$(EXE)
	$(WINE) test/unit-distribution/generate_tests$(EXE) $<


LIST_OF_GENERATED_TESTS := $(shell find src/test/unit-distribution -type f -name '*_test.hpp' | sed 's,_test.hpp,_00000_generated_test.cpp,g')

.PHONY: generate-tests
generate-tests: $(LIST_OF_GENERATED_TESTS)
