From 02ac1a43c12c821c92a2e416d0ec343dbe5784e7 Mon Sep 17 00:00:00 2001 From: Thomas Geymayer Date: Thu, 8 May 2014 02:02:36 +0200 Subject: [PATCH] Add smart pointer tests (finally using Boost.Test) --- CMakeLists.txt | 3 + CMakeModules/BoostTestTargets.cmake | 275 ++++++++++++++++++ CMakeModules/BoostTestTargetsDynamic.h | 8 + CMakeModules/BoostTestTargetsIncluded.h | 7 + CMakeModules/BoostTestTargetsStatic.h | 7 + CMakeModules/CopyResourcesToBuildTree.cmake | 83 ++++++ CMakeModules/GetForceIncludeDefinitions.cmake | 44 +++ simgear/structure/CMakeLists.txt | 5 + simgear/structure/shared_ptr_test.cpp | 90 ++++++ 9 files changed, 522 insertions(+) create mode 100644 CMakeModules/BoostTestTargets.cmake create mode 100644 CMakeModules/BoostTestTargetsDynamic.h create mode 100644 CMakeModules/BoostTestTargetsIncluded.h create mode 100644 CMakeModules/BoostTestTargetsStatic.h create mode 100644 CMakeModules/CopyResourcesToBuildTree.cmake create mode 100644 CMakeModules/GetForceIncludeDefinitions.cmake create mode 100644 simgear/structure/shared_ptr_test.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c2ad568b..7af05c81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -163,6 +163,9 @@ if(APPLE) find_library(COCOA_LIBRARY Cocoa) endif() +# Somehow this only works if included before searching for Boost... +include(BoostTestTargets) + find_package(Boost REQUIRED) set (BOOST_CXX_FLAGS "-DBOOST_MULTI_INDEX_DISABLE_SERIALIZATION -DBOOST_BIMAP_DISABLE_SERIALIZATION") diff --git a/CMakeModules/BoostTestTargets.cmake b/CMakeModules/BoostTestTargets.cmake new file mode 100644 index 00000000..c3d5dbe1 --- /dev/null +++ b/CMakeModules/BoostTestTargets.cmake @@ -0,0 +1,275 @@ +# - Add tests using boost::test +# +# Add this line to your test files in place of including a basic boost test header: +# #include +# +# If you cannot do that and must use the included form for a given test, +# include the line +# // OVERRIDE_BOOST_TEST_INCLUDED_WARNING +# in the same file with the boost test include. +# +# include(BoostTestTargets) +# add_boost_test( SOURCES [] +# [FAIL_REGULAR_EXPRESSION ] +# [LAUNCHER ] +# [LIBRARIES [...]] +# [RESOURCES [...]] +# [TESTS [...]]) +# +# If for some reason you need access to the executable target created, +# it can be found in ${${testdriver_name}_TARGET_NAME} as specified when +# you called add_boost_test +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Requires: +# GetForceIncludeDefinitions +# CopyResourcesToBuildTree +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__add_boost_test) + return() +endif() +set(__add_boost_test YES) + +set(BOOST_TEST_TARGET_PREFIX "boosttest") + +if(NOT Boost_FOUND) + find_package(Boost 1.34.0 QUIET) +endif() +if("${Boost_VERSION}0" LESS "1034000") + set(_shared_msg + "NOTE: boost::test-based targets and tests cannot " + "be added: boost >= 1.34.0 required but not found. " + "(found: '${Boost_VERSION}'; want >=103400) ") + if(BUILD_TESTING) + message(FATAL_ERROR + ${_shared_msg} + "You may disable BUILD_TESTING to continue without the " + "tests.") + else() + message(STATUS + ${_shared_msg} + "BUILD_TESTING disabled, so continuing anyway.") + endif() +endif() + +include(GetForceIncludeDefinitions) +include(CopyResourcesToBuildTree) + +if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000") + set(_boosttesttargets_libs) + set(_boostConfig "BoostTestTargetsIncluded.h") + if(NOT Boost_UNIT_TEST_FRAMEWORK_LIBRARY) + find_package(Boost 1.34.0 QUIET COMPONENTS unit_test_framework) + endif() + if(Boost_UNIT_TEST_FRAMEWORK_LIBRARY) + set(_boosttesttargets_libs "${Boost_UNIT_TEST_FRAMEWORK_LIBRARY}") + if(Boost_USE_STATIC_LIBS) + set(_boostConfig "BoostTestTargetsStatic.h") + else() + if(NOT APPLE) + set(_boostConfig "BoostTestTargetsDynamic.h") + endif() + endif() + endif() + get_filename_component(_moddir ${CMAKE_CURRENT_LIST_FILE} PATH) + configure_file("${_moddir}/${_boostConfig}" + "${CMAKE_CURRENT_BINARY_DIR}/BoostTestTargetConfig.h" + COPYONLY) + include_directories("${CMAKE_CURRENT_BINARY_DIR}") +endif() + +function(add_boost_test _name) + if(NOT BUILD_TESTING) + return() + endif() +# TODO check if 2.6 is enough +# if("${CMAKE_VERSION}" VERSION_LESS "2.8.0") +# if(NOT "${_boost_test_cmakever_pestered}x" EQUAL "${CMAKE_VERSION}x") +# message(STATUS +# "Not adding boost::test targets - CMake 2.8.0 or newer required, using ${CMAKE_VERSION}") +# set(_boost_test_cmakever_pestered +# "${CMAKE_VERSION}" +# CACHE +# INTERNAL +# "" +# FORCE) +# endif() +# return() +# endif() + + # parse arguments + set(_nowhere) + set(_curdest _nowhere) + set(_val_args + SOURCES + FAIL_REGULAR_EXPRESSION + LAUNCHER + LIBRARIES + RESOURCES + TESTS) + set(_bool_args + USE_COMPILED_LIBRARY) + foreach(_arg ${_val_args} ${_bool_args}) + set(${_arg}) + endforeach() + foreach(_element ${ARGN}) + list(FIND _val_args "${_element}" _val_arg_find) + list(FIND _bool_args "${_element}" _bool_arg_find) + if("${_val_arg_find}" GREATER "-1") + set(_curdest "${_element}") + elseif("${_bool_arg_find}" GREATER "-1") + set("${_element}" ON) + set(_curdest _nowhere) + else() + list(APPEND ${_curdest} "${_element}") + endif() + endforeach() + + if(_nowhere) + message(FATAL_ERROR "Syntax error in use of add_boost_test!") + endif() + + if(NOT SOURCES) + message(FATAL_ERROR + "Syntax error in use of add_boost_test: at least one source file required!") + endif() + + if(Boost_FOUND AND NOT "${Boost_VERSION}0" LESS "1034000") + + include_directories(${Boost_INCLUDE_DIRS}) + + set(includeType) + foreach(src ${SOURCES}) + file(READ ${src} thefile) + if("${thefile}" MATCHES ".*BoostTestTargetConfig.h.*") + set(includeType CONFIGURED) + set(includeFileLoc ${src}) + break() + elseif("${thefile}" MATCHES ".*boost/test/included/unit_test.hpp.*") + set(includeType INCLUDED) + set(includeFileLoc ${src}) + set(_boosttesttargets_libs) # clear this out - linking would be a bad idea + if(NOT + "${thefile}" + MATCHES + ".*OVERRIDE_BOOST_TEST_INCLUDED_WARNING.*") + message("Please replace the include line in ${src} with this alternate include line instead:") + message(" \#include ") + message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") + endif() + break() + endif() + endforeach() + + if(NOT _boostTestTargetsNagged${_name} STREQUAL "${includeType}") + if("includeType" STREQUAL "CONFIGURED") + message(STATUS + "Test '${_name}' uses the CMake-configurable form of the boost test framework - congrats! (Including File: ${includeFileLoc})") + elseif("${includeType}" STREQUAL "INCLUDED") + message("In test '${_name}': ${includeFileLoc} uses the 'included' form of the boost unit test framework.") + else() + message("In test '${_name}': Didn't detect the CMake-configurable boost test include.") + message("Please replace your existing boost test include in that test with the following:") + message(" \#include ") + message("Once you've saved your changes, re-run CMake. (See BoostTestTargets.cmake for more info)") + endif() + endif() + set(_boostTestTargetsNagged${_name} + "${includeType}" + CACHE + INTERNAL + "" + FORCE) + + + if(RESOURCES) + list(APPEND SOURCES ${RESOURCES}) + endif() + + # Generate a unique target name, using the relative binary dir + # and provided name. (transform all / into _ and remove all other + # non-alphabet characters) + file(RELATIVE_PATH + targetpath + "${CMAKE_BINARY_DIR}" + "${CMAKE_CURRENT_BINARY_DIR}") + string(REGEX REPLACE "[^A-Za-z/_]" "" targetpath "${targetpath}") + string(REPLACE "/" "_" targetpath "${targetpath}") + + set(_target_name ${BOOST_TEST_TARGET_PREFIX}-${targetpath}-${_name}) + set(${_name}_TARGET_NAME "${_target_name}" PARENT_SCOPE) + + # Build the test. + add_executable(${_target_name} ${SOURCES}) + + list(APPEND LIBRARIES ${_boosttesttargets_libs}) + + if(LIBRARIES) + target_link_libraries(${_target_name} ${LIBRARIES}) + endif() + + if(RESOURCES) + set_property(TARGET ${_target_name} PROPERTY RESOURCE ${RESOURCES}) + copy_resources_to_build_tree(${_target_name}) + endif() + + if(NOT Boost_TEST_FLAGS) +# set(Boost_TEST_FLAGS --catch_system_error=yes --output_format=XML) + set(Boost_TEST_FLAGS --catch_system_error=yes) + endif() + + # TODO: Figure out why only recent boost handles individual test running properly + + if(LAUNCHER) + set(_test_command ${LAUNCHER} "\$") + else() + set(_test_command ${_target_name}) + endif() + + if(TESTS AND ( "${Boost_VERSION}" VERSION_GREATER "103799" )) + foreach(_test ${TESTS}) + add_test(NAME + ${_name}-${_test} + COMMAND + ${_test_command} + --run_test=${_test} + ${Boost_TEST_FLAGS}) + if(FAIL_REGULAR_EXPRESSION) + set_tests_properties(${_name}-${_test} + PROPERTIES + FAIL_REGULAR_EXPRESSION + "${FAIL_REGULAR_EXPRESSION}") + endif() + endforeach() + else() + add_test(NAME + ${_name}-boost_test + COMMAND + ${_test_command} + ${Boost_TEST_FLAGS}) + if(FAIL_REGULAR_EXPRESSION) + set_tests_properties(${_name}-${_test} + PROPERTIES + FAIL_REGULAR_EXPRESSION + "${FAIL_REGULAR_EXPRESSION}") + endif() + endif() + + # CppCheck the test if we can. + if(COMMAND add_cppcheck) + add_cppcheck(${_target_name} STYLE UNUSED_FUNCTIONS) + endif() + + endif() +endfunction() diff --git a/CMakeModules/BoostTestTargetsDynamic.h b/CMakeModules/BoostTestTargetsDynamic.h new file mode 100644 index 00000000..4bff5677 --- /dev/null +++ b/CMakeModules/BoostTestTargetsDynamic.h @@ -0,0 +1,8 @@ +// Small header computed by CMake to set up boost test. +// include AFTER #define BOOST_TEST_MODULE whatever +// but before any other boost test includes. + +// Using the Boost UTF dynamic library + +#define BOOST_TEST_DYN_LINK +#include diff --git a/CMakeModules/BoostTestTargetsIncluded.h b/CMakeModules/BoostTestTargetsIncluded.h new file mode 100644 index 00000000..253133ce --- /dev/null +++ b/CMakeModules/BoostTestTargetsIncluded.h @@ -0,0 +1,7 @@ +// Small header computed by CMake to set up boost test. +// include AFTER #define BOOST_TEST_MODULE whatever +// but before any other boost test includes. + +// Using the Boost UTF included framework + +#include diff --git a/CMakeModules/BoostTestTargetsStatic.h b/CMakeModules/BoostTestTargetsStatic.h new file mode 100644 index 00000000..dd3cddae --- /dev/null +++ b/CMakeModules/BoostTestTargetsStatic.h @@ -0,0 +1,7 @@ +// Small header computed by CMake to set up boost test. +// include AFTER #define BOOST_TEST_MODULE whatever +// but before any other boost test includes. + +// Using the Boost UTF static library + +#include diff --git a/CMakeModules/CopyResourcesToBuildTree.cmake b/CMakeModules/CopyResourcesToBuildTree.cmake new file mode 100644 index 00000000..3512cc48 --- /dev/null +++ b/CMakeModules/CopyResourcesToBuildTree.cmake @@ -0,0 +1,83 @@ +# - Copy the resources your app needs to the build tree. +# +# copy_resources_to_build_tree() +# +# Requires CMake 2.6 or newer (uses the 'function' command) +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__copy_resources_to_build_tree) + return() +endif() +set(__copy_resources_to_build_tree YES) + +function(copy_resources_to_build_tree _target) + get_target_property(_resources ${_target} RESOURCE) + if(NOT _resources) + # Bail if no resources + message(STATUS + "Told to copy resources for target ${_target}, but " + "no resources are set!") + return() + endif() + + get_target_property(_path ${_target} LOCATION) + get_filename_component(_path "${_path}" PATH) + + if(NOT MSVC AND NOT "${CMAKE_GENERATOR}" MATCHES "Makefiles") + foreach(_config ${CMAKE_CONFIGURATION_TYPES}) + get_target_property(_path${_config} ${_target} LOCATION_${_config}) + get_filename_component(_path${_config} "${_path${_config}}" PATH) + add_custom_command(TARGET ${_target} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} + ARGS -E make_directory "${_path${_config}}/" + COMMENT "Creating directory ${_path${_config}}/") + endforeach() + endif() + + foreach(_res ${_resources}) + if(NOT IS_ABSOLUTE "${_res}") + get_filename_component(_res "${_res}" ABSOLUTE) + endif() + get_filename_component(_name "${_res}" NAME) + + if(MSVC) + # Working dir is solution file dir, not exe file dir. + add_custom_command(TARGET ${_target} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} + ARGS -E copy "${_res}" "${CMAKE_BINARY_DIR}/" + COMMENT "Copying ${_name} to ${CMAKE_BINARY_DIR}/ for MSVC") + else() + if("${CMAKE_GENERATOR}" MATCHES "Makefiles") + add_custom_command(TARGET ${_target} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} + ARGS -E copy "${_res}" "${_path}/" + COMMENT "Copying ${_name} to ${_path}/") + else() + foreach(_config ${CMAKE_CONFIGURATION_TYPES}) + add_custom_command(TARGET ${_target} + POST_BUILD + COMMAND + ${CMAKE_COMMAND} + ARGS -E copy "${_res}" "${_path${_config}}" + COMMENT "Copying ${_name} to ${_path${_config}}") + endforeach() + + endif() + endif() + endforeach() +endfunction() diff --git a/CMakeModules/GetForceIncludeDefinitions.cmake b/CMakeModules/GetForceIncludeDefinitions.cmake new file mode 100644 index 00000000..efcca047 --- /dev/null +++ b/CMakeModules/GetForceIncludeDefinitions.cmake @@ -0,0 +1,44 @@ +# - Get the platform-appropriate flags to add to force inclusion of a file +# +# The most common use of this is to use a generated config.h-type file +# placed out of the source tree in all files. +# +# get_force_include_definitions(var forcedincludefiles...) - +# where var is the name of your desired output variable, and everything +# else is a source file to forcibly include. +# a list item to be filtered. +# +# Original Author: +# 2009-2010 Ryan Pavlik +# http://academic.cleardefinition.com +# Iowa State University HCI Graduate Program/VRAC +# +# Copyright Iowa State University 2009-2010. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +if(__get_force_include_definitions) + return() +endif() +set(__get_force_include_definitions YES) + +function(get_force_include_definitions var) + set(_flagprefix) + if(CMAKE_COMPILER_IS_GNUCXX) + set(_flag "-include") + elseif(MSVC) + set(_flag "/FI") + else() + message(SEND_ERROR "You don't seem to be using MSVC or GCC, but") + message(SEND_ERROR "the project called get_force_include_definitions.") + message(SEND_ERROR "Contact this project with the name of your") + message(FATAL_ERROR "compiler and preferably the flag to force includes") + endif() + + set(_out) + foreach(_item ${ARGN}) + list(APPEND _out "${_flag} \"${_item}\"") + endforeach() + set(${var} "${_out}" PARENT_SCOPE) +endfunction() diff --git a/simgear/structure/CMakeLists.txt b/simgear/structure/CMakeLists.txt index c6180b29..7679588c 100644 --- a/simgear/structure/CMakeLists.txt +++ b/simgear/structure/CMakeLists.txt @@ -55,3 +55,8 @@ target_link_libraries(test_expressions ${TEST_LIBS}) add_test(expressions ${EXECUTABLE_OUTPUT_PATH}/test_expressions) endif(ENABLE_TESTS) + +add_boost_test(shared_ptr + SOURCES shared_ptr_test.cpp + LIBRARIES ${TEST_LIBS} +) diff --git a/simgear/structure/shared_ptr_test.cpp b/simgear/structure/shared_ptr_test.cpp new file mode 100644 index 00000000..d7b73641 --- /dev/null +++ b/simgear/structure/shared_ptr_test.cpp @@ -0,0 +1,90 @@ +/// Unit tests for reference counting and smart pointer classes +#define BOOST_TEST_MODULE structure +#include + +#include "SGSharedPtr.hxx" +#include "SGWeakPtr.hxx" + +static int instance_count = 0; +struct ReferenceCounted: + public SGReferenced +{ + ReferenceCounted() + { + ++instance_count; + } + + ~ReferenceCounted() + { + --instance_count; + } +}; +typedef SGSharedPtr RefPtr; + +BOOST_AUTO_TEST_CASE( shared_ptr ) +{ + BOOST_REQUIRE_EQUAL( ReferenceCounted::count(0), 0 ); + + RefPtr ptr( new ReferenceCounted() ); + BOOST_REQUIRE_EQUAL( instance_count, 1 ); + BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr.get()), 1 ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 ); + + RefPtr ptr2 = ptr; + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 ); + BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 2 ); + + BOOST_REQUIRE_EQUAL( ptr, ptr2 ); + BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() ); + + ptr.reset(); + BOOST_REQUIRE( !ptr.get() ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 ); + BOOST_REQUIRE_EQUAL( ReferenceCounted::count(ptr2.get()), 1 ); + BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 1 ); + + ptr2.reset(); + BOOST_REQUIRE( !ptr2.get() ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 0 ); + BOOST_REQUIRE_EQUAL( ptr2.getNumRefs(), 0 ); + BOOST_REQUIRE_EQUAL( instance_count, 0) ; +} + +class Base1: + public virtual SGVirtualWeakReferenced +{}; + +class Base2: + public virtual SGVirtualWeakReferenced +{}; + +class VirtualDerived: + public Base1, + public Base2 +{}; + +BOOST_AUTO_TEST_CASE( virtual_weak_ptr ) +{ + SGSharedPtr ptr( new VirtualDerived() ); + SGWeakPtr weak_ptr( ptr ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 1 ); + + SGSharedPtr ptr1( weak_ptr.lock() ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 2 ); + + SGSharedPtr ptr2( weak_ptr.lock() ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 ); + + BOOST_REQUIRE( ptr != NULL ); + BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() ); + BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() ); + + SGWeakPtr weak_base1( ptr ); + SGWeakPtr weak_base2( ptr ); + ptr1 = dynamic_cast(weak_base1.lock().get()); + ptr2 = dynamic_cast(weak_base2.lock().get()); + + BOOST_REQUIRE_EQUAL( ptr.get(), ptr1.get() ); + BOOST_REQUIRE_EQUAL( ptr.get(), ptr2.get() ); + BOOST_REQUIRE_EQUAL( ptr.getNumRefs(), 3 ); +} -- 2.39.5