# A sample Makefile for building Google Test and using it in user
# tests.  Please tweak it to suit your environment and project.  You
# may want to move it to your project's root directory.
#
# SYNOPSIS:
#
#   make [all]  - makes everything.
#   make TARGET - makes the given target.
#   make clean  - removes all files generated by make.


# Where to find user code.
USER_DIR = ../main
TEST_DIR = unit
ROOT = ../..

include $(ROOT)/make/system-id.mk

# specify which files that are included in the test in addition to the unittest file.
# variables available:
#   <test_name>_SRC
#   <test_name>_DEFINES


alignsensor_unittest_SRC := \
		$(USER_DIR)/sensors/boardalignment.c \
		$(USER_DIR)/common/maths.c


altitude_hold_unittest_SRC :=  \
		$(USER_DIR)/flight/altitude.c


arming_prevention_unittest_SRC := \
		$(USER_DIR)/fc/fc_core.c \
		$(USER_DIR)/fc/rc_controls.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/common/bitarray.c

atomic_unittest_SRC := \
		$(USER_DIR)/build/atomic.c \
		$(TEST_DIR)/atomic_unittest_c.c

baro_bmp085_unittest_SRC := \
		$(USER_DIR)/drivers/barometer/barometer_bmp085.c \
		$(USER_DIR)/drivers/io.c


baro_bmp280_unittest_SRC := \
		$(USER_DIR)/drivers/barometer/barometer_bmp280.c

baro_bmp280_unittest_DEFINES := \
                USE_BARO_BMP280 \
                USE_BARO_SPI_BMP280

baro_ms5611_unittest_SRC := \
		$(USER_DIR)/drivers/barometer/barometer_ms5611.c

baro_ms5611_unittest_DEFINES := \
                USE_BARO_MS5611 \
                USE_BARO_SPI_MS5611

battery_unittest_SRC := \
		$(USER_DIR)/sensors/battery.c \
		$(USER_DIR)/common/maths.c


blackbox_unittest_SRC :=  \
		$(USER_DIR)/blackbox/blackbox.c \
		$(USER_DIR)/blackbox/blackbox_encoding.c \
		$(USER_DIR)/blackbox/blackbox_io.c \
		$(USER_DIR)/common/encoding.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/drivers/gyro_sync.c

blackbox_encoding_unittest_SRC :=  \
		$(USER_DIR)/blackbox/blackbox_encoding.c \
		$(USER_DIR)/common/encoding.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/typeconversion.c

cli_unittest_SRC := \
		$(USER_DIR)/interface/cli.c \
		$(USER_DIR)/config/feature.c \
		$(USER_DIR)/config/parameter_group.c \
                $(USER_DIR)/common/typeconversion.c

cli_unittest_DEFINES := \
		USE_OSD \
		USE_CLI \
		SystemCoreClock=1000000

cms_unittest_SRC := \
		$(USER_DIR)/cms/cms.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/drivers/display.c


common_filter_unittest_SRC := \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/common/maths.c


encoding_unittest_SRC := \
		$(USER_DIR)/common/encoding.c


flight_failsafe_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/flight/failsafe.c


flight_imu_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/config/feature.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/flight/altitude.c \
		$(USER_DIR)/flight/imu.c


flight_mixer_unittest :=  \
		$(USER_DIR)/flight/mixer.c \
		$(USER_DIR)/flight/servos.c \
		$(USER_DIR)/common/maths.c


gps_conversion_unittest_SRC := \
		$(USER_DIR)/common/gps_conversion.c


io_serial_unittest_SRC := \
		$(USER_DIR)/io/serial.c \
		$(USER_DIR)/drivers/serial_pinconfig.c


ledstrip_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/io/ledstrip.c


maths_unittest_SRC := \
		$(USER_DIR)/common/maths.c


osd_unittest_SRC := \
		$(USER_DIR)/io/osd.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/drivers/display.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/time.c \
		$(USER_DIR)/fc/runtime_config.c

osd_unittest_DEFINES := \
		USE_OSD \
		USE_RTC_TIME


parameter_groups_unittest_SRC := \
		$(USER_DIR)/config/parameter_group.c


rc_controls_unittest_SRC := \
		$(USER_DIR)/fc/rc_controls.c \
		$(USER_DIR)/config/parameter_group.c \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/fc/rc_adjustments.c \
		$(USER_DIR)/fc/rc_modes.c \


rx_crsf_unittest_SRC := \
		$(USER_DIR)/rx/crsf.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/drivers/serial.c


rx_ibus_unittest_SRC := \
		$(USER_DIR)/rx/ibus.c


rx_ranges_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/rx/rx.c


rx_rx_unittest_SRC := \
		$(USER_DIR)/rx/rx.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/config/feature.c


scheduler_unittest_SRC := \
		$(USER_DIR)/scheduler/scheduler.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/streambuf.c


telemetry_crsf_unittest_SRC := \
		$(USER_DIR)/rx/crsf.c \
		$(USER_DIR)/telemetry/crsf.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/common/gps_conversion.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/fc/runtime_config.c

