test: Add build system support and a main function for unit tests
authorManuel Nickschas <sputnick@quassel-irc.org>
Mon, 24 Sep 2018 18:36:21 +0000 (20:36 +0200)
committerManuel Nickschas <sputnick@quassel-irc.org>
Sun, 18 Nov 2018 10:06:43 +0000 (11:06 +0100)
Add a new CMake option BUILD_TESTING (defaults to OFF) that, if
enabled, will build unit tests and related requirements.

Add a new library Quassel::Test::Main that provides a main function
for test cases.

Add a new CMake macro quassel_add_test for making the adding of test
cases convenient by hiding most of the boilerplate.

Test cases should #include "testglobal.h", so they automatically have
access to GTest/GMock macros as well as the imported main function.

CMakeLists.txt
cmake/QuasselMacros.cmake
src/CMakeLists.txt
src/test/CMakeLists.txt [new file with mode: 0644]
src/test/main/CMakeLists.txt [new file with mode: 0644]
src/test/main/main.cpp [new file with mode: 0644]
src/test/main/testglobal.h [new file with mode: 0644]

index 8af98b1..413c46d 100644 (file)
@@ -338,7 +338,30 @@ if (NOT WIN32)
     )
 endif()
 
+# Setup unit testing
+#####################################################################
+
+option(BUILD_TESTING "Enable unit tests" OFF)
+add_feature_info(BUILD_TESTING BUILD_TESTING "Build unit tests")
+
+if (BUILD_TESTING)
+    find_package(GTest QUIET)
+    set_package_properties(GTest PROPERTIES TYPE REQUIRED
+        DESCRIPTION "Google's unit testing framework"
+        PURPOSE "Required for building unit tests"
+    )
+
+    find_package(Qt5Test QUIET)
+    set_package_properties(Qt5Test PROPERTIES TYPE REQUIRED
+        DESCRIPTION "unit testing library for the Qt5 framework"
+        PURPOSE "Required for building unit tests"
+    )
+    enable_testing()
+endif()
+
 # Check for SSL support in Qt
+#####################################################################
+
 cmake_push_check_state(RESET)
 set(CMAKE_REQUIRED_LIBRARIES Qt5::Core)
 check_cxx_source_compiles("
index 3af589a..62ad20c 100644 (file)
@@ -33,7 +33,7 @@ include(QuasselCompileFeatures)
 # the alias name.
 #
 function(quassel_add_module _module)
-    set(options EXPORT STATIC)
+    set(options EXPORT STATIC NOINSTALL)
     set(oneValueArgs )
     set(multiValueArgs )
     cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
@@ -66,7 +66,7 @@ function(quassel_add_module _module)
         VERSION ${QUASSEL_MAJOR}.${QUASSEL_MINOR}.${QUASSEL_PATCH}
     )
 
