diff --git a/CMakeLists.txt b/CMakeLists.txt index c451d172dc62acfacb782e70643c4b25b6a26df3..abbbe2263435901db26463bafe1cc5bdaf9bf993 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ SET(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/lib) SET(CMAKE_INSTALL_PREFIX /usr/local) IF (NOT CMAKE_BUILD_TYPE) - SET(CMAKE_BUILD_TYPE "DEBUG") + SET(CMAKE_BUILD_TYPE "RELEASE") ENDIF (NOT CMAKE_BUILD_TYPE) message(STATUS "Configured to compile in ${CMAKE_BUILD_TYPE} mode.") @@ -65,6 +65,9 @@ else() endif() +#OPTION(BUILD_DOC "Build Documentation" OFF) +OPTION(BUILD_TESTS "Build Unit tests" ON) + ADD_SUBDIRECTORY(src) FIND_PACKAGE(Doxygen) @@ -124,3 +127,17 @@ ELSE(UNIX) TARGET uninstall) ENDIF(UNIX) +############# +## Testing ## +############# + +if(BUILD_TESTS) + +# Enables testing for this directory and below. +# Note that ctest expects to find a test file in the build directory root. +# Therefore, this command should be in the source directory root. +enable_testing() + +add_subdirectory(${PROJECT_SOURCE_DIR}/test) + +endif() diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 54e6a57b33fe505a1dbf94016ce44ab68ea74ebc..cacea95576ec6651a37fdd4cb05e67bab71b0135 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -31,6 +31,8 @@ option(BUILD_EXAMPLES "Build examples" ON) FIND_PACKAGE(Eigen 3 REQUIRED) +FIND_PACKAGE(Threads REQUIRED) + FIND_PACKAGE(Ceres QUIET) #Ceres is not required IF(Ceres_FOUND) MESSAGE("Ceres Library FOUND: Ceres related sources will be built.") @@ -395,10 +397,9 @@ IF(YAMLCPP_FOUND) ENDIF(laser_scan_utils_FOUND) ENDIF(YAMLCPP_FOUND) - - # create the shared library ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_WRAPPER}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_THREAD_LIBS_INIT}) #Link the created libraries #============================================================= diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..f89fb92d9831de007a72e5d3d269513b820b9fc9 --- /dev/null +++ b/test/CMakeLists.txt @@ -0,0 +1,14 @@ +# Retrieve googletest from github & compile +add_subdirectory(${PROJECT_SOURCE_DIR}/test/gtest) + +# Include config.h directory at first. +include_directories(${PROJECT_BINARY_DIR}/conf/) + +include_directories(${GTEST_INCLUDE_DIRS}) + +# Create a specific test executable for gtest_example +wolf_add_gtest(gtest_example gtest_example.cpp) +target_link_libraries(gtest_example ${PROJECT_NAME}) + +wolf_add_gtest(gtest_time_stamp gtest_time_stamp.cpp) +target_link_libraries(gtest_time_stamp ${PROJECT_NAME}) diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..6dcfd702d15939724e27b0fdd43c0ab5d1ef87e2 --- /dev/null +++ b/test/gtest/CMakeLists.txt @@ -0,0 +1,62 @@ +cmake_minimum_required(VERSION 2.8.8) +project(gtest_builder C CXX) + +# We need thread support +#find_package(Threads REQUIRED) + +# Enable ExternalProject CMake module +include(ExternalProject) + +set(GTEST_FORCE_SHARED_CRT ON) +set(GTEST_DISABLE_PTHREADS OFF) + +# For some reason I need to disable PTHREADS +# with g++ (Ubuntu 4.9.3-8ubuntu2~14.04) 4.9.3 +# This is a known issue for MinGW : +# https://github.com/google/shaderc/pull/174 +#if(MINGW) + set(GTEST_DISABLE_PTHREADS ON) +#endif() + +# Download GoogleTest +ExternalProject_Add(googletest + GIT_REPOSITORY https://github.com/google/googletest.git + CMAKE_ARGS -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG:PATH=DebugLibs + -DCMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE:PATH=ReleaseLibs + -DCMAKE_CXX_FLAGS=${MSVC_COMPILER_DEFS} + -Dgtest_force_shared_crt=${GTEST_FORCE_SHARED_CRT} + -Dgtest_disable_pthreads=${GTEST_DISABLE_PTHREADS} + -DBUILD_GTEST=ON + PREFIX "${CMAKE_CURRENT_BINARY_DIR}" + # Disable install step + INSTALL_COMMAND "" +) + +# Get GTest source and binary directories from CMake project + +# Specify include dir +ExternalProject_Get_Property(googletest source_dir) +set(GTEST_INCLUDE_DIRS ${source_dir}/googletest/include PARENT_SCOPE) + +# Specify MainTest's link libraries +ExternalProject_Get_Property(googletest binary_dir) +set(GTEST_LIBS_DIR ${binary_dir}/googlemock/gtest PARENT_SCOPE) + +# Create a libgtest target to be used as a dependency by test programs +add_library(libgtest IMPORTED STATIC GLOBAL) +add_dependencies(libgtest googletest) + +# Set libgtest properties +set_target_properties(libgtest PROPERTIES + "IMPORTED_LOCATION" "${binary_dir}/googlemock/gtest/libgtest.a" + "IMPORTED_LINK_INTERFACE_LIBRARIES" "${CMAKE_THREAD_LIBS_INIT}" +) + +function(wolf_add_gtest target) + add_executable(${target} ${ARGN}) + add_dependencies(${target} libgtest) + target_link_libraries(${target} libgtest) + + #WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin + add_test(NAME ${target} COMMAND ${target}) +endfunction() diff --git a/test/gtest_example.cpp b/test/gtest_example.cpp new file mode 100644 index 0000000000000000000000000000000000000000..9c4ae7a14daf9d9923ec040dea90629eb5c32b5d --- /dev/null +++ b/test/gtest_example.cpp @@ -0,0 +1,20 @@ +#include "utils_gtest.h" + +TEST(TestTest, DummyTestExample) +{ + EXPECT_FALSE(false); + + ASSERT_TRUE(true); + + int my_int = 5; + + ASSERT_EQ(my_int, 5); + + PRINTF("All good at TestTest::DummyTestExample !\n"); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/gtest_time_stamp.cpp b/test/gtest_time_stamp.cpp new file mode 100644 index 0000000000000000000000000000000000000000..39a75e615d59da6519212dcf5fe5d575759f2b56 --- /dev/null +++ b/test/gtest_time_stamp.cpp @@ -0,0 +1,114 @@ +#include "utils_gtest.h" +#include "../src/time_stamp.h" + +#include <thread> + +TEST(WolfTestTimeStamp, TimeStampInitNow) +{ + wolf::TimeStamp start; + + // If we don't sleep, start == time_stamp sometimes. + // And sometimes start <= time_stamp ... + std::this_thread::sleep_for(std::chrono::microseconds(1)); + + ASSERT_NE(start.get(), 0); + + wolf::TimeStamp time_stamp; + +// std::cout << std::fixed; +// std::cout << std::setprecision(15); +// std::cout << start.get() << " | " << time_stamp.get() << std::endl; + + ASSERT_NE(time_stamp.get(), start.get()); + + ASSERT_LT(start.get(), time_stamp.get()); + + PRINTF("All good at WolfTestTimeStamp::TimeStampInitNow !\n"); +} + +TEST(WolfTestTimeStamp, TimeStampInitScalar) +{ + wolf::Scalar val(101010); + + wolf::TimeStamp start(val); + + ASSERT_EQ(start.get(), val); + ASSERT_EQ(start.getSeconds(), val); + ASSERT_EQ(start.getNanoSeconds(), 0); + + std::stringstream ss; + start.print(ss); + + ASSERT_STREQ("101010.0000000000", ss.str().c_str()); + + PRINTF("All good at WolfTestTimeStamp::TimeStampInitScalar !\n"); +} + +TEST(WolfTestTimeStamp, TimeStampInitScalarSecNano) +{ + wolf::Scalar sec(101010); + wolf::Scalar nano(202020); + wolf::Scalar val(101010.000202020); + + wolf::TimeStamp start(sec, nano); + + // start.get -> 101010.000202020004508 + + ASSERT_EQ(start.get(), val); + ASSERT_EQ(start.getSeconds(), sec); + ASSERT_EQ(start.getNanoSeconds(), nano); + + std::stringstream ss; + start.print(ss); + + ASSERT_STREQ("101010.0002020200", ss.str().c_str()); + + PRINTF("All good at WolfTestTimeStamp::TimeStampInitScalarSecNano !\n"); +} + +TEST(WolfTestTimeStamp, TimeStampEquality) +{ + wolf::TimeStamp start; + + wolf::TimeStamp time_stamp(start); + + // error: no match for ‘operator==’ + //ASSERT_EQ(time_stamp, start); + + ASSERT_EQ(time_stamp.get(), start.get()); + + time_stamp.setToNow(); + + ASSERT_NE(time_stamp.get(), start.get()); + + time_stamp = start; + + ASSERT_EQ(time_stamp.get(), start.get()); + + PRINTF("All good at WolfTestTimeStamp::TimeStampEquality !\n"); +} + +TEST(WolfTestTimeStamp, TimeStampInequality) +{ + wolf::TimeStamp start; + + std::this_thread::sleep_for(std::chrono::microseconds(1)); + + wolf::TimeStamp time_stamp; + + // error: no match for ‘operator!=’ + //ASSERT_NE(time_stamp, start); + + ASSERT_LT(start, time_stamp); + + // error: no match for ‘operator>’ + //ASSERT_GT(time_stamp, start); + + PRINTF("All good at WolfTestTimeStamp::TimeStampInequality !\n"); +} + +int main(int argc, char **argv) +{ + testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} diff --git a/test/utils_gtest.h b/test/utils_gtest.h new file mode 100644 index 0000000000000000000000000000000000000000..9e792f5a33327dc73dcff5c860f1c9fe53a56709 --- /dev/null +++ b/test/utils_gtest.h @@ -0,0 +1,82 @@ +/** + * \file utils_gtest.h + * \brief Some utils for gtest + * \author Jeremie Deray + * Created on: 26/09/2016 + */ + +#ifndef WOLF_UTILS_GTEST_H +#define WOLF_UTILS_GTEST_H + +#include <gtest/gtest.h> + + +// Macros for testing equalities and inequalities. +// +// * {ASSERT|EXPECT}_EQ(expected, actual): Tests that expected == actual +// * {ASSERT|EXPECT}_NE(v1, v2): Tests that v1 != v2 +// * {ASSERT|EXPECT}_LT(v1, v2): Tests that v1 < v2 +// * {ASSERT|EXPECT}_LE(v1, v2): Tests that v1 <= v2 +// * {ASSERT|EXPECT}_GT(v1, v2): Tests that v1 > v2 +// * {ASSERT|EXPECT}_GE(v1, v2): Tests that v1 >= v2 + + +// http://stackoverflow.com/a/29155677 + +namespace testing +{ +namespace internal +{ +enum GTestColor +{ + COLOR_DEFAULT, + COLOR_RED, + COLOR_GREEN, + COLOR_YELLOW +}; + +extern void ColoredPrintf(GTestColor color, const char* fmt, ...); + +#define PRINTF(...) \ + do { testing::internal::ColoredPrintf(testing::internal::COLOR_GREEN,\ + "[ ] "); \ + testing::internal::ColoredPrintf(testing::internal::COLOR_YELLOW, __VA_ARGS__); } \ + while(0) + +// C++ stream interface +class TestCout : public std::stringstream +{ +public: + ~TestCout() + { + PRINTF("%s\n", str().c_str()); + } +}; + +#define TEST_COUT testing::internal::TestCout() + +} // namespace internal +} // namespace testing + +/** Usage : + +TEST(Test, Foo) +{ + // the following works but prints default stream + EXPECT_TRUE(false) << "Testing Stream."; + + // or you can play with AINSI color code + EXPECT_TRUE(false) << "\033[1;31m" << "Testing Stream."; + + // or use the above defined macros + + PRINTF("Hello world"); + + // or + + TEST_COUT << "Hello world"; +} + +*/ + +#endif /* WOLF_UTILS_GTEST_H */