telemetry_crsf_unittest_DEFINES := \
		FLASH_SIZE=128 \
		STM32F10X_MD \
		__TARGET__="TEST" \
		__REVISION__="revision"


telemetry_crsf_msp_unittest_SRC := \
		$(USER_DIR)/rx/crsf.c \
		$(USER_DIR)/build/atomic.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/drivers/serial.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/telemetry/crsf.c \
		$(USER_DIR)/common/gps_conversion.c \
		$(USER_DIR)/telemetry/msp_shared.c \
		$(USER_DIR)/fc/runtime_config.c

telemetry_crsf_msp_unittest_DEFINES := \
		USE_MSP_OVER_TELEMETRY


telemetry_hott_unittest_SRC := \
		$(USER_DIR)/telemetry/hott.c \
		$(USER_DIR)/common/gps_conversion.c


telemetry_ibus_unittest_SRC := \
		$(USER_DIR)/telemetry/ibus_shared.c \
		$(USER_DIR)/telemetry/ibus.c


transponder_ir_unittest_SRC := \
	        $(USER_DIR)/drivers/transponder_ir_ilap.c \
	        $(USER_DIR)/drivers/transponder_ir_arcitimer.c


type_conversion_unittest_SRC := \
		$(USER_DIR)/common/typeconversion.c


ws2811_unittest_SRC := \
		$(USER_DIR)/drivers/light_ws2811strip.c

huffman_unittest_SRC := \
		$(USER_DIR)/common/huffman.c \
		$(USER_DIR)/common/huffman_table.c

huffman_unittest_DEFINES := \
		USE_HUFFMAN

rcdevice_unittest_SRC := \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/io/rcdevice.c \
		$(USER_DIR)/io/rcdevice_osd.c \
		$(USER_DIR)/io/rcdevice_cam.c \

rcdevice_unittest_DEFINES := \
		USE_RCDEVICE

# Please tweak the following variable definitions as needed by your
# project, except GTEST_HEADERS, which you can use in your own targets
# but shouldn't modify.

# Points to the root of Google Test, relative to where this file is.
# Remember to tweak this if you move this file.
GTEST_DIR = ../../lib/test/gtest


USER_INCLUDE_DIR = $(USER_DIR)

OBJECT_DIR = ../../obj/test

# Use clang/clang++ by default
CC  := clang
CXX := clang++
#CC  := gcc
#CXX := g++

COMMON_FLAGS = \
	-g \
	-Wall \
	-Wextra \
	-Werror \
	-ggdb3 \
	-O0 \
	-DUNIT_TEST \
	-isystem $(GTEST_DIR)/inc \
	-MMD -MP

ifeq ($(shell $(CC) -v 2>&1 | grep -q "clang version" && echo "clang"),clang)
COMMON_FLAGS += -fblocks
LDFLAGS	     += -lBlocksRuntime
endif

ifndef MACOSX
COMMON_FLAGS += -pthread
endif

# Flags passed to the C compiler.
C_FLAGS = $(COMMON_FLAGS) \
	-std=gnu99

# Flags passed to the C++ compiler.
CXX_FLAGS = $(COMMON_FLAGS) \
	-std=gnu++11

# Compiler flags for coverage instrumentation
COVERAGE_FLAGS := --coverage

C_FLAGS   += $(COVERAGE_FLAGS)
CXX_FLAGS += $(COVERAGE_FLAGS)

# Set up the parameter group linker flags according to OS
ifdef MACOSX
LDFLAGS  += -Wl,-map,$(OBJECT_DIR)/$@.map
else
LDFLAGS  += -Wl,-T,$(TEST_DIR)/parameter_group.ld -Wl,-Map,$(OBJECT_DIR)/$@.map
endif

