From 63b967f5df1d77c1705c1be050be1124e861cb37 Mon Sep 17 00:00:00 2001
From: Matthias Grob <maetugr@gmail.com>
Date: Sat, 2 Mar 2019 18:18:00 +0100
Subject: [PATCH] Add unit testing possibility using googletest on POSIX

---
 CMakeLists.txt                                | 14 ++++
 Makefile                                      |  7 +-
 cmake/gtest/CMakeLists.txt.in                 | 18 +++++
 cmake/gtest/gtest.cmake                       | 43 ++++++++++++
 cmake/gtest/px4_add_gtest.cmake               | 68 +++++++++++++++++++
 src/include/visibility.h                      |  2 +-
 .../AttitudeControl/AttitudeControlTest.cpp   | 12 ++++
 .../AttitudeControl/CMakeLists.txt            |  2 +
 8 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 cmake/gtest/CMakeLists.txt.in
 create mode 100644 cmake/gtest/gtest.cmake
 create mode 100644 cmake/gtest/px4_add_gtest.cmake
 create mode 100644 src/modules/mc_att_control/AttitudeControl/AttitudeControlTest.cpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index d1815f6d8c..5ddc25ed08 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -413,6 +413,20 @@ if (NOT EXTERNAL_MODULES_LOCATION STREQUAL "")
 	endforeach()
 endif()
 
+#=============================================================================
+# Testing - Automatic unit and integration testing with CTest
+#
+
+option(unit_testing "Configure unit test targets" OFF)
+
+list(APPEND CMAKE_MODULE_PATH ${PX4_SOURCE_DIR}/cmake/gtest/)
+include(px4_add_gtest)
+
+if(unit_testing)
+   include(gtest)
+   add_custom_target(unit_test COMMAND GTEST_COLOR=1 ${CMAKE_CTEST_COMMAND} -V -R Test USES_TERMINAL)
+endif()
+
 #=============================================================================
 # subdirectories
 #
diff --git a/Makefile b/Makefile
index c1f0202204..a6550ba2e3 100644
--- a/Makefile
+++ b/Makefile
@@ -337,9 +337,14 @@ format:
 
 # Testing
 # --------------------------------------------------------------------
-.PHONY: tests tests_coverage tests_mission tests_mission_coverage tests_offboard tests_avoidance
+.PHONY: tests tests_coverage tests_mission tests_mission_coverage tests_offboard tests_avoidance unit_test
 .PHONY: rostest python_coverage
 
+unit_test:
+	$(eval CMAKE_ARGS += -Dunit_testing=ON)
+	$(eval ARGS += unit_test)
+	$(call cmake-build,px4_sitl_default)
+
 tests:
 	@$(MAKE) --no-print-directory px4_sitl_test test_results \
 	ASAN_OPTIONS="color=always:check_initialization_order=1:detect_stack_use_after_return=1" \
