diff --git a/.drone.yml b/.drone.yml index 1157fe12f..a965508f1 100644 --- a/.drone.yml +++ b/.drone.yml @@ -1,11 +1,11 @@ pipeline: setup: - image: hbb:salmon_build + image: hbb:salmon_build_new commands: - echo "Starting build" - ./.drone/build.sh test_indexing: - image: hbb:salmon_build + image: hbb:salmon_build_new commands: - echo "[Testing quant]" - ./.drone/test_quant.sh @@ -13,7 +13,7 @@ - /mnt/scratch6/avi/data:/mnt/data - /mnt/scratch6/salmon_ci:/mnt/ci_res copy_build: - image: hbb:salmon_build + image: hbb:salmon_build_new commands: - echo "[Packaging binary]" - ./.drone/copy_build.sh diff --git a/.drone/build.sh b/.drone/build.sh index cd90c4652..f660c746f 100755 --- a/.drone/build.sh +++ b/.drone/build.sh @@ -1,8 +1,11 @@ #!/bin/bash -source /hbb_exe/activate +source /hbb_shlib/activate set -e +export CFLAGS="-g -O2 -I/hbb_shlib/include" +export CXXFLAGS="-g -O2 -I/hbb_shlib/include" + CPATH=`pwd` echo "[Drone build] current path : ${CPATH}" echo "[Drone build] making build directory" diff --git a/.drone/test_quant.sh b/.drone/test_quant.sh index ac93fbc69..8254f9cca 100755 --- a/.drone/test_quant.sh +++ b/.drone/test_quant.sh @@ -5,6 +5,8 @@ set -e CPATH=`pwd` echo "[Drone test] current path : ${CPATH}" +SD=`ls -la ${CPATH}` +echo "[subdirs] : ${SD}" echo "[Drone test] making quant test directory" export PATH=/root/miniconda2/bin:$PATH diff --git a/CMakeLists.txt b/CMakeLists.txt index 01366bbcb..cf2061e7a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -610,15 +610,12 @@ if (NOT CEREAL_FOUND) endif() ## Try and find TBB first -find_package(TBB 2019.0 COMPONENTS tbb tbbmalloc tbbmalloc_proxy) +find_package(TBB 2021.4 + HINTS ${TBB_ROOT_SEARCH} + COMPONENTS tbb tbbmalloc tbbmalloc_proxy) -## NOTE: we actually require at least 2019 U4 or greater -## since we are using tbb::global_control. However, they -## seem not to have tagged minor version numbers in their -## source. Check before release if we can bump to the 2020 -## version (requires having tbb 2020 for OSX). if (${TBB_FOUND}) - if (${TBB_VERSION} VERSION_GREATER_EQUAL 2019.0) + if (${TBB_VERSION} VERSION_GREATER_EQUAL 2021.4) message("FOUND SUITABLE TBB VERSION : ${TBB_VERSION}") set(TBB_TARGET_EXISTED TRUE) else() @@ -646,42 +643,42 @@ endif() message("Build system will fetch and build Intel Threading Building Blocks") message("==================================================================") # These are useful for the custom install step we'll do later -set(TBB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/oneTBB-2020.2) +set(TBB_SOURCE_DIR ${GAT_SOURCE_DIR}/external/oneTBB-2021.5.0) set(TBB_INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/install) if("${TBB_COMPILER}" STREQUAL "gcc") ## Don't know why it's a problem yet, but if we're using ## GCC, get rid of the DO_ITT_NOTIFY flag - set(TBB_CXXFLAGS "${TBB_CXXFLAGS} -UDO_ITT_NOTIFY") + # set(TBB_CXXFLAGS "${TBB_CXXFLAGS} -UDO_ITT_NOTIFY") endif() set(TBB_CXXFLAGS "${TBB_CXXFLAGS} ${CXXSTDFLAG} ${SCHAR_FLAG}") -externalproject_add(libtbb - DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external - DOWNLOAD_COMMAND curl -k -L https://github.com/oneapi-src/oneTBB/archive/v2020.2.tar.gz -o tbb-2020_U2.tgz && - ${SHASUM} 4804320e1e6cbe3a5421997b52199e3c1a3829b2ecb6489641da4b8e32faf500 tbb-2020_U2.tgz && - tar -xzvf tbb-2020_U2.tgz - SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/oneTBB-2020.2 - INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/install - PATCH_COMMAND "${TBB_PATCH_STEP}" - CONFIGURE_COMMAND "" - BUILD_COMMAND make ${QUIET_MAKE} CXXFLAGS=${TBB_CXXFLAGS} lambdas=1 compiler=${TBB_COMPILER} cfg=release tbb_build_prefix=LIBS - INSTALL_COMMAND sh -c "mkdir -p ${TBB_INSTALL_DIR}/include && mkdir -p ${TBB_INSTALL_DIR}/lib && cp ${TBB_SOURCE_DIR}/build/LIBS_release/*.${SHARED_LIB_EXTENSION}* ${TBB_INSTALL_DIR}/lib && cp -r ${TBB_SOURCE_DIR}/include/* ${TBB_INSTALL_DIR}/include" - BUILD_IN_SOURCE 1 +ExternalProject_Add(libtbb +DOWNLOAD_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external +DOWNLOAD_COMMAND curl -k -L https://github.com/oneapi-src/oneTBB/archive/refs/tags/v2021.5.0.tar.gz -o v2021.5.tar.gz && +${SHASUM} e5b57537c741400cf6134b428fc1689a649d7d38d9bb9c1b6d64f092ea28178a v2021.5.tar.gz && +tar -xzvf v2021.5.tar.gz +SOURCE_DIR ${TBB_SOURCE_DIR} +INSTALL_DIR ${TBB_INSTALL_DIR} +PATCH_COMMAND "${TBB_PATCH_STEP}" +CMAKE_ARGS -DCMAKE_CXX_FLAGS=${TBB_CXXFLAGS} -DCMAKE_INSTALL_PREFIX= -DTBB_TEST=OFF -DTBB_EXAMPLES=OFF -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} +BUILD_IN_SOURCE TRUE ) set(RECONFIG_FLAGS ${RECONFIG_FLAGS} -DTBB_WILL_RECONFIGURE=FALSE -DTBB_RECONFIGURE=TRUE) -externalproject_add_step(libtbb reconfigure - COMMAND ${CMAKE_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR} ${RECONFIG_FLAGS} - DEPENDEES install +ExternalProject_Add_Step(libtbb reconfigure +COMMAND ${CMAKE_COMMAND} ${CMAKE_CURRENT_SOURCE_DIR} ${RECONFIG_FLAGS} +DEPENDEES install ) - set(FETCHED_TBB TRUE) -if(${FETCHED_BOOST}) - add_dependencies(libtbb libboost) -endif() -endif() +set(TBB_ROOT_SEARCH ${CMAKE_SOURCE_DIR}/external/install) + + if(${FETCHED_BOOST}) + add_dependencies(libtbb libboost) + endif() + +endif() # end of fetch tbb ## # If we're fetching tbb, we need to have dummy paths for these variables @@ -697,6 +694,7 @@ if(TBB_WILL_RECONFIGURE) #set(TBB_LIBRARIES tbb tbbmalloc) set(TBB_LIBRARIES ${TBB_INSTALL_DIR}/lib/libtbb.${SHARED_LIB_EXTENSION} ${TBB_INSTALL_DIR}/lib/libtbbmalloc.${SHARED_LIB_EXTENSION} + ${TBB_INSTALL_DIR}/lib/libtbbmalloc_proxy.${SHARED_LIB_EXTENSION} ) message("TBB_INCLUDE_DIRS = ${TBB_INCLUDE_DIRS}") message("TBB_LIBRARY_DIRS = ${TBB_LIBRARY_DIRS}") @@ -725,11 +723,13 @@ if(TBB_RECONFIGURE) set(TBB_LIBRARY ${TBB_INSTALL_DIR}/lib) set(TBB_LIB_DIR ${TBB_INSTALL_DIR}/lib) message("TBB_INSTALL_DIR = ${TBB_INSTALL_DIR}") - find_package(TBB 2018.0 COMPONENTS tbb tbbmalloc tbbmalloc_proxy) + find_package(TBB 2021.4 + HINTS ${TBB_ROOT_SEARCH} + COMPONENTS tbb tbbmalloc tbbmalloc_proxy) message("[in TBB_RECONFIGURE] TBB_LIBRARIES = ${TBB_LIBRARIES}") endif() -message("TBB_LIBRARIES = ${TBB_LIBRARIES}") +#message("TBB_LIBRARIES = ${TBB_LIBRARIES}") #message("TBB_FOUND ${TBB_FOUND} ") #message("TBB_INSTALL_DIR ${TBB_INSTALL_DIR}") #message("TBB_INCLUDE_DIRS ${TBB_INCLUDE_DIRS}") @@ -754,14 +754,7 @@ if(NOT libgff_FOUND) DOWNLOAD_COMMAND curl -k -L https://github.com/COMBINE-lab/libgff/archive/v2.0.0.tar.gz -o libgff.tgz && ${SHASUM} 7656b19459a7ca7d2fd0fcec4f2e0fd0deec1b4f39c703a114e8f4c22d82a99c libgff.tgz && tar -xzvf libgff.tgz - ## - #URL https://github.com/COMBINE-lab/libgff/archive/v1.1.tar.gz - #DOWNLOAD_NAME libff.tgz - #URL_HASH SHA1=37b3147d78391d1fabbe6a0df313fbf516abbc6f - #TLS_VERIFY FALSE - ## SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/libgff-2.0.0 - #UPDATE_COMMAND sh -c "mkdir -p /build" INSTALL_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/install BINARY_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external/libgff-2.0.0/build CMAKE_ARGS -DCMAKE_INSTALL_PREFIX:PATH= -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} diff --git a/cmake/Modules/FindTBB.cmake b/cmake/Modules/FindTBB.cmake index c8b3eb531..cb41ab731 100644 --- a/cmake/Modules/FindTBB.cmake +++ b/cmake/Modules/FindTBB.cmake @@ -1,303 +1,94 @@ -# The MIT License (MIT) +# Copyright (c) 2020-2021 Intel Corporation # -# Copyright (c) 2015 Justus Calvin -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -# -# FindTBB -# ------- -# -# Find TBB include directories and libraries. -# -# Usage: -# -# find_package(TBB [major[.minor]] [EXACT] -# [QUIET] [REQUIRED] -# [[COMPONENTS] [components...]] -# [OPTIONAL_COMPONENTS components...]) -# -# where the allowed components are tbbmalloc and tbb_preview. Users may modify -# the behavior of this module with the following variables: -# -# * TBB_ROOT_DIR - The base directory the of TBB installation. -# * TBB_INCLUDE_DIR - The directory that contains the TBB headers files. -# * TBB_LIBRARY - The directory that contains the TBB library files. -# * TBB__LIBRARY - The path of the TBB the corresponding TBB library. -# These libraries, if specified, override the -# corresponding library search results, where -# may be tbb, tbb_debug, tbbmalloc, tbbmalloc_debug, -# tbb_preview, or tbb_preview_debug. -# * TBB_USE_DEBUG_BUILD - The debug version of tbb libraries, if present, will -# be used instead of the release version. -# -# Users may modify the behavior of this module with the following environment -# variables: -# -# * TBB_INSTALL_DIR -# * TBBROOT -# * LIBRARY_PATH +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at # -# This module will set the following variables: +# http://www.apache.org/licenses/LICENSE-2.0 # -# * TBB_FOUND - Set to false, or undefined, if we haven’t found, or -# don’t want to use TBB. -# * TBB__FOUND - If False, optional part of TBB sytem is -# not available. -# * TBB_VERSION - The full version string -# * TBB_VERSION_MAJOR - The major version -# * TBB_VERSION_MINOR - The minor version -# * TBB_INTERFACE_VERSION - The interface version number defined in -# tbb/tbb_stddef.h. -# * TBB__LIBRARY_RELEASE - The path of the TBB release version of -# , where may be tbb, tbb_debug, -# tbbmalloc, tbbmalloc_debug, tbb_preview, or -# tbb_preview_debug. -# * TBB__LIBRARY_DEGUG - The path of the TBB release version of -# , where may be tbb, tbb_debug, -# tbbmalloc, tbbmalloc_debug, tbb_preview, or -# tbb_preview_debug. -# -# The following varibles should be used to build and link with TBB: -# -# * TBB_INCLUDE_DIRS - The include directory for TBB. -# * TBB_LIBRARIES - The libraries to link against to use TBB. -# * TBB_LIBRARIES_RELEASE - The release libraries to link against to use TBB. -# * TBB_LIBRARIES_DEBUG - The debug libraries to link against to use TBB. -# * TBB_DEFINITIONS - Definitions to use when compiling code that uses -# TBB. -# * TBB_DEFINITIONS_RELEASE - Definitions to use when compiling release code that -# uses TBB. -# * TBB_DEFINITIONS_DEBUG - Definitions to use when compiling debug code that -# uses TBB. -# -# This module will also create the "tbb" target that may be used when building -# executables and libraries. +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. include(FindPackageHandleStandardArgs) -if(NOT TBB_FOUND) - - ################################## - # Check the build type - ################################## - - if(NOT DEFINED TBB_USE_DEBUG_BUILD) - if(CMAKE_BUILD_TYPE MATCHES "(Debug|DEBUG|debug|RelWithDebInfo|RELWITHDEBINFO|relwithdebinfo)") - set(TBB_BUILD_TYPE DEBUG) - else() - set(TBB_BUILD_TYPE RELEASE) - endif() - elseif(TBB_USE_DEBUG_BUILD) - set(TBB_BUILD_TYPE DEBUG) - else() - set(TBB_BUILD_TYPE RELEASE) - endif() - - ################################## - # Set the TBB search directories - ################################## - - # Define search paths based on user input and environment variables - set(TBB_SEARCH_DIR ${TBB_ROOT_DIR} $ENV{TBB_INSTALL_DIR} $ENV{TBBROOT}) - - # Define the search directories based on the current platform - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") - set(TBB_DEFAULT_SEARCH_DIR "C:/Program Files/Intel/TBB" - "C:/Program Files (x86)/Intel/TBB") - - # Set the target architecture - if(CMAKE_SIZEOF_VOID_P EQUAL 8) - set(TBB_ARCHITECTURE "intel64") - else() - set(TBB_ARCHITECTURE "ia32") - endif() - - # Set the TBB search library path search suffix based on the version of VC - if(WINDOWS_STORE) - set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11_ui") - elseif(MSVC14) - set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc14") - elseif(MSVC12) - set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc12") - elseif(MSVC11) - set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc11") - elseif(MSVC10) - set(TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc10") - endif() - - # Add the library path search suffix for the VC independent version of TBB - list(APPEND TBB_LIB_PATH_SUFFIX "lib/${TBB_ARCHITECTURE}/vc_mt") - - elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") - # OS X - set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") - - # TODO: Check to see which C++ library is being used by the compiler. - if(NOT ${CMAKE_SYSTEM_VERSION} VERSION_LESS 13.0) - # The default C++ library on OS X 10.9 and later is libc++ - set(TBB_LIB_PATH_SUFFIX "lib/libc++" "lib") - else() - set(TBB_LIB_PATH_SUFFIX "lib") - endif() - elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") - # Linux - set(TBB_DEFAULT_SEARCH_DIR "/opt/intel/tbb") - - # TODO: Check compiler version to see the suffix should be /gcc4.1 or - # /gcc4.1. For now, assume that the compiler is more recent than - # gcc 4.4.x or later. - if(CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64") - set(TBB_LIB_PATH_SUFFIX "lib/intel64/gcc4.4") - elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^i.86$") - set(TBB_LIB_PATH_SUFFIX "lib/ia32/gcc4.4") - endif() - endif() - - ################################## - # Find the TBB include dir - ################################## - - find_path(TBB_INCLUDE_DIRS tbb/tbb.h - HINTS ${TBB_INCLUDE_DIR} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} - PATH_SUFFIXES include) - - ################################## - # Set version strings - ################################## - - if(TBB_INCLUDE_DIRS) - file(READ "${TBB_INCLUDE_DIRS}/tbb/tbb_stddef.h" _tbb_version_file) - string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" - TBB_VERSION_MAJOR "${_tbb_version_file}") - string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" - TBB_VERSION_MINOR "${_tbb_version_file}") - string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" - TBB_INTERFACE_VERSION "${_tbb_version_file}") - set(TBB_VERSION "${TBB_VERSION_MAJOR}.${TBB_VERSION_MINOR}") - endif() - - ################################## - # Find TBB components - ################################## - - if(TBB_VERSION VERSION_LESS 4.3) - set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc tbb) - else() - set(TBB_SEARCH_COMPOMPONENTS tbb_preview tbbmalloc_proxy tbbmalloc tbb) - endif() - - # Find each component - foreach(_comp ${TBB_SEARCH_COMPOMPONENTS}) - if(";${TBB_FIND_COMPONENTS};tbb;" MATCHES ";${_comp};") - - # Search for the libraries - find_library(TBB_${_comp}_LIBRARY_RELEASE ${_comp} - HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH - PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) - - find_library(TBB_${_comp}_LIBRARY_DEBUG ${_comp}_debug - HINTS ${TBB_LIBRARY} ${TBB_SEARCH_DIR} - PATHS ${TBB_DEFAULT_SEARCH_DIR} ENV LIBRARY_PATH - PATH_SUFFIXES ${TBB_LIB_PATH_SUFFIX}) - - if(TBB_${_comp}_LIBRARY_DEBUG) - list(APPEND TBB_LIBRARIES_DEBUG "${TBB_${_comp}_LIBRARY_DEBUG}") - endif() - if(TBB_${_comp}_LIBRARY_RELEASE) - list(APPEND TBB_LIBRARIES_RELEASE "${TBB_${_comp}_LIBRARY_RELEASE}") - endif() - if(TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE} AND NOT TBB_${_comp}_LIBRARY) - set(TBB_${_comp}_LIBRARY "${TBB_${_comp}_LIBRARY_${TBB_BUILD_TYPE}}") - endif() - - if(TBB_${_comp}_LIBRARY AND EXISTS "${TBB_${_comp}_LIBRARY}") - set(TBB_${_comp}_FOUND TRUE) - else() - set(TBB_${_comp}_FOUND FALSE) - endif() - - # Mark internal variables as advanced - mark_as_advanced(TBB_${_comp}_LIBRARY_RELEASE) - mark_as_advanced(TBB_${_comp}_LIBRARY_DEBUG) - mark_as_advanced(TBB_${_comp}_LIBRARY) - - endif() - endforeach() - - ################################## - # Set compile flags and libraries - ################################## +# Firstly search for TBB in config mode (i.e. search for TBBConfig.cmake). +find_package(TBB QUIET CONFIG) +if (TBB_FOUND) + find_package_handle_standard_args(TBB CONFIG_MODE) + return() +endif() - set(TBB_DEFINITIONS_RELEASE "") - set(TBB_DEFINITIONS_DEBUG "-DTBB_USE_DEBUG=1") - - if(TBB_LIBRARIES_${TBB_BUILD_TYPE}) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_${TBB_BUILD_TYPE}}") - set(TBB_LIBRARIES "${TBB_LIBRARIES_${TBB_BUILD_TYPE}}") - elseif(TBB_LIBRARIES_RELEASE) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_RELEASE}") - set(TBB_LIBRARIES "${TBB_LIBRARIES_RELEASE}") - elseif(TBB_LIBRARIES_DEBUG) - set(TBB_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}") - set(TBB_LIBRARIES "${TBB_LIBRARIES_DEBUG}") - endif() +if (NOT TBB_FIND_COMPONENTS) + set(TBB_FIND_COMPONENTS tbb tbbmalloc) + foreach (_tbb_component ${TBB_FIND_COMPONENTS}) + set(TBB_FIND_REQUIRED_${_tbb_component} 1) + endforeach() +endif() - find_package_handle_standard_args(TBB - REQUIRED_VARS TBB_INCLUDE_DIRS TBB_LIBRARIES - HANDLE_COMPONENTS - VERSION_VAR TBB_VERSION) +if (WIN32) + list(APPEND ADDITIONAL_LIB_DIRS ENV PATH ENV LIB) + list(APPEND ADDITIONAL_INCLUDE_DIRS ENV INCLUDE ENV CPATH) +else() + list(APPEND ADDITIONAL_LIB_DIRS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH ENV DYLD_LIBRARY_PATH) + list(APPEND ADDITIONAL_INCLUDE_DIRS ENV CPATH ENV C_INCLUDE_PATH ENV CPLUS_INCLUDE_PATH ENV INCLUDE_PATH) +endif() - ################################## - # Create targets - ################################## +find_path(_tbb_include_dir NAMES tbb/tbb.h PATHS ${ADDITIONAL_INCLUDE_DIRS}) + +if (_tbb_include_dir) + # TODO: consider TBB_VERSION handling + set(_TBB_BUILD_MODES RELEASE DEBUG) + set(_TBB_DEBUG_SUFFIX _debug) + + foreach (_tbb_component ${TBB_FIND_COMPONENTS}) + if (NOT TARGET TBB::${_tbb_component}) + add_library(TBB::${_tbb_component} SHARED IMPORTED) + set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${_tbb_include_dir}) + + foreach(_TBB_BUILD_MODE ${_TBB_BUILD_MODES}) + set(_tbb_component_lib_name ${_tbb_component}${_TBB_${_TBB_BUILD_MODE}_SUFFIX}) + if (WIN32) + find_library(${_tbb_component_lib_name}_lib ${_tbb_component_lib_name} PATHS ${ADDITIONAL_LIB_DIRS}) + find_file(${_tbb_component_lib_name}_dll ${_tbb_component_lib_name}.dll PATHS ${ADDITIONAL_LIB_DIRS}) + + set_target_properties(TBB::${_tbb_component} PROPERTIES + IMPORTED_LOCATION_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_dll}" + IMPORTED_IMPLIB_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_lib}" + ) + else() + find_library(${_tbb_component_lib_name}_so ${_tbb_component_lib_name} PATHS ${ADDITIONAL_LIB_DIRS}) + + set_target_properties(TBB::${_tbb_component} PROPERTIES + IMPORTED_LOCATION_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_so}" + ) + endif() + if (${_tbb_component_lib_name}_lib AND ${_tbb_component_lib_name}_dll OR ${_tbb_component_lib_name}_so) + set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${_TBB_BUILD_MODE}) + list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component}) + set(TBB_${_tbb_component}_FOUND 1) + endif() + unset(${_tbb_component_lib_name}_lib CACHE) + unset(${_tbb_component_lib_name}_dll CACHE) + unset(${_tbb_component_lib_name}_so CACHE) + unset(_tbb_component_lib_name) + endforeach() + endif() + endforeach() + unset(_TBB_BUILD_MODESS) + unset(_TBB_DEBUG_SUFFIX) +endif() +unset(_tbb_include_dir CACHE) - if(NOT CMAKE_VERSION VERSION_LESS 3.0 AND TBB_FOUND) - add_library(tbb SHARED IMPORTED) - set_target_properties(tbb PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${TBB_INCLUDE_DIRS}" - IMPORTED_LOCATION "${TBB_LIBRARIES}") - if(TBB_LIBRARIES_RELEASE AND TBB_LIBRARIES_DEBUG) - set_target_properties(tbb PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "$<$,$>:TBB_USE_DEBUG=1>" - IMPORTED_LOCATION_DEBUG "${TBB_LIBRARIES_DEBUG}" - IMPORTED_LOCATION_RELWITHDEBINFO "${TBB_LIBRARIES_DEBUG}" - IMPORTED_LOCATION_RELEASE "${TBB_LIBRARIES_RELEASE}" - IMPORTED_LOCATION_MINSIZEREL "${TBB_LIBRARIES_RELEASE}" - ) - elseif(TBB_LIBRARIES_RELEASE) - set_target_properties(tbb PROPERTIES IMPORTED_LOCATION "${TBB_LIBRARIES_RELEASE}") - else() - set_target_properties(tbb PROPERTIES - INTERFACE_COMPILE_DEFINITIONS "${TBB_DEFINITIONS_DEBUG}" - IMPORTED_LOCATION "${TBB_LIBRARIES_DEBUG}" - ) - endif() - endif() +list(LENGTH TBB_IMPORTED_TARGETS TBB_IT_LEN) - mark_as_advanced(TBB_INCLUDE_DIRS TBB_LIBRARIES) +if (TBB_IT_LEN GREATER 0) +list(REMOVE_DUPLICATES TBB_IMPORTED_TARGETS) +endif() - unset(TBB_ARCHITECTURE) - unset(TBB_BUILD_TYPE) - unset(TBB_LIB_PATH_SUFFIX) - unset(TBB_DEFAULT_SEARCH_DIR) +find_package_handle_standard_args(TBB + REQUIRED_VARS TBB_IMPORTED_TARGETS -endif() + HANDLE_COMPONENTS) diff --git a/current_version.txt b/current_version.txt index 5b62d1631..fb9ede991 100644 --- a/current_version.txt +++ b/current_version.txt @@ -1,3 +1,3 @@ VERSION_MAJOR 1 -VERSION_MINOR 7 +VERSION_MINOR 8 VERSION_PATCH 0 diff --git a/doc/source/conf.py b/doc/source/conf.py index cc7d9db08..580f48e4d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -55,9 +55,9 @@ # built documents. # # The short X.Y version. -version = '1.7' +version = '1.8' # The full version, including alpha/beta/rc tags. -release = '1.7.0' +release = '1.8.0' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/docker/Dockerfile b/docker/Dockerfile index 10e6a8a13..53f069b8f 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -6,7 +6,7 @@ MAINTAINER salmon.maintainer@gmail.com ENV PACKAGES git gcc make g++ libboost-all-dev liblzma-dev libbz2-dev \ ca-certificates zlib1g-dev libcurl4-openssl-dev curl unzip autoconf apt-transport-https ca-certificates gnupg software-properties-common wget -ENV SALMON_VERSION 1.7.0 +ENV SALMON_VERSION 1.8.0 # salmon binary will be installed in /home/salmon/bin/salmon diff --git a/docker/build_test.sh b/docker/build_test.sh index f3641c328..45976506b 100644 --- a/docker/build_test.sh +++ b/docker/build_test.sh @@ -1,3 +1,3 @@ #! /bin/bash -SALMON_VERSION=1.7.0 +SALMON_VERSION=1.8.0 docker build --no-cache -t combinelab/salmon:${SALMON_VERSION} -t combinelab/salmon:latest . diff --git a/include/AlignmentLibrary.hpp b/include/AlignmentLibrary.hpp index c576e1c17..193e7bc17 100644 --- a/include/AlignmentLibrary.hpp +++ b/include/AlignmentLibrary.hpp @@ -391,12 +391,12 @@ for (auto& txp : transcripts_) { // SequenceBiasModel& sequenceBiasModel() { return seqBiasModel_; } - // inline tbb::concurrent_queue& fragmentQueue() { - inline tbb::concurrent_queue& fragmentQueue() { + // inline oneapi::tbb::concurrent_queue& fragmentQueue() { + inline oneapi::tbb::concurrent_queue& fragmentQueue() { return bq->getFragmentQueue(); } - // inline tbb::concurrent_bounded_queue*>& + // inline oneapi::tbb::concurrent_bounded_queue*>& // alignmentGroupQueue() { inline moodycamel::ConcurrentQueue*>& alignmentGroupQueue() { diff --git a/include/AlignmentModel.hpp b/include/AlignmentModel.hpp index 1fe96928f..efa320bed 100644 --- a/include/AlignmentModel.hpp +++ b/include/AlignmentModel.hpp @@ -5,7 +5,7 @@ #include "AlignmentCommon.hpp" #include "AtomicMatrix.hpp" -#include "tbb/concurrent_vector.h" +#include "oneapi/tbb/concurrent_vector.h" class AlignmentModel : public AlignmentCommon diff --git a/include/AtomicMatrix.hpp b/include/AtomicMatrix.hpp index 0212da8de..af34d033b 100644 --- a/include/AtomicMatrix.hpp +++ b/include/AtomicMatrix.hpp @@ -1,7 +1,7 @@ #ifndef ATOMIC_MATRIX #define ATOMIC_MATRIX -#include "tbb/concurrent_vector.h" +#include "oneapi/tbb/concurrent_vector.h" #include "SalmonMath.hpp" #include "SalmonUtils.hpp" diff --git a/include/BAMQueue.hpp b/include/BAMQueue.hpp index d5df05c7d..ee83b10c0 100644 --- a/include/BAMQueue.hpp +++ b/include/BAMQueue.hpp @@ -23,7 +23,7 @@ #include "spdlog/spdlog.h" #include #include -#include +#include extern "C" { #include "io_lib/os.h" @@ -75,10 +75,10 @@ template class BAMQueue { void reset(); - tbb::concurrent_queue& getFragmentQueue(); + oneapi::tbb::concurrent_queue& getFragmentQueue(); // moodycamel::ConcurrentQueue& getFragmentQueue(); - // tbb::concurrent_bounded_queue*>& + // oneapi::tbb::concurrent_bounded_queue*>& // getAlignmentGroupQueue(); moodycamel::ConcurrentQueue*>& getAlignmentGroupQueue(); @@ -114,13 +114,13 @@ template class BAMQueue { size_t numUnaligned_; size_t numMappedReads_; size_t numUniquelyMappedReads_; - tbb::concurrent_queue fragmentQueue_; + oneapi::tbb::concurrent_queue fragmentQueue_; // moodycamel::ConcurrentQueue fragmentQueue_; - // tbb::concurrent_bounded_queue*> alnGroupPool_; + // oneapi::tbb::concurrent_bounded_queue*> alnGroupPool_; moodycamel::ConcurrentQueue*> alnGroupPool_; - // tbb::concurrent_bounded_queue*> alnGroupQueue_; + // oneapi::tbb::concurrent_bounded_queue*> alnGroupQueue_; moodycamel::ReaderWriterQueue*> alnGroupQueue_; /* diff --git a/include/FragmentStartPositionDistribution.hpp b/include/FragmentStartPositionDistribution.hpp index 4d9dd6f1f..3f32a1978 100644 --- a/include/FragmentStartPositionDistribution.hpp +++ b/include/FragmentStartPositionDistribution.hpp @@ -9,7 +9,7 @@ #ifndef FRAGMENT_START_POSITION_DISTRIBUTION #define FRAGMENT_START_POSITION_DISTRIBUTION -// #include "tbb/atomic.h" +// #include "oneapi/tbb/atomic.h" #include #include #include @@ -36,7 +36,7 @@ class FragmentStartPositionDistribution { * A private double that stores the (logged) sum of the product of observed * lengths and masses for quick mean calculations. */ - //tbb::atomic sum_; + //oneapi::tbb::atomic sum_; /** * The number of bins we consider within each transcript. */ diff --git a/include/GenomicFeature.hpp b/include/GenomicFeature.hpp index 8f4edc041..e2323b4c8 100644 --- a/include/GenomicFeature.hpp +++ b/include/GenomicFeature.hpp @@ -29,7 +29,7 @@ #include #include -#include "tbb/concurrent_queue.h" +#include "oneapi/tbb/concurrent_queue.h" struct TranscriptGeneID { std::string transcript_id; @@ -161,7 +161,7 @@ readGTFFile(const std::string& fname) { bool done = false; std::vector threads; - tbb::concurrent_queue queue; + oneapi::tbb::concurrent_queue queue; // boost::lockfree::queue queue(5000); threads.push_back(std::thread([&ifile, &queue, &done]() { StringPtr line = new std::string(); @@ -177,7 +177,7 @@ readGTFFile(const std::string& fname) { size_t nreader = 10; std::atomic tctr(nreader); - tbb::concurrent_queue*> outQueue; + oneapi::tbb::concurrent_queue*> outQueue; // boost::lockfree::queue*> outQueue(5000); for (size_t i = 0; i < nreader; ++i) { diff --git a/include/MiniBatchInfo.hpp b/include/MiniBatchInfo.hpp index 005eb2142..cc0186404 100644 --- a/include/MiniBatchInfo.hpp +++ b/include/MiniBatchInfo.hpp @@ -22,9 +22,9 @@ template class MiniBatchInfo { double logForgettingMass; template - void release(tbb::concurrent_queue& fragmentQueue, + void release(oneapi::tbb::concurrent_queue& fragmentQueue, moodycamel::ConcurrentQueue& alignmentGroupQueue) { - // tbb::concurrent_bounded_queue& alignmentGroupQueue){ + // oneapi::tbb::concurrent_bounded_queue& alignmentGroupQueue){ size_t ng{0}; for (auto& alnGroup : *alignments) { // fragmentQueue.enqueue_bulk(alnGroup->alignments().begin(), @@ -51,8 +51,8 @@ template class MiniBatchInfo { /* template <> void MiniBatchInfo>::release( - tbb::concurrent_bounded_queue& alignmentStructureQueue, - tbb::concurrent_bounded_queue*>& + oneapi::tbb::concurrent_bounded_queue& alignmentStructureQueue, + oneapi::tbb::concurrent_bounded_queue*>& alignmentGroupQueue) { size_t ng{0}; for (auto& alnGroup : *alignments) { for (auto& aln : alnGroup->alignments()) { diff --git a/include/ONTAlignmentModel.hpp b/include/ONTAlignmentModel.hpp index 1738c1ad5..2bc8ecdca 100644 --- a/include/ONTAlignmentModel.hpp +++ b/include/ONTAlignmentModel.hpp @@ -11,7 +11,7 @@ #include "AlignmentCommon.hpp" // #include "AtomicMatrix.hpp" -// #include "tbb/concurrent_vector.h" +// #include "oneapi/tbb/concurrent_vector.h" class ONTAlignmentModel diff --git a/include/OutputUnmappedFilter.hpp b/include/OutputUnmappedFilter.hpp index 89ed13cf5..e04e373a9 100644 --- a/include/OutputUnmappedFilter.hpp +++ b/include/OutputUnmappedFilter.hpp @@ -4,11 +4,11 @@ #include "ReadPair.hpp" #include "UnpairedRead.hpp" #include -#include +#include template class OutputUnmappedFilter { public: - OutputUnmappedFilter(tbb::concurrent_bounded_queue* outQueue) + OutputUnmappedFilter(oneapi::tbb::concurrent_bounded_queue* outQueue) : outQueue_(outQueue), qlen_(0) { memset(&qname_[0], 0, 255); } @@ -37,7 +37,7 @@ template class OutputUnmappedFilter { } private: - tbb::concurrent_bounded_queue* outQueue_ = nullptr; + oneapi::tbb::concurrent_bounded_queue* outQueue_ = nullptr; char qname_[255]; uint32_t qlen_; }; diff --git a/include/SalmonConfig.hpp b/include/SalmonConfig.hpp index a782d3bf6..277485959 100644 --- a/include/SalmonConfig.hpp +++ b/include/SalmonConfig.hpp @@ -1,6 +1,6 @@ /** >HEADER - Copyright (c) 2014-2021 Rob Patro rob@cs.umd.edu + Copyright (c) 2014-2022 Rob Patro rob@cs.umd.edu This file is part of Salmon. @@ -26,9 +26,9 @@ namespace salmon { constexpr char majorVersion[] = "1"; -constexpr char minorVersion[] = "7"; +constexpr char minorVersion[] = "8"; constexpr char patchVersion[] = "0"; -constexpr char version[] = "1.7.0"; +constexpr char version[] = "1.8.0"; constexpr uint32_t indexVersion = 5; constexpr char requiredQuasiIndexVersion[] = "p7"; } // namespace salmon diff --git a/include/SalmonUtils.hpp b/include/SalmonUtils.hpp index a5507732c..b6049b6a7 100644 --- a/include/SalmonUtils.hpp +++ b/include/SalmonUtils.hpp @@ -21,6 +21,8 @@ extern "C" { #include +#include "oneapi/tbb/task_arena.h" + #include "cereal/archives/json.hpp" #include "spdlog/fmt/fmt.h" @@ -151,7 +153,7 @@ Eigen::VectorXd updateEffectiveLengths( template Eigen::VectorXd -updateEffectiveLengths(SalmonOpts& sopt, ReadExpT& readExp, +updateEffectiveLengths(oneapi::tbb::task_arena& arena, SalmonOpts& sopt, ReadExpT& readExp, Eigen::VectorXd& effLensIn, AbundanceVecT& alphas, std::vector& available, bool finalRound = false); diff --git a/include/Sampler.hpp b/include/Sampler.hpp index a71a1527d..236805123 100644 --- a/include/Sampler.hpp +++ b/include/Sampler.hpp @@ -25,7 +25,7 @@ extern "C" { #include #include -#include +#include #include #include @@ -64,10 +64,10 @@ using salmon::math::logSub; template using AlignmentBatch = std::vector; template -using MiniBatchQueue = tbb::concurrent_queue*>; +using MiniBatchQueue = oneapi::tbb::concurrent_queue*>; template -using OutputQueue = tbb::concurrent_bounded_queue; +using OutputQueue = oneapi::tbb::concurrent_bounded_queue; template using AlignmentLibraryT = AlignmentLibrary, AlignModelT>; diff --git a/include/SequenceBiasModel.hpp b/include/SequenceBiasModel.hpp index 08ff300e0..6c2052d15 100644 --- a/include/SequenceBiasModel.hpp +++ b/include/SequenceBiasModel.hpp @@ -9,7 +9,7 @@ #include "spdlog/spdlog.h" #include "AtomicMatrix.hpp" -#include "tbb/concurrent_vector.h" +#include "oneapi/tbb/concurrent_vector.h" class Transcript; class LibraryFormat; diff --git a/include/WhiteList.hpp b/include/WhiteList.hpp index 67bf2b6a6..1eac3676e 100644 --- a/include/WhiteList.hpp +++ b/include/WhiteList.hpp @@ -16,8 +16,8 @@ //#include "RapMapUtils.hpp" #include "SingleCellProtocols.hpp" -#include "tbb/parallel_for.h" -#include "tbb/blocked_range.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/blocked_range.h" #include #include @@ -27,7 +27,7 @@ namespace alevin { namespace whitelist { - using BlockedIndexRange = tbb::blocked_range; + using BlockedIndexRange = oneapi::tbb::blocked_range; using DoubleMatrixT = std::vector> ; using DoubleVectorT = std::vector ; diff --git a/scripts/fetchPufferfish.sh b/scripts/fetchPufferfish.sh index fd20f5879..c5227453f 100755 --- a/scripts/fetchPufferfish.sh +++ b/scripts/fetchPufferfish.sh @@ -23,11 +23,11 @@ if [ -d ${INSTALL_DIR}/src/pufferfish ] ; then rm -fr ${INSTALL_DIR}/src/pufferfish fi -SVER=salmon-v1.7.0 +SVER=salmon-v1.8.0 #SVER=develop #SVER=sketch-mode -EXPECTED_SHA256=5894fabbf6829a3d4a627135edc8326e931eb07fc792bfff3a0714e8fee8bb8b +EXPECTED_SHA256=63811834c41745f3f7530f5f3457f10993bcff604662b9b1b05c88fd8ef179d5 mkdir -p ${EXTERNAL_DIR} curl -k -L https://github.com/COMBINE-lab/pufferfish/archive/${SVER}.zip -o ${EXTERNAL_DIR}/pufferfish.zip @@ -46,7 +46,7 @@ if [ -z "${hashcheck-}" ]; then echo "Couldn't find shasum command; can't verify contents of downloaded pufferfish"; else - if [[ $SVER != develop ]]; then + if [[ $SVER != develop && $SVER != onetbb ]]; then echo "${EXPECTED_SHA256} ${EXTERNAL_DIR}/pufferfish.zip" | ${hashcheck} -c - || { echo "pufferfish.zip did not match expected SHA1! Exiting."; exit 1; } else echo "not testing sha since pulling from develop" diff --git a/src/BuildSalmonIndex.cpp b/src/BuildSalmonIndex.cpp index 96e49f860..bde2206a9 100644 --- a/src/BuildSalmonIndex.cpp +++ b/src/BuildSalmonIndex.cpp @@ -26,9 +26,9 @@ #include #include -#include "tbb/parallel_for.h" -#include "tbb/parallel_for_each.h" -#include "tbb/parallel_sort.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/parallel_for_each.h" +#include "oneapi/tbb/parallel_sort.h" #include "GenomicFeature.hpp" #include "SalmonIndex.hpp" @@ -114,6 +114,8 @@ int salmonIndex(int argc, const char* argv[], std::unique_ptr& /* s "Treat these sequences ids from the reference as the decoys that may " "have sequence homologous to some known transcript. for example in " "case of the genome, provide a list of chromosome name --- one per line") + ("no-clip,n", po::bool_switch(&idxOpt.noclip_polya)->default_value(false), + "Don't clip poly-A tails from the ends of target sequences") ("type", po::value(&indexTypeStr)->default_value("puff")->required(), "The type of index to build; the only option is \"puff\" in this version " diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b70968e7b..6ac84212e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,3 +1,7 @@ +if(${TBB_FOUND}) + get_target_property(TBB_INCLUDE_DIRS TBB::tbb INTERFACE_INCLUDE_DIRECTORIES) +endif() + include_directories( ${GAT_SOURCE_DIR}/include ${GAT_SOURCE_DIR}/include/eigen3 @@ -93,10 +97,17 @@ if(HAS_IPO AND (NOT NO_IPO)) set_property(TARGET ksw2pp PROPERTY INTERPROCEDURAL_OPTIMIZATION True) endif() -set ( UNIT_TESTS_SRCS +set (UNIT_TESTS_ENTRY_SRCS ${GAT_SOURCE_DIR}/tests/UnitTests.cpp - FragmentLengthDistribution.cpp - ${GAT_SOURCE_DIR}/external/install/src/pufferfish/rank9b.cpp + ${GAT_SOURCE_DIR}/tests/catch.hpp +) + +set (UNIT_TESTS_INDIVIDUAL_SRCS + ${GAT_SOURCE_DIR}/src/FragmentLengthDistribution.cpp + ${GAT_SOURCE_DIR}/external/install/src/pufferfish/rank9b.cpp + ${GAT_SOURCE_DIR}/tests/GCSampleTests.cpp + ${GAT_SOURCE_DIR}/tests/LibraryTypeTests.cpp + # ${GAT_SOURCE_DIR}/tests/KmerHistTests.cpp ) @@ -186,7 +197,11 @@ if(HAS_IPO AND (NOT NO_IPO)) set_property(TARGET salmon PROPERTY INTERPROCEDURAL_OPTIMIZATION True) endif() -add_executable(unitTests ${UNIT_TESTS_SRCS}) +add_library(UnitTestsMain STATIC ${UNIT_TESTS_ENTRY_SRCS} ${GAT_SOURCE_DIR}/tests/catch.hpp) + +add_executable(unitTests ${UNIT_TESTS_INDIVIDUAL_SRCS} ${GAT_SOURCE_DIR}/tests/catch.hpp) +target_compile_options(unitTests PUBLIC "$<$:${TGT_DEBUG_FLAGS}>") +target_compile_options(unitTests PUBLIC "$<$:${TGT_RELEASE_FLAGS}>") #add_executable(salmon-read ${SALMON_READ_SRCS}) #set_target_properties(salmon-read PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS} -DHAVE_LIBPTHREAD -D_PBGZF_USE -fopenmp" @@ -202,10 +217,17 @@ add_executable(unitTests ${UNIT_TESTS_SRCS}) # message ("Setting libdivsufsort64 = ${SUFFARRAY_LIB64}") #endif() - +add_dependencies(salmon puffer) +add_dependencies(salmon twopaco) +add_dependencies(salmon graphdump) +add_dependencies(salmon ntcard) +add_dependencies(salmon ksw2pp) +add_dependencies(salmon salmon_core) +add_dependencies(salmon alevin_core) +if(TBB_RECONFIGURE OR TBB_TARGET_EXISTED) # Link the executable target_link_libraries(salmon - Threads::Threads + Threads::Threads puffer salmon_core twopaco @@ -216,32 +238,41 @@ target_link_libraries(salmon ${ICU_LIBS} ${STADEN_LIBRARIES} ${CURL_LIBRARIES} ${ZLIB_LIBRARY} - #${SUFFARRAY_LIB} - #${SUFFARRAY_LIB64} - #${GAT_SOURCE_DIR}/external/install/lib/libbwa.a m ${LIBLZMA_LIBRARIES} ${BZIP2_LIBRARIES} ${LIBSALMON_LINKER_FLAGS} ${NON_APPLECLANG_LIBS} ksw2pp -## PUFF_INTEGRATION alevin_core ${ASAN_LIB} ${FAST_MALLOC_LIB} - ${TBB_LIBRARIES} + TBB::tbb + TBB::tbbmalloc ${LIBRT} ${CMAKE_DL_LIBS} - #ubsan ) +endif() + +# dependencies for unitTests +add_dependencies(salmon salmon_core) +add_dependencies(salmon alevin_core) +add_dependencies(unitTests UnitTestsMain) +#add_dependencies(salmon puffer) +#add_dependencies(salmon twopaco) +#add_dependencies(salmon graphdump) +#add_dependencies(salmon ntcard) +#add_dependencies(salmon ksw2pp) + +if(TBB_RECONFIGURE OR TBB_TARGET_EXISTED) -# Link the executable target_link_libraries(unitTests Threads::Threads ## PUFF_INTEGRATION - alevin_core salmon_core + alevin_core gff + UnitTestsMain ${STADEN_LIBRARIES} ${Boost_LIBRARIES} ${ICU_LIBS} @@ -250,7 +281,9 @@ target_link_libraries(unitTests m ${LIBLZMA_LIBRARIES} ${BZIP2_LIBRARIES} - ${TBB_LIBRARIES} + #${TBB_LIBRARIES} + TBB::tbb + TBB::tbbmalloc ${LIBSALMON_LINKER_FLAGS} ${NON_APPLECLANG_LIBS} ${ASAN_LIB} @@ -258,6 +291,7 @@ target_link_libraries(unitTests ${CMAKE_DL_LIBS} #ubsan ) +endif() if(NOT Iconv_IS_BUILT_IN) target_link_libraries(unitTests Iconv::Iconv) @@ -265,6 +299,8 @@ if(NOT Iconv_IS_BUILT_IN) endif() add_dependencies(salmon unitTests) +add_dependencies(unitTests salmon_core) +add_dependencies(unitTests alevin_core) ## # External dependencies of salmon_core and salmon @@ -276,18 +312,16 @@ if (${FETCHED_JEMALLOC}) endif() if (${FETCHED_BOOST}) -## PUFF_INTEGRATION -# add_dependencies(alevin_core libboost) add_dependencies(alevin_core libboost) add_dependencies(salmon_core libboost) add_dependencies(salmon libboost) endif() if (${FETCHED_TBB}) + message("Fetched oneTBB, so libtbb must be a dependency for targets") add_dependencies(alevin_core libtbb) add_dependencies(salmon_core libtbb) -## PUFF_INTEGRATION -# add_dependencies(alevin_core libtbb) + add_dependencies(unitTests libtbb) add_dependencies(salmon libtbb) endif() @@ -361,11 +395,35 @@ set(INSTALL_LIB_DIR lib ) set(INSTALL_BIN_DIR bin ) set(INSTALL_INCLUDE_DIR include ) -install(DIRECTORY - ${GAT_SOURCE_DIR}/external/install/lib/ - DESTINATION ${INSTALL_LIB_DIR} - FILES_MATCHING PATTERN "libtbb*.${SHARED_LIB_EXTENSION}*" - ) +if(TBB_RECONFIGURE OR TBB_TARGET_EXISTED) +#set(TBB_SOURCE_DIR $) +#add_custom_target(genexdebug COMMAND ${CMAKE_COMMAND} -E echo "$") +get_target_property(TBB_LIB_INSTALL_NAME TBB::tbb IMPORTED_LOCATION_RELEASE) +get_filename_component(TBB_LIB_INSTALL_DIR ${TBB_LIB_INSTALL_NAME} DIRECTORY) +message("TBB_LIB_INSTALL_DIR = ${TBB_LIB_INSTALL_DIR}") +file(GLOB TBB_FILES ${TBB_LIB_INSTALL_DIR}/libtbb*.${SHARED_LIB_EXTENSION}*) +message("TBBGLOBS = ${TBB_FILES}") + +install(FILES + ${TBB_FILES} + DESTINATION ${INSTALL_LIB_DIR} +) +#install(FILES +# $ +# DESTINATION ${INSTALL_LIB_DIR} +#) +#install(DIRECTORY +# ${TBB_SOURCE_DIR} +# DESTINATION ${INSTALL_LIB_DIR} +# FILES_MATCHING PATTERN "libtbb*.${SHARED_LIB_EXTENSION}*" +#) +endif() + +#install(DIRECTORY +# ${GAT_SOURCE_DIR}/external/install/lib/ +# DESTINATION ${INSTALL_LIB_DIR} +# FILES_MATCHING PATTERN "libtbb*.${SHARED_LIB_EXTENSION}*" +# ) # install(FILES ${Boost_LIBRARIES} # DESTINATION ${INSTALL_LIB_DIR}) diff --git a/src/CollapsedEMOptimizer.cpp b/src/CollapsedEMOptimizer.cpp index 3fee84077..660341457 100644 --- a/src/CollapsedEMOptimizer.cpp +++ b/src/CollapsedEMOptimizer.cpp @@ -3,13 +3,12 @@ #include #include -#include "tbb/blocked_range.h" -#include "tbb/parallel_for.h" -#include "tbb/parallel_for_each.h" -#include "tbb/parallel_reduce.h" -#include "tbb/partitioner.h" -// <-- deprecated in TBB --> #include "tbb/task_scheduler_init.h" -#include "tbb/global_control.h" +#include "oneapi/tbb/task_arena.h" +#include "oneapi/tbb/blocked_range.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/parallel_for_each.h" +#include "oneapi/tbb/parallel_reduce.h" +#include "oneapi/tbb/partitioner.h" //#include "fastapprox.h" #include @@ -32,7 +31,7 @@ #include "UnpairedRead.hpp" #include "EMUtils.hpp" -using BlockedIndexRange = tbb::blocked_range; +using BlockedIndexRange = oneapi::tbb::blocked_range; // intelligently chosen value originally adopted from // https://github.com/pachterlab/kallisto/blob/master/src/EMAlgorithm.h#L18 @@ -176,14 +175,16 @@ void VBEMUpdate_(std::vector>& txpGroupLabels, * given the current estimates (alphaIn). */ template -void EMUpdate_(EQVecT& eqVec, +void EMUpdate_(oneapi::tbb::task_arena& arena, + EQVecT& eqVec, std::vector& priorAlphas, const CollapsedEMOptimizer::VecType& alphaIn, CollapsedEMOptimizer::VecType& alphaOut) { assert(alphaIn.size() == alphaOut.size()); - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(eqVec.size())), [&eqVec, &priorAlphas, &alphaIn, &alphaOut](const BlockedIndexRange& range) -> void { for (auto eqID : boost::irange(range.begin(), range.end())) { @@ -228,6 +229,7 @@ void EMUpdate_(EQVecT& eqVec, } } }); + }); } /* @@ -236,7 +238,8 @@ void EMUpdate_(EQVecT& eqVec, * given the current estimates (alphaIn). */ template -void VBEMUpdate_(EQVecT& eqVec, +void VBEMUpdate_(oneapi::tbb::task_arena& arena, + EQVecT& eqVec, std::vector& priorAlphas, const CollapsedEMOptimizer::VecType& alphaIn, CollapsedEMOptimizer::VecType& alphaOut, @@ -251,7 +254,8 @@ void VBEMUpdate_(EQVecT& eqVec, double logNorm = boost::math::digamma(alphaSum); - tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(priorAlphas.size())), + arena.execute([&]{ + oneapi::tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(priorAlphas.size())), [logNorm, &priorAlphas, &alphaIn, &alphaOut, &expTheta](const BlockedIndexRange& range) -> void { @@ -269,8 +273,10 @@ void VBEMUpdate_(EQVecT& eqVec, alphaOut[i] = 0.0; } }); + }); - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(eqVec.size())), [&eqVec, &alphaIn, &alphaOut, &expTheta](const BlockedIndexRange& range) -> void { @@ -318,6 +324,7 @@ void VBEMUpdate_(EQVecT& eqVec, } } }); + }); } template @@ -689,9 +696,12 @@ bool CollapsedEMOptimizer::gatherBootstraps( template void updateEqClassWeights( + oneapi::tbb::task_arena& arena, EQVecT& eqVec, Eigen::VectorXd& effLens) { - tbb::parallel_for( + + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(eqVec.size())), [&eqVec, &effLens](const BlockedIndexRange& range) -> void { // For each index in the equivalence class vector @@ -721,14 +731,15 @@ void updateEqClassWeights( } } }); + }); } template bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, double relDiffTolerance, uint32_t maxIter) { - // <-- deprecated in TBB --> tbb::task_scheduler_init tbbScheduler(sopt.numThreads); - tbb::global_control c(tbb::global_control::max_allowed_parallelism, sopt.numThreads); + oneapi::tbb::task_arena arena(sopt.numThreads); + std::vector& transcripts = readExp.transcripts(); std::vector available(transcripts.size(), false); @@ -824,7 +835,8 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, // the weights with the effective length terms (here, the *inverse* of // the effective length). Otherwise, multiply the existing weight terms // by the effective length term. - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(eqVec.size())), [&eqVec, &effLens, noRichEq, &sopt](const BlockedIndexRange& range) -> void { // For each index in the equivalence class vector @@ -866,6 +878,7 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, } } }); + }); auto numRemoved = markDegenerateClasses(eqVec, alphas, available, sopt.jointLog); @@ -898,7 +911,7 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, jointLog->info( "iteration {:n}, adjusting effective lengths to account for biases", itNum); - effLens = salmon::utils::updateEffectiveLengths(sopt, readExp, effLens, + effLens = salmon::utils::updateEffectiveLengths(arena, sopt, readExp, effLens, alphas, available, true); // if we're doing the VB optimization, update the priors if (useVBEM) { @@ -912,7 +925,7 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, jointLog->warn("Transcript {} had length {}", i, effLens(i)); } } - updateEqClassWeights(eqVec, effLens); + updateEqClassWeights(arena, eqVec, effLens); needBias = false; if ( sopt.eqClassMode ) { @@ -923,7 +936,7 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, } if (useVBEM) { - VBEMUpdate_(eqVec, priorAlphas, alphas, + VBEMUpdate_(arena, eqVec, priorAlphas, alphas, alphasPrime, expTheta); } else { /* @@ -934,7 +947,7 @@ bool CollapsedEMOptimizer::optimize(ExpT& readExp, SalmonOpts& sopt, } */ - EMUpdate_(eqVec, priorAlphas, alphas, alphasPrime); + EMUpdate_(arena, eqVec, priorAlphas, alphas, alphasPrime); } converged = true; diff --git a/src/CollapsedGibbsSampler.cpp b/src/CollapsedGibbsSampler.cpp index fd851bc47..e0c6561e7 100644 --- a/src/CollapsedGibbsSampler.cpp +++ b/src/CollapsedGibbsSampler.cpp @@ -5,15 +5,14 @@ #include #include -#include "tbb/blocked_range.h" -#include "tbb/combinable.h" -#include "tbb/enumerable_thread_specific.h" -#include "tbb/parallel_for.h" -#include "tbb/parallel_for_each.h" -#include "tbb/parallel_reduce.h" -#include "tbb/partitioner.h" -// <-- deprecated in TBB --> #include "tbb/task_scheduler_init.h" -#include "tbb/global_control.h" +#include "oneapi/tbb/task_arena.h" +#include "oneapi/tbb/blocked_range.h" +#include "oneapi/tbb/combinable.h" +#include "oneapi/tbb/enumerable_thread_specific.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/parallel_for_each.h" +#include "oneapi/tbb/parallel_reduce.h" +#include "oneapi/tbb/partitioner.h" //#include "fastapprox.h" #include @@ -40,7 +39,7 @@ #include "UnpairedRead.hpp" #include "ezETAProgressBar.hpp" -using BlockedIndexRange = tbb::blocked_range; +using BlockedIndexRange = oneapi::tbb::blocked_range; // intelligently chosen value adopted from // https://github.com/pachterlab/kallisto/blob/master/src/EMAlgorithm.h#L18 @@ -92,6 +91,7 @@ divide_work(Iterator begin, Iterator end, std::size_t n) { **/ template void sampleRoundNonCollapsedMultithreaded_( + oneapi::tbb::task_arena& arena, EQVecT& eqVec, /*std::vector& active,*/ std::vector& activeList, /*std::vector& countMap,*/ std::vector& probMap, @@ -106,7 +106,7 @@ void sampleRoundNonCollapsedMultithreaded_( // Sample the transcript fractions \mu from a gamma distribution, and // reset txpCounts to zero for each transcript. - typedef tbb::enumerable_thread_specific GeneratorType; + typedef oneapi::tbb::enumerable_thread_specific GeneratorType; auto getGenerator = []() -> pcg32_unique { // why this mess below? see SalmonUtils.hpp : get_random_device() for more // details. @@ -121,41 +121,44 @@ void sampleRoundNonCollapsedMultithreaded_( // Compute the mu to be used in the equiv class resampling // If we are doing a gamma draw (including shot-noise) if (noGammaDraw) { - tbb::parallel_for( - BlockedIndexRange( - size_t(0), size_t(activeList.size())), // 1024 is grainsize, use only - // with simple_partitioner - [&, beta](const BlockedIndexRange& range) -> void { - for (auto activeIdx : boost::irange(range.begin(), range.end())) { - auto i = activeList[activeIdx]; - double ci = static_cast(txpCount[i] + priorAlphas[i]); - muGlobal[i] = ci / effLens(i); - txpCount[i] = 0.0; - } + arena.execute([&]{ + oneapi::tbb::parallel_for( + BlockedIndexRange( + size_t(0), size_t(activeList.size())), // 1024 is grainsize, use only + // with simple_partitioner + [&, beta](const BlockedIndexRange& range) -> void { + for (auto activeIdx : boost::irange(range.begin(), range.end())) { + auto i = activeList[activeIdx]; + double ci = static_cast(txpCount[i] + priorAlphas[i]); + muGlobal[i] = ci / effLens(i); + txpCount[i] = 0.0; + } }); - + }); } else { - tbb::parallel_for( - BlockedIndexRange( - size_t(0), size_t(activeList.size())), // 1024 is grainsize, use only - // with simple_partitioner - [&, beta](const BlockedIndexRange& range) -> void { - GeneratorType::reference gen = localGenerator.local(); - for (auto activeIdx : boost::irange(range.begin(), range.end())) { - auto i = activeList[activeIdx]; - double ci = static_cast(txpCount[i] + priorAlphas[i]); - std::gamma_distribution d(ci, 1.0 / (beta + effLens(i))); - muGlobal[i] = d(gen); - txpCount[i] = 0.0; - /** DEBUG - if (std::isnan(muGlobal[i]) or std::isinf(muGlobal[i])) { - std::cerr << "txpCount = " << txpCount[i] << ", prior = " << - priorAlphas[i] << ", alpha = " << ci << ", beta = " << (1.0 / (beta + - effLens(i))) << ", mu = " << muGlobal[i] << "\n"; std::exit(1); + arena.execute([&]{ + oneapi::tbb::parallel_for( + BlockedIndexRange( + size_t(0), size_t(activeList.size())), // 1024 is grainsize, use only + // with simple_partitioner + [&, beta](const BlockedIndexRange& range) -> void { + GeneratorType::reference gen = localGenerator.local(); + for (auto activeIdx : boost::irange(range.begin(), range.end())) { + auto i = activeList[activeIdx]; + double ci = static_cast(txpCount[i] + priorAlphas[i]); + std::gamma_distribution d(ci, 1.0 / (beta + effLens(i))); + muGlobal[i] = d(gen); + txpCount[i] = 0.0; + /** DEBUG + if (std::isnan(muGlobal[i]) or std::isinf(muGlobal[i])) { + std::cerr << "txpCount = " << txpCount[i] << ", prior = " << + priorAlphas[i] << ", alpha = " << ci << ", beta = " << (1.0 / (beta + + effLens(i))) << ", mu = " << muGlobal[i] << "\n"; std::exit(1); + } + **/ } - **/ - } - }); + }); + }); } /** @@ -178,11 +181,12 @@ void sampleRoundNonCollapsedMultithreaded_( std::vector txpCount; std::unique_ptr gen{nullptr}; }; - tbb::combinable combineableCounts(txpCount.size()); + oneapi::tbb::combinable combineableCounts(txpCount.size()); std::mutex writeMut; // resample within each equivalence class - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(eqVec.size())), [&](const BlockedIndexRange& range) -> void { @@ -268,6 +272,7 @@ void sampleRoundNonCollapsedMultithreaded_( } // valid group } // loop over all eq classes }); + }); auto combineCounts = [&txpCount](const CombineableTxpCounts& p) -> void { for (size_t i = 0; i < txpCount.size(); ++i) { @@ -323,8 +328,7 @@ bool CollapsedGibbsSampler::sample( namespace bfs = boost::filesystem; auto& jointLog = sopt.jointLog; - // <-- deprecated in TBB --> tbb::task_scheduler_init tbbScheduler(sopt.numThreads); - tbb::global_control c(tbb::global_control::max_allowed_parallelism, sopt.numThreads); + oneapi::tbb::task_arena arena(sopt.numThreads); std::vector& transcripts = readExp.transcripts(); @@ -470,6 +474,7 @@ bool CollapsedGibbsSampler::sample( // Thin the chain by a factor of (numInternalRounds) for (size_t i = 0; i < numInternalRounds; ++i) { sampleRoundNonCollapsedMultithreaded_( + arena, eqVec, // encodes equivalence classes /*active, // the set of active transcripts*/ activeList, // the list of active transcript ids @@ -782,7 +787,7 @@ bool CollapsedGibbsSampler::sampleMultipleChains(ExpT& readExp, namespace bfs = boost::filesystem; auto& jointLog = sopt.jointLog; - tbb::task_scheduler_init tbbScheduler(sopt.numThreads); + oneapi::tbb::task_scheduler_init tbbScheduler(sopt.numThreads); std::vector& transcripts = readExp.transcripts(); // Fill in the effective length vector @@ -814,7 +819,7 @@ readExp.numMappedFragments(); effLens(i) = txp.EffectiveLength; } - tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(numSamples)), + oneapi::tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(numSamples)), [&eqVec, &transcripts, &alphasIn, &priorAlphas, &effLens, &allSamples, &writeBootstrap, useScaledCounts, numInternalRounds, @@ -971,7 +976,7 @@ maxIter); std::vector ds(numTranscripts); // get posterior means - tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(numTranscripts)), + oneapi::tbb::parallel_for(BlockedIndexRange(size_t(0), size_t(numTranscripts)), [&allSamples, &transcripts, &ds, numMappedFragments, numSamples]( const BlockedIndexRange& range) -> void { diff --git a/src/SalmonAlevin.cpp b/src/SalmonAlevin.cpp index 2dde45e84..e5f45d988 100644 --- a/src/SalmonAlevin.cpp +++ b/src/SalmonAlevin.cpp @@ -62,15 +62,15 @@ #include // TBB Includes -#include "tbb/blocked_range.h" -#include "tbb/concurrent_queue.h" -#include "tbb/concurrent_unordered_map.h" -#include "tbb/concurrent_unordered_set.h" -#include "tbb/concurrent_vector.h" -#include "tbb/parallel_for.h" -#include "tbb/parallel_for_each.h" -#include "tbb/parallel_reduce.h" -#include "tbb/partitioner.h" +#include "oneapi/tbb/blocked_range.h" +#include "oneapi/tbb/concurrent_queue.h" +#include "oneapi/tbb/concurrent_unordered_map.h" +#include "oneapi/tbb/concurrent_unordered_set.h" +#include "oneapi/tbb/concurrent_vector.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/parallel_for_each.h" +#include "oneapi/tbb/parallel_reduce.h" +#include "oneapi/tbb/partitioner.h" // logger includes #include "spdlog/spdlog.h" @@ -173,7 +173,7 @@ namespace alevin{ using AlnGroupQueue = moodycamel::ConcurrentQueue*>; #else template - using AlnGroupQueue = tbb::concurrent_queue*>; + using AlnGroupQueue = oneapi::tbb::concurrent_queue*>; #endif //#include "LightweightAlignmentDefs.hpp" @@ -185,7 +185,7 @@ using namespace alevin; /* ALEVIN DECLERATIONS*/ using bcEnd = BarcodeEnd; namespace aut = alevin::utils; -using BlockedIndexRange = tbb::blocked_range; +using BlockedIndexRange = oneapi::tbb::blocked_range; using ReadExperimentT = ReadExperiment>; /////// REDUNDANT CODE END// @@ -430,6 +430,7 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re bw << num_reads_in_chunk; size_t minK = qidx->k(); + int32_t signed_k = static_cast(minK); size_t locRead{0}; size_t rangeSize{0}; uint64_t localNumAssignedFragments{0}; @@ -484,10 +485,11 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re enum class HitDirection : uint8_t {FW, RC, BOTH}; struct SketchHitInfo { - // add a hit to the current target that occurs in the forward // orientation with respect to the target. - bool add_fw(int32_t ref_pos, int32_t read_pos, int32_t max_stretch, float score_inc) { + bool add_fw(int32_t ref_pos, int32_t read_pos, int32_t rl, int32_t k, int32_t max_stretch, float score_inc) { + (void)rl; + (void)k; bool added{false}; // since hits are collected by moving _forward_ in the @@ -514,7 +516,7 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re // add a hit to the current target that occurs in the forward // orientation with respect to the target. - bool add_rc(int32_t ref_pos, int32_t read_pos, int32_t max_stretch, float score_inc) { + bool add_rc(int32_t ref_pos, int32_t read_pos, int32_t rl, int32_t k, int32_t max_stretch, float score_inc) { bool added{false}; // since hits are collected by moving _forward_ in the @@ -524,7 +526,7 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re // This ensures that we don't double-count a k-mer that // might occur twice on this target. if (ref_pos < last_ref_pos_rc and read_pos > last_read_pos_rc) { - approx_pos_rc = ref_pos; + approx_pos_rc = (ref_pos - (rl - (read_pos + k))); if (last_read_pos_rc == -1) { approx_end_pos_rc = ref_pos + read_pos; } else { @@ -738,7 +740,8 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re // mapping position are allowed to have. // NOTE this is still > read_length b/c the stretch is measured wrt the // START of the terminal k-mer. - int32_t max_stretch = static_cast(readSubSeq->length() * 1.0); + int32_t signed_rl = static_cast(readSubSeq->length()); + int32_t max_stretch = static_cast(signed_rl * 1.0); // a raw hit is a pair of read_pos and a projected hit @@ -752,7 +755,7 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re auto collect_mappings_from_hits = [&max_stretch, &min_occ, &hit_map, &salmonOpts, &num_valid_hits, &total_occs, - &largest_occ, &qidx]( + &largest_occ, &qidx, signed_rl, signed_k]( auto& raw_hits, auto& prev_read_pos, auto& max_allowed_occ, auto& had_alt_max_occ ) -> bool { @@ -789,9 +792,11 @@ void process_reads_sc_sketch(paired_parser* parser, ReadExperimentT& readExp, Re // So, we must allow for that here. if (target.max_hits_for_target() >= num_valid_hits) { if (ori) { - target.add_fw(pos, static_cast(read_pos), max_stretch, score_inc); + target.add_fw(pos, static_cast(read_pos), + signed_rl, signed_k, max_stretch, score_inc); } else { - target.add_rc(pos, static_cast(read_pos), max_stretch, score_inc); + target.add_rc(pos, static_cast(read_pos), + signed_rl, signed_k, max_stretch, score_inc); } still_have_valid_target |= (target.max_hits_for_target() >= num_valid_hits + 1); diff --git a/src/SalmonQuantify.cpp b/src/SalmonQuantify.cpp index be7adaa6f..357829f5f 100644 --- a/src/SalmonQuantify.cpp +++ b/src/SalmonQuantify.cpp @@ -61,15 +61,15 @@ #include "core/range.hpp" // TBB Includes -#include "tbb/blocked_range.h" -#include "tbb/concurrent_queue.h" -#include "tbb/concurrent_unordered_map.h" -#include "tbb/concurrent_unordered_set.h" -#include "tbb/concurrent_vector.h" -#include "tbb/parallel_for.h" -#include "tbb/parallel_for_each.h" -#include "tbb/parallel_reduce.h" -#include "tbb/partitioner.h" +#include "oneapi/tbb/blocked_range.h" +#include "oneapi/tbb/concurrent_queue.h" +#include "oneapi/tbb/concurrent_unordered_map.h" +#include "oneapi/tbb/concurrent_unordered_set.h" +#include "oneapi/tbb/concurrent_vector.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/parallel_for_each.h" +#include "oneapi/tbb/parallel_reduce.h" +#include "oneapi/tbb/partitioner.h" // logger includes #include "spdlog/spdlog.h" @@ -152,7 +152,7 @@ template using AlnGroupQueue = moodycamel::ConcurrentQueue*>; #else template -using AlnGroupQueue = tbb::concurrent_queue*>; +using AlnGroupQueue = oneapi::tbb::concurrent_queue*>; #endif //#include "LightweightAlignmentDefs.hpp" diff --git a/src/SalmonQuantifyAlignments.cpp b/src/SalmonQuantifyAlignments.cpp index 747d1ee35..136d1ee74 100644 --- a/src/SalmonQuantifyAlignments.cpp +++ b/src/SalmonQuantifyAlignments.cpp @@ -21,7 +21,7 @@ extern "C" { #include #include -#include +#include #include #include @@ -78,7 +78,7 @@ constexpr uint32_t miniBatchSize{1000}; template using AlignmentBatch = std::vector; template -using MiniBatchQueue = tbb::concurrent_queue*>; +using MiniBatchQueue = oneapi::tbb::concurrent_queue*>; using PriorAbundanceVector = std::vector; using PosteriorAbundanceVector = std::vector; diff --git a/src/SalmonUtils.cpp b/src/SalmonUtils.cpp index cfd1d7e29..3519a175d 100644 --- a/src/SalmonUtils.cpp +++ b/src/SalmonUtils.cpp @@ -11,8 +11,9 @@ #include #include "json.hpp" -#include "tbb/combinable.h" -#include "tbb/parallel_for.h" +#include "oneapi/tbb/combinable.h" +#include "oneapi/tbb/parallel_for.h" +#include "oneapi/tbb/task_arena.h" #include "AlignmentLibrary.hpp" #include "DistributionUtils.hpp" @@ -2380,12 +2381,13 @@ void markAuxiliaryTargets(SalmonOpts& sopt, std::vector& transcripts */ template Eigen::VectorXd -updateEffectiveLengths(SalmonOpts& sopt, ReadExpT& readExp, +updateEffectiveLengths(oneapi::tbb::task_arena& arena, + SalmonOpts& sopt, ReadExpT& readExp, Eigen::VectorXd& effLensIn, AbundanceVecT& alphas, std::vector& available, bool writeBias) { using std::vector; - using BlockedIndexRange = tbb::blocked_range; + using BlockedIndexRange = oneapi::tbb::blocked_range; using salmon::math::EPSILON; using salmon::math::LOG_EPSILON; @@ -2653,10 +2655,11 @@ int contextSize = outsideContext + insideContext; return CombineableBiasParams(K, sopt.numConditionalGCBins, sopt.numFragGCBins); }; - tbb::combinable expectedDist(getBiasParams); + oneapi::tbb::combinable expectedDist(getBiasParams); std::atomic numBackgroundTranscripts{0}; - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(transcripts.size())), [&](const BlockedIndexRange& range) -> void { @@ -2826,6 +2829,7 @@ int contextSize = outsideContext + insideContext; } // end tbb for function ); + }); size_t bgCutoff = std::min(static_cast(150), @@ -2906,7 +2910,8 @@ int contextSize = outsideContext + insideContext; /** * Compute the effective lengths of each transcript (in parallel) */ - tbb::parallel_for( + arena.execute([&]{ + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(transcripts.size())), [&](const BlockedIndexRange& range) -> void { @@ -3147,6 +3152,7 @@ int contextSize = outsideContext + insideContext; } } // end parallel_for lambda ); + }); sopt.jointLog->info("processed bias for 100.0% of the transcripts"); return effLensOut; @@ -3478,6 +3484,7 @@ template void salmon::utils::normalizeAlphas>, BulkExpT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkExpT& readExp, Eigen::VectorXd& effLensIn, std::vector>& alphas, std::vector& available, bool finalRound); @@ -3485,23 +3492,27 @@ salmon::utils::updateEffectiveLengths>, template Eigen::VectorXd salmon::utils::updateEffectiveLengths>, SCExpT>( - SalmonOpts& sopt, SCExpT& readExp, Eigen::VectorXd& effLensIn, - std::vector>& alphas, std::vector& available, - bool finalRound); + oneapi::tbb::task_arena& arena, + SalmonOpts& sopt, SCExpT& readExp, Eigen::VectorXd& effLensIn, + std::vector>& alphas, std::vector& available, + bool finalRound); template Eigen::VectorXd salmon::utils::updateEffectiveLengths, BulkExpT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkExpT& readExp, Eigen::VectorXd& effLensIn, std::vector& alphas, std::vector& available, bool finalRound); template Eigen::VectorXd salmon::utils::updateEffectiveLengths, SCExpT>( - SalmonOpts& sopt, SCExpT& readExp, Eigen::VectorXd& effLensIn, - std::vector& alphas, std::vector& available, bool finalRound); + oneapi::tbb::task_arena& arena, + SalmonOpts& sopt, SCExpT& readExp, Eigen::VectorXd& effLensIn, + std::vector& alphas, std::vector& available, bool finalRound); template Eigen::VectorXd salmon::utils::updateEffectiveLengths, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector& alphas, std::vector& available, bool finalRound); @@ -3509,6 +3520,7 @@ salmon::utils::updateEffectiveLengths, template Eigen::VectorXd salmon::utils::updateEffectiveLengths>, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector>& alphas, std::vector& available, bool finalRound); @@ -3516,6 +3528,7 @@ salmon::utils::updateEffectiveLengths>, template Eigen::VectorXd salmon::utils::updateEffectiveLengths>, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector>& alphas, std::vector& available, bool finalRound); @@ -3523,6 +3536,7 @@ salmon::utils::updateEffectiveLengths>, template Eigen::VectorXd salmon::utils::updateEffectiveLengths>, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector>& alphas, std::vector& available, bool finalRound); @@ -3530,6 +3544,7 @@ salmon::utils::updateEffectiveLengths>, template Eigen::VectorXd salmon::utils::updateEffectiveLengths, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector& alphas, std::vector& available, bool finalRound); @@ -3537,6 +3552,7 @@ salmon::utils::updateEffectiveLengths, template Eigen::VectorXd salmon::utils::updateEffectiveLengths, BulkAlignLibT>( + oneapi::tbb::task_arena& arena, SalmonOpts& sopt, BulkAlignLibT& readExp, Eigen::VectorXd& effLensIn, std::vector& alphas, std::vector& available, bool finalRound); @@ -3591,7 +3607,7 @@ Eigen::VectorXd updateEffectiveLengths(SalmonOpts& sopt, ReadExpT& readExp, AbundanceVecT& alphas, bool writeBias) { using std::vector; - using BlockedIndexRange = tbb::blocked_range; + using BlockedIndexRange = oneapi::tbb::blocked_range; double minAlpha = 1e-8; uint32_t gcSamp{sopt.pdfSampFactor}; @@ -3732,11 +3748,11 @@ Eigen::VectorXd updateEffectiveLengths(SalmonOpts& sopt, ReadExpT& readExp, auto getBiasParams = [K]() -> CombineableBiasParams { return CombineableBiasParams(K); }; - tbb::combinable expectedDist(getBiasParams); + oneapi::tbb::combinable expectedDist(getBiasParams); std::atomic numBackgroundTranscripts{0}; std::atomic numExpressedTranscripts{0}; - tbb::parallel_for( + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(transcripts.size())), [&](const BlockedIndexRange& range) -> void { @@ -4010,7 +4026,7 @@ txp.uniqueUpdateFraction() < 0.90) { std::mutex updateMutex; // Compute the effective lengths of each transcript (in parallel) - tbb::parallel_for( + oneapi::tbb::parallel_for( BlockedIndexRange(size_t(0), size_t(transcripts.size())), [&](const BlockedIndexRange& range) -> void { diff --git a/src/WhiteList.cpp b/src/WhiteList.cpp index 39ce75fcf..fd6559811 100644 --- a/src/WhiteList.cpp +++ b/src/WhiteList.cpp @@ -1,5 +1,5 @@ #include "WhiteList.hpp" -#include "tbb/task_scheduler_init.h" +//#include "tbb/task_scheduler_init.h" #include #include diff --git a/tests/GCSampleTests.cpp b/tests/GCSampleTests.cpp index 743a5330f..829e0445c 100644 --- a/tests/GCSampleTests.cpp +++ b/tests/GCSampleTests.cpp @@ -1,4 +1,12 @@ +#include "catch.hpp" #include +#include +#include +#include "LibraryFormat.hpp" +#include "SalmonUtils.hpp" +#include "Transcript.hpp" +#include "UtilityFunctions.hpp" + std::string generateRandomSequence(size_t length, std::uniform_int_distribution<>& dis, std::mt19937& gen) { char nucs[] = {'A', 'C', 'G', 'T'}; @@ -44,6 +52,7 @@ SCENARIO("GC sampling works properly") { THEN("Sampled is the same as unsampled : ") { for (size_t tn = 0; tn < 1000; ++tn) { + auto l = txpsSampled[tn].RefLength; for (size_t i = 0; i < l; ++i) { REQUIRE(txpsSampled[tn].gcAt(i) == txpsUnSampled[tn].gcAt(i)); diff --git a/tests/KmerHistTests.cpp b/tests/KmerHistTests.cpp index de6fc7a45..425052c13 100644 --- a/tests/KmerHistTests.cpp +++ b/tests/KmerHistTests.cpp @@ -1,3 +1,4 @@ +#include "catch.hpp" #include "UtilityFunctions.hpp" // from http://stackoverflow.com/questions/2380962/generate-all-combinations-of-arbitrary-alphabet-up-to-arbitrary-length diff --git a/tests/LibraryTypeTests.cpp b/tests/LibraryTypeTests.cpp index f7f30b8bb..9ed6097ea 100644 --- a/tests/LibraryTypeTests.cpp +++ b/tests/LibraryTypeTests.cpp @@ -1,3 +1,13 @@ +#include "catch.hpp" +#include +#include +#include +#include "LibraryFormat.hpp" +#include "SalmonUtils.hpp" +#include "Transcript.hpp" +#include "UtilityFunctions.hpp" + + SCENARIO("Library types are encoded/decoded properly") { GIVEN("A collection of library formats") { diff --git a/tests/UnitTests.cpp b/tests/UnitTests.cpp index aaa23f0da..27eaff68b 100644 --- a/tests/UnitTests.cpp +++ b/tests/UnitTests.cpp @@ -1,14 +1,8 @@ #define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file -#include -#include #include "catch.hpp" -#include "LibraryFormat.hpp" -#include "SalmonUtils.hpp" -#include "Transcript.hpp" -#include "UtilityFunctions.hpp" bool verbose=false; // Apparently, we *need* this (OSX) -#include "GCSampleTests.cpp" -#include "LibraryTypeTests.cpp" +//#include "GCSampleTests.cpp" +//#include "LibraryTypeTests.cpp" //#include "KmerHistTests.cpp" diff --git a/tests/catch.hpp b/tests/catch.hpp index 6c1756a6c..db1fed3b9 100644 --- a/tests/catch.hpp +++ b/tests/catch.hpp @@ -1,9 +1,9 @@ /* - * Catch v2.11.1 - * Generated: 2019-12-28 21:22:11.930976 + * Catch v2.13.8 + * Generated: 2022-01-03 21:20:09.589503 * ---------------------------------------------------------- * This file has been merged from multiple headers. Please don't edit it directly - * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * Copyright (c) 2022 Two Blue Cubes Ltd. All rights reserved. * * 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) @@ -14,8 +14,8 @@ #define CATCH_VERSION_MAJOR 2 -#define CATCH_VERSION_MINOR 11 -#define CATCH_VERSION_PATCH 1 +#define CATCH_VERSION_MINOR 13 +#define CATCH_VERSION_PATCH 8 #ifdef __clang__ # pragma clang system_header @@ -66,13 +66,16 @@ #if !defined(CATCH_CONFIG_IMPL_ONLY) // start catch_platform.h +// See e.g.: +// https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-18.1/TargetConditionals.h.auto.html #ifdef __APPLE__ -# include -# if TARGET_OS_OSX == 1 -# define CATCH_PLATFORM_MAC -# elif TARGET_OS_IPHONE == 1 -# define CATCH_PLATFORM_IPHONE -# endif +# include +# if (defined(TARGET_OS_OSX) && TARGET_OS_OSX == 1) || \ + (defined(TARGET_OS_MAC) && TARGET_OS_MAC == 1) +# define CATCH_PLATFORM_MAC +# elif (defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1) +# define CATCH_PLATFORM_IPHONE +# endif #elif defined(linux) || defined(__linux) || defined(__linux__) # define CATCH_PLATFORM_LINUX @@ -132,15 +135,14 @@ namespace Catch { #endif -#if defined(CATCH_CPP17_OR_GREATER) -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - -// We have to avoid both ICC and Clang, because they try to mask themselves -// as gcc, and we want only GCC in this block -#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +// Only GCC compiler should be used in this block, so other compilers trying to +// mask themselves as GCC should be ignored. +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) && !defined(__CUDACC__) && !defined(__LCC__) # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + #endif #if defined(__clang__) @@ -148,6 +150,21 @@ namespace Catch { # define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) # define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) && !defined(__CUDACC__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + # define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") @@ -223,13 +240,6 @@ namespace Catch { // Visual C++ #if defined(_MSC_VER) -# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) -# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) - -# if _MSC_VER >= 1900 // Visual Studio 2015 or newer -# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -# endif - // Universal Windows platform does not support SEH // Or console colours (or console at all...) # if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) @@ -238,13 +248,18 @@ namespace Catch { # define CATCH_INTERNAL_CONFIG_WINDOWS_SEH # endif +# if !defined(__clang__) // Handle Clang masquerading for msvc + // MSVC traditional preprocessor needs some workaround for __VA_ARGS__ // _MSVC_TRADITIONAL == 0 means new conformant preprocessor // _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor -# if !defined(__clang__) // Handle Clang masquerading for msvc # if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) # define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR # endif // MSVC_TRADITIONAL + +// Only do this if we're not using clang on Windows, which uses `diagnostic push` & `diagnostic pop` +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) # endif // __clang__ #endif // _MSC_VER @@ -294,7 +309,7 @@ namespace Catch { #define CATCH_CONFIG_COLOUR_NONE #endif -#if defined(__UCLIBC__) +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) #define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER #endif @@ -312,7 +327,10 @@ namespace Catch { // Check if byte is available and usable # if __has_include() && defined(CATCH_CPP17_OR_GREATER) - # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # include + # if defined(__cpp_lib_byte) && (__cpp_lib_byte > 0) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) // Check if variant is available and usable @@ -355,10 +373,6 @@ namespace Catch { # define CATCH_CONFIG_CPP17_OPTIONAL #endif -#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) -# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS -#endif - #if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) # define CATCH_CONFIG_CPP17_STRING_VIEW #endif @@ -420,6 +434,12 @@ namespace Catch { # define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS #endif +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + #if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) # undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS #elif defined(__clang__) && (__clang_major__ < 5) @@ -751,7 +771,7 @@ constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) n #define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) #define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) #define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) -#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) #define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) #define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) #define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) @@ -920,13 +940,13 @@ namespace Catch { #if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703 // std::result_of is deprecated in C++17 and removed in C++20. Hence, it is - // replaced with std::invoke_result here. Also *_t format is preferred over - // typename *::type format. - template - using FunctionReturnType = std::remove_reference_t>>; + // replaced with std::invoke_result here. + template + using FunctionReturnType = std::remove_reference_t>>; #else - template - using FunctionReturnType = typename std::remove_reference::type>::type>::type; + // Keep ::type here because we still support C++11 + template + using FunctionReturnType = typename std::remove_reference::type>::type>::type; #endif } // namespace Catch @@ -992,34 +1012,34 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG_NO_REGISTRATION(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG_NO_REGISTRATION( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_NO_REGISTRATION_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #endif @@ -1032,7 +1052,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ static void TestName() #define INTERNAL_CATCH_TESTCASE( ... ) \ - INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), __VA_ARGS__ ) + INTERNAL_CATCH_TESTCASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \ @@ -1054,7 +1074,7 @@ struct AutoReg : NonCopyable { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ void TestName::test() #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... ) \ - INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), ClassName, __VA_ARGS__ ) + INTERNAL_CATCH_TEST_CASE_METHOD2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), ClassName, __VA_ARGS__ ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_REGISTER_TESTCASE( Function, ... ) \ @@ -1081,7 +1101,7 @@ struct AutoReg : NonCopyable { int index = 0; \ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ using expander = int[];\ - (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ + (void)expander{(reg_test(Types{}, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -1095,18 +1115,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE(Name, Tags, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename TestType, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_SIG(Name, Tags, Signature, ...) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(TestName, TestFuncName, Name, Tags, Signature, TmplTypes, TypesList) \ @@ -1127,7 +1147,7 @@ struct AutoReg : NonCopyable { constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFuncName ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */\ } \ }; \ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ @@ -1144,18 +1164,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T,__VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T,__VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE(Name, Tags, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_SIG(Name, Tags, Signature, ...)\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2(TestName, TestFunc, Name, Tags, TmplList)\ @@ -1171,7 +1191,7 @@ struct AutoReg : NonCopyable { void reg_tests() { \ int index = 0; \ using expander = int[]; \ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */\ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestFunc ), CATCH_INTERNAL_LINEINFO, Catch::StringRef(), Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */\ } \ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){ \ @@ -1186,7 +1206,7 @@ struct AutoReg : NonCopyable { static void TestFunc() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE(Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), Name, Tags, TmplList ) #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, Signature, ... ) \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ @@ -1205,7 +1225,7 @@ struct AutoReg : NonCopyable { int index = 0; \ constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, __VA_ARGS__)};\ using expander = int[];\ - (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++, 0)... };/* NOLINT */ \ + (void)expander{(reg_test(Types{}, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index]), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -1219,18 +1239,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD( ClassName, Name, Tags,... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, typename T, __VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... ) \ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____C_L_A_S_S____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_C_L_A_S_S_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ) , ClassName, Name, Tags, Signature, __VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2(TestNameClass, TestName, ClassName, Name, Tags, Signature, TmplTypes, TypesList)\ @@ -1254,7 +1274,7 @@ struct AutoReg : NonCopyable { constexpr char const* tmpl_types[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TmplTypes))};\ constexpr char const* types_list[] = {CATCH_REC_LIST(INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS, INTERNAL_CATCH_REMOVE_PARENS(TypesList))};\ constexpr auto num_types = sizeof(types_list) / sizeof(types_list[0]);\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++, 0)... };/* NOLINT */ \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(tmpl_types[index / num_types]) + "<" + std::string(types_list[index % num_types]) + ">", Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -1271,18 +1291,18 @@ struct AutoReg : NonCopyable { #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD( ClassName, Name, Tags, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, typename T,__VA_ARGS__ ) ) #endif #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) + INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature, __VA_ARGS__ ) #else #define INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_SIG( ClassName, Name, Tags, Signature, ... )\ - INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) + INTERNAL_CATCH_EXPAND_VARGS( INTERNAL_CATCH_TEMPLATE_PRODUCT_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, Signature,__VA_ARGS__ ) ) #endif #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( TestNameClass, TestName, ClassName, Name, Tags, TmplList) \ @@ -1301,7 +1321,7 @@ struct AutoReg : NonCopyable { void reg_tests(){\ int index = 0;\ using expander = int[];\ - (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++, 0)... };/* NOLINT */ \ + (void)expander{(Catch::AutoReg( Catch::makeTestInvoker( &TestName::test ), CATCH_INTERNAL_LINEINFO, #ClassName, Catch::NameAndTags{ Name " - " + std::string(INTERNAL_CATCH_STRINGIZE(TmplList)) + " - " + std::to_string(index), Tags } ), index++)... };/* NOLINT */ \ }\ };\ static int INTERNAL_CATCH_UNIQUE_NAME( globalRegistrar ) = [](){\ @@ -1316,7 +1336,7 @@ struct AutoReg : NonCopyable { void TestName::test() #define INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD(ClassName, Name, Tags, TmplList) \ - INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____ ), INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_M_P_L_A_T_E____T_E_S_T____F_U_N_C____ ), ClassName, Name, Tags, TmplList ) + INTERNAL_CATCH_TEMPLATE_LIST_TEST_CASE_METHOD_2( INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_ ), INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_M_P_L_A_T_E_T_E_S_T_F_U_N_C_ ), ClassName, Name, Tags, TmplList ) // end catch_test_registry.h // start catch_capture.hpp @@ -1805,8 +1825,8 @@ namespace Catch { #endif namespace Detail { - template - std::string rangeToString(InputIterator first, InputIterator last) { + template + std::string rangeToString(InputIterator first, Sentinel last) { ReusableStringStream rss; rss << "{ "; if (first != last) { @@ -1964,20 +1984,27 @@ namespace Catch { #endif // CATCH_CONFIG_ENABLE_VARIANT_STRINGMAKER namespace Catch { - struct not_this_one {}; // Tag type for detecting which begin/ end are being selected - - // Import begin/ end from std here so they are considered alongside the fallback (...) overloads in this namespace + // Import begin/ end from std here using std::begin; using std::end; - not_this_one begin( ... ); - not_this_one end( ... ); + namespace detail { + template + struct void_type { + using type = void; + }; + + template + struct is_range_impl : std::false_type { + }; + + template + struct is_range_impl()))>::type> : std::true_type { + }; + } // namespace detail template - struct is_range { - static const bool value = - !std::is_same())), not_this_one>::value && - !std::is_same())), not_this_one>::value; + struct is_range : detail::is_range_impl { }; #if defined(_MANAGED) // Managed types are never ranges @@ -2345,6 +2372,18 @@ namespace Catch { auto operator <= ( RhsT const& rhs ) -> BinaryExpr const { return { static_cast(m_lhs <= rhs), m_lhs, "<=", rhs }; } + template + auto operator | (RhsT const& rhs) -> BinaryExpr const { + return { static_cast(m_lhs | rhs), m_lhs, "|", rhs }; + } + template + auto operator & (RhsT const& rhs) -> BinaryExpr const { + return { static_cast(m_lhs & rhs), m_lhs, "&", rhs }; + } + template + auto operator ^ (RhsT const& rhs) -> BinaryExpr const { + return { static_cast(m_lhs ^ rhs), m_lhs, "^", rhs }; + } template auto operator && ( RhsT const& ) -> BinaryExpr const { @@ -2425,7 +2464,7 @@ namespace Catch { virtual void sectionEnded( SectionEndInfo const& endInfo ) = 0; virtual void sectionEndedEarly( SectionEndInfo const& endInfo ) = 0; - virtual auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; + virtual auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& = 0; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) virtual void benchmarkPreparing( std::string const& name ) = 0; @@ -2663,6 +2702,7 @@ namespace Catch { /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_TEST( macroName, resultDisposition, ... ) \ do { \ + CATCH_INTERNAL_IGNORE_BUT_WARN(__VA_ARGS__); \ Catch::AssertionHandler catchAssertionHandler( macroName##_catch_sr, CATCH_INTERNAL_LINEINFO, CATCH_INTERNAL_STRINGIFY(__VA_ARGS__), resultDisposition ); \ INTERNAL_CATCH_TRY { \ CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ @@ -2671,8 +2711,7 @@ namespace Catch { CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION \ } INTERNAL_CATCH_CATCH( catchAssertionHandler ) \ INTERNAL_CATCH_REACT( catchAssertionHandler ) \ - } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) // the expression here is never evaluated at runtime but it forces the compiler to give it a look - // The double negation silences MSVC's C4800 warning, the static_cast forces short-circuit evaluation if the type has overloaded &&. + } while( (void)0, (false) && static_cast( !!(__VA_ARGS__) ) ) /////////////////////////////////////////////////////////////////////////////// #define INTERNAL_CATCH_IF( macroName, resultDisposition, ... ) \ @@ -2989,6 +3028,9 @@ namespace Catch { {} std::string translate( ExceptionTranslators::const_iterator it, ExceptionTranslators::const_iterator itEnd ) const override { +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return ""; +#else try { if( it == itEnd ) std::rethrow_exception(std::current_exception()); @@ -2998,6 +3040,7 @@ namespace Catch { catch( T& ex ) { return m_translateFunction( ex ); } +#endif } protected: @@ -3050,7 +3093,7 @@ namespace Detail { Approx operator-() const; template ::value>::type> - Approx operator()( T const& value ) { + Approx operator()( T const& value ) const { Approx approx( static_cast(value) ); approx.m_epsilon = m_epsilon; approx.m_margin = m_margin; @@ -3266,9 +3309,10 @@ namespace Matchers { return description; } - MatchAllOf& operator && ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; + MatchAllOf operator && ( MatcherBase const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; } std::vector const*> m_matchers; @@ -3299,9 +3343,10 @@ namespace Matchers { return description; } - MatchAnyOf& operator || ( MatcherBase const& other ) { - m_matchers.push_back( &other ); - return *this; + MatchAnyOf operator || ( MatcherBase const& other ) { + auto copy(*this); + copy.m_matchers.push_back( &other ); + return copy; } std::vector const*> m_matchers; @@ -3558,12 +3603,12 @@ namespace Catch { namespace Matchers { namespace Vector { - template - struct ContainsElementMatcher : MatcherBase> { + template + struct ContainsElementMatcher : MatcherBase> { ContainsElementMatcher(T const &comparator) : m_comparator( comparator) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const override { for (auto const& el : v) { if (el == m_comparator) { return true; @@ -3579,12 +3624,12 @@ namespace Matchers { T const& m_comparator; }; - template - struct ContainsMatcher : MatcherBase> { + template + struct ContainsMatcher : MatcherBase> { - ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + ContainsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const override { // !TBD: see note in EqualsMatcher if (m_comparator.size() > v.size()) return false; @@ -3606,18 +3651,18 @@ namespace Matchers { return "Contains: " + ::Catch::Detail::stringify( m_comparator ); } - std::vector const& m_comparator; + std::vector const& m_comparator; }; - template - struct EqualsMatcher : MatcherBase> { + template + struct EqualsMatcher : MatcherBase> { - EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} + EqualsMatcher(std::vector const &comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const override { // !TBD: This currently works if all elements can be compared using != // - a more general approach would be via a compare template that defaults - // to using !=. but could be specialised for, e.g. std::vector etc + // to using !=. but could be specialised for, e.g. std::vector etc // - then just call that directly if (m_comparator.size() != v.size()) return false; @@ -3629,15 +3674,15 @@ namespace Matchers { std::string describe() const override { return "Equals: " + ::Catch::Detail::stringify( m_comparator ); } - std::vector const& m_comparator; + std::vector const& m_comparator; }; - template - struct ApproxMatcher : MatcherBase> { + template + struct ApproxMatcher : MatcherBase> { - ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} + ApproxMatcher(std::vector const& comparator) : m_comparator( comparator ) {} - bool match(std::vector const &v) const override { + bool match(std::vector const &v) const override { if (m_comparator.size() != v.size()) return false; for (std::size_t i = 0; i < v.size(); ++i) @@ -3664,16 +3709,14 @@ namespace Matchers { return *this; } - std::vector const& m_comparator; + std::vector const& m_comparator; mutable Catch::Detail::Approx approx = Catch::Detail::Approx::custom(); }; - template - struct UnorderedEqualsMatcher : MatcherBase> { - UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} - bool match(std::vector const& vec) const override { - // Note: This is a reimplementation of std::is_permutation, - // because I don't want to include inside the common path + template + struct UnorderedEqualsMatcher : MatcherBase> { + UnorderedEqualsMatcher(std::vector const& target) : m_target(target) {} + bool match(std::vector const& vec) const override { if (m_target.size() != vec.size()) { return false; } @@ -3684,7 +3727,7 @@ namespace Matchers { return "UnorderedEquals: " + ::Catch::Detail::stringify(m_target); } private: - std::vector const& m_target; + std::vector const& m_target; }; } // namespace Vector @@ -3692,29 +3735,29 @@ namespace Matchers { // The following functions create the actual matcher objects. // This allows the types to be inferred - template - Vector::ContainsMatcher Contains( std::vector const& comparator ) { - return Vector::ContainsMatcher( comparator ); + template, typename AllocMatch = AllocComp> + Vector::ContainsMatcher Contains( std::vector const& comparator ) { + return Vector::ContainsMatcher( comparator ); } - template - Vector::ContainsElementMatcher VectorContains( T const& comparator ) { - return Vector::ContainsElementMatcher( comparator ); + template> + Vector::ContainsElementMatcher VectorContains( T const& comparator ) { + return Vector::ContainsElementMatcher( comparator ); } - template - Vector::EqualsMatcher Equals( std::vector const& comparator ) { - return Vector::EqualsMatcher( comparator ); + template, typename AllocMatch = AllocComp> + Vector::EqualsMatcher Equals( std::vector const& comparator ) { + return Vector::EqualsMatcher( comparator ); } - template - Vector::ApproxMatcher Approx( std::vector const& comparator ) { - return Vector::ApproxMatcher( comparator ); + template, typename AllocMatch = AllocComp> + Vector::ApproxMatcher Approx( std::vector const& comparator ) { + return Vector::ApproxMatcher( comparator ); } - template - Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { - return Vector::UnorderedEqualsMatcher(target); + template, typename AllocMatch = AllocComp> + Vector::UnorderedEqualsMatcher UnorderedEquals(std::vector const& target) { + return Vector::UnorderedEqualsMatcher( target ); } } // namespace Matchers @@ -4033,16 +4076,16 @@ namespace Generators { return makeGenerators( value( T( std::forward( val ) ) ), std::forward( moreGenerators )... ); } - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker&; template // Note: The type after -> is weird, because VS2015 cannot parse // the expression used in the typedef inside, when it is in // return type. Yeah. - auto generate( SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { + auto generate( StringRef generatorName, SourceLineInfo const& lineInfo, L const& generatorExpression ) -> decltype(std::declval().get()) { using UnderlyingType = typename decltype(generatorExpression())::type; - IGeneratorTracker& tracker = acquireGeneratorTracker( lineInfo ); + IGeneratorTracker& tracker = acquireGeneratorTracker( generatorName, lineInfo ); if (!tracker.hasGenerator()) { tracker.setGenerator(pf::make_unique>(generatorExpression())); } @@ -4055,11 +4098,17 @@ namespace Generators { } // namespace Catch #define GENERATE( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [ ]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_COPY( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [=]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) #define GENERATE_REF( ... ) \ - Catch::Generators::generate( CATCH_INTERNAL_LINEINFO, [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) + Catch::Generators::generate( INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_UNIQUE_NAME(generator)), \ + CATCH_INTERNAL_LINEINFO, \ + [&]{ using namespace Catch::Generators; return makeGenerators( __VA_ARGS__ ); } ) //NOLINT(google-build-using-namespace) // end catch_generators.hpp // start catch_generators_generic.hpp @@ -4116,7 +4165,7 @@ namespace Generators { if (!m_predicate(m_generator.get())) { // It might happen that there are no values that pass the // filter. In that case we throw an exception. - auto has_initial_value = next(); + auto has_initial_value = nextImpl(); if (!has_initial_value) { Catch::throw_exception(GeneratorException("No valid value found in filtered generator")); } @@ -4128,6 +4177,11 @@ namespace Generators { } bool next() override { + return nextImpl(); + } + + private: + bool nextImpl() { bool success = m_generator.next(); if (!success) { return false; @@ -4411,6 +4465,7 @@ namespace Catch { } // end namespace Catch // end catch_option.hpp +#include #include #include #include @@ -4468,6 +4523,7 @@ namespace Catch { virtual int abortAfter() const = 0; virtual bool showInvisibles() const = 0; virtual ShowDurations::OrNot showDurations() const = 0; + virtual double minDuration() const = 0; virtual TestSpec const& testSpec() const = 0; virtual bool hasTestFilters() const = 0; virtual std::vector const& getTestsOrTags() const = 0; @@ -4481,6 +4537,7 @@ namespace Catch { virtual int benchmarkSamples() const = 0; virtual double benchmarkConfidenceInterval() const = 0; virtual unsigned int benchmarkResamples() const = 0; + virtual std::chrono::milliseconds benchmarkWarmupTime() const = 0; }; using IConfigPtr = std::shared_ptr; @@ -5234,10 +5291,12 @@ namespace Catch { unsigned int benchmarkSamples = 100; double benchmarkConfidenceInterval = 0.95; unsigned int benchmarkResamples = 100000; + std::chrono::milliseconds::rep benchmarkWarmupTime = 100; Verbosity verbosity = Verbosity::Normal; WarnAbout::What warnings = WarnAbout::Nothing; ShowDurations::OrNot showDurations = ShowDurations::DefaultForReporter; + double minDuration = -1; RunTests::InWhatOrder runOrder = RunTests::InDeclarationOrder; UseColour::YesOrNo useColour = UseColour::Auto; WaitForKeypress::When waitForKeypress = WaitForKeypress::Never; @@ -5288,6 +5347,7 @@ namespace Catch { bool warnAboutMissingAssertions() const override; bool warnAboutNoTests() const override; ShowDurations::OrNot showDurations() const override; + double minDuration() const override; RunTests::InWhatOrder runOrder() const override; unsigned int rngSeed() const override; UseColour::YesOrNo useColour() const override; @@ -5299,6 +5359,7 @@ namespace Catch { int benchmarkSamples() const override; double benchmarkConfidenceInterval() const override; unsigned int benchmarkResamples() const override; + std::chrono::milliseconds benchmarkWarmupTime() const override; private: @@ -5404,6 +5465,8 @@ namespace Catch { } // namespace Catch // end catch_outlier_classification.hpp + +#include #endif // CATCH_CONFIG_ENABLE_BENCHMARKING #include @@ -5664,6 +5727,9 @@ namespace Catch { // Returns double formatted as %.3f (format expected on output) std::string getFormattedDuration( double duration ); + //! Should the reporter show + bool shouldShowDuration( IConfig const& config, double duration ); + std::string serializeFilters( std::vector const& container ); template @@ -6057,8 +6123,6 @@ namespace Catch { static std::string getDescription(); - ReporterPreferences getPreferences() const override; - void noMatchingTestCases(std::string const& spec) override; void assertionStarting(AssertionInfo const&) override; @@ -6287,9 +6351,10 @@ namespace Catch { void writeTestCase(TestCaseNode const& testCaseNode); - void writeSection(std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode); + void writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail ); void writeAssertions(SectionNode const& sectionNode); void writeAssertion(AssertionStats const& stats); @@ -6506,20 +6571,18 @@ namespace Catch { return {}; } }; - template - using ResultOf_t = typename std::result_of::type; // invoke and not return void :( template - CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { - return CompleteInvoker>::invoke(std::forward(fun), std::forward(args)...); + CompleteType_t> complete_invoke(Fun&& fun, Args&&... args) { + return CompleteInvoker>::invoke(std::forward(fun), std::forward(args)...); } const std::string benchmarkErrorMsg = "a benchmark failed to run successfully"; } // namespace Detail template - Detail::CompleteType_t> user_code(Fun&& fun) { + Detail::CompleteType_t> user_code(Fun&& fun) { CATCH_TRY{ return Detail::complete_invoke(std::forward(fun)); } CATCH_CATCH_ALL{ @@ -6764,8 +6827,8 @@ namespace Catch { Result result; int iterations; }; - template - using TimingOf = Timing, Detail::CompleteType_t>>; + template + using TimingOf = Timing, Detail::CompleteType_t>>; } // namespace Benchmark } // namespace Catch @@ -6776,7 +6839,7 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure(Fun&& fun, Args&&... args) { + TimingOf measure(Fun&& fun, Args&&... args) { auto start = Clock::now(); auto&& r = Detail::complete_invoke(fun, std::forward(args)...); auto end = Clock::now(); @@ -6795,11 +6858,11 @@ namespace Catch { namespace Benchmark { namespace Detail { template - TimingOf measure_one(Fun&& fun, int iters, std::false_type) { + TimingOf measure_one(Fun&& fun, int iters, std::false_type) { return Detail::measure(fun, iters); } template - TimingOf measure_one(Fun&& fun, int iters, std::true_type) { + TimingOf measure_one(Fun&& fun, int iters, std::true_type) { Detail::ChronometerModel meter; auto&& result = Detail::complete_invoke(fun, Chronometer(meter, iters)); @@ -6816,7 +6879,7 @@ namespace Catch { }; template - TimingOf)> run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { + TimingOf> run_for_at_least(ClockDuration how_long, int seed, Fun&& fun) { auto iters = seed; while (iters < (1 << 30)) { auto&& Timing = measure_one(fun, iters, is_callable()); @@ -6826,7 +6889,7 @@ namespace Catch { } iters *= 2; } - throw optimized_away_error{}; + Catch::throw_exception(optimized_away_error{}); } } // namespace Detail } // namespace Benchmark @@ -6834,6 +6897,7 @@ namespace Catch { // end catch_run_for_at_least.hpp #include +#include namespace Catch { namespace Benchmark { @@ -6884,11 +6948,13 @@ namespace Catch { #include #include #include +#include #include #include #include #include #include +#include namespace Catch { namespace Benchmark { @@ -7002,8 +7068,8 @@ namespace Catch { double b2 = bias - z1; double a1 = a(b1); double a2 = a(b2); - auto lo = std::max(cumn(a1), 0); - auto hi = std::min(cumn(a2), n - 1); + auto lo = (std::max)(cumn(a1), 0); + auto hi = (std::min)(cumn(a2), n - 1); return { point, resample[lo], resample[hi], confidence_level }; } @@ -7072,7 +7138,9 @@ namespace Catch { } template EnvironmentEstimate> estimate_clock_cost(FloatDuration resolution) { - auto time_limit = std::min(resolution * clock_cost_estimation_tick_limit, FloatDuration(clock_cost_estimation_time_limit)); + auto time_limit = (std::min)( + resolution * clock_cost_estimation_tick_limit, + FloatDuration(clock_cost_estimation_time_limit)); auto time_clock = [](int k) { return Detail::measure([k] { for (int i = 0; i < k; ++i) { @@ -7238,10 +7306,10 @@ namespace Catch { template ExecutionPlan> prepare(const IConfig &cfg, Environment> env) const { auto min_time = env.clock_resolution.mean * Detail::minimum_ticks; - auto run_time = std::max(min_time, std::chrono::duration_cast(Detail::warmup_time)); + auto run_time = std::max(min_time, std::chrono::duration_cast(cfg.benchmarkWarmupTime())); auto&& test = Detail::run_for_at_least(std::chrono::duration_cast>(run_time), 1, fun); int new_iters = static_cast(std::ceil(min_time * test.iterations / test.elapsed)); - return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(Detail::warmup_time), Detail::warmup_iterations }; + return { new_iters, test.elapsed / test.iterations * new_iters * cfg.benchmarkSamples(), fun, std::chrono::duration_cast>(cfg.benchmarkWarmupTime()), Detail::warmup_iterations }; } template @@ -7412,23 +7480,37 @@ namespace TestCaseTracking { SourceLineInfo location; NameAndLocation( std::string const& _name, SourceLineInfo const& _location ); + friend bool operator==(NameAndLocation const& lhs, NameAndLocation const& rhs) { + return lhs.name == rhs.name + && lhs.location == rhs.location; + } }; - struct ITracker; + class ITracker; using ITrackerPtr = std::shared_ptr; - struct ITracker { - virtual ~ITracker(); + class ITracker { + NameAndLocation m_nameAndLocation; + + public: + ITracker(NameAndLocation const& nameAndLoc) : + m_nameAndLocation(nameAndLoc) + {} // static queries - virtual NameAndLocation const& nameAndLocation() const = 0; + NameAndLocation const& nameAndLocation() const { + return m_nameAndLocation; + } + + virtual ~ITracker(); // dynamic queries virtual bool isComplete() const = 0; // Successfully completed or failed virtual bool isSuccessfullyCompleted() const = 0; virtual bool isOpen() const = 0; // Started but not complete virtual bool hasChildren() const = 0; + virtual bool hasStarted() const = 0; virtual ITracker& parent() = 0; @@ -7483,7 +7565,6 @@ namespace TestCaseTracking { }; using Children = std::vector; - NameAndLocation m_nameAndLocation; TrackerContext& m_ctx; ITracker* m_parent; Children m_children; @@ -7492,11 +7573,13 @@ namespace TestCaseTracking { public: TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ); - NameAndLocation const& nameAndLocation() const override; bool isComplete() const override; bool isSuccessfullyCompleted() const override; bool isOpen() const override; bool hasChildren() const override; + bool hasStarted() const override { + return m_runState != NotStarted; + } void addChild( ITrackerPtr const& child ) override; @@ -7535,6 +7618,10 @@ namespace TestCaseTracking { void addInitialFilters( std::vector const& filters ); void addNextFilters( std::vector const& filters ); + //! Returns filters active in this tracker + std::vector const& getFilters() const; + //! Returns whitespace-trimmed name of the tracked section + std::string const& trimmedName() const; }; } // namespace TestCaseTracking @@ -7700,7 +7787,7 @@ namespace Catch { double sb = stddev.point; double mn = mean.point / n; double mg_min = mn / 2.; - double sg = std::min(mg_min / 4., sb / std::sqrt(n)); + double sg = (std::min)(mg_min / 4., sb / std::sqrt(n)); double sg2 = sg * sg; double sb2 = sb * sb; @@ -7719,7 +7806,7 @@ namespace Catch { return (nc / n) * (sb2 - nc * sg2); }; - return std::min(var_out(1), var_out(std::min(c_max(0.), c_max(mg_min)))) / sb2; + return (std::min)(var_out(1), var_out((std::min)(c_max(0.), c_max(mg_min)))) / sb2; } bootstrap_analysis analyse_samples(double confidence_level, int n_resamples, std::vector::iterator first, std::vector::iterator last) { @@ -7859,7 +7946,11 @@ namespace Catch { #ifdef CATCH_PLATFORM_MAC - #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #if defined(__i386__) || defined(__x86_64__) + #define CATCH_TRAP() __asm__("int $3\n" : : ) /* NOLINT */ + #elif defined(__aarch64__) + #define CATCH_TRAP() __asm__(".inst 0xd4200000") + #endif #elif defined(CATCH_PLATFORM_IPHONE) @@ -7868,8 +7959,10 @@ namespace Catch { #define CATCH_TRAP() __asm__("int $3") #elif defined(__aarch64__) #define CATCH_TRAP() __asm__(".inst 0xd4200000") - #elif defined(__arm__) + #elif defined(__arm__) && !defined(__thumb__) #define CATCH_TRAP() __asm__(".inst 0xe7f001f0") + #elif defined(__arm__) && defined(__thumb__) + #define CATCH_TRAP() __asm__(".inst 0xde01") #endif #elif defined(CATCH_PLATFORM_LINUX) @@ -7890,10 +7983,12 @@ namespace Catch { #define CATCH_TRAP() DebugBreak() #endif -#ifdef CATCH_TRAP - #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() -#else - #define CATCH_BREAK_INTO_DEBUGGER() []{}() +#ifndef CATCH_BREAK_INTO_DEBUGGER + #ifdef CATCH_TRAP + #define CATCH_BREAK_INTO_DEBUGGER() []{ if( Catch::isDebuggerActive() ) { CATCH_TRAP(); } }() + #else + #define CATCH_BREAK_INTO_DEBUGGER() []{}() + #endif #endif // end catch_debugger.h @@ -7901,86 +7996,58 @@ namespace Catch { // start catch_fatal_condition.h -// start catch_windows_h_proxy.h - - -#if defined(CATCH_PLATFORM_WINDOWS) - -#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) -# define CATCH_DEFINED_NOMINMAX -# define NOMINMAX -#endif -#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) -# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -#endif - -#ifdef __AFXDLL -#include -#else -#include -#endif - -#ifdef CATCH_DEFINED_NOMINMAX -# undef NOMINMAX -#endif -#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN -# undef WIN32_LEAN_AND_MEAN -#endif - -#endif // defined(CATCH_PLATFORM_WINDOWS) - -// end catch_windows_h_proxy.h -#if defined( CATCH_CONFIG_WINDOWS_SEH ) +#include namespace Catch { - struct FatalConditionHandler { - - static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo); + // Wrapper for platform-specific fatal error (signals/SEH) handlers + // + // Tries to be cooperative with other handlers, and not step over + // other handlers. This means that unknown structured exceptions + // are passed on, previous signal handlers are called, and so on. + // + // Can only be instantiated once, and assumes that once a signal + // is caught, the binary will end up terminating. Thus, there + class FatalConditionHandler { + bool m_started = false; + + // Install/disengage implementation for specific platform. + // Should be if-defed to work on current platform, can assume + // engage-disengage 1:1 pairing. + void engage_platform(); + void disengage_platform(); + public: + // Should also have platform-specific implementations as needed FatalConditionHandler(); - static void reset(); ~FatalConditionHandler(); - private: - static bool isSet; - static ULONG guaranteeSize; - static PVOID exceptionHandlerHandle; - }; - -} // namespace Catch - -#elif defined ( CATCH_CONFIG_POSIX_SIGNALS ) - -#include - -namespace Catch { - - struct FatalConditionHandler { - - static bool isSet; - static struct sigaction oldSigActions[]; - static stack_t oldSigStack; - static char altStackMem[]; - - static void handleSignal( int sig ); + void engage() { + assert(!m_started && "Handler cannot be installed twice."); + m_started = true; + engage_platform(); + } - FatalConditionHandler(); - ~FatalConditionHandler(); - static void reset(); + void disengage() { + assert(m_started && "Handler cannot be uninstalled without being installed first"); + m_started = false; + disengage_platform(); + } }; -} // namespace Catch - -#else - -namespace Catch { - struct FatalConditionHandler { - void reset(); + //! Simple RAII guard for (dis)engaging the FatalConditionHandler + class FatalConditionHandlerGuard { + FatalConditionHandler* m_handler; + public: + FatalConditionHandlerGuard(FatalConditionHandler* handler): + m_handler(handler) { + m_handler->engage(); + } + ~FatalConditionHandlerGuard() { + m_handler->disengage(); + } }; -} -#endif +} // end namespace Catch // end catch_fatal_condition.h #include @@ -8040,7 +8107,7 @@ namespace Catch { void sectionEnded( SectionEndInfo const& endInfo ) override; void sectionEndedEarly( SectionEndInfo const& endInfo ) override; - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& override; #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) void benchmarkPreparing( std::string const& name ) override; @@ -8106,6 +8173,7 @@ namespace Catch { std::vector m_unfinishedSections; std::vector m_activeSections; TrackerContext m_trackerContext; + FatalConditionHandler m_fatalConditionhandler; bool m_lastAssertionPassed = false; bool m_shouldReportUnexpected = true; bool m_includeSuccessfulResults; @@ -9016,7 +9084,7 @@ namespace detail { } inline auto convertInto( std::string const &source, bool &target ) -> ParserResult { std::string srcLC = source; - std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( char c ) { return static_cast( std::tolower(c) ); } ); + std::transform( srcLC.begin(), srcLC.end(), srcLC.begin(), []( unsigned char c ) { return static_cast( std::tolower(c) ); } ); if (srcLC == "y" || srcLC == "1" || srcLC == "true" || srcLC == "yes" || srcLC == "on") target = true; else if (srcLC == "n" || srcLC == "0" || srcLC == "false" || srcLC == "no" || srcLC == "off") @@ -9665,8 +9733,7 @@ namespace Catch { if( !startsWith( line, '"' ) ) line = '"' + line + '"'; config.testsOrTags.push_back( line ); - config.testsOrTags.push_back( "," ); - + config.testsOrTags.emplace_back( "," ); } } //Remove comma in the end @@ -9707,14 +9774,16 @@ namespace Catch { }; auto const setWaitForKeypress = [&]( std::string const& keypress ) { auto keypressLc = toLower( keypress ); - if( keypressLc == "start" ) + if (keypressLc == "never") + config.waitForKeypress = WaitForKeypress::Never; + else if( keypressLc == "start" ) config.waitForKeypress = WaitForKeypress::BeforeStart; else if( keypressLc == "exit" ) config.waitForKeypress = WaitForKeypress::BeforeExit; else if( keypressLc == "both" ) config.waitForKeypress = WaitForKeypress::BeforeStartAndExit; else - return ParserResult::runtimeError( "keypress argument must be one of: start, exit or both. '" + keypress + "' not recognised" ); + return ParserResult::runtimeError( "keypress argument must be one of: never, start, exit or both. '" + keypress + "' not recognised" ); return ParserResult::ok( ParseResultType::Matched ); }; auto const setVerbosity = [&]( std::string const& verbosity ) { @@ -9784,6 +9853,9 @@ namespace Catch { | Opt( [&]( bool flag ) { config.showDurations = flag ? ShowDurations::Always : ShowDurations::Never; }, "yes|no" ) ["-d"]["--durations"] ( "show test durations" ) + | Opt( config.minDuration, "seconds" ) + ["-D"]["--min-duration"] + ( "show test durations for tests taking at least the given number of seconds" ) | Opt( loadTestNamesFromFile, "filename" ) ["-f"]["--input-file"] ( "load test names to run from a file" ) @@ -9814,7 +9886,7 @@ namespace Catch { | Opt( config.libIdentify ) ["--libidentify"] ( "report name and version according to libidentify standard" ) - | Opt( setWaitForKeypress, "start|exit|both" ) + | Opt( setWaitForKeypress, "never|start|exit|both" ) ["--wait-for-keypress"] ( "waits for a keypress before exiting" ) | Opt( config.benchmarkSamples, "samples" ) @@ -9829,7 +9901,10 @@ namespace Catch { | Opt( config.benchmarkNoAnalysis ) ["--benchmark-no-analysis"] ( "perform only measurements; do not perform any analysis" ) - | Arg( config.testsOrTags, "test name|pattern|tags" ) + | Opt( config.benchmarkWarmupTime, "benchmarkWarmupTime" ) + ["--benchmark-warmup-time"] + ( "amount of time in milliseconds spent on warming up each test (default: 100)" ) + | Arg( config.testsOrTags, "test name|pattern|tags" ) ( "which test or tests to use" ); return cli; @@ -9928,6 +10003,7 @@ namespace Catch { bool Config::warnAboutMissingAssertions() const { return !!(m_data.warnings & WarnAbout::NoAssertions); } bool Config::warnAboutNoTests() const { return !!(m_data.warnings & WarnAbout::NoTests); } ShowDurations::OrNot Config::showDurations() const { return m_data.showDurations; } + double Config::minDuration() const { return m_data.minDuration; } RunTests::InWhatOrder Config::runOrder() const { return m_data.runOrder; } unsigned int Config::rngSeed() const { return m_data.rngSeed; } UseColour::YesOrNo Config::useColour() const { return m_data.useColour; } @@ -9936,10 +10012,11 @@ namespace Catch { bool Config::showInvisibles() const { return m_data.showInvisibles; } Verbosity Config::verbosity() const { return m_data.verbosity; } - bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } - int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } - double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } - unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } + bool Config::benchmarkNoAnalysis() const { return m_data.benchmarkNoAnalysis; } + int Config::benchmarkSamples() const { return m_data.benchmarkSamples; } + double Config::benchmarkConfidenceInterval() const { return m_data.benchmarkConfidenceInterval; } + unsigned int Config::benchmarkResamples() const { return m_data.benchmarkResamples; } + std::chrono::milliseconds Config::benchmarkWarmupTime() const { return std::chrono::milliseconds(m_data.benchmarkWarmupTime); } IStream const* Config::openStream() { return Catch::makeStream(m_data.outputFilename); @@ -9969,6 +10046,36 @@ namespace Catch { } // end catch_errno_guard.h +// start catch_windows_h_proxy.h + + +#if defined(CATCH_PLATFORM_WINDOWS) + +#if !defined(NOMINMAX) && !defined(CATCH_CONFIG_NO_NOMINMAX) +# define CATCH_DEFINED_NOMINMAX +# define NOMINMAX +#endif +#if !defined(WIN32_LEAN_AND_MEAN) && !defined(CATCH_CONFIG_NO_WIN32_LEAN_AND_MEAN) +# define CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +#endif + +#ifdef __AFXDLL +#include +#else +#include +#endif + +#ifdef CATCH_DEFINED_NOMINMAX +# undef NOMINMAX +#endif +#ifdef CATCH_DEFINED_WIN32_LEAN_AND_MEAN +# undef WIN32_LEAN_AND_MEAN +#endif + +#endif // defined(CATCH_PLATFORM_WINDOWS) + +// end catch_windows_h_proxy.h #include namespace Catch { @@ -9980,7 +10087,7 @@ namespace Catch { }; struct NoColourImpl : IColourImpl { - void use( Colour::Code ) {} + void use( Colour::Code ) override {} static IColourImpl* instance() { static NoColourImpl s_instance; @@ -10153,13 +10260,13 @@ namespace Catch { namespace Catch { Colour::Colour( Code _colourCode ) { use( _colourCode ); } - Colour::Colour( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; + Colour::Colour( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; } - Colour& Colour::operator=( Colour&& rhs ) noexcept { - m_moved = rhs.m_moved; - rhs.m_moved = true; + Colour& Colour::operator=( Colour&& other ) noexcept { + m_moved = other.m_moved; + other.m_moved = true; return *this; } @@ -10171,7 +10278,7 @@ namespace Catch { // However, under some conditions it does happen (see #1626), // and this change is small enough that we can let practicality // triumph over purity in this case. - if (impl != NULL) { + if (impl != nullptr) { impl->use( _colourCode ); } } @@ -10291,8 +10398,7 @@ namespace Catch { #if defined(CATCH_PLATFORM_MAC) || defined(CATCH_PLATFORM_IPHONE) -# include -# include +# include # include # include # include @@ -10486,7 +10592,7 @@ namespace Catch { // Extracts the actual name part of an enum instance // In other words, it returns the Blue part of Bikeshed::Colour::Blue StringRef extractInstanceName(StringRef enumInstance) { - // Find last occurence of ":" + // Find last occurrence of ":" size_t name_start = enumInstance.size(); while (name_start > 0 && enumInstance[name_start - 1] != ':') { --name_start; @@ -10524,7 +10630,7 @@ namespace Catch { assert( valueNames.size() == values.size() ); std::size_t i = 0; for( auto value : values ) - enumInfo->m_values.push_back({ value, valueNames[i++] }); + enumInfo->m_values.emplace_back(value, valueNames[i++]); return enumInfo; } @@ -10648,25 +10754,47 @@ namespace Catch { // end catch_exception_translator_registry.cpp // start catch_fatal_condition.cpp -#if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif +#include + +#if !defined( CATCH_CONFIG_WINDOWS_SEH ) && !defined( CATCH_CONFIG_POSIX_SIGNALS ) + +namespace Catch { + + // If neither SEH nor signal handling is required, the handler impls + // do not have to do anything, and can be empty. + void FatalConditionHandler::engage_platform() {} + void FatalConditionHandler::disengage_platform() {} + FatalConditionHandler::FatalConditionHandler() = default; + FatalConditionHandler::~FatalConditionHandler() = default; + +} // end namespace Catch + +#endif // !CATCH_CONFIG_WINDOWS_SEH && !CATCH_CONFIG_POSIX_SIGNALS + +#if defined( CATCH_CONFIG_WINDOWS_SEH ) && defined( CATCH_CONFIG_POSIX_SIGNALS ) +#error "Inconsistent configuration: Windows' SEH handling and POSIX signals cannot be enabled at the same time" +#endif // CATCH_CONFIG_WINDOWS_SEH && CATCH_CONFIG_POSIX_SIGNALS #if defined( CATCH_CONFIG_WINDOWS_SEH ) || defined( CATCH_CONFIG_POSIX_SIGNALS ) namespace { - // Report the error condition + //! Signals fatal error message to the run context void reportFatal( char const * const message ) { Catch::getCurrentContext().getResultCapture()->handleFatalErrorCondition( message ); } -} -#endif // signals/SEH handling + //! Minimal size Catch2 needs for its own fatal error handling. + //! Picked anecdotally, so it might not be sufficient on all + //! platforms, and for all configurations. + constexpr std::size_t minStackSizeForErrors = 32 * 1024; +} // end unnamed namespace + +#endif // CATCH_CONFIG_WINDOWS_SEH || CATCH_CONFIG_POSIX_SIGNALS #if defined( CATCH_CONFIG_WINDOWS_SEH ) namespace Catch { + struct SignalDefs { DWORD id; const char* name; }; // There is no 1-1 mapping between signals and windows exceptions. @@ -10679,7 +10807,7 @@ namespace Catch { { static_cast(EXCEPTION_INT_DIVIDE_BY_ZERO), "Divide by zero error" }, }; - LONG CALLBACK FatalConditionHandler::handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { + static LONG CALLBACK handleVectoredException(PEXCEPTION_POINTERS ExceptionInfo) { for (auto const& def : signalDefs) { if (ExceptionInfo->ExceptionRecord->ExceptionCode == def.id) { reportFatal(def.name); @@ -10690,38 +10818,50 @@ namespace Catch { return EXCEPTION_CONTINUE_SEARCH; } + // Since we do not support multiple instantiations, we put these + // into global variables and rely on cleaning them up in outlined + // constructors/destructors + static PVOID exceptionHandlerHandle = nullptr; + + // For MSVC, we reserve part of the stack memory for handling + // memory overflow structured exception. FatalConditionHandler::FatalConditionHandler() { - isSet = true; - // 32k seems enough for Catch to handle stack overflow, - // but the value was found experimentally, so there is no strong guarantee - guaranteeSize = 32 * 1024; - exceptionHandlerHandle = nullptr; + ULONG guaranteeSize = static_cast(minStackSizeForErrors); + if (!SetThreadStackGuarantee(&guaranteeSize)) { + // We do not want to fully error out, because needing + // the stack reserve should be rare enough anyway. + Catch::cerr() + << "Failed to reserve piece of stack." + << " Stack overflows will not be reported successfully."; + } + } + + // We do not attempt to unset the stack guarantee, because + // Windows does not support lowering the stack size guarantee. + FatalConditionHandler::~FatalConditionHandler() = default; + + void FatalConditionHandler::engage_platform() { // Register as first handler in current chain exceptionHandlerHandle = AddVectoredExceptionHandler(1, handleVectoredException); - // Pass in guarantee size to be filled - SetThreadStackGuarantee(&guaranteeSize); + if (!exceptionHandlerHandle) { + CATCH_RUNTIME_ERROR("Could not register vectored exception handler"); + } } - void FatalConditionHandler::reset() { - if (isSet) { - RemoveVectoredExceptionHandler(exceptionHandlerHandle); - SetThreadStackGuarantee(&guaranteeSize); - exceptionHandlerHandle = nullptr; - isSet = false; + void FatalConditionHandler::disengage_platform() { + if (!RemoveVectoredExceptionHandler(exceptionHandlerHandle)) { + CATCH_RUNTIME_ERROR("Could not unregister vectored exception handler"); } + exceptionHandlerHandle = nullptr; } - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } +} // end namespace Catch -bool FatalConditionHandler::isSet = false; -ULONG FatalConditionHandler::guaranteeSize = 0; -PVOID FatalConditionHandler::exceptionHandlerHandle = nullptr; +#endif // CATCH_CONFIG_WINDOWS_SEH -} // namespace Catch +#if defined( CATCH_CONFIG_POSIX_SIGNALS ) -#elif defined( CATCH_CONFIG_POSIX_SIGNALS ) +#include namespace Catch { @@ -10730,10 +10870,6 @@ namespace Catch { const char* name; }; - // 32kb for the alternate stack seems to be sufficient. However, this value - // is experimentally determined, so that's not guaranteed. - static constexpr std::size_t sigStackSize = 32768 >= MINSIGSTKSZ ? 32768 : MINSIGSTKSZ; - static SignalDefs signalDefs[] = { { SIGINT, "SIGINT - Terminal interrupt signal" }, { SIGILL, "SIGILL - Illegal instruction signal" }, @@ -10743,7 +10879,32 @@ namespace Catch { { SIGABRT, "SIGABRT - Abort (abnormal termination) signal" } }; - void FatalConditionHandler::handleSignal( int sig ) { +// Older GCCs trigger -Wmissing-field-initializers for T foo = {} +// which is zero initialization, but not explicit. We want to avoid +// that. +#if defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#endif + + static char* altStackMem = nullptr; + static std::size_t altStackSize = 0; + static stack_t oldSigStack{}; + static struct sigaction oldSigActions[sizeof(signalDefs) / sizeof(SignalDefs)]{}; + + static void restorePreviousSignalHandlers() { + // We set signal handlers back to the previous ones. Hopefully + // nobody overwrote them in the meantime, and doesn't expect + // their signal handlers to live past ours given that they + // installed them after ours.. + for (std::size_t i = 0; i < sizeof(signalDefs) / sizeof(SignalDefs); ++i) { + sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); + } + // Return the old stack + sigaltstack(&oldSigStack, nullptr); + } + + static void handleSignal( int sig ) { char const * name = ""; for (auto const& def : signalDefs) { if (sig == def.id) { @@ -10751,16 +10912,33 @@ namespace Catch { break; } } - reset(); - reportFatal(name); + // We need to restore previous signal handlers and let them do + // their thing, so that the users can have the debugger break + // when a signal is raised, and so on. + restorePreviousSignalHandlers(); + reportFatal( name ); raise( sig ); } FatalConditionHandler::FatalConditionHandler() { - isSet = true; + assert(!altStackMem && "Cannot initialize POSIX signal handler when one already exists"); + if (altStackSize == 0) { + altStackSize = std::max(static_cast(SIGSTKSZ), minStackSizeForErrors); + } + altStackMem = new char[altStackSize](); + } + + FatalConditionHandler::~FatalConditionHandler() { + delete[] altStackMem; + // We signal that another instance can be constructed by zeroing + // out the pointer. + altStackMem = nullptr; + } + + void FatalConditionHandler::engage_platform() { stack_t sigStack; sigStack.ss_sp = altStackMem; - sigStack.ss_size = sigStackSize; + sigStack.ss_size = altStackSize; sigStack.ss_flags = 0; sigaltstack(&sigStack, &oldSigStack); struct sigaction sa = { }; @@ -10772,40 +10950,17 @@ namespace Catch { } } - FatalConditionHandler::~FatalConditionHandler() { - reset(); - } +#if defined(__GNUC__) +# pragma GCC diagnostic pop +#endif - void FatalConditionHandler::reset() { - if( isSet ) { - // Set signals back to previous values -- hopefully nobody overwrote them in the meantime - for( std::size_t i = 0; i < sizeof(signalDefs)/sizeof(SignalDefs); ++i ) { - sigaction(signalDefs[i].id, &oldSigActions[i], nullptr); - } - // Return the old stack - sigaltstack(&oldSigStack, nullptr); - isSet = false; - } + void FatalConditionHandler::disengage_platform() { + restorePreviousSignalHandlers(); } - bool FatalConditionHandler::isSet = false; - struct sigaction FatalConditionHandler::oldSigActions[sizeof(signalDefs)/sizeof(SignalDefs)] = {}; - stack_t FatalConditionHandler::oldSigStack = {}; - char FatalConditionHandler::altStackMem[sigStackSize] = {}; - -} // namespace Catch - -#else - -namespace Catch { - void FatalConditionHandler::reset() {} -} - -#endif // signals/SEH handling +} // end namespace Catch -#if defined(__GNUC__) -# pragma GCC diagnostic pop -#endif +#endif // CATCH_CONFIG_POSIX_SIGNALS // end catch_fatal_condition.cpp // start catch_generators.cpp @@ -10824,8 +10979,8 @@ namespace Generators { GeneratorUntypedBase::~GeneratorUntypedBase() {} - auto acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { - return getResultCapture().acquireGeneratorTracker( lineInfo ); + auto acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + return getResultCapture().acquireGeneratorTracker( generatorName, lineInfo ); } } // namespace Generators @@ -11100,7 +11255,7 @@ namespace Catch { namespace Catch { std::size_t listTests( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Matching test cases:\n"; else { @@ -11134,7 +11289,7 @@ namespace Catch { } std::size_t listTestsNamesOnly( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); std::size_t matchedTests = 0; std::vector matchedTestCases = filterTests( getAllTestCasesSorted( config ), testSpec, config ); for( auto const& testCaseInfo : matchedTestCases ) { @@ -11172,7 +11327,7 @@ namespace Catch { } std::size_t listTags( Config const& config ) { - TestSpec testSpec = config.testSpec(); + TestSpec const& testSpec = config.testSpec(); if( config.hasTestFilters() ) Catch::cout() << "Tags for matching test cases:\n"; else { @@ -11360,20 +11515,13 @@ namespace { return lhs == rhs; } - auto ulpDiff = std::abs(lc - rc); + // static cast as a workaround for IBM XLC + auto ulpDiff = std::abs(static_cast(lc - rc)); return static_cast(ulpDiff) <= maxUlpDiff; } -} //end anonymous namespace - #if defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) -#if defined(__clang__) -#pragma clang diagnostic push -// The long double overload is currently unused -#pragma clang diagnostic ignored "-Wunused-function" -#endif - float nextafter(float x, float y) { return ::nextafterf(x, y); } @@ -11382,18 +11530,8 @@ namespace { return ::nextafter(x, y); } - long double nextafter(long double x, long double y) { - return ::nextafterl(x, y); - } - -#if defined(__clang__) -#pragma clang diagnostic pop -#endif - #endif // ^^^ CATCH_CONFIG_GLOBAL_NEXTAFTER ^^^ -namespace { - template FP step(FP start, FP direction, uint64_t steps) { for (uint64_t i = 0; i < steps; ++i) { @@ -11552,7 +11690,6 @@ Floating::WithinRelMatcher WithinRel(float target) { } // namespace Matchers } // namespace Catch - // end catch_matchers_floating.cpp // start catch_matchers_generic.cpp @@ -11730,10 +11867,10 @@ namespace Catch { Capturer::Capturer( StringRef macroName, SourceLineInfo const& lineInfo, ResultWas::OfType resultType, StringRef names ) { auto trimmed = [&] (size_t start, size_t end) { - while (names[start] == ',' || isspace(names[start])) { + while (names[start] == ',' || isspace(static_cast(names[start]))) { ++start; } - while (names[end] == ',' || isspace(names[end])) { + while (names[end] == ',' || isspace(static_cast(names[end]))) { --end; } return names.substr(start, end - start + 1); @@ -11772,7 +11909,7 @@ namespace Catch { pos = skipq(pos, c); break; case ',': - if (start != pos && openings.size() == 0) { + if (start != pos && openings.empty()) { m_messages.emplace_back(macroName, lineInfo, resultType); m_messages.back().message = static_cast(trimmed(start, pos)); m_messages.back().message += " := "; @@ -11780,7 +11917,7 @@ namespace Catch { } } } - assert(openings.size() == 0 && "Mismatched openings"); + assert(openings.empty() && "Mismatched openings"); m_messages.emplace_back(macroName, lineInfo, resultType); m_messages.back().message = static_cast(trimmed(start, names.size() - 1)); m_messages.back().message += " := "; @@ -11968,7 +12105,7 @@ namespace Catch { if (tmpnam_s(m_buffer)) { CATCH_RUNTIME_ERROR("Could not get a temp filename"); } - if (fopen_s(&m_file, m_buffer, "w")) { + if (fopen_s(&m_file, m_buffer, "w+")) { char buffer[100]; if (strerror_s(buffer, errno)) { CATCH_RUNTIME_ERROR("Could not translate errno to a string"); @@ -12263,11 +12400,13 @@ namespace Catch { namespace Catch { class StartupExceptionRegistry { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) public: void add(std::exception_ptr const& exception) noexcept; std::vector const& getExceptions() const noexcept; private: std::vector m_exceptions; +#endif }; } // end namespace Catch @@ -12350,7 +12489,11 @@ namespace Catch { m_tagAliasRegistry.add( alias, tag, lineInfo ); } void registerStartupException() noexcept override { +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) m_exceptionRegistry.add(std::current_exception()); +#else + CATCH_INTERNAL_ERROR("Attempted to register active exception under CATCH_CONFIG_DISABLE_EXCEPTIONS!"); +#endif } IMutableEnumValuesRegistry& getMutableEnumValuesRegistry() override { return m_enumValuesRegistry; @@ -12454,17 +12597,32 @@ namespace Catch { std::shared_ptr tracker; ITracker& currentTracker = ctx.currentTracker(); - if( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { + // Under specific circumstances, the generator we want + // to acquire is also the current tracker. If this is + // the case, we have to avoid looking through current + // tracker's children, and instead return the current + // tracker. + // A case where this check is important is e.g. + // for (int i = 0; i < 5; ++i) { + // int n = GENERATE(1, 2); + // } + // + // without it, the code above creates 5 nested generators. + if (currentTracker.nameAndLocation() == nameAndLocation) { + auto thisTracker = currentTracker.parent().findChild(nameAndLocation); + assert(thisTracker); + assert(thisTracker->isGeneratorTracker()); + tracker = std::static_pointer_cast(thisTracker); + } else if ( TestCaseTracking::ITrackerPtr childTracker = currentTracker.findChild( nameAndLocation ) ) { assert( childTracker ); assert( childTracker->isGeneratorTracker() ); tracker = std::static_pointer_cast( childTracker ); - } - else { + } else { tracker = std::make_shared( nameAndLocation, ctx, ¤tTracker ); currentTracker.addChild( tracker ); } - if( !ctx.completedCycle() && !tracker->isComplete() ) { + if( !tracker->isComplete() ) { tracker->open(); } @@ -12478,8 +12636,68 @@ namespace Catch { } void close() override { TrackerBase::close(); - // Generator interface only finds out if it has another item on atual move - if (m_runState == CompletedSuccessfully && m_generator->next()) { + // If a generator has a child (it is followed by a section) + // and none of its children have started, then we must wait + // until later to start consuming its values. + // This catches cases where `GENERATE` is placed between two + // `SECTION`s. + // **The check for m_children.empty cannot be removed**. + // doing so would break `GENERATE` _not_ followed by `SECTION`s. + const bool should_wait_for_child = [&]() { + // No children -> nobody to wait for + if ( m_children.empty() ) { + return false; + } + // If at least one child started executing, don't wait + if ( std::find_if( + m_children.begin(), + m_children.end(), + []( TestCaseTracking::ITrackerPtr tracker ) { + return tracker->hasStarted(); + } ) != m_children.end() ) { + return false; + } + + // No children have started. We need to check if they _can_ + // start, and thus we should wait for them, or they cannot + // start (due to filters), and we shouldn't wait for them + auto* parent = m_parent; + // This is safe: there is always at least one section + // tracker in a test case tracking tree + while ( !parent->isSectionTracker() ) { + parent = &( parent->parent() ); + } + assert( parent && + "Missing root (test case) level section" ); + + auto const& parentSection = + static_cast( *parent ); + auto const& filters = parentSection.getFilters(); + // No filters -> no restrictions on running sections + if ( filters.empty() ) { + return true; + } + + for ( auto const& child : m_children ) { + if ( child->isSectionTracker() && + std::find( filters.begin(), + filters.end(), + static_cast( *child ) + .trimmedName() ) != + filters.end() ) { + return true; + } + } + return false; + }(); + + // This check is a bit tricky, because m_generator->next() + // has a side-effect, where it consumes generator's current + // value, but we do not want to invoke the side-effect if + // this generator is still waiting for any child to start. + if ( should_wait_for_child || + ( m_runState == CompletedSuccessfully && + m_generator->next() ) ) { m_children.clear(); m_runState = Executing; } @@ -12615,10 +12833,10 @@ namespace Catch { return true; } - auto RunContext::acquireGeneratorTracker( SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { + auto RunContext::acquireGeneratorTracker( StringRef generatorName, SourceLineInfo const& lineInfo ) -> IGeneratorTracker& { using namespace Generators; - GeneratorTracker& tracker = GeneratorTracker::acquire( m_trackerContext, TestCaseTracking::NameAndLocation( "generator", lineInfo ) ); - assert( tracker.isOpen() ); + GeneratorTracker& tracker = GeneratorTracker::acquire(m_trackerContext, + TestCaseTracking::NameAndLocation( static_cast(generatorName), lineInfo ) ); m_lastAssertionInfo.lineInfo = lineInfo; return tracker; } @@ -12661,17 +12879,17 @@ namespace Catch { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) void RunContext::benchmarkPreparing(std::string const& name) { - m_reporter->benchmarkPreparing(name); - } + m_reporter->benchmarkPreparing(name); + } void RunContext::benchmarkStarting( BenchmarkInfo const& info ) { m_reporter->benchmarkStarting( info ); } void RunContext::benchmarkEnded( BenchmarkStats<> const& stats ) { m_reporter->benchmarkEnded( stats ); } - void RunContext::benchmarkFailed(std::string const & error) { - m_reporter->benchmarkFailed(error); - } + void RunContext::benchmarkFailed(std::string const & error) { + m_reporter->benchmarkFailed(error); + } #endif // CATCH_CONFIG_ENABLE_BENCHMARKING void RunContext::pushScopedMessage(MessageInfo const & message) { @@ -12805,9 +13023,8 @@ namespace Catch { } void RunContext::invokeActiveTestCase() { - FatalConditionHandler fatalConditionHandler; // Handle signals + FatalConditionHandlerGuard _(&m_fatalConditionhandler); m_activeTestCase->invoke(); - fatalConditionHandler.reset(); } void RunContext::handleUnfinishedSections() { @@ -13268,11 +13485,11 @@ namespace Catch { char **utf8Argv = new char *[ argc ]; for ( int i = 0; i < argc; ++i ) { - int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, NULL, 0, NULL, NULL ); + int bufSize = WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, nullptr, 0, nullptr, nullptr ); utf8Argv[ i ] = new char[ bufSize ]; - WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, NULL, NULL ); + WideCharToMultiByte( CP_UTF8, 0, argv[i], -1, utf8Argv[i], bufSize, nullptr, nullptr ); } int returnCode = applyCommandLine( argc, utf8Argv ); @@ -13392,6 +13609,7 @@ namespace Catch { // end catch_singletons.cpp // start catch_startup_exception_registry.cpp +#if !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) namespace Catch { void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexcept { CATCH_TRY { @@ -13407,6 +13625,7 @@ void StartupExceptionRegistry::add( std::exception_ptr const& exception ) noexce } } // end namespace Catch +#endif // end catch_startup_exception_registry.cpp // start catch_stream.cpp @@ -13591,7 +13810,7 @@ namespace Catch { namespace { char toLowerCh(char c) { - return static_cast( std::tolower( c ) ); + return static_cast( std::tolower( static_cast(c) ) ); } } @@ -13871,7 +14090,8 @@ namespace Catch { } } if( isHidden ) { - tags.push_back( "." ); + // Add all "hidden" tags to make them behave identically + tags.insert( tags.end(), { ".", "!hide" } ); } TestCaseInfo info( static_cast(nameAndTags.name), _className, desc, tags, _lineInfo ); @@ -13966,27 +14186,81 @@ namespace Catch { // end catch_test_case_info.cpp // start catch_test_case_registry_impl.cpp +#include #include namespace Catch { - std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { + namespace { + struct TestHasher { + using hash_t = uint64_t; + + explicit TestHasher( hash_t hashSuffix ): + m_hashSuffix{ hashSuffix } {} + + uint32_t operator()( TestCase const& t ) const { + // FNV-1a hash with multiplication fold. + const hash_t prime = 1099511628211u; + hash_t hash = 14695981039346656037u; + for ( const char c : t.name ) { + hash ^= c; + hash *= prime; + } + hash ^= m_hashSuffix; + hash *= prime; + const uint32_t low{ static_cast( hash ) }; + const uint32_t high{ static_cast( hash >> 32 ) }; + return low * high; + } - std::vector sorted = unsortedTestCases; + private: + hash_t m_hashSuffix; + }; + } // end unnamed namespace + std::vector sortTests( IConfig const& config, std::vector const& unsortedTestCases ) { switch( config.runOrder() ) { - case RunTests::InLexicographicalOrder: - std::sort( sorted.begin(), sorted.end() ); - break; - case RunTests::InRandomOrder: - seedRng( config ); - std::shuffle( sorted.begin(), sorted.end(), rng() ); - break; case RunTests::InDeclarationOrder: // already in declaration order break; + + case RunTests::InLexicographicalOrder: { + std::vector sorted = unsortedTestCases; + std::sort( sorted.begin(), sorted.end() ); + return sorted; + } + + case RunTests::InRandomOrder: { + seedRng( config ); + TestHasher h{ config.rngSeed() }; + + using hashedTest = std::pair; + std::vector indexed_tests; + indexed_tests.reserve( unsortedTestCases.size() ); + + for (auto const& testCase : unsortedTestCases) { + indexed_tests.emplace_back(h(testCase), &testCase); + } + + std::sort(indexed_tests.begin(), indexed_tests.end(), + [](hashedTest const& lhs, hashedTest const& rhs) { + if (lhs.first == rhs.first) { + return lhs.second->name < rhs.second->name; + } + return lhs.first < rhs.first; + }); + + std::vector sorted; + sorted.reserve( indexed_tests.size() ); + + for (auto const& hashed : indexed_tests) { + sorted.emplace_back(*hashed.second); + } + + return sorted; + } } - return sorted; + return unsortedTestCases; } bool isThrowSafe( TestCase const& testCase, IConfig const& config ) { @@ -14123,15 +14397,12 @@ namespace TestCaseTracking { m_currentTracker = tracker; } - TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ) - : m_nameAndLocation( nameAndLocation ), + TrackerBase::TrackerBase( NameAndLocation const& nameAndLocation, TrackerContext& ctx, ITracker* parent ): + ITracker(nameAndLocation), m_ctx( ctx ), m_parent( parent ) {} - NameAndLocation const& TrackerBase::nameAndLocation() const { - return m_nameAndLocation; - } bool TrackerBase::isComplete() const { return m_runState == CompletedSuccessfully || m_runState == Failed; } @@ -14247,7 +14518,8 @@ namespace TestCaseTracking { bool SectionTracker::isComplete() const { bool complete = true; - if ((m_filters.empty() || m_filters[0] == "") + if (m_filters.empty() + || m_filters[0] == "" || std::find(m_filters.begin(), m_filters.end(), m_trimmed_name) != m_filters.end()) { complete = TrackerBase::isComplete(); } @@ -14282,8 +14554,8 @@ namespace TestCaseTracking { void SectionTracker::addInitialFilters( std::vector const& filters ) { if( !filters.empty() ) { m_filters.reserve( m_filters.size() + filters.size() + 2 ); - m_filters.push_back(""); // Root - should never be consulted - m_filters.push_back(""); // Test Case - not a section filter + m_filters.emplace_back(""); // Root - should never be consulted + m_filters.emplace_back(""); // Test Case - not a section filter m_filters.insert( m_filters.end(), filters.begin(), filters.end() ); } } @@ -14292,6 +14564,14 @@ namespace TestCaseTracking { m_filters.insert( m_filters.end(), filters.begin()+1, filters.end() ); } + std::vector const& SectionTracker::getFilters() const { + return m_filters; + } + + std::string const& SectionTracker::trimmedName() const { + return m_trimmed_name; + } + } // namespace TestCaseTracking using TestCaseTracking::ITracker; @@ -14580,6 +14860,7 @@ namespace Catch { m_pos = m_arg.size(); m_substring.clear(); m_patternName.clear(); + m_realPatternPos = 0; return false; } endMode(); @@ -14598,6 +14879,7 @@ namespace Catch { } m_patternName.clear(); + m_realPatternPos = 0; return token; } @@ -15024,11 +15306,48 @@ namespace Catch { // end catch_totals.cpp // start catch_uncaught_exceptions.cpp +// start catch_config_uncaught_exceptions.hpp + +// Copyright Catch2 Authors +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +// SPDX-License-Identifier: BSL-1.0 + +#ifndef CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +#define CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP + +#if defined(_MSC_VER) +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif +#endif + +#include + +#if defined(__cpp_lib_uncaught_exceptions) \ + && !defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif // __cpp_lib_uncaught_exceptions + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) \ + && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) + +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#endif // CATCH_CONFIG_UNCAUGHT_EXCEPTIONS_HPP +// end catch_config_uncaught_exceptions.hpp #include namespace Catch { bool uncaught_exceptions() { -#if defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) + return false; +#elif defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) return std::uncaught_exceptions() > 0; #else return std::uncaught_exception(); @@ -15068,7 +15387,7 @@ namespace Catch { } Version const& libraryVersion() { - static Version version( 2, 11, 1, "", 0 ); + static Version version( 2, 13, 8, "", 0 ); return version; } @@ -15118,8 +15437,6 @@ namespace Catch { #include #include -using uchar = unsigned char; - namespace Catch { namespace { @@ -15192,7 +15509,7 @@ namespace { // (see: http://www.w3.org/TR/xml/#syntax) for( std::size_t idx = 0; idx < m_str.size(); ++ idx ) { - uchar c = m_str[idx]; + unsigned char c = m_str[idx]; switch (c) { case '<': os << "<"; break; case '&': os << "&"; break; @@ -15252,7 +15569,7 @@ namespace { bool valid = true; uint32_t value = headerValue(c); for (std::size_t n = 1; n < encBytes; ++n) { - uchar nc = m_str[idx + n]; + unsigned char nc = m_str[idx + n]; valid &= ((nc & 0xC0) == 0x80); value = (value << 6) | (nc & 0x3F); } @@ -15472,6 +15789,17 @@ namespace Catch { return std::string(buffer); } + bool shouldShowDuration( IConfig const& config, double duration ) { + if ( config.showDurations() == ShowDurations::Always ) { + return true; + } + if ( config.showDurations() == ShowDurations::Never ) { + return false; + } + const double min = config.minDuration(); + return min >= 0 && duration >= min; + } + std::string serializeFilters( std::vector const& container ) { ReusableStringStream oss; bool first = true; @@ -15738,10 +16066,6 @@ class AssertionPrinter { return "Reports test results on a single line, suitable for IDEs"; } - ReporterPreferences CompactReporter::getPreferences() const { - return m_reporterPrefs; - } - void CompactReporter::noMatchingTestCases( std::string const& spec ) { stream << "No test cases matched '" << spec << '\'' << std::endl; } @@ -15768,8 +16092,9 @@ class AssertionPrinter { } void CompactReporter::sectionEnded(SectionStats const& _sectionStats) { - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if ( shouldShowDuration( *m_config, dur ) ) { + stream << getFormattedDuration( dur ) << " s: " << _sectionStats.sectionInfo.name << std::endl; } } @@ -15981,15 +16306,11 @@ class Duration { static const uint64_t s_nanosecondsInASecond = 1000 * s_nanosecondsInAMillisecond; static const uint64_t s_nanosecondsInAMinute = 60 * s_nanosecondsInASecond; - uint64_t m_inNanoseconds; + double m_inNanoseconds; Unit m_units; public: - explicit Duration(double inNanoseconds, Unit units = Unit::Auto) - : Duration(static_cast(inNanoseconds), units) { - } - - explicit Duration(uint64_t inNanoseconds, Unit units = Unit::Auto) + explicit Duration(double inNanoseconds, Unit units = Unit::Auto) : m_inNanoseconds(inNanoseconds), m_units(units) { if (m_units == Unit::Auto) { @@ -16018,7 +16339,7 @@ class Duration { case Unit::Minutes: return m_inNanoseconds / static_cast(s_nanosecondsInAMinute); default: - return static_cast(m_inNanoseconds); + return m_inNanoseconds; } } auto unitsAsString() const -> std::string { @@ -16137,7 +16458,7 @@ ConsoleReporter::ConsoleReporter(ReporterConfig const& config) else { return{ - { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 32, ColumnInfo::Left }, + { "benchmark name", CATCH_CONFIG_CONSOLE_WIDTH - 43, ColumnInfo::Left }, { "samples mean std dev", 14, ColumnInfo::Right }, { "iterations low mean low std dev", 14, ColumnInfo::Right }, { "estimated high mean high std dev", 14, ColumnInfo::Right } @@ -16193,8 +16514,9 @@ void ConsoleReporter::sectionEnded(SectionStats const& _sectionStats) { stream << "\nNo assertions in test case"; stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl; } - if (m_config->showDurations() == ShowDurations::Always) { - stream << getFormattedDuration(_sectionStats.durationInSeconds) << " s: " << _sectionStats.sectionInfo.name << std::endl; + double dur = _sectionStats.durationInSeconds; + if (shouldShowDuration(*m_config, dur)) { + stream << getFormattedDuration(dur) << " s: " << _sectionStats.sectionInfo.name << std::endl; } if (m_headerPrinted) { m_headerPrinted = false; @@ -16454,8 +16776,10 @@ void ConsoleReporter::printSummaryDivider() { } void ConsoleReporter::printTestFilters() { - if (m_config->testSpec().hasFilters()) - stream << Colour(Colour::BrightYellow) << "Filters: " << serializeFilters( m_config->getTestsOrTags() ) << '\n'; + if (m_config->testSpec().hasFilters()) { + Colour guard(Colour::BrightYellow); + stream << "Filters: " << serializeFilters(m_config->getTestsOrTags()) << '\n'; + } } CATCH_REGISTER_REPORTER("console", ConsoleReporter) @@ -16476,6 +16800,7 @@ CATCH_REGISTER_REPORTER("console", ConsoleReporter) #include #include #include +#include namespace Catch { @@ -16503,7 +16828,7 @@ namespace Catch { #else std::strftime(timeStamp, timeStampSize, fmt, timeInfo); #endif - return std::string(timeStamp); + return std::string(timeStamp, timeStampSize-1); } std::string fileNameTag(const std::vector &tags) { @@ -16514,6 +16839,17 @@ namespace Catch { return it->substr(1); return std::string(); } + + // Formats the duration in seconds to 3 decimal places. + // This is done because some genius defined Maven Surefire schema + // in a way that only accepts 3 decimal places, and tools like + // Jenkins use that schema for validation JUnit reporter output. + std::string formatDuration( double seconds ) { + ReusableStringStream rss; + rss << std::fixed << std::setprecision( 3 ) << seconds; + return rss.str(); + } + } // anonymous namespace JunitReporter::JunitReporter( ReporterConfig const& _config ) @@ -16583,7 +16919,7 @@ namespace Catch { if( m_config->showDurations() == ShowDurations::Never ) xml.writeAttribute( "time", "" ); else - xml.writeAttribute( "time", suiteTime ); + xml.writeAttribute( "time", formatDuration( suiteTime ) ); xml.writeAttribute( "timestamp", getCurrentTimestamp() ); // Write properties if there are any @@ -16628,12 +16964,13 @@ namespace Catch { if ( !m_config->name().empty() ) className = m_config->name() + "." + className; - writeSection( className, "", rootSection ); + writeSection( className, "", rootSection, stats.testInfo.okToFail() ); } - void JunitReporter::writeSection( std::string const& className, - std::string const& rootName, - SectionNode const& sectionNode ) { + void JunitReporter::writeSection( std::string const& className, + std::string const& rootName, + SectionNode const& sectionNode, + bool testOkToFail) { std::string name = trim( sectionNode.stats.sectionInfo.name ); if( !rootName.empty() ) name = rootName + '/' + name; @@ -16650,7 +16987,17 @@ namespace Catch { xml.writeAttribute( "classname", className ); xml.writeAttribute( "name", name ); } - xml.writeAttribute( "time", ::Catch::Detail::stringify( sectionNode.stats.durationInSeconds ) ); + xml.writeAttribute( "time", formatDuration( sectionNode.stats.durationInSeconds ) ); + // This is not ideal, but it should be enough to mimic gtest's + // junit output. + // Ideally the JUnit reporter would also handle `skipTest` + // events and write those out appropriately. + xml.writeAttribute( "status", "run" ); + + if (sectionNode.stats.assertions.failedButOk) { + xml.scopedElement("skipped") + .writeAttribute("message", "TEST_CASE tagged with !mayfail"); + } writeAssertions( sectionNode ); @@ -16661,9 +17008,9 @@ namespace Catch { } for( auto const& childNode : sectionNode.childSections ) if( className.empty() ) - writeSection( name, "", *childNode ); + writeSection( name, "", *childNode, testOkToFail ); else - writeSection( className, name, *childNode ); + writeSection( className, name, *childNode, testOkToFail ); } void JunitReporter::writeAssertions( SectionNode const& sectionNode ) { @@ -16681,11 +17028,7 @@ namespace Catch { elementName = "error"; break; case ResultWas::ExplicitFailure: - elementName = "failure"; - break; case ResultWas::ExpressionFailed: - elementName = "failure"; - break; case ResultWas::DidntThrowException: elementName = "failure"; break; @@ -17089,6 +17432,10 @@ namespace Catch { .writeAttribute( "successes", testGroupStats.totals.assertions.passed ) .writeAttribute( "failures", testGroupStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testGroupStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testGroupStats.totals.testCases.passed ) + .writeAttribute( "failures", testGroupStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testGroupStats.totals.testCases.failedButOk ); m_xml.endElement(); } @@ -17098,6 +17445,10 @@ namespace Catch { .writeAttribute( "successes", testRunStats.totals.assertions.passed ) .writeAttribute( "failures", testRunStats.totals.assertions.failed ) .writeAttribute( "expectedFailures", testRunStats.totals.assertions.failedButOk ); + m_xml.scopedElement( "OverallResultsCases") + .writeAttribute( "successes", testRunStats.totals.testCases.passed ) + .writeAttribute( "failures", testRunStats.totals.testCases.failed ) + .writeAttribute( "expectedFailures", testRunStats.totals.testCases.failedButOk ); m_xml.endElement(); } @@ -17111,16 +17462,16 @@ namespace Catch { m_xml.writeAttribute("samples", info.samples) .writeAttribute("resamples", info.resamples) .writeAttribute("iterations", info.iterations) - .writeAttribute("clockResolution", static_cast(info.clockResolution)) - .writeAttribute("estimatedDuration", static_cast(info.estimatedDuration)) + .writeAttribute("clockResolution", info.clockResolution) + .writeAttribute("estimatedDuration", info.estimatedDuration) .writeComment("All values in nano seconds"); } void XmlReporter::benchmarkEnded(BenchmarkStats<> const& benchmarkStats) { m_xml.startElement("mean") - .writeAttribute("value", static_cast(benchmarkStats.mean.point.count())) - .writeAttribute("lowerBound", static_cast(benchmarkStats.mean.lower_bound.count())) - .writeAttribute("upperBound", static_cast(benchmarkStats.mean.upper_bound.count())) + .writeAttribute("value", benchmarkStats.mean.point.count()) + .writeAttribute("lowerBound", benchmarkStats.mean.lower_bound.count()) + .writeAttribute("upperBound", benchmarkStats.mean.upper_bound.count()) .writeAttribute("ci", benchmarkStats.mean.confidence_interval); m_xml.endElement(); m_xml.startElement("standardDeviation") @@ -17171,7 +17522,7 @@ namespace Catch { #ifndef __OBJC__ -#if defined(CATCH_CONFIG_WCHAR) && defined(WIN32) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) +#if defined(CATCH_CONFIG_WCHAR) && defined(CATCH_PLATFORM_WINDOWS) && defined(_UNICODE) && !defined(DO_NOT_USE_WMAIN) // Standard C/C++ Win32 Unicode wmain entry point extern "C" int wmain (int argc, wchar_t * argv[], wchar_t * []) { #else @@ -17304,9 +17655,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define CATCH_BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define CATCH_BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING // If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required @@ -17408,9 +17759,9 @@ int main (int argc, char * const argv[]) { #if defined(CATCH_CONFIG_ENABLE_BENCHMARKING) #define BENCHMARK(...) \ - INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) + INTERNAL_CATCH_BENCHMARK(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), INTERNAL_CATCH_GET_1_ARG(__VA_ARGS__,,), INTERNAL_CATCH_GET_2_ARG(__VA_ARGS__,,)) #define BENCHMARK_ADVANCED(name) \ - INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(____C_A_T_C_H____B_E_N_C_H____), name) + INTERNAL_CATCH_BENCHMARK_ADVANCED(INTERNAL_CATCH_UNIQUE_NAME(C_A_T_C_H_B_E_N_C_H_), name) #endif // CATCH_CONFIG_ENABLE_BENCHMARKING using Catch::Detail::Approx; @@ -17457,8 +17808,8 @@ using Catch::Detail::Approx; #define CATCH_WARN( msg ) (void)(0) #define CATCH_CAPTURE( msg ) (void)(0) -#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define CATCH_METHOD_AS_TEST_CASE( method, ... ) #define CATCH_REGISTER_TEST_CASE( Function, ... ) (void)(0) #define CATCH_SECTION( ... ) @@ -17467,7 +17818,7 @@ using Catch::Detail::Approx; #define CATCH_FAIL_CHECK( ... ) (void)(0) #define CATCH_SUCCEED( ... ) (void)(0) -#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define CATCH_TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17490,8 +17841,8 @@ using Catch::Detail::Approx; #endif // "BDD-style" convenience wrappers -#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define CATCH_SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define CATCH_GIVEN( desc ) #define CATCH_AND_GIVEN( desc ) #define CATCH_WHEN( desc ) @@ -17541,8 +17892,8 @@ using Catch::Detail::Approx; #define WARN( msg ) (void)(0) #define CAPTURE( msg ) (void)(0) -#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) -#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) +#define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #define METHOD_AS_TEST_CASE( method, ... ) #define REGISTER_TEST_CASE( Function, ... ) (void)(0) #define SECTION( ... ) @@ -17550,7 +17901,7 @@ using Catch::Detail::Approx; #define FAIL( ... ) (void)(0) #define FAIL_CHECK( ... ) (void)(0) #define SUCCEED( ... ) (void)(0) -#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )) +#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ )) #ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR #define TEMPLATE_TEST_CASE( ... ) INTERNAL_CATCH_TEMPLATE_TEST_CASE_NO_REGISTRATION(__VA_ARGS__) @@ -17580,8 +17931,8 @@ using Catch::Detail::Approx; #define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION_NO_REG( INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ), signature ) // "BDD-style" convenience wrappers -#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) ) -#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ), className ) +#define SCENARIO( ... ) INTERNAL_CATCH_TESTCASE_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ) ) +#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TESTCASE_METHOD_NO_REGISTRATION(INTERNAL_CATCH_UNIQUE_NAME( C_A_T_C_H_T_E_S_T_ ), className ) #define GIVEN( desc ) #define AND_GIVEN( desc )