-    if (buildmode STREQUAL "SHARED")
+    if (buildmode STREQUAL "SHARED" AND NOT ${ARG_NOINSTALL})
         install(TARGETS ${target}
             RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
             LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
@@ -168,6 +168,63 @@ function(quassel_add_resource _name)
     set(RESOURCE_TARGET ${TARGET} PARENT_SCOPE)
 endfunction()
 
+###################################################################################################
+# Adds a unit test case
+#
+# quassel_add_test(TestName
+#                  [LIBRARIES lib1 lib2...]
+# )
+#
+# The test name is given in CamelCase as first and mandatory parameter. The corresponding source file
+# is expected the lower-cased test name plus the .cpp extension.
+# The test case is automatically linked against Qt5::Test, GMock, Quassel::Common and
+# Quassel::Test::Main, which contains the main function. This main function also instantiates a
+# QCoreApplication, so the event loop can be used in test cases.
+#
+# Additional libraries can be given using the LIBRARIES argument.
+#
+# Test cases should include testglobal.h, which transitively includes the GTest/GMock headers and
+# exports the main function.
+#
+# The compiled test case binary is located in the unit/ directory in the build directory.
+#
+function(quassel_add_test _target)
+    set(options )
+    set(oneValueArgs )
+    set(multiValueArgs LIBRARIES)
+    cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+    string(TOLOWER ${_target} lower_target)
+    set(srcfile ${lower_target}.cpp)
+
+    list(APPEND ARG_LIBRARIES
+        Qt5::Test
+        Quassel::Common
+        Quassel::Test::Main
+    )
+
+    if (WIN32)
+        # On Windows, tests need to be built in the same directory that contains the libraries
+        set(output_dir "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
+    else()
+        # On other platforms, separate the test cases out
+        set(output_dir "${CMAKE_BINARY_DIR}/unit")
+    endif()
+
+    add_executable(${_target} ${srcfile})
+    set_target_properties(${_target} PROPERTIES
+        OUTPUT_NAME ${_target}
+        RUNTIME_OUTPUT_DIRECTORY "${output_dir}"
+    )
+    target_link_libraries(${_target} PUBLIC ${ARG_LIBRARIES})
+
+    add_test(
+        NAME ${_target}
+        COMMAND $<TARGET_FILE:${_target}>
+        WORKING_DIRECTORY "${CMAKE_BINARY_DIR}"
+    )
+endfunction()
+
 ###################################################################################################
 # target_link_if_exists(Target
 #                       [PUBLIC dep1 dep2...]
index 7b2a512..130144b 100644 (file)
@@ -8,3 +8,7 @@ if (BUILD_GUI)
     add_subdirectory(uisupport)
     add_subdirectory(qtui)
 endif()
+
+if (BUILD_TESTING)
+    add_subdirectory(test)
+endif()
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
new file mode 100644 (file)
index 0000000..9a263aa
--- /dev/null
@@ -0,0 +1 @@
+add_subdirectory(main)
diff --git a/src/test/main/CMakeLists.txt b/src/test/main/CMakeLists.txt
new file mode 100644 (file)
index 0000000..6d6993f
--- /dev/null
@@ -0,0 +1,13 @@
+quassel_add_module(Test::Main EXPORT NOINSTALL)
+
+target_sources(${TARGET} PRIVATE
+    main.cpp
+    testglobal.h
+)
+
+target_link_libraries(${TARGET}
+    PUBLIC
+        GTest::GTest
+        Qt5::Core
+        Quassel::Common
+)
diff --git a/src/test/main/main.cpp b/src/test/main/main.cpp
new file mode 100644 (file)
index 0000000..08adf10
--- /dev/null
@@ -0,0 +1,33 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#include "test-main-export.h"
+
+#include <gmock/gmock.h>
+
+#include <QCoreApplication>
+
+TEST_MAIN_EXPORT int main(int argc, char **argv)
+{
+    ::testing::InitGoogleTest(&argc, argv);
+    QCoreApplication app(argc, argv);
+
+    return RUN_ALL_TESTS();
+}
diff --git a/src/test/main/testglobal.h b/src/test/main/testglobal.h
new file mode 100644 (file)
index 0000000..3276377
--- /dev/null
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *   Copyright (C) 2005-2018 by the Quassel Project                        *
+ *   devel@quassel-irc.org                                                 *
+ *                                                                         *
+ *   This program is free software; you can redistribute it and/or modify  *
+ *   it under the terms of the GNU General Public License as published by  *
+ *   the Free Software Foundation; either version 2 of the License, or     *
+ *   (at your option) version 3.                                           *
+ *                                                                         *
+ *   This program is distributed in the hope that it will be useful,       *
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
+ *   GNU General Public License for more details.                          *
+ *                                                                         *
+ *   You should have received a copy of the GNU General Public License     *
+ *   along with this program; if not, write to the                         *
+ *   Free Software Foundation, Inc.,                                       *
+ *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
+ ***************************************************************************/
+
+#pragma once
+
+#include <gmock/gmock.h>
+
+#include "test-main-export.h"