diff --git a/cmake/gtest/CMakeLists.txt.in b/cmake/gtest/CMakeLists.txt.in
new file mode 100644
index 0000000000..0634841841
--- /dev/null
+++ b/cmake/gtest/CMakeLists.txt.in
@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 2.8.4)
+
+project(googletest-download NONE)
+
+include(ExternalProject)
+ExternalProject_Add(googletest
+	URL https://github.com/google/googletest/archive/master.zip
+	SOURCE_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-src"
+	BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/googletest-build"
+	CONFIGURE_COMMAND ""
+	BUILD_COMMAND ""
+	INSTALL_COMMAND ""
+	TEST_COMMAND ""
+	# Wrap download, configure and build steps in a script to log output
+    LOG_DOWNLOAD ON
+    LOG_CONFIGURE ON
+    LOG_BUILD ON
+)
diff --git a/cmake/gtest/gtest.cmake b/cmake/gtest/gtest.cmake
new file mode 100644
index 0000000000..94c4103ce5
--- /dev/null
+++ b/cmake/gtest/gtest.cmake
@@ -0,0 +1,43 @@
+############################################################################
+#
+# Copyright (c) 2019 PX4 Development Team. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 3. Neither the name PX4 nor the names of its contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+# Download and unpack googletest at configure time
+configure_file(${CMAKE_CURRENT_LIST_DIR}/CMakeLists.txt.in googletest-download/CMakeLists.txt)
+execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . RESULT_VARIABLE result1 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
+execute_process(COMMAND ${CMAKE_COMMAND} --build . RESULT_VARIABLE result2 WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/googletest-download)
+if(result1 OR result2)
+	message(FATAL_ERROR "Preparing googletest failed: ${result1} ${result2}")
+endif()
+
+# Add googletest, defines gtest and gtest_main targets
+add_subdirectory(${CMAKE_CURRENT_BINARY_DIR}/googletest-src ${CMAKE_CURRENT_BINARY_DIR}/googletest-build EXCLUDE_FROM_ALL)
diff --git a/cmake/gtest/px4_add_gtest.cmake b/cmake/gtest/px4_add_gtest.cmake
new file mode 100644
index 0000000000..42124acac3
--- /dev/null
+++ b/cmake/gtest/px4_add_gtest.cmake
@@ -0,0 +1,68 @@
+############################################################################
+#
+# Copyright (c) 2019 PX4 Development Team. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in
+#    the documentation and/or other materials provided with the
+#    distribution.
+# 3. Neither the name PX4 nor the names of its contributors may be
+#    used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+############################################################################
+
+include(px4_base)
+
+#=============================================================================
+#
+#	px4_add_gtest
+#
+#	Adds a googletest unit test to the unit_test target.
+#
+function(px4_add_gtest)
+	# skip if unit testing is not configured
+	if(unit_testing)
+		# parse source file and library dependencies from arguments
+		px4_parse_function_args(
+			NAME px4_add_gtest
+			ONE_VALUE SRC
+			MULTI_VALUE LINKLIBS
+			REQUIRED SRC
+			ARGN ${ARGN})
+
+		# infer test name from source filname without extension
+		get_filename_component(TESTNAME ${SRC} NAME_WE)
+
+		# build a binary for the unit test
+		add_executable(${TESTNAME} EXCLUDE_FROM_ALL ${SRC})
+
+		# link the libary to test and gtest
+		target_link_libraries(${TESTNAME} ${LINKLIBS} gtest_main)
+
+		# add the test to the ctest plan
+		add_test(NAME ${TESTNAME} COMMAND ${TESTNAME})
+
+		# attach it to the unit test target
+		add_dependencies(unit_test ${TESTNAME})
+	endif()
+endfunction()
diff --git a/src/include/visibility.h b/src/include/visibility.h
index 1a956f02e8..3717b63704 100644
--- a/src/include/visibility.h
+++ b/src/include/visibility.h
@@ -86,7 +86,7 @@
 #ifdef __cplusplus
 #include <cstdlib>
 #endif
-#pragma GCC poison exit
+//#pragma GCC poison exit
 
 #include <stdlib.h>
 
diff --git a/src/modules/mc_att_control/AttitudeControl/AttitudeControlTest.cpp b/src/modules/mc_att_control/AttitudeControl/AttitudeControlTest.cpp
new file mode 100644
index 0000000000..7dc0055078
--- /dev/null
+++ b/src/modules/mc_att_control/AttitudeControl/AttitudeControlTest.cpp
@@ -0,0 +1,12 @@
+#include <gtest/gtest.h>
+#include <AttitudeControl.hpp>
+
+using namespace matrix;
+
+TEST(AttitudeControlTest, AllZeroCase) {
+	AttitudeControl attitude_control;
+	matrix::Vector3f rate_setpoint = attitude_control.update(Quatf(), Quatf(), 0.f);
+	EXPECT_EQ(rate_setpoint(0), 0.f);
+	EXPECT_EQ(rate_setpoint(1), 0.f);
+	EXPECT_EQ(rate_setpoint(2), 0.f);
+}
diff --git a/src/modules/mc_att_control/AttitudeControl/CMakeLists.txt b/src/modules/mc_att_control/AttitudeControl/CMakeLists.txt
index 6e29d4762a..f4b1ace74a 100644
--- a/src/modules/mc_att_control/AttitudeControl/CMakeLists.txt
+++ b/src/modules/mc_att_control/AttitudeControl/CMakeLists.txt
@@ -38,3 +38,5 @@ target_include_directories(AttitudeControl
 	PUBLIC
 	${CMAKE_CURRENT_SOURCE_DIR}
 )
+
+px4_add_gtest(SRC AttitudeControlTest.cpp LINKLIBS AttitudeControl)
-- 
GitLab