# A sample Makefile for building Google Test and using it in user
# 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 = ../..
OBJECT_DIR = $(ROOT)/obj/test
TARGET_DIR = $(USER_DIR)/target
MAKE_SCRIPT_DIR := $(ROOT)/mk

include $(MAKE_SCRIPT_DIR)/system-id.mk

VPATH := $(VPATH):$(USER_DIR):$(TEST_DIR)

# specify which files that are included in the test in addition to the unittest file.
# variables available:
#   <test_name>_SRC
#   <test_name>_DEFINES
#   <test_name>_INCLUDE_DIRS
#   <test_name>_EXPAND (run for each target, call the above with target as $1)
#   <test_name>_BLACKLIST (targets to exclude from an expanded test's run)

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

althold_unittest_SRC := \
		$(USER_DIR)/flight/alt_hold_multirotor.c \
		$(USER_DIR)/flight/autopilot_multirotor.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/vector.c \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/pg/rx.c

althold_unittest_DEFINES := \
		USE_ALTITUDE_HOLD= \

arming_prevention_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/common/vector.c \
		$(USER_DIR)/fc/core.c \
		$(USER_DIR)/fc/dispatch.c \
		$(USER_DIR)/fc/rc_controls.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/flight/autopilot_multirotor.c \
		$(USER_DIR)/flight/gps_rescue_multirotor.c

arming_prevention_unittest_DEFINES := \
            USE_GPS_RESCUE=

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

baro_bmp085_unittest_DEFINES := \
                USE_BARO_BMP085=

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

baro_bmp280_unittest_DEFINES := \
                USE_BARO_BMP280= \
                USE_BARO_SPI_BMP280=

baro_bmp388_unittest_SRC := \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/drivers/barometer/barometer_bmp388.c

baro_bmp388_unittest_DEFINES := \
                USE_EXTI= \
                USE_BARO_BMP388= \
                USE_BARO_SPI_BMP388=

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

baro_ms5611_unittest_DEFINES := \
                USE_BARO_MS5611= \
                USE_BARO_SPI_MS5611=

# This test is disabled due to build errors.
# Its source code is archived in unit/battery_unittest.cc.txt
#
#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/accgyro/gyro_sync.c \
		$(USER_DIR)/pg/gps.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)/cli/cli.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/gps_conversion.c \
		$(USER_DIR)/config/feature.c \
		$(USER_DIR)/io/gps.c \
		$(USER_DIR)/io/serial_resource.c \
		$(USER_DIR)/pg/pg.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/drivers/serial.c \
		$(USER_DIR)/drivers/serial_impl.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)/cms/cms_menu_saveexit.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_failsafe_unittest_DEFINES := \
		USE_GPS_RESCUE=


flight_imu_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/vector.c \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/config/feature.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/flight/position.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)/io/serial_resource.c


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

ledstrip_unittest_DEFINES := \
		USE_LED_STRIP=


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


motor_output_unittest_SRC := \
		$(USER_DIR)/build/atomic.c \
		$(USER_DIR)/drivers/dshot.c

motor_output_unittest_DEFINES := \
		USE_DSHOT=

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

osd_unittest_DEFINES := \
		USE_OSD= \
		USE_GPS= \
		USE_RTC_TIME= \
		USE_ADC_INTERNAL=

link_quality_unittest_SRC := \
		$(USER_DIR)/osd/osd.c \
		$(USER_DIR)/osd/osd_elements.c \
		$(USER_DIR)/osd/osd_warnings.c \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/printf.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/common/time.c \
		$(USER_DIR)/common/typeconversion.c \
		$(USER_DIR)/common/vector.c \
		$(USER_DIR)/drivers/display.c \
		$(USER_DIR)/drivers/serial.c \
		$(USER_DIR)/drivers/serial_impl.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/pg/pg.c \
		$(USER_DIR)/pg/rx.c \
		$(USER_DIR)/rx/rx.c \
		$(USER_DIR)/rx/crsf.c

link_quality_unittest_DEFINES := \
		USE_OSD= \
		USE_CRSF_LINK_STATISTICS= \
		USE_RX_LINK_QUALITY_INFO=

pg_unittest_SRC := \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/pg/pg.c


rc_controls_unittest_SRC := \
		$(USER_DIR)/fc/rc_controls.c \
		$(USER_DIR)/pg/pg.c \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/streambuf.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 \
		$(USER_DIR)/drivers/serial_impl.c


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