# Gather up all of the tests.
TEST_SRC = $(sort $(wildcard $(TEST_DIR)/*.cc))
TESTS = $(TEST_SRC:$(TEST_DIR)/%.cc=%)

# All Google Test headers.  Usually you shouldn't change this
# definition.
GTEST_HEADERS = $(GTEST_DIR)/inc/gtest/*.h

## V                 : Set verbosity level based on the V= parameter
##                     V=0 Low
##                     V=1 High
include ../../make/build_verbosity.mk

# House-keeping build targets.

## test        : Build and run the Unit Tests (default goal)
test: $(TESTS:%=test_%)

## junittest   : Build and run the Unit Tests, producing Junit XML result files."
junittest: EXEC_OPTS = "--gtest_output=xml:$<_results.xml"
junittest: $(TESTS:%=test_%)



## help        : print this help message and exit
## what        : print this help message and exit
## usage       : print this help message and exit
help what usage: Makefile
	@echo ""
	@echo "Makefile for Unit Tests"
	@echo ""
	@echo "Usage:"
	@echo "        make [goal] "
	@echo ""
	@echo "Valid goals are:"
	@echo ""
	@sed -n 's/^## //p' $<
	@echo ""
	@echo "Any of the Unit Test programs can be used as goals to build:"
	@$(foreach test, $(TESTS), echo "    $(OBJECT_DIR)/$(test)/$(test)";)
	@echo ""
	@echo "Any of the Unit Test programs can be used as goals to build and run:"
	@$(foreach test, $(TESTS), echo "    test_$(test)";)

## clean       : Cleanup the UnitTest binaries.
clean :
	rm -rf $(OBJECT_DIR)


# Builds gtest.a and gtest_main.a.

# Usually you shouldn't tweak such internal variables, indicated by a
# trailing _.
GTEST_SRCS_ = $(GTEST_DIR)/src/*.cc $(GTEST_DIR)/inc/gtest/*.h $(GTEST_HEADERS)

# For simplicity and to avoid depending on Google Test's
# implementation details, the dependencies specified below are
# conservative and not optimized.  This is fine as Google Test
# compiles fast and for ordinary users its source rarely changes.
$(OBJECT_DIR)/gtest-all.o : $(GTEST_SRCS_)
	@echo "compiling $@" "$(STDOUT)"
	@mkdir -p $(dir $@)
	$(V1) $(CXX) $(CXX_FLAGS) -I$(GTEST_DIR) -Wno-missing-field-initializers -Wno-unused-const-variable -c \
            $(GTEST_DIR)/src/gtest-all.cc -o $@

$(OBJECT_DIR)/gtest_main.o : $(GTEST_SRCS_)
	@echo "compiling $@" "$(STDOUT)"
	@mkdir -p $(dir $@)
	$(V1) $(CXX) $(CXX_FLAGS) -I$(GTEST_DIR) -c \
            $(GTEST_DIR)/src/gtest_main.cc -o $@

$(OBJECT_DIR)/gtest.a : $(OBJECT_DIR)/gtest-all.o
	@echo "linking $@" "$(STDOUT)"
	$(V1) $(AR) $(ARFLAGS) $@ $^

$(OBJECT_DIR)/gtest_main.a : $(OBJECT_DIR)/gtest-all.o $(OBJECT_DIR)/gtest_main.o
	@echo "linking $@" "$(STDOUT)"
	$(V1) $(AR) $(ARFLAGS) $@ $^

-include $(OBJECT_DIR)/gtest-all.d \
         $(OBJECT_DIR)/gtest_main.d


# includes in test dir must override includes in user dir
TEST_INCLUDE_DIRS := $(TEST_DIR) \
	$(USER_INCLUDE_DIR)

TEST_CFLAGS	 = $(addprefix -I,$(TEST_INCLUDE_DIRS))




# canned recipe for all test builds
# param $1 = testname
define test-specific-stuff

$$1_OBJS = $$(patsubst $$(TEST_DIR)%,$$(OBJECT_DIR)/$1%, $$(patsubst $$(USER_DIR)%,$$(OBJECT_DIR)/$1%,$$($1_SRC:=.o)))

# $$(info $1 -v-v-------)
# $$(info $1_SRC:  $($1_SRC))
# $$(info $1_OBJS: $$($$1_OBJS))
# $$(info $1 -^-^-------)


#include generated dependencies
-include $$($$1_OBJS:.o=.d)
-include $(OBJECT_DIR)/$1/$1.d


$(OBJECT_DIR)/$1/%.c.o: $(USER_DIR)/%.c
	@echo "compiling $$<" "$(STDOUT)"
	$(V1) mkdir -p $$(dir $$@)
	$(V1) $(CC) $(C_FLAGS) $(TEST_CFLAGS) \
                $(foreach def,$($1_DEFINES),-D $(def)) \
                -c $$< -o $$@

$(OBJECT_DIR)/$1/%.c.o: $(TEST_DIR)/%.c
	@echo "compiling test c file: $$<" "$(STDOUT)"
	$(V1) mkdir -p $$(dir $$@)
	$(V1) $(CC) $(C_FLAGS) $(TEST_CFLAGS) \
                $(foreach def,$($1_DEFINES),-D $(def)) \
                -c $$< -o $$@

$(OBJECT_DIR)/$1/$1.o: $(TEST_DIR)/$1.cc
	@echo "compiling $$<" "$(STDOUT)"
	$(V1) mkdir -p $$(dir $$@)
	$(V1) $(CXX) $(CXX_FLAGS) $(TEST_CFLAGS)  \
                 $(foreach def,$($1_DEFINES),-D $(def)) \
                 -c $$< -o $$@


$(OBJECT_DIR)/$1/$1 : $$($$1_OBJS) \
    $(OBJECT_DIR)/$1/$1.o \
	$(OBJECT_DIR)/gtest_main.a

	@echo "linking $$@" "$(STDOUT)"
	$(V1) mkdir -p $(dir $$@)
	$(V1) $(CXX) $(CXX_FLAGS) $(LDFLAGS) $$^ -o $$@

test_$1: $(OBJECT_DIR)/$1/$1
	$(V1) $$< $$(EXEC_OPTS) "$(STDOUT)" && echo "running $$@: PASS"

endef

#apply the canned recipe above to all tests
$(eval $(foreach test,$(TESTS),$(call test-specific-stuff,$(test))))