rx_ranges_unittest_SRC := \
		$(USER_DIR)/common/bitarray.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/rx/rx.c \
		$(USER_DIR)/pg/pg.c \
		$(USER_DIR)/pg/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 \
		$(USER_DIR)/pg/rx.c

rx_sumd_unittest_SRC := \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/rx/sumd.c

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

scheduler_unittest_DEFINES := \
		USE_OSD=

sensor_gyro_unittest_SRC := \
		$(USER_DIR)/sensors/gyro.c \
		$(USER_DIR)/sensors/gyro_init.c \
		$(USER_DIR)/sensors/boardalignment.c \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/common/sensor_alignment.c \
		$(USER_DIR)/common/vector.c \
		$(USER_DIR)/drivers/accgyro/accgyro_virtual.c \
		$(USER_DIR)/drivers/accgyro/gyro_sync.c \
		$(USER_DIR)/pg/pg.c \
		$(USER_DIR)/pg/gyrodev.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 \
		__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)/drivers/serial_impl.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)/io/serial_resource.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

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_cam.c \
		$(USER_DIR)/pg/pg.c \

pid_unittest_SRC :=  \
		$(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/filter.c \
		$(USER_DIR)/common/maths.c \
		$(USER_DIR)/common/pwl.c \
		$(USER_DIR)/common/streambuf.c \
		$(USER_DIR)/drivers/accgyro/gyro_sync.c \
		$(USER_DIR)/fc/controlrate_profile.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/flight/pid.c \
		$(USER_DIR)/flight/pid_init.c \
		$(USER_DIR)/pg/pg.c

pid_unittest_DEFINES := \
		USE_ITERM_RELAX= \
		USE_RC_SMOOTHING_FILTER= \
		USE_ABSOLUTE_CONTROL= \
		USE_LAUNCH_CONTROL= \
		USE_FEEDFORWARD= \
		USE_ADVANCED_TPA= \

rcdevice_unittest_DEFINES := \
		USE_RCDEVICE=

vtx_unittest_SRC := \
		$(USER_DIR)/fc/core.c \
		$(USER_DIR)/fc/dispatch.c \
		$(USER_DIR)/fc/rc_controls.c \
		$(USER_DIR)/fc/rc_modes.c \
		$(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/drivers/vtx_common.c \
		$(USER_DIR)/drivers/vtx_table.c \
		$(USER_DIR)/io/vtx_control.c \
		$(USER_DIR)/io/vtx.c \
		$(USER_DIR)/common/bitarray.c

vtx_unittest_DEFINES := \
		USE_VTX_COMMON= \
		USE_VTX_CONTROL= \
		USE_VTX_SMARTAUDIO=

rx_spi_spektrum_unittest_SRC := \
		$(USER_DIR)/rx/cyrf6936_spektrum.c

rx_spi_spektrum_unittest_DEFINES := \
		USE_RX_SPI= \
		USE_RX_SPEKTRUM=

rx_spi_expresslrs_unittest_SRC := \
        $(USER_DIR)/pg/rx_spi_expresslrs.c \
		$(USER_DIR)/rx/expresslrs_common.c \
		$(USER_DIR)/rx/expresslrs.c \
		$(USER_DIR)/build/atomic.c \

rx_spi_expresslrs_unittest_DEFINES := \
		USE_RX_SPI= \
		USE_RX_EXPRESSLRS= \
		USE_RX_SX1280= \
		USE_RX_SX127X= \

rx_spi_expresslrs_telemetry_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)/rx/expresslrs_telemetry.c \
		$(USER_DIR)/build/atomic.c \
		$(USER_DIR)/telemetry/msp_shared.c \

rx_spi_expresslrs_telemetry_unittest_DEFINES := \
		USE_RX_EXPRESSLRS= \
		USE_GPS= \
		USE_MSP_OVER_TELEMETRY= \

vtx_msp_unittest_SRC := \
        $(USER_DIR)/common/crc.c \
		$(USER_DIR)/common/streambuf.c \
        $(USER_DIR)/fc/runtime_config.c \
		$(USER_DIR)/drivers/vtx_common.c \
		$(USER_DIR)/drivers/vtx_table.c \
		$(USER_DIR)/pg/vtx_table.c \
		$(USER_DIR)/io/vtx_control.c \
		$(USER_DIR)/io/vtx.c \
		$(USER_DIR)/io/vtx_msp.c \

vtx_msp_unittest_DEFINES := \
		USE_VTX_COMMON= \
		USE_VTX_CONTROL= \
		USE_VTX_TABLE= \
		USE_VTX_MSP=

pwl_unittest_SRC := \
		$(USER_DIR)/common/pwl.c

# 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

# Use clang/clang++ by default

CC  := clang-18
CXX := clang++-18
ifeq ($(and $(shell which $(CC) 2>/dev/null), $(shell which $(CXX) 2>/dev/null)),)
$(info Falling back to 'clang')
CC  := clang
CXX := clang++
endif

OPTIMIZE = -O0

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

CC_VERSION = $(shell $(CC) -dumpversion)
CXX_VERSION = $(shell $(CXX) -dumpversion)

ifeq ($(shell $(CC) -v 2>&1 | grep -q "clang version" && echo "clang"),clang)

# Please revisit versions when new clang version arrive. Supported versions: { Linux / OSX: 7 - 18 }
CC_VERSION_MAJOR := $(firstword $(subst ., ,$(CC_VERSION)))
CC_VERSION_CHECK_MIN := 7
CC_VERSION_CHECK_MAX := 18

# c99-designator is fine, code is not expected to be clean C++
COMMON_FLAGS += -Wno-c99-designator

# no warning expected on clang
COMMON_FLAGS += -Werror

ifeq ($(shell expr $(CC_VERSION_MAJOR) \< $(CC_VERSION_CHECK_MIN) \| $(CC_VERSION_MAJOR) \> $(CC_VERSION_CHECK_MAX)),1)
$(error $(CC) $(CC_VERSION) is not supported. The officially supported version of clang is 'clang-18'. If this is not found, 'clang' is used as a fallback. The version of the compiler must be between $(CC_VERSION_CHECK_MIN) and $(CC_VERSION_CHECK_MAX).)
endif

COMMON_FLAGS += -fblocks
ifndef CYGWIN
ifneq ($(OSFAMILY), macosx)
LDFLAGS	     += -lBlocksRuntime
endif # !macosx
endif # !CYGWIN

else ifeq ($(shell $(CC) -v 2>&1 | grep -q "gcc version" && echo "gcc"),gcc)

$(warning warning: gcc/g++ support is experimental. For normal testing, clang is recommended)

# no -Werror, allow warning for gcc now
COMMON_FLAGS += -Wno-missing-field-initializers

endif # is clang / gcc

$(info CC version: $(shell $(CC) --version))
$(info CXX version: $(shell $(CXX) --version))

USE_PTHREAD = YES
USE_COVERAGE = YES
ifeq ($(OSFAMILY), macosx)
	USE_PTHREAD =
endif
ifdef CYGWIN
	USE_PTHREAD =
	USE_COVERAGE =
endif

ifdef USE_PTHREAD
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++14

# Compiler flags for coverage instrumentation
ifdef USE_COVERAGE
COVERAGE_FLAGS := --coverage
endif

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

C_FLAGS   += -D_GNU_SOURCE

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

# Gather up all of the tests.
TEST_SRCS = $(sort $(wildcard $(TEST_DIR)/*.cc))
TEST_BASENAMES = $(TEST_SRCS:$(TEST_DIR)/%.cc=%)
TESTS_TARGET_SPECIFIC = $(foreach test,$(TEST_BASENAMES),$(if $($(test)_EXPAND),$(test)))

TESTS = $(foreach test,$(TEST_BASENAMES),$(if $($(test)_EXPAND),,$(test)))
TESTS_ALL = $(TESTS)

# 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_SCRIPT_DIR)/build_verbosity.mk

# House-keeping build targets.

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

## test-all : Build and run all Unit Tests
test-all: $(TESTS_ALL:%=test_%)

## test-representative : Build and run a representative subset of the Unit Tests (i.e. run every expanded test only for the first target)
test-representative: $(TESTS_REPRESENTATIVE:%=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 (except for target specific unit tests) can be used as goals to build and run:"
	@$(foreach test, $(TESTS), echo "    test_$(test)";)

versions:
	@echo "C compiler: $(CC): $(CC_VERSION)"
	@echo "C++ compiler: $(CXX): $(CXX_VERSION)"

## 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, unless the user
# specifies a list of endorsed directories in ${target}_INCLUDE_DIRS.
test_include_dirs  = $1 $(TEST_DIR) $(USER_DIR) $(ROOT)/lib/main/MAVLink
test_cflags	   = $(addprefix -I,$(call test_include_dirs,$1))


# target name extractor
# param $1 = expanded test name in the form of test.target
target = $(1:$(basename $1).%=%)

# canned recipe for all test builds
#
# variable expansion rules of thumb (number of $'s):
# * parameters: one $, e.g. $1
# * statically accessed variables set elsewhere: one $, e.g. $(C_FLAGS)
# * dynamically accessed variables set elsewhere: one $, e.g. $($1_SRC)
# * make functions accessing only the above: one $, e.g. $(basename $1)
# * dynamically set and accessed variables: two $, e.g. $$($1_OBJS)
# * make functions accessing dynamically set variables: two $,
#   e.g. $$(call test_cflags,$$($1_INCLUDE_DIRS))
#
# param $1 = plain test name for global tests, test.target for per-target tests
define test-specific-stuff

ifeq ($1,$(basename $1))
# standard global test
$1_OBJS = $(patsubst \
	$(TEST_DIR)/%,$(OBJECT_DIR)/$1/%,$(patsubst \
	$(USER_DIR)/%,$(OBJECT_DIR)/$1/%,$($1_SRC:=.o)))
else
# test executed for each target, $1 has the form of test.target
$1_SRC = $(addsuffix .o,$(call $(basename $1)_SRC,$(call target,$1)))
$1_OBJS = $$(patsubst \
	$(TEST_DIR)/%,$(OBJECT_DIR)/$1/%,$$(patsubst \
	$(USER_DIR)/%,$(OBJECT_DIR)/$1/%,$$(patsubst \
	$(TARGET_DIR)/$(TARGET)/%,$(OBJECT_DIR)/$1/%,$$($1_SRC))))
$1_DEFINES = $(call $(basename $1)_DEFINES,$(call target,$1))
$1_INCLUDE_DIRS = $(call $(basename $1)_INCLUDE_DIRS,$(call target,$1))
endif

# $$(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/$(basename $1).d

$(OBJECT_DIR)/$1/%.c.o: $(USER_DIR)/%.c
	@echo "compiling $$<" "$(STDOUT)"
	$(V1) mkdir -p $$(dir $$@)
	$(V1) $(CC) $(C_FLAGS) $$(call test_cflags,$$($1_INCLUDE_DIRS)) \
                $$(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) $$(call test_cflags,$$($1_INCLUDE_DIRS)) \
                $$(foreach def,$$($1_DEFINES),-D $$(def)) \
                -c $$< -o $$@

ifneq ($1,$(basename $1))
# per-target tests may compile files from the target directory
$(OBJECT_DIR)/$1/%.c.o: $(TARGET_DIR)/$(TARGET)/%.c
	@echo "compiling target c file: $$<" "$(STDOUT)"
	$(V1) mkdir -p $$(dir $$@)
	$(V1) $(CC) $(C_FLAGS) $$(call test_cflags,$$($1_INCLUDE_DIRS)) \
                $$(foreach def,$$($1_DEFINES),-D $$(def)) \
                -c $$< -o $$@
endif

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

$(OBJECT_DIR)/$1/$(basename $1): $$($1_OBJS) \
	$(OBJECT_DIR)/$1/$(basename $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/$(basename $1)
	$(V1) $$< $$(EXEC_OPTS) "$(STDOUT)" && echo "running $$@: PASS"

endef


ifeq ($(MAKECMDGOALS),test-all)
    $(eval $(foreach test,$(TESTS_ALL),$(call test-specific-stuff,$(test))))
else
    ifeq ($(MAKECMDGOALS),test-representative)
        $(eval $(foreach test,$(TESTS_REPRESENTATIVE),$(call test-specific-stuff,$(test))))
    else
        $(eval $(foreach test,$(TESTS),$(call test-specific-stuff,$(test))))
    endif
endif

$(foreach test,$(TESTS_ALL),$(if $($(basename $(test))_SRC),,$(error \
	Test 'unit/$(basename $(test)).cc' has no '$(basename $(test))_SRC' variable defined)))
