├── docs ├── gitignore.txt └── CMakeLists.txt ├── .gitignore ├── cmake ├── mimicpp-config.cmake.in ├── Findmimicpp-uni-algo.cmake ├── Findsanitizers-cmake.cmake ├── Findmimicpp-fmt.cmake ├── get_cpm.cmake ├── Findmimicpp-cpptrace.cmake ├── Mimic++-EnableSanitizers.cmake ├── Mimic++-InstallRules.cmake ├── Mimic++-ReadProjectVersion.cmake └── Mimic++-InternalTargets.cmake ├── test ├── unit-tests │ ├── mimic++.cpp │ ├── signature-traits │ │ └── CMakeLists.txt │ ├── config │ │ ├── CMakeLists.txt │ │ ├── Version.cpp │ │ └── Config.cpp │ ├── macros │ │ ├── CMakeLists.txt │ │ └── Common.cpp │ ├── facade │ │ ├── CMakeLists.txt │ │ └── Common.hpp │ ├── utilities │ │ ├── CMakeLists.txt │ │ ├── Concepts.cpp │ │ ├── C++23Backports.cpp │ │ ├── SourceLocation.cpp │ │ └── StaticString.cpp │ ├── policies │ │ └── CMakeLists.txt │ ├── matchers │ │ └── CMakeLists.txt │ ├── reporting │ │ ├── CMakeLists.txt │ │ ├── TargetReport.cpp │ │ ├── NoMatchReport.cpp │ │ └── TypeReport.cpp │ ├── printing │ │ ├── CMakeLists.txt │ │ ├── Format.cpp │ │ └── PathPrinter.cpp │ ├── Catch2FallbackStringifier.hpp │ ├── call-conventions │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ └── SuppressionMacros.hpp ├── cmake │ ├── Findtrompeloeil.cmake │ ├── FindCatch2.cmake │ ├── FindBoost.cmake │ ├── Findlibassert.cmake │ ├── Mimic++-EnableWarnings.cmake │ ├── Mimic++-EnableAdditionalTestFlags.cmake │ ├── Mimic++-HasStdStacktrace.cmake │ └── Mimic++-LinkStdStacktrace.cmake ├── adapter-tests │ ├── CMakeLists.txt │ ├── catch2 │ │ └── CMakeLists.txt │ ├── gtest │ │ ├── CMakeLists.txt │ │ └── main.cpp │ ├── doctest │ │ ├── CMakeLists.txt │ │ └── main.cpp │ └── boost-test │ │ ├── CMakeLists.txt │ │ └── main.cpp ├── test-basics │ ├── TestAssert.hpp │ └── CMakeLists.txt ├── package-test │ ├── package-consumer │ │ ├── main.cpp │ │ └── CMakeLists.txt │ ├── CMakeLists.txt │ └── RunTest.cmake ├── compile-errors │ ├── missing-finalizer-for-non-void.cpp │ ├── manual-init-finalize-policy.cpp │ ├── multiple-times-policies.cpp │ ├── multiple-finalize-policies.cpp │ └── CMakeLists.txt ├── module-test │ ├── CMakeLists.txt │ └── main.cpp ├── unicode-str-matcher-tests │ └── CMakeLists.txt ├── stacktrace-tests │ ├── custom │ │ ├── CMakeLists.txt │ │ ├── CustomStacktrace.cpp │ │ ├── CustomStacktrace.hpp │ │ └── Printing.cpp │ ├── CMakeLists.txt │ └── test.cpp └── CMakeLists.txt ├── module ├── include │ └── mimic++ │ │ └── MacroExports.hpp ├── CMakeLists.txt └── mimic++.cppm ├── include ├── mimic++ │ ├── printing │ │ ├── StatePrinter.hpp │ │ ├── TypePrinter.hpp │ │ ├── Fwd.hpp │ │ ├── PathPrinter.hpp │ │ ├── state │ │ │ └── C++23Backports.hpp │ │ └── type │ │ │ └── Signature.hpp │ ├── Printing.hpp │ ├── utilities │ │ ├── AlwaysFalse.hpp │ │ ├── PriorityTag.hpp │ │ ├── PassKey.hpp │ │ ├── C++26Backports.hpp │ │ ├── C++20Compatibility.hpp │ │ ├── C++23Backports.hpp │ │ ├── StaticString.hpp │ │ └── Concepts.hpp │ ├── reporting │ │ ├── Fwd.hpp │ │ ├── TargetReport.hpp │ │ ├── NoMatchReport.hpp │ │ ├── SequenceReport.hpp │ │ ├── TypeReport.hpp │ │ ├── ExpectationReport.hpp │ │ ├── BasicReporter.hpp │ │ └── CallReport.hpp │ ├── config │ │ ├── Version.hpp │ │ ├── Settings.hpp │ │ └── Config.hpp │ ├── Reporting.hpp │ ├── Utilities.hpp │ ├── macros │ │ └── ScopedExpectation.hpp │ ├── Call.hpp │ └── mimic++.hpp └── mimic++_ext │ ├── adapters │ ├── Doctest.hpp │ ├── gtest.hpp │ ├── BoostTest.hpp │ └── Catch2.hpp │ └── stacktrace │ ├── std-stacktrace.hpp │ ├── boost-stacktrace.hpp │ └── cpptrace.hpp ├── FUNDING.yml ├── .github └── workflows │ ├── release_adapter_headers.yml │ ├── generate_cheat_sheet.yml │ ├── generate_amalgamated_header.yml │ ├── generate_docs.yml │ └── codeql.yml ├── tools └── amalgamate-headers │ └── CMakeLists.txt ├── LICENSE_1_0.txt ├── examples ├── CMakeLists.txt ├── RegisterCallConvention.cpp ├── CustomPrinter.cpp ├── SideEffects.cpp ├── Times.cpp └── VariadicMocks.cpp └── CMakeLists.txt /docs/gitignore.txt: -------------------------------------------------------------------------------- 1 | build/ 2 | 3 | Doxyfile 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | build 3 | .vs 4 | .idea 5 | *.user 6 | CMakeSettings.json -------------------------------------------------------------------------------- /cmake/mimicpp-config.cmake.in: -------------------------------------------------------------------------------- 1 | @PACKAGE_INIT@ 2 | 3 | set(mimicpp_VERSION "@PROJECT_VERSION@") 4 | include("${CMAKE_CURRENT_LIST_DIR}/mimicpp-targets.cmake") 5 | check_required_components("@PROJECT_NAME@") 6 | -------------------------------------------------------------------------------- /test/unit-tests/mimic++.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/mimic++.hpp" 7 | -------------------------------------------------------------------------------- /test/cmake/Findtrompeloeil.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(get_cpm) 7 | 8 | CPMAddPackage("gh:rollbear/trompeloeil@49") 9 | -------------------------------------------------------------------------------- /test/unit-tests/signature-traits/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} PRIVATE 7 | "AddRefQualifier.cpp" 8 | ) 9 | -------------------------------------------------------------------------------- /test/unit-tests/config/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} PRIVATE 7 | "Config.cpp" 8 | "Version.cpp" 9 | ) 10 | -------------------------------------------------------------------------------- /test/unit-tests/macros/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} PRIVATE 7 | "Common.cpp" 8 | "Facade.cpp" 9 | ) 10 | -------------------------------------------------------------------------------- /test/unit-tests/facade/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} PRIVATE 7 | "Generators.cpp" 8 | "Limits.cpp" 9 | "Traits.cpp" 10 | ) 11 | -------------------------------------------------------------------------------- /test/adapter-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | add_subdirectory("boost-test") 7 | add_subdirectory("catch2") 8 | add_subdirectory("doctest") 9 | add_subdirectory("gtest") 10 | -------------------------------------------------------------------------------- /test/test-basics/TestAssert.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include 9 | 10 | #define MIMICPP_ASSERT(condition, msg) ASSERT(condition, msg) 11 | -------------------------------------------------------------------------------- /test/package-test/package-consumer/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include 7 | 8 | int main() 9 | { 10 | mimicpp::Mock mock{}; 11 | SCOPED_EXP mock.expect_call(); 12 | mock(); 13 | } 14 | -------------------------------------------------------------------------------- /test/unit-tests/utilities/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} 7 | PRIVATE 8 | "Algorithm.cpp" 9 | "Concepts.cpp" 10 | "C++23Backports.cpp" 11 | "SourceLocation.cpp" 12 | "Stacktrace.cpp" 13 | "StaticString.cpp" 14 | "TypeList.cpp" 15 | ) 16 | -------------------------------------------------------------------------------- /test/unit-tests/policies/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} 7 | PRIVATE 8 | "ArgRequirementPolicies.cpp" 9 | "ArgumentList.cpp" 10 | "ControlPolicies.cpp" 11 | "FinalizerPolicies.cpp" 12 | "GeneralPolicies.cpp" 13 | "SideEffectPolicies.cpp" 14 | ) 15 | -------------------------------------------------------------------------------- /test/cmake/FindCatch2.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(get_cpm) 7 | 8 | # fixes reporting in clion 9 | set(CATCH_CONFIG_CONSOLE_WIDTH 800 CACHE STRING "") 10 | 11 | CPMAddPackage("gh:catchorg/Catch2@3.10.0") 12 | 13 | if (Catch2_ADDED) 14 | include("${Catch2_SOURCE_DIR}/extras/Catch.cmake") 15 | endif() 16 | -------------------------------------------------------------------------------- /cmake/Findmimicpp-uni-algo.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(UNI_ALGO_INSTALL ON CACHE BOOL "") 7 | 8 | message(DEBUG "${MESSAGE_PREFIX} Searching for `uni-algo`-package.") 9 | find_package(uni-algo QUIET) 10 | if (NOT uni-algo_FOUND) 11 | include(get_cpm) 12 | CPMAddPackage("gh:uni-algo/uni-algo@1.2.0") 13 | endif () 14 | -------------------------------------------------------------------------------- /test/unit-tests/matchers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} PRIVATE 7 | "Common.cpp" 8 | "FloatingPointMatchers.cpp" 9 | "GeneralMatchers.cpp" 10 | "RangeMatchers.cpp" 11 | "StringContains.cpp" 12 | "StringEndsWith.cpp" 13 | "StringEq.cpp" 14 | "StringStartsWith.cpp" 15 | ) 16 | -------------------------------------------------------------------------------- /module/include/mimic++/MacroExports.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_MACRO_EXPORTS_HPP 7 | #define MIMICPP_MACRO_EXPORTS_HPP 8 | 9 | #include "mimic++/macros/Common.hpp" 10 | #include "mimic++/macros/Facade.hpp" 11 | #include "mimic++/macros/InterfaceMocking.hpp" 12 | #include "mimic++/macros/ScopedExpectation.hpp" 13 | 14 | #endif 15 | -------------------------------------------------------------------------------- /include/mimic++/printing/StatePrinter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_STATE_PRINTER_HPP 7 | #define MIMICPP_PRINTING_STATE_PRINTER_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/printing/state/Print.hpp" 12 | 13 | #include "mimic++/printing/state/C++23Backports.hpp" 14 | #include "mimic++/printing/state/CommonTypes.hpp" 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /test/unit-tests/reporting/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} 7 | PRIVATE 8 | "CallReport.cpp" 9 | "ExpectationReport.cpp" 10 | "NoMatchReport.cpp" 11 | "StringifyReports.cpp" 12 | "TargetReport.cpp" 13 | "TypeReport.cpp" 14 | 15 | "BasicReporter.cpp" 16 | "DefaultReporter.cpp" 17 | "GlobalReporter.cpp" 18 | ) 19 | -------------------------------------------------------------------------------- /test/unit-tests/printing/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | target_sources(${TARGET_NAME} 7 | PRIVATE 8 | "ContainerTypePrinting.cpp" 9 | "Format.cpp" 10 | "PathPrinter.cpp" 11 | "StatePrinter.cpp" 12 | "FunctionTypePostProcessing.cpp" 13 | "TypePostProcessing.cpp" 14 | "TypePrinter.cpp" 15 | "TypeNameLexer.cpp" 16 | "TypeNameParser.cpp" 17 | ) 18 | -------------------------------------------------------------------------------- /include/mimic++/Printing.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTER_HPP 7 | #define MIMICPP_PRINTER_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/printing/Format.hpp" 12 | #include "mimic++/printing/Fwd.hpp" 13 | 14 | #include "mimic++/printing/PathPrinter.hpp" 15 | #include "mimic++/printing/StatePrinter.hpp" 16 | #include "mimic++/printing/TypePrinter.hpp" 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /cmake/Findsanitizers-cmake.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(get_cpm) 7 | 8 | CPMAddPackage( 9 | NAME sanitizers-cmake 10 | GITHUB_REPOSITORY "arsenm/sanitizers-cmake" 11 | GIT_TAG "3f0542e4e034aab417c51b2b22c94f83355dee15" 12 | SYSTEM YES 13 | EXCLUDE_FROM_ALL YES 14 | DOWNLOAD_ONLY YES 15 | ) 16 | 17 | list(APPEND CMAKE_MODULE_PATH "${sanitizers-cmake_SOURCE_DIR}/cmake") 18 | 19 | find_package(Sanitizers REQUIRED) 20 | -------------------------------------------------------------------------------- /test/compile-errors/missing-finalizer-for-non-void.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/mimic++.hpp" 7 | 8 | /* 9 | 10 | For non-void return types, a finalize-policy must be specified\. 11 | See: https://dnkpp\.github\.io/mimicpp 12 | 13 | */ 14 | 15 | void check() 16 | { 17 | mimicpp::Mock mock{}; 18 | SCOPED_EXP mock.expect_call(); 19 | } 20 | -------------------------------------------------------------------------------- /test/cmake/FindBoost.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(get_cpm) 7 | 8 | set(BOOST_INCLUDE_LIBRARIES test stacktrace) 9 | CPMAddPackage( 10 | NAME Boost 11 | URL "https://github.com/boostorg/boost/releases/download/boost-1.89.0/boost-1.89.0-cmake.tar.gz" 12 | URL_HASH "SHA256=954a01219bf818c7fb850fa610c2c8c71a4fa28fa32a1900056bcb6ff58cf908" 13 | VERSION 1.89.0 14 | EXCLUDE_FROM_ALL YES 15 | SYSTEM YES 16 | ) 17 | -------------------------------------------------------------------------------- /test/compile-errors/manual-init-finalize-policy.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/mimic++.hpp" 7 | 8 | /* 9 | 10 | Explicitly specifying the `expectation_policies::InitFinalize` is disallowed\. 11 | 12 | */ 13 | 14 | void check() 15 | { 16 | mimicpp::Mock mock{}; 17 | SCOPED_EXP mock.expect_call() 18 | and mimicpp::expectation_policies::InitFinalize{}; 19 | } 20 | -------------------------------------------------------------------------------- /test/cmake/Findlibassert.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(get_cpm) 7 | 8 | if (MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__) 9 | set(LIBASSERT_DISABLE_CXX_20_MODULES OFF CACHE BOOL "") 10 | else () 11 | set(LIBASSERT_DISABLE_CXX_20_MODULES ON CACHE BOOL "") 12 | endif () 13 | 14 | find_package(mimicpp-cpptrace MODULE REQUIRED) 15 | set(LIBASSERT_USE_EXTERNAL_CPPTRACE ON CACHE BOOL "") 16 | CPMAddPackage("gh:jeremy-rifkin/libassert@2.1.5") 17 | -------------------------------------------------------------------------------- /test/unit-tests/Catch2FallbackStringifier.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "mimic++/printing/StatePrinter.hpp" 9 | 10 | #include 11 | 12 | // see: https://github.com/catchorg/Catch2/blob/devel/docs/configuration.md#fallback-stringifier 13 | [[nodiscard]] 14 | std::string catch2_fallback_stringifier(auto const& object) 15 | { 16 | return mimicpp::print(object); 17 | } 18 | 19 | #define CATCH_CONFIG_FALLBACK_STRINGIFIER catch2_fallback_stringifier 20 | -------------------------------------------------------------------------------- /test/compile-errors/multiple-times-policies.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/mimic++.hpp" 7 | 8 | /* 9 | 10 | Only one times-policy may be specified per expectation\. 11 | See: https://dnkpp\.github\.io/mimicpp/ 12 | 13 | */ 14 | 15 | void check() 16 | { 17 | mimicpp::Mock mock{}; 18 | SCOPED_EXP mock.expect_call() 19 | and mimicpp::expect::at_least(1u) 20 | and mimicpp::expect::at_most(42u); 21 | } 22 | -------------------------------------------------------------------------------- /test/compile-errors/multiple-finalize-policies.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/mimic++.hpp" 7 | 8 | /* 9 | 10 | Only one finalize-policy may be specified per expectation\. 11 | See: https://dnkpp\.github\.io/mimicpp/ 12 | 13 | */ 14 | 15 | void check() 16 | { 17 | mimicpp::Mock mock{}; 18 | SCOPED_EXP mock.expect_call() 19 | and mimicpp::finally::throws(1u) 20 | and mimicpp::finally::throws(42u); 21 | } 22 | -------------------------------------------------------------------------------- /module/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | add_library(mimicpp-module) 7 | add_library(mimicpp::module ALIAS mimicpp-module) 8 | 9 | target_sources(mimicpp-module PUBLIC 10 | FILE_SET CXX_MODULES 11 | TYPE CXX_MODULES FILES mimic++.cppm 12 | ) 13 | 14 | target_include_directories(mimicpp-module PUBLIC 15 | "$" 16 | "$" 17 | ) 18 | 19 | target_link_libraries(mimicpp-module PUBLIC 20 | mimicpp::header-only 21 | ) 22 | -------------------------------------------------------------------------------- /include/mimic++/utilities/AlwaysFalse.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_ALWAYS_FALSE_HPP 7 | #define MIMICPP_UTILITIES_ALWAYS_FALSE_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #endif 16 | 17 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 18 | { 19 | template 20 | struct always_false 21 | : public std::bool_constant 22 | { 23 | }; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/mimic++/printing/TypePrinter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_TYPE_PRINTER_HPP 7 | #define MIMICPP_PRINTING_TYPE_PRINTER_HPP 8 | 9 | #include "mimic++/printing/type/CommonTypes.hpp" 10 | #include "mimic++/printing/type/NameLexer.hpp" 11 | #include "mimic++/printing/type/NameParser.hpp" 12 | #include "mimic++/printing/type/NamePrintVisitor.hpp" 13 | #include "mimic++/printing/type/PrintType.hpp" 14 | #include "mimic++/printing/type/Signature.hpp" 15 | #include "mimic++/printing/type/Templated.hpp" 16 | 17 | #endif 18 | -------------------------------------------------------------------------------- /include/mimic++/reporting/Fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_FWD_HPP 7 | #define MIMICPP_REPORTING_FWD_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 14 | { 15 | class IReporter; 16 | class DefaultReporter; 17 | 18 | class TypeReport; 19 | class TargetReport; 20 | class CallReport; 21 | class ExpectationReport; 22 | class NoMatchReport; 23 | class RequirementOutcomes; 24 | } 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/mimic++/config/Version.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_CONFIG_VERSION_HPP 7 | #define MIMICPP_CONFIG_VERSION_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/macros/Common.hpp" 12 | 13 | #define MIMICPP_VERSION_MAJOR 9 14 | #define MIMICPP_VERSION_MINOR 2 15 | #define MIMICPP_VERSION_PATCH 1 16 | 17 | #define MIMICPP_VERSION \ 18 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_VERSION_MAJOR) "." \ 19 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_VERSION_MINOR) "." \ 20 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_VERSION_PATCH) 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /test/adapter-tests/catch2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-adapter-tests-catch2) 7 | add_executable(${TARGET_NAME} 8 | "main.cpp" 9 | ) 10 | 11 | include(Mimic++-EnableSanitizers) 12 | enable_sanitizers(${TARGET_NAME}) 13 | 14 | find_package(Catch2 REQUIRED) 15 | target_link_libraries(${TARGET_NAME} PRIVATE 16 | mimicpp::header-only 17 | mimicpp::test::basics 18 | Catch2::Catch2WithMain 19 | ) 20 | 21 | target_precompile_headers(${TARGET_NAME} PRIVATE 22 | 23 | ) 24 | 25 | catch_discover_tests(${TARGET_NAME}) 26 | -------------------------------------------------------------------------------- /test/module-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-module-test) 7 | add_executable(${TARGET_NAME} 8 | "main.cpp" 9 | ) 10 | 11 | target_compile_options(${TARGET_NAME} PRIVATE 12 | "$<$:-Wno-deprecated-declarations>" 13 | ) 14 | 15 | include(Mimic++-EnableSanitizers) 16 | enable_sanitizers(${TARGET_NAME}) 17 | 18 | find_package(Catch2 REQUIRED) 19 | target_link_libraries(${TARGET_NAME} PRIVATE 20 | mimicpp::module 21 | mimicpp::test::basics 22 | Catch2::Catch2WithMain 23 | ) 24 | 25 | catch_discover_tests(${TARGET_NAME}) 26 | -------------------------------------------------------------------------------- /test/unit-tests/call-conventions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" 7 | OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT APPLE)) 8 | 9 | message(STATUS "${MESSAGE_PREFIX} Adding __vectorcall tests.") 10 | target_sources(mimicpp-tests PRIVATE 11 | "Vectorcall.cpp" 12 | ) 13 | 14 | endif () 15 | 16 | 17 | if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 18 | 19 | message(STATUS "${MESSAGE_PREFIX} Adding gcc call-convention tests.") 20 | target_sources(mimicpp-tests PRIVATE 21 | "GccCallConvention.cpp" 22 | ) 23 | 24 | endif () 25 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: DNKpp 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: dnkpp 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 12 | polar: # Replace with a single Polar username 13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username 14 | thanks_dev: # Replace with a single thanks.dev username 15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 16 | -------------------------------------------------------------------------------- /include/mimic++/utilities/PriorityTag.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_PRIORITY_TAG_HPP 7 | #define MIMICPP_UTILITIES_PRIORITY_TAG_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #endif 16 | 17 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 18 | { 19 | template 20 | struct priority_tag 21 | /** \cond Help doxygen with recursion.*/ 22 | : public priority_tag 23 | /** \endcond */ 24 | { 25 | }; 26 | 27 | template <> 28 | struct priority_tag<0u> 29 | { 30 | }; 31 | } 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /test/unit-tests/printing/Format.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/printing/Format.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | namespace 11 | { 12 | class NonPrintable 13 | { 14 | }; 15 | } 16 | 17 | TEMPLATE_TEST_CASE_SIG( 18 | "detail::formattable determines whether the given type has a format::formatter specialization.", 19 | "[print]", 20 | ((bool expected, typename T, typename Char), expected, T, Char), 21 | (true, int, char), 22 | (true, const int, char), 23 | (true, int&, char), 24 | (true, const int&, char), 25 | (true, int, wchar_t), 26 | (false, NonPrintable, char)) 27 | { 28 | STATIC_REQUIRE(expected == format::detail::formattable); 29 | } 30 | -------------------------------------------------------------------------------- /test/adapter-tests/gtest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-adapter-tests-gtest) 7 | add_executable(${TARGET_NAME} 8 | "main.cpp" 9 | ) 10 | 11 | include(Mimic++-EnableSanitizers) 12 | enable_sanitizers(${TARGET_NAME}) 13 | 14 | CPMAddPackage( 15 | NAME GTest 16 | VERSION 1.15.2 17 | GITHUB_REPOSITORY "google/googletest" 18 | EXCLUDE_FROM_ALL YES 19 | SYSTEM YES 20 | OPTIONS 21 | "gtest_force_shared_crt ON" 22 | ) 23 | 24 | target_link_libraries(${TARGET_NAME} PRIVATE 25 | mimicpp::header-only 26 | mimicpp::test::basics 27 | GTest::gtest_main 28 | ) 29 | 30 | target_precompile_headers(${TARGET_NAME} PRIVATE 31 | 32 | ) 33 | 34 | include(GoogleTest) 35 | gtest_discover_tests(${TARGET_NAME}) 36 | -------------------------------------------------------------------------------- /cmake/Findmimicpp-fmt.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | message(DEBUG "${MESSAGE_PREFIX} Searching for {fmt}-package.") 7 | 8 | include(CMakeDependentOption) 9 | cmake_dependent_option( 10 | MIMICPP_CONFIG_IMPORT_FMT 11 | "Determines, whether fmt will be consumed as a c++20 module." 12 | ON 13 | "MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__" 14 | OFF 15 | ) 16 | 17 | set(FMT_INSTALL ON) 18 | if (CMAKE_SKIP_INSTALL_RULES) 19 | set(FMT_INSTALL OFF) 20 | endif () 21 | set(FMT_INSTALL ${FMT_INSTALL} CACHE BOOL "" FORCE) 22 | set(FMT_MODULE ${MIMICPP_CONFIG_IMPORT_FMT} CACHE BOOL "" FORCE) 23 | 24 | find_package(fmt QUIET) 25 | if (NOT fmt_FOUND) 26 | include(get_cpm) 27 | CPMAddPackage("gh:fmtlib/fmt#12.1.0") 28 | endif () 29 | -------------------------------------------------------------------------------- /.github/workflows/release_adapter_headers.yml: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | name: "Release adapter headers" 7 | 8 | on: 9 | release: 10 | types: [ released ] 11 | 12 | jobs: 13 | release-headers: 14 | runs-on: ubuntu-latest 15 | 16 | # this is required for the asset attachment 17 | permissions: 18 | contents: write 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - name: Attach adapter headers as release asset 24 | uses: ncipollo/release-action@v1 25 | with: 26 | artifacts: "include/mimic++_ext/adapters/*.hpp" 27 | token: ${{ secrets.GITHUB_TOKEN }} 28 | allowUpdates: true 29 | artifactErrorsFailBuild: true 30 | omitBody: true 31 | omitName: true 32 | -------------------------------------------------------------------------------- /include/mimic++/reporting/TargetReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_TARGET_REPORT_HPP 7 | #define MIMICPP_REPORTING_TARGET_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/reporting/TypeReport.hpp" 14 | 15 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 16 | { 17 | /** 18 | * \brief Contains the extracted mock info. 19 | * \ingroup REPORTING_REPORTS 20 | */ 21 | class TargetReport 22 | { 23 | public: 24 | StringT name; 25 | TypeReport overloadReport; 26 | 27 | [[nodiscard]] 28 | friend bool operator==(const TargetReport&, const TargetReport&) = default; 29 | }; 30 | } 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /test/adapter-tests/doctest/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-adapter-tests-doctest) 7 | add_executable(${TARGET_NAME} 8 | "main.cpp" 9 | ) 10 | 11 | include(Mimic++-EnableSanitizers) 12 | enable_sanitizers(${TARGET_NAME}) 13 | 14 | CPMAddPackage("gh:doctest/doctest@2.4.12") 15 | target_link_libraries(${TARGET_NAME} PRIVATE 16 | mimicpp::header-only 17 | mimicpp::test::basics 18 | doctest::doctest 19 | ) 20 | 21 | target_compile_options(${TARGET_NAME} PRIVATE 22 | "$<$:-Wno-#warnings>" 23 | ) 24 | 25 | target_precompile_headers(${TARGET_NAME} PRIVATE 26 | 27 | ) 28 | 29 | list(APPEND CMAKE_MODULE_PATH "${doctest_SOURCE_DIR}/scripts/cmake") 30 | include(doctest) 31 | doctest_discover_tests(${TARGET_NAME}) 32 | -------------------------------------------------------------------------------- /include/mimic++/Reporting.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_HPP 7 | #define MIMICPP_REPORTING_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/reporting/Fwd.hpp" 12 | 13 | #include "mimic++/reporting/CallReport.hpp" 14 | #include "mimic++/reporting/ExpectationReport.hpp" 15 | #include "mimic++/reporting/NoMatchReport.hpp" 16 | #include "mimic++/reporting/SequenceReport.hpp" 17 | #include "mimic++/reporting/TargetReport.hpp" 18 | #include "mimic++/reporting/TypeReport.hpp" 19 | 20 | #include "mimic++/reporting/StringifyReports.hpp" 21 | 22 | #include "mimic++/reporting/BasicReporter.hpp" 23 | #include "mimic++/reporting/DefaultReporter.hpp" 24 | #include "mimic++/reporting/GlobalReporter.hpp" 25 | #include "mimic++/reporting/IReporter.hpp" 26 | 27 | #endif 28 | -------------------------------------------------------------------------------- /cmake/get_cpm.cmake: -------------------------------------------------------------------------------- 1 | # SPDX-License-Identifier: MIT 2 | # 3 | # SPDX-FileCopyrightText: Copyright (c) 2019-2023 Lars Melchior and contributors 4 | 5 | set(CPM_DOWNLOAD_VERSION 0.42.0) 6 | set(CPM_HASH_SUM "2020b4fc42dba44817983e06342e682ecfc3d2f484a581f11cc5731fbe4dce8a") 7 | 8 | if(CPM_SOURCE_CACHE) 9 | set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 10 | elseif(DEFINED ENV{CPM_SOURCE_CACHE}) 11 | set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 12 | else() 13 | set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 14 | endif() 15 | 16 | # Expand relative path. This is important if the provided path contains a tilde (~) 17 | get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) 18 | 19 | file(DOWNLOAD 20 | https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake 21 | ${CPM_DOWNLOAD_LOCATION} EXPECTED_HASH SHA256=${CPM_HASH_SUM} 22 | ) 23 | 24 | include(${CPM_DOWNLOAD_LOCATION}) 25 | -------------------------------------------------------------------------------- /include/mimic++/reporting/NoMatchReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_NO_MATCH_REPORT_HPP 7 | #define MIMICPP_REPORTING_NO_MATCH_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | #include "mimic++/reporting/ExpectationReport.hpp" 13 | 14 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 15 | { 16 | /** 17 | * \brief Contains the requirement-outcomes (where at least one is negative) and the related expectation-report. 18 | * \ingroup REPORTING_REPORTS 19 | */ 20 | class NoMatchReport 21 | { 22 | public: 23 | ExpectationReport expectationReport; 24 | RequirementOutcomes requirementOutcomes; 25 | 26 | [[nodiscard]] 27 | friend bool operator==(NoMatchReport const&, NoMatchReport const&) = default; 28 | }; 29 | } 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /cmake/Findmimicpp-cpptrace.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | message(DEBUG "${MESSAGE_PREFIX} Searching for `cpptrace`-package.") 7 | 8 | include(CMakeDependentOption) 9 | cmake_dependent_option( 10 | MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE 11 | "Determines whether cpptrace will be consumed as a c++20 module." 12 | OFF 13 | "MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__" 14 | OFF 15 | ) 16 | 17 | if (NOT MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE) 18 | set(CPPTRACE_DISABLE_CXX_20_MODULES ON CACHE BOOL "" FORCE) 19 | else () 20 | set(CPPTRACE_DISABLE_CXX_20_MODULES OFF CACHE BOOL "" FORCE) 21 | endif () 22 | 23 | find_package(cpptrace QUIET) 24 | if (NOT cpptrace_FOUND) 25 | message(DEBUG "${MESSAGE_PREFIX} No installed `cpptrace`-package found. Fetching via cpm.") 26 | 27 | include(get_cpm) 28 | CPMAddPackage("gh:jeremy-rifkin/cpptrace@1.0.4") 29 | endif () 30 | -------------------------------------------------------------------------------- /test/adapter-tests/boost-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-adapter-tests-boost-test) 7 | add_executable(${TARGET_NAME} 8 | "main.cpp" 9 | ) 10 | 11 | include(Mimic++-EnableSanitizers) 12 | enable_sanitizers(${TARGET_NAME}) 13 | 14 | find_package(Boost COMPONENTS test) 15 | target_link_libraries(${TARGET_NAME} PRIVATE 16 | mimicpp::header-only 17 | mimicpp::test::basics 18 | Boost::unit_test_framework 19 | ) 20 | 21 | target_precompile_headers(${TARGET_NAME} PRIVATE 22 | 23 | ) 24 | 25 | add_test( 26 | NAME boost_adapter_test 27 | COMMAND ${TARGET_NAME} --run_test=SuccessSuite 28 | ) 29 | 30 | # executes test which are expected to fail 31 | add_test( 32 | NAME failing_boost_adapter_test 33 | COMMAND ${TARGET_NAME} --run_test=FailureSuite 34 | ) 35 | set_property( 36 | TEST failing_boost_adapter_test 37 | PROPERTY WILL_FAIL TRUE 38 | ) 39 | -------------------------------------------------------------------------------- /include/mimic++/Utilities.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_HPP 7 | #define MIMICPP_UTILITIES_HPP 8 | 9 | #include "mimic++/utilities/Algorithm.hpp" 10 | #include "mimic++/utilities/AlwaysFalse.hpp" 11 | #include "mimic++/utilities/C++23Backports.hpp" 12 | #include "mimic++/utilities/C++26Backports.hpp" 13 | #include "mimic++/utilities/Concepts.hpp" 14 | #include "mimic++/utilities/PassKey.hpp" 15 | #include "mimic++/utilities/PriorityTag.hpp" 16 | #include "mimic++/utilities/SourceLocation.hpp" 17 | #include "mimic++/utilities/Stacktrace.hpp" 18 | #include "mimic++/utilities/StaticString.hpp" 19 | #include "mimic++/utilities/TypeList.hpp" 20 | 21 | namespace mimicpp::util 22 | { 23 | /** 24 | * \defgroup UTILITIES utilities 25 | * \brief Contains various utility used by *mimic++*. 26 | * \details The contained features are mainly used by *mimic++* but are also available to users. 27 | */ 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /include/mimic++/macros/ScopedExpectation.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_MACROS_SCOPED_EXPECTATION_HPP 7 | #define MIMICPP_MACROS_SCOPED_EXPECTATION_HPP 8 | 9 | #define MIMICPP_DETAIL_UNIQUE_NAME(prefix, counter) prefix##counter 10 | #define MIMICPP_DETAIL_SCOPED_EXPECTATION_IMPL(counter) \ 11 | [[maybe_unused]] \ 12 | ::mimicpp::ScopedExpectation const MIMICPP_DETAIL_UNIQUE_NAME(_mimicpp_expectation_, counter) = 13 | 14 | /** 15 | * \brief Convenience macro, which creates a ScopedExpectation with a unique name. 16 | * \ingroup MOCK 17 | */ 18 | #define MIMICPP_SCOPED_EXPECTATION MIMICPP_DETAIL_SCOPED_EXPECTATION_IMPL(__COUNTER__) 19 | 20 | #ifndef MIMICPP_CONFIG_ONLY_PREFIXED_MACROS 21 | 22 | /** 23 | * \brief Shorthand variant of \ref MIMICPP_SCOPED_EXPECTATION. 24 | * \ingroup MOCK 25 | */ 26 | #define SCOPED_EXP MIMICPP_SCOPED_EXPECTATION 27 | 28 | #endif 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /test/unicode-str-matcher-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-unicode-str-matcher-tests) 7 | 8 | add_executable(${TARGET_NAME} 9 | "StringContains.cpp" 10 | "../unit-tests/matchers/StringContains.cpp" 11 | "StringEq.cpp" 12 | "../unit-tests/matchers/StringEq.cpp" 13 | "StringStartsWith.cpp" 14 | "../unit-tests/matchers/StringStartsWith.cpp" 15 | "StringEndsWith.cpp" 16 | "../unit-tests/matchers/StringEndsWith.cpp" 17 | ) 18 | 19 | include(Mimic++-EnableSanitizers) 20 | enable_sanitizers(${TARGET_NAME}) 21 | 22 | find_package(Catch2 REQUIRED) 23 | target_link_libraries(${TARGET_NAME} PRIVATE 24 | mimicpp::header-only 25 | mimicpp::test::basics 26 | Catch2::Catch2WithMain 27 | ) 28 | 29 | target_precompile_headers(${TARGET_NAME} PRIVATE 30 | 31 | "../unit-tests/Catch2FallbackStringifier.hpp" 32 | 33 | ) 34 | 35 | catch_discover_tests(${TARGET_NAME}) 36 | -------------------------------------------------------------------------------- /cmake/Mimic++-EnableSanitizers.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | function(enable_sanitizers TARGET_NAME) 7 | find_package(sanitizers-cmake) 8 | 9 | if (SANITIZE_ADDRESS) 10 | # workaround linker errors on msvc 11 | # see: https://learn.microsoft.com/en-us/answers/questions/864574/enabling-address-sanitizer-results-in-error-lnk203 12 | target_compile_definitions(${TARGET_NAME} 13 | PRIVATE 14 | "$<$:_DISABLE_VECTOR_ANNOTATION;_DISABLE_STRING_ANNOTATION>" 15 | ) 16 | 17 | target_compile_options(${TARGET_NAME} 18 | PRIVATE 19 | # see: https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#index-fsanitize_003dbuiltin 20 | "$<$:-g;-fno-omit-frame-pointer;-fno-optimize-sibling-calls;-fno-ipa-icf>" 21 | # see: https://clang.llvm.org/docs/AddressSanitizer.html#id3 22 | "$<$:-g;-fno-omit-frame-pointer;-fno-optimize-sibling-calls>" 23 | ) 24 | endif() 25 | 26 | add_sanitizers(${TARGET_NAME}) 27 | endfunction() -------------------------------------------------------------------------------- /test/cmake/Mimic++-EnableWarnings.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if (NOT TARGET enable-warnings) 7 | 8 | add_library(enable-warnings INTERFACE) 9 | add_library(mimicpp::internal::warnings ALIAS enable-warnings) 10 | 11 | # We need to circumvent the huge nonsense warnings from clang-cl 12 | # see: https://discourse.cmake.org/t/wall-with-visual-studio-clang-toolchain-results-in-way-too-many-warnings/7927 13 | if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" 14 | AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") 15 | 16 | set(WARNING_FLAGS /W4 -Wextra -Wpedantic -Werror -Wno-unknown-attributes) 17 | else () 18 | # @formatter:off 19 | string(CONCAT WARNING_FLAGS 20 | "$," 22 | "/W4;/WX;/permissive-," 23 | "-Wall;-Wextra;-Wpedantic;-Werror" 24 | ">" 25 | ) 26 | # @formatter:on 27 | endif () 28 | 29 | target_compile_options(enable-warnings INTERFACE 30 | 31 | ${WARNING_FLAGS} 32 | ) 33 | 34 | endif () 35 | -------------------------------------------------------------------------------- /test/adapter-tests/boost-test/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "../../unit-tests/SuppressionMacros.hpp" 7 | #include "mimic++/Mock.hpp" 8 | 9 | #define BOOST_TEST_MODULE BoostAdapterTest 10 | #include "mimic++_ext/adapters/BoostTest.hpp" 11 | 12 | BOOST_AUTO_TEST_SUITE(SuccessSuite) 13 | 14 | BOOST_AUTO_TEST_CASE(ReportSuccess) 15 | { 16 | mimicpp::reporting::detail::boost_test::send_success("Report Success"); 17 | } 18 | 19 | BOOST_AUTO_TEST_CASE(ReportWarning) 20 | { 21 | mimicpp::reporting::detail::boost_test::send_warning("Report Warning"); 22 | } 23 | 24 | BOOST_AUTO_TEST_SUITE_END() 25 | 26 | // This tests will fail. ctest has appropriate properties set, thus should be reported as success 27 | BOOST_AUTO_TEST_SUITE(FailureSuite) 28 | 29 | START_WARNING_SUPPRESSION 30 | SUPPRESS_UNREACHABLE_CODE 31 | 32 | BOOST_AUTO_TEST_CASE(ReportFail) 33 | { 34 | mimicpp::reporting::detail::boost_test::send_fail("Report fail"); 35 | } 36 | 37 | STOP_WARNING_SUPPRESSION 38 | 39 | BOOST_AUTO_TEST_SUITE_END() 40 | -------------------------------------------------------------------------------- /test/cmake/Mimic++-EnableAdditionalTestFlags.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if (NOT TARGET enable-additional-test-flags) 7 | 8 | add_library(enable-additional-test-flags INTERFACE) 9 | add_library(mimicpp::internal::additional-test-flags ALIAS enable-additional-test-flags) 10 | 11 | if (MIMICPP_TEST_ADDITIONAL_COMPILER_FLAGS) 12 | 13 | message(DEBUG "${MESSAGE_PREFIX} enabled additional compiler-flags: ${MIMICPP_TEST_ADDITIONAL_COMPILER_FLAGS}") 14 | 15 | target_compile_options(enable-additional-test-flags 16 | INTERFACE 17 | ${MIMICPP_TEST_ADDITIONAL_COMPILER_FLAGS} 18 | ) 19 | 20 | endif () 21 | 22 | if (MIMICPP_TEST_ADDITIONAL_LINKER_FLAGS) 23 | 24 | message(DEBUG "${MESSAGE_PREFIX} enabled additional linker-flags: ${MIMICPP_TEST_ADDITIONAL_LINKER_FLAGS}") 25 | 26 | target_link_options(enable-additional-test-flags 27 | INTERFACE 28 | ${MIMICPP_TEST_ADDITIONAL_LINKER_FLAGS} 29 | ) 30 | 31 | endif () 32 | endif () 33 | -------------------------------------------------------------------------------- /test/unit-tests/facade/Common.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UNIT_TESTS_FACADE_COMMON_HPP 7 | #define MIMICPP_UNIT_TESTS_FACADE_COMMON_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Facade.hpp" 12 | #include "mimic++/Mock.hpp" 13 | 14 | struct TestTraits 15 | { 16 | static constexpr bool is_member{true}; 17 | 18 | template 19 | using target_type = mimicpp::Mock; 20 | 21 | template 22 | static constexpr decltype(auto) invoke( 23 | auto& mock, 24 | [[maybe_unused]] auto* self, 25 | std::tuple&& args) 26 | { 27 | return mimicpp::facade::detail::apply(mock, std::move(args)); 28 | } 29 | 30 | template 31 | [[nodiscard]] 32 | static mimicpp::MockSettings make_settings([[maybe_unused]] Self const* const self, mimicpp::StringT functionName) 33 | { 34 | return mimicpp::MockSettings{.name = std::move(functionName), .stacktraceSkip = 1u}; 35 | } 36 | }; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /tools/amalgamate-headers/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | message(TRACE "Begin amalgamate headers") 7 | 8 | set(AMALGAMATE_VERSION "v0.99.0") 9 | 10 | if (WIN32) 11 | set(AMALGAMATE_URL_SUFFIX "windows-amd64.zip") 12 | elseif(UNIX AND NOT APPLE) 13 | set(AMALGAMATE_URL_SUFFIX "linux-amd64.zip") 14 | else() 15 | message(FATAL_ERROR "Unsupported platform.") 16 | endif() 17 | 18 | include(get_cpm) 19 | CPMAddPackage( 20 | NAME amalgamate 21 | URL "https://github.com/rindeal/Amalgamate/releases/download/${AMALGAMATE_VERSION}/amalgamate-${AMALGAMATE_VERSION}-${AMALGAMATE_URL_SUFFIX}" 22 | DOWNLOAD_ONLY YES 23 | EXCLUDE_FROM_ALL YES 24 | ) 25 | 26 | set(AMALGAMATE_COMMAND "${amalgamate_SOURCE_DIR}/amalgamate") 27 | add_custom_target( 28 | mimicpp-amalgamate-headers 29 | COMMAND "${AMALGAMATE_COMMAND}" -v -i .. mimic++.hpp "${CMAKE_CURRENT_BINARY_DIR}/mimic++-amalgamated.hpp" 30 | COMMENT "Amalgamate headers" 31 | WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../include/mimic++" 32 | COMMAND_EXPAND_LISTS 33 | VERBATIM 34 | USES_TERMINAL 35 | ) 36 | 37 | message(TRACE "End amalgamate headers") 38 | -------------------------------------------------------------------------------- /test/cmake/Mimic++-HasStdStacktrace.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(Mimic++-LinkStdStacktrace) 7 | include(CheckCXXSourceCompiles) 8 | include(CheckCXXCompilerFlag) 9 | 10 | function(check_std_stacktrace_support) 11 | 12 | if (MSVC) 13 | set(CXX23_FLAG "/std:c++latest") 14 | else () 15 | set(CXX23_FLAG "-std=c++23") 16 | endif () 17 | 18 | check_cxx_compiler_flag(${CXX23_FLAG} COMPILER_SUPPORTS_CXX23) 19 | if (NOT COMPILER_SUPPORTS_CXX23) 20 | return() 21 | endif () 22 | 23 | set(CMAKE_CXX_STANDARD 23) 24 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 25 | 26 | get_target_property(LIBS mimicpp::internal::link-std-stacktrace INTERFACE_LINK_LIBRARIES) 27 | set(CMAKE_REQUIRED_LIBRARIES "${LIBS}") 28 | 29 | set(CODE " 30 | #include 31 | int main() 32 | { 33 | [[maybe_unused]] auto const st = std::stacktrace::current(); 34 | return 0; 35 | } 36 | ") 37 | check_cxx_source_compiles("${CODE}" HAS_STD_STACKTRACE) 38 | set(HAS_STD_STACKTRACE ${HAS_STD_STACKTRACE} PARENT_SCOPE) 39 | endfunction() 40 | 41 | check_std_stacktrace_support() 42 | -------------------------------------------------------------------------------- /test/package-test/package-consumer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | cmake_minimum_required(VERSION 3.15...3.31) 7 | 8 | project(package-consumer 9 | LANGUAGES CXX 10 | ) 11 | 12 | message(DEBUG "CMAKE_PREFIX_PATH: ${CMAKE_PREFIX_PATH}") 13 | message(DEBUG "CMAKE_MODULE_PATH: ${CMAKE_MODULE_PATH}") 14 | message(DEBUG "CMAKE_BUILD_TYPE: ${CMAKE_BUILD_TYPE}") 15 | set(TARGET_NAME package-consumer) 16 | add_executable(${TARGET_NAME} 17 | "main.cpp" 18 | ) 19 | 20 | if (MIMICPP_WITH_STACKTRACE STREQUAL "cpptrace") 21 | find_package(mimicpp-cpptrace MODULE REQUIRED) 22 | endif () 23 | 24 | if (MIMICPP_WITH_FMT) 25 | find_package(mimicpp-fmt MODULE REQUIRED) 26 | endif () 27 | 28 | if (MIMICPP_WITH_UNICODE_STR_MATCHER) 29 | find_package(mimicpp-uni-algo MODULE REQUIRED) 30 | endif () 31 | 32 | include("../../cmake/Mimic++-LinkStdStacktrace.cmake") 33 | find_package(mimicpp REQUIRED) 34 | target_link_libraries(${TARGET_NAME} PRIVATE 35 | mimicpp::mimicpp 36 | mimicpp::internal::link-std-stacktrace 37 | ) 38 | 39 | include(CTest) 40 | add_test(NAME package-test 41 | COMMAND ${TARGET_NAME} 42 | ) 43 | -------------------------------------------------------------------------------- /test/unit-tests/utilities/Concepts.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/utilities/Concepts.hpp" 7 | 8 | #include 9 | 10 | using namespace mimicpp; 11 | 12 | TEMPLATE_TEST_CASE_SIG( 13 | "satisfies determines, whether T satisfies the given trait.", 14 | "[utility]", 15 | ((bool expected, typename T, template typename Trait), expected, T, Trait), 16 | (false, int, std::is_floating_point), 17 | (false, int&, std::is_integral), 18 | (true, int, std::is_integral)) 19 | { 20 | STATIC_REQUIRE(expected == util::satisfies); 21 | } 22 | 23 | TEMPLATE_TEST_CASE_SIG( 24 | "same_as_any determines, whether T is the same as any of the given types.", 25 | "[utility]", 26 | ((bool expected, typename T, typename... Others), expected, T, Others...), 27 | (false, int), 28 | (false, int, int&), 29 | (false, int, int&, int&), 30 | (false, int, int&, double, float), 31 | (true, int, int), 32 | (true, int, int&, int), 33 | (true, int, double, int, int&)) 34 | { 35 | STATIC_REQUIRE(expected == util::same_as_any); 36 | } 37 | -------------------------------------------------------------------------------- /test/test-basics/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-test-basics) 7 | 8 | add_library(${TARGET_NAME} INTERFACE) 9 | add_library(mimicpp::test::basics ALIAS ${TARGET_NAME}) 10 | 11 | target_include_directories(${TARGET_NAME} INTERFACE 12 | "$" 13 | ) 14 | 15 | target_compile_options(${TARGET_NAME} INTERFACE 16 | # some test files exceed some limits 17 | # see: https://learn.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/fatal-error-c1128?view=msvc-170 18 | "$<$:/bigobj>" 19 | "$<$:/Zc:__cplusplus>" 20 | ) 21 | 22 | target_compile_definitions(${TARGET_NAME} INTERFACE 23 | "LIBASSERT_BREAK_ON_FAIL" 24 | ) 25 | 26 | include(Mimic++-EnableAdditionalTestFlags) 27 | include(Mimic++-EnableWarnings) 28 | include(Mimic++-LinkStdStacktrace) 29 | find_package(libassert REQUIRED) 30 | target_link_libraries(${TARGET_NAME} INTERFACE 31 | mimicpp::internal::additional-test-flags 32 | mimicpp::internal::warnings 33 | mimicpp::internal::link-std-stacktrace 34 | libassert::assert 35 | ) 36 | -------------------------------------------------------------------------------- /test/stacktrace-tests/custom/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | # This separate executable is required, because in this case the ``mimicpp::find_stacktrace_backend`` 7 | # trait is specialized. As this shall only be for the duration of these tests, I've extracted it 8 | # into a separate test-executable. 9 | # see: https://eel.is/c++draft/temp.spec#general-5 for the technical reason 10 | 11 | set(TARGET_NAME mimicpp-stacktrace-custom-tests) 12 | add_executable(${TARGET_NAME} 13 | "CustomStacktrace.cpp" 14 | "EqualityComparison.cpp" 15 | "Printing.cpp" 16 | ) 17 | 18 | include(Mimic++-EnableSanitizers) 19 | enable_sanitizers(${TARGET_NAME}) 20 | 21 | find_package(Catch2 REQUIRED) 22 | find_package(trompeloeil REQUIRED) 23 | target_link_libraries(${TARGET_NAME} PRIVATE 24 | mimicpp::header-only 25 | mimicpp::test::basics 26 | mimicpp::internal::enable-custom-stacktrace 27 | Catch2::Catch2WithMain 28 | trompeloeil::trompeloeil 29 | ) 30 | 31 | target_precompile_headers(${TARGET_NAME} PRIVATE 32 | 33 | 34 | 35 | ) 36 | 37 | catch_discover_tests(${TARGET_NAME}) 38 | -------------------------------------------------------------------------------- /LICENSE_1_0.txt: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /include/mimic++/utilities/PassKey.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_PASS_KEY_HPP 7 | #define MIMICPP_UTILITIES_PASS_KEY_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 14 | { 15 | /** 16 | * \brief A helper type that enables fine-grained access control to specific functions without using friend declarations. 17 | * \ingroup UTILITIES 18 | * \tparam Trusted The type that is allowed to create this key and therefore granted access. 19 | * 20 | * \details 21 | * This type provides a way to restrict access to certain functions by requiring a special key object. 22 | * Only the designated `Trusted` type can construct this key, allowing it to call functions that accept the key as a parameter. 23 | * This avoids broad friendship declarations and keeps access control explicit and localized. 24 | * 25 | * \see https://speakerdeck.com/rollbear/using-types-to-save-your-codes-future?slide=54 26 | */ 27 | template 28 | struct pass_key 29 | { 30 | private: 31 | friend Trusted; 32 | pass_key() = default; 33 | }; 34 | } 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /include/mimic++/utilities/C++26Backports.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_CXX26_BACKPORTS_HPP 7 | #define MIMICPP_UTILITIES_CXX26_BACKPORTS_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #include 16 | #include 17 | #include 18 | #endif 19 | 20 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 21 | { 22 | /** 23 | * \brief The alias template projected_value_t obtains the value type by stripping any reference and its topmost 24 | * cv-qualifiers of the result type of applying Proj to `std::iter_value_t&`. 25 | * \tparam I an indirectly readable type. 26 | * \tparam Projection projection applied to an lvalue reference to value type of `I`. 27 | * \see https://en.cppreference.com/w/cpp/iterator/projected_value_t 28 | * \note Implementation directly taken from https://en.cppreference.com/w/cpp/iterator/projected_value_t 29 | */ 30 | template Projection> 31 | using projected_value_t = std::remove_cvref_t< 32 | std::invoke_result_t&>>; 33 | } 34 | 35 | #endif 36 | -------------------------------------------------------------------------------- /examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-examples) 7 | add_executable(${TARGET_NAME} 8 | "CustomMatcher.cpp" 9 | "CustomPrinter.cpp" 10 | "CustomString.cpp" 11 | "Deprecated_InterfaceMock.cpp" 12 | "FacadeMock.cpp" 13 | "Finalizers.cpp" 14 | "Mock.cpp" 15 | "Requirements.cpp" 16 | "Sequences.cpp" 17 | "SideEffects.cpp" 18 | "Times.cpp" 19 | "Watcher.cpp" 20 | "VariadicMocks.cpp" 21 | ) 22 | 23 | if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" 24 | OR (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")) 25 | 26 | message(DEBUG "${MESSAGE_PREFIX} Adding RegisterCallConvention example.") 27 | target_sources(${TARGET_NAME} 28 | PRIVATE 29 | "RegisterCallConvention.cpp" 30 | ) 31 | 32 | endif () 33 | 34 | include(Mimic++-EnableSanitizers) 35 | enable_sanitizers(${TARGET_NAME}) 36 | 37 | find_package(Catch2 REQUIRED) 38 | find_package(trompeloeil REQUIRED) 39 | target_link_libraries(${TARGET_NAME} PRIVATE 40 | mimicpp::header-only 41 | mimicpp::test::basics 42 | Catch2::Catch2WithMain 43 | ) 44 | 45 | target_precompile_headers(${TARGET_NAME} PRIVATE 46 | 47 | 48 | ) 49 | 50 | catch_discover_tests(${TARGET_NAME}) 51 | -------------------------------------------------------------------------------- /test/unit-tests/macros/Common.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/macros/Common.hpp" 7 | 8 | TEST_CASE( 9 | "MIMICPP_DETAIL_STRIP_PARENS removes outer parens, if present.", 10 | "[macro][detail]") 11 | { 12 | namespace Matches = Catch::Matchers; 13 | 14 | REQUIRE_THAT( 15 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS()), 16 | Matches::Equals("")); 17 | 18 | REQUIRE_THAT( 19 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS(())), 20 | Matches::Equals("")); 21 | 22 | REQUIRE_THAT( 23 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS((()))), 24 | Matches::Equals("()")); 25 | 26 | REQUIRE_THAT( 27 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS(Test())), 28 | Matches::Equals("Test()")); 29 | 30 | REQUIRE_THAT( 31 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS((Test()))), 32 | Matches::Equals("Test()")); 33 | 34 | REQUIRE_THAT( 35 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS(((Test())))), 36 | Matches::Equals("(Test())")); 37 | 38 | // clang-format off 39 | REQUIRE_THAT( 40 | MIMICPP_DETAIL_STRINGIFY(MIMICPP_DETAIL_STRIP_PARENS(((,Test(),)))), 41 | Matches::Equals("(,Test(),)")); 42 | // clang-format on 43 | } 44 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 7 | 8 | add_subdirectory(test-basics) 9 | add_subdirectory(compile-errors) 10 | 11 | option(MIMICPP_ENABLE_UNIT_TESTS "Determines, whether the unit-tests shall be built." ON) 12 | if (MIMICPP_ENABLE_UNIT_TESTS) 13 | add_subdirectory(unit-tests) 14 | endif () 15 | 16 | if (MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__) 17 | add_subdirectory(module-test) 18 | endif () 19 | 20 | option(MIMICPP_ENABLE_ADAPTER_TESTS "Determines, whether the adapter tests shall be built." OFF) 21 | if (MIMICPP_ENABLE_ADAPTER_TESTS) 22 | add_subdirectory(adapter-tests) 23 | endif () 24 | 25 | option(MIMICPP_ENABLE_STACKTRACE_TESTS "Determines, whether the stacktrace tests shall be built." OFF) 26 | if (MIMICPP_ENABLE_STACKTRACE_TESTS) 27 | add_subdirectory(stacktrace-tests) 28 | endif () 29 | 30 | option(MIMICPP_ENABLE_UNICODE_STR_MATCHER_TESTS "Determines, whether the unicode-str-matcher tests shall be built." OFF) 31 | if (MIMICPP_ENABLE_UNICODE_STR_MATCHER_TESTS) 32 | add_subdirectory(unicode-str-matcher-tests) 33 | endif () 34 | 35 | option(MIMICPP_ENABLE_PACKAGE_TEST "Determines, whether the package tests shall be executed." OFF) 36 | if (MIMICPP_ENABLE_PACKAGE_TEST) 37 | add_subdirectory(package-test) 38 | endif () 39 | -------------------------------------------------------------------------------- /test/package-test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | function(collect_cmake_env outConfigArgs outBuildArgs) 7 | set(configArgs "") 8 | set(buildArgs "") 9 | 10 | list(APPEND configArgs "-D CMAKE_BUILD_TYPE=$") 11 | list(APPEND configArgs "-D MIMICPP_WITH_FMT=${MIMICPP_CONFIG_USE_FMT}") 12 | list(APPEND configArgs "-D MIMICPP_WITH_UNICODE_STR_MATCHER=${MIMICPP_CONFIG_EXPERIMENTAL_UNICODE_STR_MATCHER}") 13 | list(APPEND configArgs "-D MIMICPP_WITH_STACKTRACE=${MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE}") 14 | 15 | if(MSVC) 16 | list(APPEND buildArgs "--config $") 17 | endif () 18 | 19 | set(${outConfigArgs} ${configArgs} PARENT_SCOPE) 20 | set(${outBuildArgs} ${buildArgs} PARENT_SCOPE) 21 | endfunction() 22 | 23 | collect_cmake_env(CONFIG_ARGS BUILD_ARGS) 24 | # We propagate `CONFIG_ARGS` directly to the script and also pass it as literal string 25 | add_test(NAME package-test 26 | COMMAND ${CMAKE_COMMAND} 27 | ${CONFIG_ARGS} 28 | -D CONFIG_ARGS=[[${CONFIG_ARGS}]] 29 | -D BUILD_ARGS=[[${BUILD_ARGS}]] 30 | -D CUR_BINARY_DIR=${CMAKE_BINARY_DIR} 31 | -D PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR} 32 | -D TEST_SOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR} 33 | -D TEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test-run 34 | -P "${CMAKE_CURRENT_SOURCE_DIR}/RunTest.cmake" 35 | ) 36 | -------------------------------------------------------------------------------- /test/unit-tests/config/Version.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2025 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/config/Version.hpp" 7 | 8 | TEST_CASE( 9 | "MIMICPP_VERSION_MAJOR is an integral number.", 10 | "[config]") 11 | { 12 | constexpr int version{MIMICPP_VERSION_MAJOR}; 13 | STATIC_CHECK(0 <= version); 14 | } 15 | 16 | TEST_CASE( 17 | "MIMICPP_VERSION_MINOR is an integral number.", 18 | "[config]") 19 | { 20 | constexpr int version{MIMICPP_VERSION_MINOR}; 21 | STATIC_CHECK(0 <= version); 22 | } 23 | 24 | TEST_CASE( 25 | "MIMICPP_VERSION_PATCH is an integral number.", 26 | "[config]") 27 | { 28 | constexpr int version{MIMICPP_VERSION_PATCH}; 29 | STATIC_CHECK(0 <= version); 30 | } 31 | 32 | TEST_CASE( 33 | "MIMICPP_VERSION_PATCH is a string-literal, containing a dotted triple.", 34 | "[config]") 35 | { 36 | std::string const expected = mimicpp::format::format( 37 | "{}.{}.{}", 38 | MIMICPP_VERSION_MAJOR, 39 | MIMICPP_VERSION_MINOR, 40 | MIMICPP_VERSION_PATCH); 41 | 42 | CHECK_THAT( 43 | std::string{MIMICPP_VERSION}, 44 | Catch::Matchers::Equals(expected)); 45 | } 46 | 47 | TEST_CASE( 48 | "Accumulated version is greater 0.", 49 | "[config]") 50 | { 51 | constexpr int accumulatedVersion{MIMICPP_VERSION_MAJOR + MIMICPP_VERSION_MINOR + MIMICPP_VERSION_PATCH}; 52 | STATIC_CHECK(0 < accumulatedVersion); 53 | } 54 | -------------------------------------------------------------------------------- /test/unit-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(TARGET_NAME mimicpp-tests) 7 | 8 | add_executable(${TARGET_NAME} 9 | "Expectation.cpp" 10 | "ExpectationBuilder.cpp" 11 | "InterfaceMock.cpp" 12 | "mimic++.cpp" 13 | "Mock.cpp" 14 | "ObjectWatcher.cpp" 15 | "Sequence.cpp" 16 | "ScopedSequence.cpp" 17 | "String.cpp" 18 | "TypeTraits.cpp" 19 | ) 20 | 21 | add_subdirectory(call-conventions) 22 | add_subdirectory(config) 23 | add_subdirectory(facade) 24 | add_subdirectory(macros) 25 | add_subdirectory(matchers) 26 | add_subdirectory(policies) 27 | add_subdirectory(printing) 28 | add_subdirectory(reporting) 29 | add_subdirectory(signature-traits) 30 | add_subdirectory(utilities) 31 | 32 | target_include_directories(${TARGET_NAME} PRIVATE 33 | "$" 34 | ) 35 | 36 | include(Mimic++-EnableSanitizers) 37 | enable_sanitizers(${TARGET_NAME}) 38 | 39 | find_package(Catch2 REQUIRED) 40 | find_package(trompeloeil REQUIRED) 41 | target_link_libraries(${TARGET_NAME} PRIVATE 42 | mimicpp::header-only 43 | mimicpp::test::basics 44 | Catch2::Catch2WithMain 45 | trompeloeil::trompeloeil 46 | ) 47 | 48 | target_precompile_headers(${TARGET_NAME} PRIVATE 49 | 50 | "Catch2FallbackStringifier.hpp" 51 | 52 | 53 | ) 54 | 55 | catch_discover_tests(${TARGET_NAME}) 56 | -------------------------------------------------------------------------------- /cmake/Mimic++-InstallRules.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(CMakePackageConfigHelpers) 7 | include(GNUInstallDirs) 8 | 9 | set(MIMICPP_CMAKE_INSTALL_DIR "cmake/mimicpp") 10 | 11 | configure_package_config_file( 12 | "${PROJECT_SOURCE_DIR}/cmake/mimicpp-config.cmake.in" 13 | "mimicpp-config.cmake" 14 | INSTALL_DESTINATION "${MIMICPP_CMAKE_INSTALL_DIR}" 15 | ) 16 | 17 | write_basic_package_version_file( 18 | "mimicpp-version.cmake" 19 | VERSION ${PROJECT_VERSION} 20 | COMPATIBILITY AnyNewerVersion 21 | ARCH_INDEPENDENT 22 | ) 23 | 24 | # Gather all targets starting with `mimicpp-internal-enable-` 25 | get_property(MIMICPP_FEATURE_TARGETS DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY BUILDSYSTEM_TARGETS) 26 | list(FILTER MIMICPP_FEATURE_TARGETS INCLUDE REGEX "^mimicpp-internal-enable-") 27 | install(TARGETS mimicpp mimicpp-enable-config-options ${MIMICPP_FEATURE_TARGETS} 28 | EXPORT mimicpp-targets 29 | ) 30 | 31 | install(DIRECTORY "include/" 32 | TYPE INCLUDE 33 | FILES_MATCHING PATTERN "*.hpp" 34 | ) 35 | 36 | install( 37 | EXPORT mimicpp-targets 38 | FILE mimicpp-targets.cmake 39 | DESTINATION "${MIMICPP_CMAKE_INSTALL_DIR}" 40 | NAMESPACE mimicpp:: 41 | ) 42 | 43 | install(FILES 44 | "${PROJECT_BINARY_DIR}/mimicpp-config.cmake" 45 | "${PROJECT_BINARY_DIR}/mimicpp-version.cmake" 46 | DESTINATION "${MIMICPP_CMAKE_INSTALL_DIR}" 47 | ) 48 | -------------------------------------------------------------------------------- /test/unit-tests/reporting/TargetReport.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/reporting/TargetReport.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | "reporting::TargetReport is equality comparable.", 12 | "[reporting]") 13 | { 14 | reporting::TargetReport const target{ 15 | .name = "Test mock", 16 | .overloadReport = reporting::TypeReport::make()}; 17 | 18 | SECTION("Compares equal, when both sides are equal.") 19 | { 20 | reporting::TargetReport const other{target}; 21 | 22 | REQUIRE(other == target); 23 | REQUIRE(target == other); 24 | REQUIRE_FALSE(other != target); 25 | REQUIRE_FALSE(target != other); 26 | } 27 | 28 | SECTION("Compares unequal, when name differs.") 29 | { 30 | reporting::TargetReport other{target}; 31 | other.name = "Other test mock"; 32 | 33 | REQUIRE_FALSE(other == target); 34 | REQUIRE_FALSE(target == other); 35 | REQUIRE(other != target); 36 | REQUIRE(target != other); 37 | } 38 | 39 | SECTION("Compares unequal, when name differs.") 40 | { 41 | reporting::TargetReport other{target}; 42 | other.overloadReport = reporting::TypeReport::make(); 43 | 44 | REQUIRE_FALSE(other == target); 45 | REQUIRE_FALSE(target == other); 46 | REQUIRE(other != target); 47 | REQUIRE(target != other); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /include/mimic++/reporting/SequenceReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_SEQUENCE_REPORT_HPP 7 | #define MIMICPP_REPORTING_SEQUENCE_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/utilities/SourceLocation.hpp" 14 | 15 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 16 | { 17 | /** 18 | * \addtogroup REPORTING_REPORTS 19 | * 20 | * \{ 21 | */ 22 | 23 | class SequenceReport 24 | { 25 | public: 26 | sequence::Tag tag{}; 27 | util::SourceLocation from{}; 28 | std::optional headFrom{}; 29 | 30 | [[nodiscard]] 31 | friend bool operator==(SequenceReport const&, SequenceReport const&) = default; 32 | }; 33 | 34 | template 35 | [[nodiscard]] 36 | constexpr SequenceReport make_sequence_report(sequence::detail::BasicSequence const& seq) 37 | { 38 | return SequenceReport{seq.tag(), seq.from(), seq.head_from()}; 39 | } 40 | 41 | template 42 | [[nodiscard]] 43 | constexpr SequenceReport make_sequence_report(sequence::detail::BasicSequenceInterface const& seq) 44 | { 45 | return SequenceReport{seq.tag(), seq.from(), seq.head_from()}; 46 | } 47 | 48 | /** 49 | * \} 50 | */ 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/mimic++/utilities/C++20Compatibility.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_CXX20_COMPATIBILITY_HPP 7 | #define MIMICPP_UTILITIES_CXX20_COMPATIBILITY_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #endif 16 | 17 | #ifdef __cpp_lib_bit_cast 18 | 19 | #ifndef MIMICPP_DETAIL_IS_MODULE 20 | #include 21 | #endif 22 | 23 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 24 | { 25 | using std::bit_cast; 26 | } 27 | 28 | #else 29 | 30 | #ifndef MIMICPP_DETAIL_IS_MODULE 31 | #include 32 | #include 33 | #endif 34 | 35 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 36 | { 37 | // taken from: https://www.en.cppreference.com/w/cpp/numeric/bit_cast.html 38 | template 39 | std::enable_if_t< 40 | sizeof(To) == sizeof(From) 41 | && std::is_trivially_copyable_v 42 | && std::is_trivially_copyable_v, 43 | To> 44 | // constexpr support needs compiler magic 45 | bit_cast(From const& src) noexcept 46 | { 47 | static_assert(std::is_trivially_constructible_v, "This implementation additionally requires destination type to be trivially constructible"); 48 | 49 | To dst; 50 | std::memcpy(&dst, &src, sizeof(To)); 51 | 52 | return dst; 53 | } 54 | } 55 | 56 | #endif 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/mimic++/Call.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_CALL_HPP 7 | #define MIMICPP_CALL_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/TypeTraits.hpp" 13 | #include "mimic++/utilities/SourceLocation.hpp" 14 | #include "mimic++/utilities/Stacktrace.hpp" 15 | 16 | #ifndef MIMICPP_DETAIL_IS_MODULE 17 | #include 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | namespace mimicpp::call 24 | { 25 | template 26 | class Info 27 | { 28 | public: 29 | using ArgListT = std::tuple>...>; 30 | 31 | ArgListT args; 32 | ValueCategory fromCategory{}; 33 | Constness fromConstness{}; 34 | util::SourceLocation fromSourceLocation{}; 35 | std::size_t baseStacktraceSkip{}; 36 | }; 37 | 38 | template 39 | struct info_for_signature 40 | /** \cond Help doxygen with recursion.*/ 41 | : public info_for_signature> 42 | /** \endcond */ 43 | { 44 | }; 45 | 46 | template 47 | using info_for_signature_t = typename info_for_signature::type; 48 | 49 | template 50 | struct info_for_signature 51 | { 52 | using type = Info; 53 | }; 54 | } 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /include/mimic++/printing/Fwd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_FWD_HPP 7 | #define MIMICPP_PRINTING_FWD_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::custom 14 | { 15 | /** 16 | * \brief User may add specializations, which will then be used during ``print`` calls. 17 | * \ingroup PRINTING_STATE 18 | */ 19 | template 20 | class Printer; 21 | 22 | /** 23 | * \brief User may add specializations that will be utilized during ``type_print`` calls. 24 | * \ingroup PRINTING_TYPE 25 | */ 26 | template 27 | class TypePrinter; 28 | } 29 | 30 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::printing 31 | { 32 | class PrintFn; 33 | 34 | template 35 | class PrintTypeFn; 36 | } 37 | 38 | namespace mimicpp::printing::detail::state 39 | { 40 | template 41 | struct common_type_printer; 42 | 43 | template 44 | struct cxx23_backport_printer; 45 | 46 | template 47 | struct formattable_type_printer; 48 | 49 | template 50 | struct unknown_type_printer; 51 | } 52 | 53 | namespace mimicpp::printing::type::detail 54 | { 55 | template 56 | struct common_type_printer; 57 | 58 | template 59 | struct signature_type_printer; 60 | 61 | template 62 | struct template_type_printer; 63 | } 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /test/unit-tests/reporting/NoMatchReport.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/reporting/NoMatchReport.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | "reporting::NoMatchReport is equality-comparable.", 12 | "[reporting]") 13 | { 14 | reporting::NoMatchReport const report{ 15 | .expectationReport = { 16 | .from = {}, 17 | .target = {"Test", reporting::TypeReport::make()}}, 18 | .requirementOutcomes = {{true}}}; 19 | 20 | SECTION("Compares equal, when both sides are equal.") 21 | { 22 | reporting::NoMatchReport const other = report; 23 | 24 | REQUIRE(other == report); 25 | REQUIRE(report == other); 26 | REQUIRE_FALSE(other != report); 27 | REQUIRE_FALSE(report != other); 28 | } 29 | 30 | SECTION("Compares unequal, when expectation reports differ.") 31 | { 32 | reporting::NoMatchReport other{report}; 33 | other.expectationReport.from = {}; 34 | 35 | REQUIRE_FALSE(other == report); 36 | REQUIRE_FALSE(report == other); 37 | REQUIRE(other != report); 38 | REQUIRE(report != other); 39 | } 40 | 41 | SECTION("Compares unequal, when outcomes differ.") 42 | { 43 | reporting::NoMatchReport other{report}; 44 | other.requirementOutcomes.outcomes = {false}; 45 | 46 | REQUIRE_FALSE(other == report); 47 | REQUIRE_FALSE(report == other); 48 | REQUIRE(other != report); 49 | REQUIRE(report != other); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /include/mimic++/mimic++.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_MIMICPP_HPP 7 | #define MIMICPP_MIMICPP_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | #include "mimic++/config/Settings.hpp" 13 | #include "mimic++/config/Version.hpp" 14 | 15 | #include "mimic++/Fwd.hpp" 16 | 17 | #include "mimic++/Call.hpp" 18 | #include "mimic++/CallConvention.hpp" 19 | #include "mimic++/Expectation.hpp" 20 | #include "mimic++/ExpectationBuilder.hpp" 21 | #include "mimic++/Facade.hpp" 22 | #include "mimic++/Mock.hpp" 23 | #include "mimic++/ObjectWatcher.hpp" 24 | #include "mimic++/Printing.hpp" 25 | #include "mimic++/Reporting.hpp" 26 | #include "mimic++/ScopedSequence.hpp" 27 | #include "mimic++/Sequence.hpp" 28 | #include "mimic++/String.hpp" 29 | #include "mimic++/TypeTraits.hpp" 30 | #include "mimic++/Utilities.hpp" 31 | 32 | #include "mimic++/macros/Common.hpp" 33 | #include "mimic++/macros/Facade.hpp" 34 | #include "mimic++/macros/InterfaceMocking.hpp" 35 | #include "mimic++/macros/ScopedExpectation.hpp" 36 | 37 | #include "mimic++/matchers/Common.hpp" 38 | #include "mimic++/matchers/FloatingPointMatchers.hpp" 39 | #include "mimic++/matchers/GeneralMatchers.hpp" 40 | #include "mimic++/matchers/RangeMatchers.hpp" 41 | #include "mimic++/matchers/StringMatchers.hpp" 42 | 43 | #include "mimic++/policies/ArgRequirementPolicies.hpp" 44 | #include "mimic++/policies/ArgumentList.hpp" 45 | #include "mimic++/policies/ControlPolicies.hpp" 46 | #include "mimic++/policies/FinalizerPolicies.hpp" 47 | #include "mimic++/policies/GeneralPolicies.hpp" 48 | #include "mimic++/policies/SideEffectPolicies.hpp" 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /test/unit-tests/utilities/C++23Backports.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/utilities/C++23Backports.hpp" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace mimicpp; 13 | 14 | TEMPLATE_TEST_CASE( 15 | "to_underlying converts the enum value to its underlying representation.", 16 | "[utility]", 17 | std::int8_t, 18 | std::uint8_t, 19 | std::int16_t, 20 | std::uint16_t, 21 | std::int32_t, 22 | std::uint32_t, 23 | std::int64_t, 24 | std::uint64_t) 25 | { 26 | using UnderlyingT = TestType; 27 | 28 | SECTION("When an enum value is given.") 29 | { 30 | enum Test : UnderlyingT 31 | { 32 | }; 33 | 34 | const UnderlyingT value = GENERATE( 35 | std::numeric_limits::min(), 36 | 0, 37 | 1, 38 | std::numeric_limits::max()); 39 | 40 | STATIC_REQUIRE(std::same_as); 41 | REQUIRE(value == util::to_underlying(Test{value})); 42 | } 43 | 44 | SECTION("When an class enum value is given.") 45 | { 46 | enum class Test : UnderlyingT 47 | { 48 | }; 49 | 50 | const UnderlyingT value = GENERATE( 51 | std::numeric_limits::min(), 52 | 0, 53 | 1, 54 | std::numeric_limits::max()); 55 | 56 | STATIC_REQUIRE(std::same_as); 57 | REQUIRE(value == util::to_underlying(Test{value})); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /examples/RegisterCallConvention.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/CallConvention.hpp" 7 | #include "mimic++/Facade.hpp" 8 | 9 | //! [register __stdcall] 10 | MIMICPP_REGISTER_CALL_CONVENTION(__stdcall, detail::stdcall_convention); 11 | 12 | //! [register __stdcall] 13 | 14 | TEST_CASE( 15 | "Mock supports signatures with explicit call-convention.", 16 | "[example][example::call-convention]") 17 | { 18 | //! [mock __stdcall] 19 | mimicpp::Mock mock{}; // the call-convention must be registered 20 | SCOPED_EXP mock.expect_call(); // define expectations as usual 21 | // note: ``expect_call`` still uses the default call-convention 22 | mock(); // as usual, but this time, the compiler uses the __stdcall convention 23 | //! [mock __stdcall] 24 | } 25 | 26 | TEST_CASE( 27 | "Interface mocks supports signatures with explicit call-convention.", 28 | "[example][example::call-convention]") 29 | { 30 | //! [mock interface __stdcall] 31 | struct interface 32 | { 33 | virtual ~interface() = default; 34 | virtual void __stdcall foo() const = 0; // note the explicit call-convention specification 35 | }; 36 | 37 | struct derived 38 | : public interface 39 | { 40 | MIMICPP_MAKE_MEMBER_MOCK(foo, void, (), const override, __stdcall); // the call-convention goes last 41 | }; 42 | 43 | derived mock{}; 44 | SCOPED_EXP mock.foo_.expect_call(); // as usual for interface mocks: the mock has a ``_`` suffix 45 | mock.foo(); 46 | //! [mock interface __stdcall] 47 | } 48 | -------------------------------------------------------------------------------- /.github/workflows/generate_cheat_sheet.yml: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | name: "Generate Cheat-Sheet" 7 | 8 | on: 9 | push: 10 | branches: [ main, development ] 11 | pull_request: 12 | branches: [ main, development ] 13 | release: 14 | types: [ released ] 15 | 16 | jobs: 17 | generate-cheat-sheet: 18 | runs-on: ubuntu-latest 19 | 20 | steps: 21 | - uses: actions/checkout@v4 22 | 23 | - uses: rlespinasse/drawio-export-action@v2 24 | with: 25 | action-mode: all 26 | path: docs 27 | output: . 28 | format: pdf 29 | crop: true 30 | transparent: false 31 | remove-page-suffix: true 32 | 33 | - name: Upload Cheat-Sheet 34 | uses: actions/upload-artifact@v4 35 | with: 36 | name: mimic++_cheat-sheet 37 | path: docs/mimic++_cheat-sheet.pdf 38 | if-no-files-found: error 39 | 40 | release-cheat-sheet: 41 | runs-on: ubuntu-latest 42 | needs: generate-cheat-sheet 43 | if: ${{ github.event_name == 'release' }} 44 | 45 | # this is required for the asset attachment 46 | permissions: 47 | contents: write 48 | 49 | steps: 50 | - uses: actions/download-artifact@v4 51 | with: 52 | name: mimic++_cheat-sheet 53 | path: . 54 | 55 | - name: Attach Assets to Release 56 | uses: ncipollo/release-action@v1 57 | with: 58 | artifacts: "mimic++_cheat-sheet.pdf" 59 | token: ${{ secrets.GITHUB_TOKEN }} 60 | allowUpdates: true 61 | artifactErrorsFailBuild: true 62 | omitBody: true 63 | omitName: true 64 | -------------------------------------------------------------------------------- /test/module-test/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #if MIMICPP_CONFIG_USE_FMT 7 | // Todo: This is currently a workaround for msvc, which rejects compiling without an actual error message. 8 | #include 9 | #endif 10 | 11 | #include 12 | 13 | #include "mimic++/MacroExports.hpp" 14 | import mimicpp; 15 | 16 | TEST_CASE("mimic++ supports modules!") 17 | { 18 | mimicpp::Mock mock{}; 19 | mimicpp::ScopedSequence sequence{}; 20 | 21 | SCOPED_EXP mock.expect_call(mimicpp::matches::str::eq("Hello, mimic++!")) 22 | and mimicpp::expect::in_sequence(sequence) 23 | and mimicpp::expect::times(2) 24 | and mimicpp::expect::arg<0>(!mimicpp::matches::range::is_empty()) 25 | and mimicpp::then::invoke([] {}) 26 | and mimicpp::finally::returns(42); 27 | 28 | sequence += mock.expect_call("Test") 29 | and mimicpp::finally::throws(std::runtime_error{"Exception"}); 30 | 31 | CHECK(42 == mock("Hello, mimic++!")); 32 | CHECK(42 == mock("Hello, mimic++!")); 33 | 34 | CHECK_THROWS(mock("Test")); 35 | } 36 | 37 | TEST_CASE("mimic++ interface mocks support modules!") 38 | { 39 | class Interface 40 | { 41 | public: 42 | virtual ~Interface() = default; 43 | virtual void foo() = 0; 44 | }; 45 | 46 | struct Derived 47 | : public Interface 48 | { 49 | public: 50 | MOCK_METHOD(foo, void, ()); 51 | }; 52 | 53 | auto mock = std::make_unique(); 54 | Interface& interface{*mock}; 55 | 56 | SCOPED_EXP mock->foo_.expect_call(); 57 | 58 | interface.foo(); 59 | } 60 | -------------------------------------------------------------------------------- /test/stacktrace-tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | find_package(Catch2 REQUIRED) 7 | add_subdirectory("custom") 8 | 9 | function(create_stacktrace_test BACKEND CXX_TYPE LIBS) 10 | set(TARGET_NAME mimicpp-stacktrace-${BACKEND}-tests) 11 | 12 | add_executable(${TARGET_NAME} 13 | "test.cpp" 14 | ) 15 | 16 | target_compile_definitions(${TARGET_NAME} PRIVATE 17 | TEST_CASE_PREFIX="${BACKEND}" 18 | EXPECTED_BACKEND_TYPE=${CXX_TYPE} 19 | ) 20 | 21 | target_link_libraries(${TARGET_NAME} PRIVATE 22 | mimicpp::header-only 23 | mimicpp::test::basics 24 | mimicpp::internal::enable-${BACKEND} 25 | Catch2::Catch2WithMain 26 | ${LIBS} 27 | ) 28 | 29 | target_precompile_headers(${TARGET_NAME} PRIVATE 30 | 31 | "../unit-tests/Catch2FallbackStringifier.hpp" 32 | 33 | ) 34 | 35 | catch_discover_tests(${TARGET_NAME}) 36 | endfunction() 37 | 38 | include(Mimic++-HasStdStacktrace) 39 | include(Mimic++-InternalTargets) 40 | include(Mimic++-LinkStdStacktrace) 41 | 42 | if (HAS_STD_STACKTRACE) 43 | message(DEBUG "${MESSAGE_PREFIX} adding std-stacktrace test.") 44 | create_stacktrace_test(std-stacktrace std::stacktrace mimicpp::internal::link-std-stacktrace) 45 | else () 46 | message(DEBUG "${MESSAGE_PREFIX} skipping std-stacktrace test.") 47 | endif () 48 | 49 | find_package(cpptrace REQUIRED) 50 | create_stacktrace_test(cpptrace cpptrace::stacktrace cpptrace::cpptrace) 51 | 52 | find_package(Boost REQUIRED COMPONENTS stacktrace) 53 | create_stacktrace_test(boost-stacktrace boost::stacktrace::stacktrace Boost::stacktrace) 54 | -------------------------------------------------------------------------------- /include/mimic++/reporting/TypeReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_TYPE_REPORT_HPP 7 | #define MIMICPP_REPORTING_TYPE_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/printing/TypePrinter.hpp" 14 | 15 | #ifndef MIMICPP_DETAIL_IS_MODULE 16 | #include 17 | #endif 18 | 19 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 20 | { 21 | /** 22 | * \brief Contains information about a specific (potentially cv-ref-qualified) type. 23 | */ 24 | class TypeReport 25 | { 26 | private: 27 | using make_name_fn = StringT (*)(); 28 | 29 | template 30 | [[nodiscard]] 31 | static MIMICPP_DETAIL_CONSTEXPR_STRING StringT make_type_name() 32 | { 33 | return mimicpp::print_type(); 34 | } 35 | 36 | public: 37 | template 38 | [[nodiscard]] 39 | static constexpr TypeReport make() noexcept 40 | { 41 | return TypeReport{&TypeReport::make_type_name}; 42 | } 43 | 44 | [[nodiscard]] 45 | MIMICPP_DETAIL_CONSTEXPR_STRING StringT name() const 46 | { 47 | return std::invoke(m_MakeNameFn); 48 | } 49 | 50 | [[nodiscard]] 51 | friend bool operator==(TypeReport const&, TypeReport const&) = default; 52 | 53 | private: 54 | make_name_fn m_MakeNameFn; 55 | 56 | explicit constexpr TypeReport(make_name_fn const makeFn) noexcept 57 | : m_MakeNameFn{makeFn} 58 | { 59 | MIMICPP_ASSERT(m_MakeNameFn, "Null make-function is not allowed."); 60 | } 61 | }; 62 | } 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /docs/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #[[ Adds a custom target, which generates the doxygen documentation. 7 | The working directory is set to the project origin, as this is an effective way to use the relative paths for the documentation. 8 | #]] 9 | 10 | message(TRACE "Begin generating docs") 11 | 12 | include(get_cpm) 13 | 14 | CPMAddPackage("gh:jothepro/doxygen-awesome-css@2.3.4") 15 | 16 | set(DOXY_PROJECT_VERSION ${PROJECT_VERSION}) 17 | set(DOXY_INPUT_DIR "include docs") 18 | set(DOXY_EXAMPLE_DIR "examples") 19 | set(DOXY_README_PATH "README.md") 20 | cmake_path( 21 | RELATIVE_PATH CMAKE_CURRENT_BINARY_DIR 22 | BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" 23 | OUTPUT_VARIABLE DOXY_OUTPUT_DIR 24 | ) 25 | cmake_path( 26 | RELATIVE_PATH doxygen-awesome-css_SOURCE_DIR 27 | BASE_DIRECTORY "${PROJECT_SOURCE_DIR}" 28 | OUTPUT_VARIABLE DOXY_HTML_EXTRA_STYLESHEET 29 | ) 30 | set(DOXY_HTML_EXTRA_STYLESHEET "${DOXY_HTML_EXTRA_STYLESHEET}/doxygen-awesome.css") 31 | 32 | if (MIMICPP_ENABLE_GENERATE_DOCS) 33 | 34 | message(TRACE "Start configure docs target") 35 | 36 | find_package(Doxygen REQUIRED COMPONENTS dot) 37 | if (NOT DOXYGEN_FOUND) 38 | message(FATAL_ERROR "Doxygen not found.") 39 | endif() 40 | 41 | get_target_property(DOXY_DOT_PATH Doxygen::dot LOCATION) 42 | message(VERBOSE "Using dot at: ${DOXY_DOT_PATH}") 43 | 44 | add_custom_target( 45 | mimicpp-generate-docs 46 | COMMAND "$" "${CMAKE_CURRENT_BINARY_DIR}/Doxyfile" 47 | COMMENT "Generate Documentation" 48 | WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}" 49 | COMMAND_EXPAND_LISTS 50 | VERBATIM 51 | USES_TERMINAL 52 | ) 53 | 54 | message(TRACE "End configure docs target") 55 | 56 | endif() 57 | 58 | configure_file(Doxyfile.in Doxyfile @ONLY) 59 | 60 | message(TRACE "Finished generating docs") 61 | -------------------------------------------------------------------------------- /include/mimic++/config/Settings.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_CONFIG_SETTINGS_HPP 7 | #define MIMICPP_CONFIG_SETTINGS_HPP 8 | 9 | #include "mimic++/config/Config.hpp" 10 | 11 | #ifndef MIMICPP_DETAIL_IS_MODULE 12 | #include 13 | #endif 14 | 15 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::settings 16 | { 17 | /** 18 | * \defgroup SETTINGS settings 19 | * \brief Contains global settings, which can be changed at runtime. 20 | * \{ 21 | */ 22 | 23 | /** 24 | * \brief Controls whether successful matches are reported. 25 | * \details Reporting can be an expensive operation, particularly when stacktraces are collected. 26 | * To reduce overhead, `mimic++` reports only violations by default. 27 | * \note This setting affects only the behavior of mimic++. 28 | * When using a test adapter, additional configuration in the test framework may be required to receive such reports. 29 | * \returns a mutable reference to the actual settings value. 30 | */ 31 | [[nodiscard]] 32 | inline std::atomic_bool& report_success() noexcept 33 | { 34 | static std::atomic_bool value{false}; 35 | 36 | return value; 37 | } 38 | 39 | /** 40 | * \brief Controls whether the base stacktrace-skip value. 41 | * \details This value will be added to all user-supplied *skip* values. 42 | * This comes in handy when the current stacktrace backend captures more frames than other backends would usually do. 43 | * \returns a mutable reference to the actual settings value. 44 | */ 45 | [[nodiscard]] 46 | inline std::atomic_size_t& stacktrace_base_skip() noexcept 47 | { 48 | static std::atomic_size_t value{0u}; 49 | 50 | return value; 51 | } 52 | 53 | /** 54 | * \} 55 | */ 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /test/cmake/Mimic++-LinkStdStacktrace.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if (NOT TARGET link-std-stacktrace) 7 | 8 | add_library(link-std-stacktrace INTERFACE) 9 | add_library(mimicpp::internal::link-std-stacktrace ALIAS link-std-stacktrace) 10 | 11 | # @formatter:off 12 | string(CONCAT GCC_LINK_LIBBACKTRACE 13 | "$<" 14 | "$," 16 | "$," 17 | "$,13>," 18 | "$,14>>" 19 | ":stdc++_libbacktrace>" 20 | ) 21 | string(CONCAT GCC_LINK_EXP 22 | "$<" 23 | "$," 25 | "$," 26 | "$,14>>" 27 | ":stdc++exp>" 28 | ) 29 | string(CONCAT CLANG_LINK_LIBBACKTRACE 30 | "$<" 31 | "$," 33 | "$," 34 | "$,17>," 35 | "$,19>>" 36 | ":stdc++_libbacktrace>" 37 | ) 38 | string(CONCAT CLANG_LINK_EXP 39 | "$<" 40 | "$," 42 | "$," 43 | "$,19>>" 44 | ":stdc++exp>" 45 | ) 46 | # @formatter:on 47 | 48 | target_link_libraries(link-std-stacktrace 49 | INTERFACE 50 | ${GCC_LINK_LIBBACKTRACE} 51 | ${GCC_LINK_EXP} 52 | ${CLANG_LINK_LIBBACKTRACE} 53 | ${CLANG_LINK_EXP} 54 | ) 55 | 56 | endif () 57 | -------------------------------------------------------------------------------- /include/mimic++/utilities/C++23Backports.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_CXX23_BACKPORTS_HPP 7 | #define MIMICPP_UTILITIES_CXX23_BACKPORTS_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #include 16 | #endif 17 | 18 | // GCOVR_EXCL_START 19 | #ifdef __cpp_lib_unreachable 20 | 21 | #ifndef MIMICPP_DETAIL_IS_MODULE 22 | #include 23 | #endif 24 | 25 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 26 | { 27 | using std::unreachable; 28 | } 29 | 30 | #else 31 | 32 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 33 | { 34 | /** 35 | * \brief Invokes undefined behavior 36 | * \see https://en.cppreference.com/w/cpp/utility/unreachable 37 | * \note Implementation directly taken from https://en.cppreference.com/w/cpp/utility/unreachable 38 | */ 39 | [[noreturn]] 40 | inline void unreachable() 41 | { 42 | MIMICPP_ASSERT(false, "Reached the unreachable."); 43 | 44 | // Uses compiler specific extensions if possible. 45 | // Even if no extension is used, undefined behavior is still raised by 46 | // an empty function body and the noreturn attribute. 47 | #if MIMICPP_DETAIL_IS_MSVC // MSVC 48 | __assume(false); 49 | #else // GCC, Clang 50 | __builtin_unreachable(); 51 | #endif 52 | } 53 | } 54 | #endif 55 | // GCOVR_EXCL_STOP 56 | 57 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 58 | { 59 | template 60 | requires std::is_enum_v 61 | [[nodiscard]] 62 | constexpr std::underlying_type_t to_underlying(T const value) noexcept 63 | { 64 | return static_cast>(value); 65 | } 66 | } 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /.github/workflows/generate_amalgamated_header.yml: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | name: generate amalgamated header 7 | 8 | on: 9 | push: 10 | branches: [main, development] 11 | pull_request: 12 | branches: [main, development] 13 | release: 14 | types: [released] 15 | 16 | jobs: 17 | amalgamate-header: 18 | runs-on: ubuntu-latest 19 | container: 20 | image: ghcr.io/dnkpp/gcc:14 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Configure 26 | run: | 27 | cmake \ 28 | -S . \ 29 | -B build \ 30 | --log-level=VERBOSE \ 31 | -DMIMICPP_ENABLE_AMALGAMATE_HEADERS=ON \ 32 | -DMIMICPP_BUILD_TESTS=OFF \ 33 | -DMIMICPP_BUILD_EXAMPLES=OFF 34 | 35 | - name: Generate Doxygen Documentation 36 | run: | 37 | cmake --build build --target mimicpp-amalgamate-headers 38 | 39 | - name: Upload header 40 | uses: actions/upload-artifact@v4 41 | with: 42 | name: amalgamated-header 43 | path: build/tools/amalgamate-headers/mimic++-amalgamated.hpp 44 | 45 | release-amalgamated-header: 46 | runs-on: ubuntu-latest 47 | needs: amalgamate-header 48 | if: ${{ github.event_name == 'release' }} 49 | 50 | # this is required for the asset attachment 51 | permissions: 52 | contents: write 53 | 54 | steps: 55 | - uses: actions/download-artifact@v4 56 | with: 57 | name: amalgamated-header 58 | path: ./header 59 | 60 | - name: attach release assets 61 | uses: ncipollo/release-action@v1 62 | with: 63 | artifacts: "header/mimic++-amalgamated.hpp" 64 | token: ${{ secrets.GITHUB_TOKEN }} 65 | allowUpdates: true 66 | artifactErrorsFailBuild: true 67 | omitBody: true 68 | omitName: true 69 | -------------------------------------------------------------------------------- /cmake/Mimic++-ReadProjectVersion.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | function(mimicpp_read_project_version FILE_PATH OUT_VERSION) 7 | 8 | file(READ ${FILE_PATH} FILE_CONTENT) 9 | if (NOT FILE_CONTENT) 10 | message(FATAL_ERROR "${MESSAGE_PREFIX} mimicpp_read_project_version failed - Unable to read file from: ${FILE_PATH}") 11 | endif () 12 | 13 | set(VERSION_MAJOR_REGEX "#define[ \t]+MIMICPP_VERSION_MAJOR[ \t]+([0-9]+)") 14 | string(REGEX MATCH ${VERSION_MAJOR_REGEX} _ ${FILE_CONTENT}) 15 | set(VERSION_MAJOR ${CMAKE_MATCH_1}) 16 | if (NOT VERSION_MAJOR GREATER_EQUAL 0) 17 | message(FATAL_ERROR "${MESSAGE_PREFIX} mimicpp_read_project_version failed - Major version not found.") 18 | endif () 19 | 20 | set(VERSION_MINOR_REGEX "#define[ \t]+MIMICPP_VERSION_MINOR[ \t]+([0-9]+)") 21 | string(REGEX MATCH ${VERSION_MINOR_REGEX} _ ${FILE_CONTENT}) 22 | set(VERSION_MINOR ${CMAKE_MATCH_1}) 23 | if (NOT VERSION_MINOR GREATER_EQUAL 0) 24 | message(FATAL_ERROR "${MESSAGE_PREFIX} mimicpp_read_project_version failed - Minor version not found.") 25 | endif () 26 | 27 | set(VERSION_PATCH_REGEX "#define[ \t]+MIMICPP_VERSION_PATCH[ \t]+([0-9]+)") 28 | string(REGEX MATCH ${VERSION_PATCH_REGEX} _ ${FILE_CONTENT}) 29 | set(VERSION_PATCH ${CMAKE_MATCH_1}) 30 | if (NOT VERSION_PATCH GREATER_EQUAL 0) 31 | message(FATAL_ERROR "${MESSAGE_PREFIX} mimicpp_read_project_version failed - Patch version not found.") 32 | endif () 33 | 34 | set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") 35 | if (NOT VERSION VERSION_GREATER 0) 36 | message(FATAL_ERROR "${MESSAGE_PREFIX} mimicpp_read_project_version failed - Unable to read version.") 37 | endif () 38 | 39 | message(DEBUG "${MESSAGE_PREFIX} mimicpp_read_project_version succeeded - Version is ${VERSION}.") 40 | set(${OUT_VERSION} ${VERSION} PARENT_SCOPE) 41 | 42 | endfunction() 43 | -------------------------------------------------------------------------------- /examples/CustomPrinter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/Printing.hpp" 7 | 8 | namespace 9 | { 10 | //! [my_type] 11 | struct my_type 12 | { 13 | int data{}; 14 | }; 15 | 16 | //! [my_type] 17 | } 18 | 19 | //! [my_type printer] 20 | template <> 21 | class mimicpp::custom::Printer 22 | { 23 | public: 24 | static auto print(auto outIter, const my_type& object) 25 | { 26 | return format::format_to( 27 | outIter, 28 | "Object of my_type has value: {}", 29 | object.data); 30 | } 31 | }; 32 | 33 | //! [my_type printer] 34 | 35 | TEST_CASE( 36 | "mimicpp::custom::Printer can be specialized for arbitrary user types.", 37 | "[example][example::printer]") 38 | { 39 | //! [my_type print] 40 | constexpr my_type myObject{42}; 41 | const std::string text = mimicpp::print(myObject); 42 | 43 | REQUIRE_THAT( 44 | text, 45 | Catch::Matchers::Equals("Object of my_type has value: 42")); 46 | //! [my_type print] 47 | } 48 | 49 | //! [my_type type-printer] 50 | template <> 51 | class mimicpp::custom::TypePrinter 52 | { 53 | public: 54 | static auto print(auto out) 55 | { 56 | return format::format_to(out, "This-Is-My-Mighty-Type"); 57 | } 58 | }; 59 | 60 | //! [my_type type-printer] 61 | 62 | TEST_CASE( 63 | "mimicpp::custom::TypePrinter can be specialized for arbitrary types." 64 | "[example][example::printer]") 65 | { 66 | //! [my_type type-print] 67 | const std::string name = mimicpp::print_type(); 68 | 69 | REQUIRE_THAT( 70 | name, 71 | Catch::Matchers::Equals("This-Is-My-Mighty-Type")); 72 | 73 | const std::string qualifiedName = mimicpp::print_type(); 74 | REQUIRE_THAT( 75 | qualifiedName, 76 | Catch::Matchers::Equals("This-Is-My-Mighty-Type* const&&")); 77 | //! [my_type type-print] 78 | } 79 | -------------------------------------------------------------------------------- /test/unit-tests/reporting/TypeReport.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/reporting/TypeReport.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEMPLATE_TEST_CASE( 11 | "TypeReport contains info about the specified type.", 12 | "[reporting]", 13 | std::string, 14 | std::string const, 15 | std::string&, 16 | std::string&&, 17 | std::string*, 18 | std::string[], 19 | std::string**) 20 | { 21 | using T = TestType; 22 | 23 | reporting::TypeReport const report = reporting::TypeReport::make(); 24 | REQUIRE_THAT( 25 | report.name(), 26 | Catch::Matchers::Equals(print_type())); 27 | } 28 | 29 | TEST_CASE( 30 | "TypeReport is equality-comparable.", 31 | "[reporting]") 32 | { 33 | reporting::TypeReport const report = reporting::TypeReport::make(); 34 | 35 | SECTION("Two reports compare equal, if they both are constructed for the same type.") 36 | { 37 | reporting::TypeReport const other = reporting::TypeReport::make(); 38 | REQUIRE(report == other); 39 | REQUIRE_FALSE(report != other); 40 | } 41 | 42 | SECTION("Two reports compare unequal, if they both are constructed for the same type but with different qualifications.") 43 | { 44 | reporting::TypeReport const constOther = reporting::TypeReport::make(); 45 | REQUIRE_FALSE(report == constOther); 46 | REQUIRE(report != constOther); 47 | 48 | reporting::TypeReport const refOther = reporting::TypeReport::make(); 49 | REQUIRE_FALSE(report == refOther); 50 | REQUIRE(report != refOther); 51 | } 52 | 53 | SECTION("Two reports compare unequal, if they both are constructed for different type.") 54 | { 55 | reporting::TypeReport const other = reporting::TypeReport::make(); 56 | REQUIRE_FALSE(report == other); 57 | REQUIRE(report != other); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /include/mimic++/config/Config.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_CONFIG_CONFIG_HPP 7 | #define MIMICPP_CONFIG_CONFIG_HPP 8 | 9 | #pragma once 10 | 11 | #ifndef MIMICPP_DETAIL_IS_MODULE 12 | #include 13 | #include 14 | #endif 15 | 16 | #ifdef MIMICPP_DETAIL_IS_MODULE 17 | #define MIMICPP_DETAIL_MODULE_EXPORT export 18 | #else 19 | #define MIMICPP_DETAIL_MODULE_EXPORT 20 | #endif 21 | 22 | #if INTPTR_MAX < INT64_MAX 23 | #define MIMICPP_DETAIL_IS_32BIT 1 24 | #endif 25 | 26 | #ifdef _LIBCPP_VERSION 27 | #define MIMICPP_DETAIL_USES_LIBCXX 1 28 | #endif 29 | 30 | #ifdef __GNUC__ 31 | #ifdef __clang__ 32 | #define MIMICPP_DETAIL_IS_CLANG 1 33 | #else 34 | #define MIMICPP_DETAIL_IS_GCC 1 35 | #endif 36 | #endif 37 | 38 | #ifdef _WIN32 39 | #define MIMICPP_DETAIL_IS_WINDOWS 1 40 | #endif 41 | 42 | #ifdef _MSC_VER 43 | #ifdef __clang__ 44 | #define MIMICPP_DETAIL_IS_CLANG_CL 1 45 | #else 46 | #define MIMICPP_DETAIL_IS_MSVC 1 47 | #endif 48 | #endif 49 | 50 | #ifndef MIMICPP_ASSERT 51 | #define MIMICPP_ASSERT(condition, msg) (void(0)) 52 | #endif 53 | 54 | // clang-format off 55 | // Prevent number from getting decorated with '. 56 | #if 201907L <= __cpp_lib_constexpr_string 57 | // clang-format on 58 | #define MIMICPP_DETAIL_CONSTEXPR_STRING constexpr 59 | #else 60 | #define MIMICPP_DETAIL_CONSTEXPR_STRING inline 61 | #endif 62 | 63 | // clang-format off 64 | // Prevent number from getting decorated with '. 65 | #if 201907L <= __cpp_lib_constexpr_vector 66 | // clang-format on 67 | #define MIMICPP_DETAIL_CONSTEXPR_VECTOR constexpr 68 | #else 69 | #define MIMICPP_DETAIL_CONSTEXPR_VECTOR inline 70 | #endif 71 | 72 | // gcc 10 requires a workaround, due to some ambiguities. 73 | // see: https://github.com/DNKpp/mimicpp/issues/151 74 | #if MIMICPP_DETAIL_IS_GCC \ 75 | && __GNUC__ <= 10 76 | #define MIMICPP_DETAIL_STD_GET_WORKAROUND 1 77 | #endif 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /test/unit-tests/SuppressionMacros.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | #include "mimic++/config/Config.hpp" 9 | 10 | #if MIMICPP_DETAIL_IS_MSVC 11 | 12 | #define START_WARNING_SUPPRESSION __pragma(warning(push)) 13 | #define STOP_WARNING_SUPPRESSION __pragma(warning(pop)) 14 | 15 | #define SUPPRESS_UNREACHABLE_CODE __pragma(warning(disable: 4702)) 16 | #define SUPPRESS_SELF_MOVE // seems not required on msvc 17 | #define SUPPRESS_SELF_ASSIGN // seems not required on msvc 18 | #define SUPPRESS_MAYBE_UNINITIALIZED // seems not required on msvc 19 | #define SUPPRESS_DEPRECATION __pragma(warning(disable: 4996)) 20 | 21 | #else 22 | 23 | // clang accepts GCC diagnostic 24 | #define START_WARNING_SUPPRESSION _Pragma("GCC diagnostic push") 25 | #define STOP_WARNING_SUPPRESSION _Pragma("GCC diagnostic pop") 26 | 27 | #define SUPPRESS_UNREACHABLE_CODE _Pragma("GCC diagnostic ignored \"-Wunreachable-code\"") 28 | 29 | // clang doesn't know -Wmaybe-uninitialized, 30 | // but gcc doesn't know -Wunknown-warning-option 31 | // but this combination works 32 | #define SUPPRESS_MAYBE_UNINITIALIZED \ 33 | _Pragma("GCC diagnostic ignored \"-Wpragmas\"") \ 34 | _Pragma("GCC diagnostic ignored \"-Wunknown-warning-option\"") \ 35 | _Pragma("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") 36 | 37 | // gcc 12 doesn't know -Wself-move option 38 | #if MIMICPP_DETAIL_IS_GCC \ 39 | && 12 >= __GNUC__ 40 | #define SUPPRESS_SELF_MOVE 41 | #else 42 | #define SUPPRESS_SELF_MOVE _Pragma("GCC diagnostic ignored \"-Wself-move\"") 43 | #endif 44 | 45 | // gcc doesn't know -Wself-assign-overloaded option 46 | #if not MIMICPP_DETAIL_IS_GCC 47 | #define SUPPRESS_SELF_ASSIGN _Pragma("GCC diagnostic ignored \"-Wself-assign-overloaded\"") 48 | #else 49 | #define SUPPRESS_SELF_ASSIGN 50 | #endif 51 | 52 | #define SUPPRESS_DEPRECATION _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") 53 | #endif 54 | -------------------------------------------------------------------------------- /test/unit-tests/utilities/SourceLocation.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/utilities/SourceLocation.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | "util::SourceLocation is default constructible.", 12 | "[util]") 13 | { 14 | constexpr util::SourceLocation before{}; 15 | constexpr util::SourceLocation loc{}; 16 | constexpr util::SourceLocation after{}; 17 | 18 | CHECK_THAT( 19 | std::string{loc.file_name()}, 20 | Catch::Matchers::Equals(std::string{before.file_name()})); 21 | CHECK_THAT( 22 | std::string{loc.function_name()}, 23 | Catch::Matchers::Equals(std::string{before.function_name()})); 24 | CHECK(before.line() < loc.line()); 25 | CHECK(loc.line() < after.line()); 26 | } 27 | 28 | TEST_CASE( 29 | "util::SourceLocation is equality-comparable.", 30 | "[util]") 31 | { 32 | SECTION("Compares equal, when both sides denote the same source-location.") 33 | { 34 | constexpr util::SourceLocation loc{}; 35 | constexpr util::SourceLocation other{loc}; 36 | 37 | CHECK(loc == other); 38 | CHECK(other == loc); 39 | CHECK_FALSE(loc != other); 40 | CHECK_FALSE(other != loc); 41 | } 42 | 43 | SECTION("Compares unequal, when line differs.") 44 | { 45 | constexpr util::SourceLocation loc{}; 46 | constexpr util::SourceLocation other{}; 47 | REQUIRE(other.line() != loc.line()); 48 | 49 | CHECK_FALSE(loc == other); 50 | CHECK_FALSE(other == loc); 51 | CHECK(loc != other); 52 | CHECK(other != loc); 53 | } 54 | 55 | SECTION("Compares unequal, when function differs.") 56 | { 57 | constexpr util::SourceLocation loc{}; 58 | constexpr auto other = std::invoke( 59 | [] { return util::SourceLocation{}; }); 60 | 61 | CHECK_FALSE(loc == other); 62 | CHECK_FALSE(other == loc); 63 | CHECK(loc != other); 64 | CHECK(other != loc); 65 | } 66 | 67 | SECTION("Compares unequal, when source-file differs.") 68 | { 69 | // trust me, bro 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /cmake/Mimic++-InternalTargets.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | if (NOT TARGET mimicpp::internal::enable-std-stacktrace) 7 | add_library(mimicpp-internal-enable-std-stacktrace INTERFACE) 8 | add_library(mimicpp::internal::enable-std-stacktrace ALIAS mimicpp-internal-enable-std-stacktrace) 9 | 10 | target_compile_features(mimicpp-internal-enable-std-stacktrace INTERFACE 11 | cxx_std_23 12 | ) 13 | target_compile_definitions(mimicpp-internal-enable-std-stacktrace INTERFACE 14 | MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE=1 15 | MIMICPP_CONFIG_EXPERIMENTAL_USE_CXX23_STACKTRACE=1 16 | ) 17 | endif () 18 | 19 | if (NOT TARGET mimicpp::internal::enable-cpptrace) 20 | add_library(mimicpp-internal-enable-cpptrace INTERFACE) 21 | add_library(mimicpp::internal::enable-cpptrace ALIAS mimicpp-internal-enable-cpptrace) 22 | 23 | target_compile_definitions(mimicpp-internal-enable-cpptrace INTERFACE 24 | MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE=1 25 | MIMICPP_CONFIG_EXPERIMENTAL_USE_CPPTRACE=1 26 | $<$:MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE=1> 27 | ) 28 | endif () 29 | 30 | if (NOT TARGET mimicpp::internal::enable-boost-stacktrace) 31 | add_library(mimicpp-internal-enable-boost-stacktrace INTERFACE) 32 | add_library(mimicpp::internal::enable-boost-stacktrace ALIAS mimicpp-internal-enable-boost-stacktrace) 33 | 34 | target_compile_definitions(mimicpp-internal-enable-boost-stacktrace INTERFACE 35 | MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE=1 36 | MIMICPP_CONFIG_EXPERIMENTAL_USE_BOOST_STACKTRACE=1 37 | ) 38 | endif () 39 | 40 | if (NOT TARGET mimicpp::internal::enable-custom-stacktrace) 41 | add_library(mimicpp-internal-enable-custom-stacktrace INTERFACE) 42 | add_library(mimicpp::internal::enable-custom-stacktrace ALIAS mimicpp-internal-enable-custom-stacktrace) 43 | 44 | target_compile_definitions(mimicpp-internal-enable-custom-stacktrace INTERFACE 45 | MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE=1 46 | MIMICPP_CONFIG_EXPERIMENTAL_USE_CUSTOM_STACKTRACE=1 47 | ) 48 | endif () 49 | -------------------------------------------------------------------------------- /include/mimic++_ext/adapters/Doctest.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_ADAPTERS_DOCTEST_HPP 7 | #define MIMICPP_ADAPTERS_DOCTEST_HPP 8 | 9 | #pragma once 10 | 11 | #if __has_include("mimic++/Reporting.hpp") 12 | #include "mimic++/Reporting.hpp" 13 | #include "mimic++/utilities/C++23Backports.hpp" 14 | #elif not defined(MIMICPP_VERSION) 15 | #error "It appears that the test-adapter is not included in the mimic++ project or package." \ 16 | "If you plan to use it alongside the mimic++-amalgamated header, please ensure to include the adapter-header afterwards." 17 | #endif 18 | 19 | #if __has_include() 20 | #include 21 | #else 22 | #error "Unable to find Doctest includes." 23 | #endif 24 | 25 | namespace mimicpp::reporting::detail::doctest 26 | { 27 | using namespace ::doctest; 28 | 29 | [[noreturn]] 30 | inline void send_fail(StringViewT const msg) 31 | { 32 | DOCTEST_FAIL(msg); 33 | util::unreachable(); 34 | } 35 | 36 | inline void send_success(StringViewT const msg) 37 | { 38 | DOCTEST_REQUIRE_MESSAGE(true, msg); 39 | } 40 | 41 | inline void send_warning(StringViewT const msg) 42 | { 43 | DOCTEST_MESSAGE(msg); 44 | } 45 | } 46 | 47 | namespace mimicpp::reporting 48 | { 49 | // GCOVR_EXCL_START 50 | 51 | /** 52 | * \brief Reporter for the integration into Doctest. 53 | * \ingroup REPORTING_ADAPTERS 54 | * \details This reporter enables the integration of ``mimic++`` into ``Doctest`` and prefixes the headers 55 | * of ``Doctest`` with ``doctest/``. 56 | * 57 | * This reporter installs itself by simply including this header file into any source file of the test executable. 58 | */ 59 | using DoctestReporterT = BasicReporter< 60 | &detail::doctest::send_success, 61 | &detail::doctest::send_warning, 62 | &detail::doctest::send_fail>; 63 | 64 | // GCOVR_EXCL_STOP 65 | } 66 | 67 | namespace mimicpp::reporting::detail::doctest 68 | { 69 | [[maybe_unused]] 70 | inline ReporterInstaller const installer{}; 71 | } 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /include/mimic++_ext/adapters/gtest.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_ADAPTERS_GTEST_HPP 7 | #define MIMICPP_ADAPTERS_GTEST_HPP 8 | 9 | #pragma once 10 | 11 | #if __has_include("mimic++/Reporting.hpp") 12 | #include "mimic++/Reporting.hpp" 13 | #elif not defined(MIMICPP_VERSION) 14 | #error "It appears that the test-adapter is not included in the mimic++ project or package." \ 15 | "If you plan to use it alongside the mimic++-amalgamated header, please ensure to include the adapter-header afterwards." 16 | #endif 17 | 18 | #if __has_include() 19 | #include 20 | #else 21 | #error "Unable to find gtest includes." 22 | #endif 23 | 24 | namespace mimicpp::reporting::detail::gtest 25 | { 26 | struct failure 27 | { 28 | }; 29 | 30 | [[noreturn]] 31 | inline void send_fail(StringViewT const msg) 32 | { 33 | // GTEST_FAIL has an immediate return 34 | std::invoke( 35 | [&] { 36 | GTEST_FAIL() << msg; 37 | }); 38 | 39 | throw failure{}; 40 | } 41 | 42 | inline void send_success(StringViewT const msg) 43 | { 44 | GTEST_SUCCEED() << msg; 45 | } 46 | 47 | inline void send_warning([[maybe_unused]] StringViewT const msg) 48 | { 49 | // seems unsupported 50 | } 51 | } 52 | 53 | namespace mimicpp::reporting 54 | { 55 | // GCOVR_EXCL_START 56 | 57 | /** 58 | * \brief Reporter for the integration into gtest. 59 | * \ingroup REPORTING_ADAPTERS 60 | * \details This reporter enables the integration of ``mimic++`` into ``gtest`` and prefixes the headers 61 | * of ``gtest`` with ``gtest/``. 62 | * 63 | * This reporter installs itself by simply including this header file into any source file of the test executable. 64 | */ 65 | using GTestReporterT = BasicReporter< 66 | &detail::gtest::send_success, 67 | &detail::gtest::send_warning, 68 | &detail::gtest::send_fail>; 69 | 70 | // GCOVR_EXCL_STOP 71 | } 72 | 73 | namespace mimicpp::reporting::detail::gtest 74 | { 75 | [[maybe_unused]] 76 | inline ReporterInstaller const installer{}; 77 | } 78 | 79 | #endif 80 | -------------------------------------------------------------------------------- /include/mimic++_ext/adapters/BoostTest.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_ADAPTERS_BOOST_TEST_HPP 7 | #define MIMICPP_ADAPTERS_BOOST_TEST_HPP 8 | 9 | #pragma once 10 | 11 | #if __has_include("mimic++/Reporting.hpp") 12 | #include "mimic++/Reporting.hpp" 13 | #include "mimic++/utilities/C++23Backports.hpp" 14 | #elif not defined(MIMICPP_VERSION) 15 | #error "It appears that the test-adapter is not included in the mimic++ project or package." \ 16 | "If you plan to use it alongside the mimic++-amalgamated header, please ensure to include the adapter-header afterwards." 17 | #endif 18 | 19 | #if __has_include() 20 | #include 21 | #else 22 | #error "Unable to find Boost.Test includes." 23 | #endif 24 | 25 | namespace mimicpp::reporting::detail::boost_test 26 | { 27 | struct failure 28 | { 29 | }; 30 | 31 | [[noreturn]] 32 | inline void send_fail(StringViewT const msg) 33 | { 34 | BOOST_TEST_FAIL(msg); 35 | util::unreachable(); 36 | } 37 | 38 | inline void send_success(StringViewT const msg) 39 | { 40 | BOOST_TEST_MESSAGE(msg); 41 | } 42 | 43 | inline void send_warning(StringViewT const msg) 44 | { 45 | BOOST_TEST_MESSAGE("warning: ") << msg.data(); 46 | } 47 | } 48 | 49 | namespace mimicpp::reporting 50 | { 51 | // GCOVR_EXCL_START 52 | 53 | /** 54 | * \brief Reporter for the integration into ``Boost.Test``. 55 | * \ingroup REPORTING_ADAPTERS 56 | * \details This reporter enables the integration of ``mimic++`` into ``Boost.Test`` and prefixes the headers 57 | * of ``Boost.Test`` with ``boost/test``. 58 | * 59 | * This reporter installs itself by simply including this header file into any source file of the test executable. 60 | */ 61 | using BoostTestReporterT = BasicReporter< 62 | &detail::boost_test::send_success, 63 | &detail::boost_test::send_warning, 64 | &detail::boost_test::send_fail>; 65 | 66 | // GCOVR_EXCL_STOP 67 | } 68 | 69 | namespace mimicpp::reporting::detail::boost_test 70 | { 71 | [[maybe_unused]] 72 | inline ReporterInstaller const installer{}; 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /module/mimic++.cppm: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | module; 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #if defined(MIMICPP_CONFIG_EXPERIMENTAL_PRETTY_TYPES) \ 44 | && __has_include() 45 | #include 46 | #endif 47 | 48 | #if MIMICPP_CONFIG_USE_FMT 49 | #if !MIMICPP_CONFIG_IMPORT_FMT 50 | #include 51 | #endif 52 | #else 53 | #include 54 | #endif 55 | 56 | #if MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE 57 | 58 | #if MIMICPP_CONFIG_EXPERIMENTAL_USE_CPPTRACE 59 | 60 | #if !MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE 61 | #if __has_include() 62 | #include 63 | #elif __has_include() 64 | // This is necessary for older cpptrace versions. 65 | // see: https://github.com/jeremy-rifkin/libassert/issues/110 66 | #include 67 | #endif 68 | #endif 69 | 70 | #elif defined(__cpp_lib_stacktrace) 71 | #include 72 | #endif 73 | 74 | #endif 75 | 76 | #ifdef MIMICPP_CONFIG_EXPERIMENTAL_UNICODE_STR_MATCHER 77 | #include 78 | #include 79 | #endif 80 | 81 | export module mimicpp; 82 | 83 | #if MIMICPP_CONFIG_IMPORT_FMT 84 | import fmt; 85 | #endif 86 | 87 | #if MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE 88 | import cpptrace; 89 | #endif 90 | 91 | #define MIMICPP_DETAIL_IS_MODULE 1 92 | #include "mimic++/mimic++.hpp" 93 | -------------------------------------------------------------------------------- /include/mimic++_ext/stacktrace/std-stacktrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_EXT_STACKTRACE_STD_STACKTRACE_HPP 7 | #define MIMICPP_EXT_STACKTRACE_STD_STACKTRACE_HPP 8 | 9 | #include "mimic++/Fwd.hpp" 10 | #include "mimic++/config/Config.hpp" 11 | 12 | #ifndef MIMICPP_DETAIL_IS_MODULE 13 | #include 14 | #include 15 | #include 16 | #endif 17 | 18 | struct mimicpp::util::stacktrace::find_backend 19 | { 20 | using type = std::stacktrace; 21 | }; 22 | 23 | template 24 | struct mimicpp::util::stacktrace::backend_traits> 25 | { 26 | using Backend = std::basic_stacktrace; 27 | 28 | [[nodiscard]] 29 | static Backend current(std::size_t const skip, std::size_t const max) noexcept 30 | { 31 | MIMICPP_ASSERT(skip < std::numeric_limits::max() - max, "Skip + max is too high."); 32 | 33 | return Backend::current(skip + 1, max); 34 | } 35 | 36 | [[nodiscard]] 37 | static Backend current(std::size_t const skip) noexcept 38 | { 39 | MIMICPP_ASSERT(skip < std::numeric_limits::max(), "Skip is too high."); 40 | 41 | return Backend::current(skip + 1); 42 | } 43 | 44 | [[nodiscard]] 45 | static std::size_t size(Backend const& backend) noexcept 46 | { 47 | return backend.size(); 48 | } 49 | 50 | [[nodiscard]] 51 | static bool empty(Backend const& backend) noexcept 52 | { 53 | return backend.empty(); 54 | } 55 | 56 | [[nodiscard]] 57 | static std::string description(Backend const& backend, std::size_t const at) 58 | { 59 | return entry(backend, at).description(); 60 | } 61 | 62 | [[nodiscard]] 63 | static std::string source_file(Backend const& backend, std::size_t const at) 64 | { 65 | return entry(backend, at).source_file(); 66 | } 67 | 68 | [[nodiscard]] 69 | static std::size_t source_line(Backend const& backend, std::size_t const at) 70 | { 71 | return entry(backend, at).source_line(); 72 | } 73 | 74 | [[nodiscard]] 75 | static std::stacktrace_entry const& entry(Backend const& backend, std::size_t const at) 76 | { 77 | return backend.at(at); 78 | } 79 | }; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /include/mimic++_ext/stacktrace/boost-stacktrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_EXT_STACKTRACE_BOOST_STACKTRACE_HPP 7 | #define MIMICPP_EXT_STACKTRACE_BOOST_STACKTRACE_HPP 8 | 9 | #include "mimic++/Fwd.hpp" 10 | #include "mimic++/config/Config.hpp" 11 | 12 | #ifndef MIMICPP_DETAIL_IS_MODULE 13 | #if __has_include() 14 | #include 15 | #else 16 | #error "The boost::stacktrace backend is explicitly enabled, but the the required include-file can not be found." 17 | #endif 18 | 19 | #include 20 | #include 21 | #endif 22 | 23 | struct mimicpp::util::stacktrace::find_backend 24 | { 25 | using type = boost::stacktrace::stacktrace; 26 | }; 27 | 28 | template <> 29 | struct mimicpp::util::stacktrace::backend_traits 30 | { 31 | using Backend = boost::stacktrace::stacktrace; 32 | 33 | [[nodiscard]] 34 | static Backend current(std::size_t const skip, std::size_t const max) noexcept 35 | { 36 | MIMICPP_ASSERT(skip < std::numeric_limits::max() - max, "Skip + max is too high."); 37 | 38 | return Backend{skip + 1, max}; 39 | } 40 | 41 | [[nodiscard]] 42 | static Backend current(std::size_t const skip) 43 | { 44 | MIMICPP_ASSERT(skip < std::numeric_limits::max(), "Skip is too high."); 45 | 46 | return Backend{skip + 1, std::numeric_limits::max()}; 47 | } 48 | 49 | [[nodiscard]] 50 | static std::size_t size(Backend const& stacktrace) 51 | { 52 | return stacktrace.size(); 53 | } 54 | 55 | [[nodiscard]] 56 | static bool empty(Backend const& stacktrace) 57 | { 58 | return stacktrace.empty(); 59 | } 60 | 61 | [[nodiscard]] 62 | static std::string description(Backend const& stacktrace, std::size_t const at) 63 | { 64 | return stacktrace[at].name(); 65 | } 66 | 67 | [[nodiscard]] 68 | static std::string source_file(Backend const& stacktrace, std::size_t const at) 69 | { 70 | return stacktrace[at].source_file(); 71 | } 72 | 73 | [[nodiscard]] 74 | static std::size_t source_line(Backend const& stacktrace, std::size_t const at) 75 | { 76 | return stacktrace[at].source_line(); 77 | } 78 | }; 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /test/package-test/RunTest.cmake: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | set(PACKAGE_PREFIX "${TEST_BINARY_DIR}/package") 7 | 8 | function(unwrap_args LIST OUT_LIST) 9 | string(LENGTH ${LIST} STR_LENGTH) 10 | math(EXPR STR_LENGTH "${STR_LENGTH} - 4") 11 | string(SUBSTRING ${LIST} 2 ${STR_LENGTH} LIST) 12 | set(${OUT_LIST} "${LIST}" PARENT_SCOPE) 13 | endfunction() 14 | 15 | unwrap_args(${CONFIG_ARGS} CONFIG_ARGS) 16 | unwrap_args(${BUILD_ARGS} BUILD_ARGS) 17 | message(STATUS CONFIG_ARGS: "${CONFIG_ARGS}") 18 | message(STATUS BUILD_ARGS: "${BUILD_ARGS}") 19 | 20 | # Clear any previous attempt 21 | execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf "${TEST_BINARY_DIR}" 22 | COMMAND_ERROR_IS_FATAL ANY 23 | COMMAND_ECHO STDOUT 24 | ) 25 | 26 | # Install mimic++ 27 | execute_process(COMMAND ${CMAKE_COMMAND} --install "${CUR_BINARY_DIR}" --prefix "${PACKAGE_PREFIX}/origin" 28 | COMMAND_ERROR_IS_FATAL ANY 29 | COMMAND_ECHO STDOUT 30 | ) 31 | 32 | # Relocate the package, to test that it is properly relocatable 33 | execute_process(COMMAND ${CMAKE_COMMAND} -E rm -rf "${PACKAGE_PREFIX}/other-location" 34 | COMMAND_ERROR_IS_FATAL ANY 35 | COMMAND_ECHO STDOUT 36 | ) 37 | execute_process(COMMAND ${CMAKE_COMMAND} -E make_directory "${PACKAGE_PREFIX}/other/location" 38 | COMMAND_ERROR_IS_FATAL ANY 39 | COMMAND_ECHO STDOUT 40 | ) 41 | execute_process(COMMAND ${CMAKE_COMMAND} -E rename "${PACKAGE_PREFIX}/origin" "${PACKAGE_PREFIX}/other/location/mimicpp" 42 | COMMAND_ERROR_IS_FATAL ANY 43 | COMMAND_ECHO STDOUT 44 | ) 45 | 46 | # Configure, build and run the test 47 | set(PACKAGE_TEST_BINARY_DIR "${TEST_BINARY_DIR}/package-consumer") 48 | execute_process(COMMAND ${CMAKE_COMMAND} 49 | -S "${TEST_SOURCE_DIR}/package-consumer" 50 | -B "${PACKAGE_TEST_BINARY_DIR}" 51 | --fresh 52 | --log-level=DEBUG 53 | ${CONFIG_ARGS} 54 | -D CMAKE_PREFIX_PATH=${PACKAGE_PREFIX}/other/location 55 | -D CMAKE_MODULE_PATH=${PROJECT_SOURCE_DIR}/cmake 56 | COMMAND_ERROR_IS_FATAL ANY 57 | COMMAND_ECHO STDOUT 58 | ) 59 | execute_process(COMMAND ${CMAKE_COMMAND} --build "${PACKAGE_TEST_BINARY_DIR}" ${BUILD_ARGS} -j 60 | COMMAND_ERROR_IS_FATAL ANY 61 | COMMAND_ECHO STDOUT 62 | ) 63 | execute_process(COMMAND ${CMAKE_CTEST_COMMAND} --test-dir "${PACKAGE_TEST_BINARY_DIR}" -C ${CMAKE_BUILD_TYPE} 64 | COMMAND_ERROR_IS_FATAL ANY 65 | COMMAND_ECHO STDOUT 66 | ) 67 | -------------------------------------------------------------------------------- /test/unit-tests/utilities/StaticString.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/utilities/StaticString.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | #define MAKE_STATIC_STRING(text) util::StaticString{#text}; 11 | 12 | TEST_CASE( 13 | "util::StaticString can hold compile-time usable strings.", 14 | "[util]") 15 | { 16 | SECTION("Empty string is supported.") 17 | { 18 | constexpr util::StaticString text{""}; 19 | 20 | CHECK_THAT( 21 | text, 22 | Catch::Matchers::IsEmpty()); 23 | CHECK_THAT( 24 | text, 25 | Catch::Matchers::SizeIs(0u)); 26 | CHECK_THAT( 27 | text, 28 | Catch::Matchers::RangeEquals(std::vector{})); 29 | } 30 | 31 | SECTION("When arbitrary string is given.") 32 | { 33 | constexpr util::StaticString text{"Hello, World!"}; 34 | 35 | CHECK_THAT( 36 | (std::string{text.begin(), text.end()}), 37 | Catch::Matchers::Equals("Hello, World!")); 38 | CHECK_THAT( 39 | text, 40 | !Catch::Matchers::IsEmpty()); 41 | CHECK_THAT( 42 | text, 43 | Catch::Matchers::SizeIs(std::ranges::size("Hello, World!") - 1u)); 44 | } 45 | 46 | SECTION("When empty macro arg is converted.") 47 | { 48 | constexpr util::StaticString text = MAKE_STATIC_STRING(); 49 | 50 | CHECK_THAT( 51 | text, 52 | Catch::Matchers::IsEmpty()); 53 | CHECK_THAT( 54 | text, 55 | Catch::Matchers::SizeIs(0u)); 56 | CHECK_THAT( 57 | text, 58 | Catch::Matchers::RangeEquals(std::vector{})); 59 | } 60 | 61 | SECTION("When arbitrary macro arg is converted.") 62 | { 63 | constexpr util::StaticString text = MAKE_STATIC_STRING(test_input); 64 | 65 | CHECK_THAT( 66 | (std::string{text.begin(), text.end()}), 67 | Catch::Matchers::Equals("test_input")); 68 | CHECK_THAT( 69 | text, 70 | !Catch::Matchers::IsEmpty()); 71 | CHECK_THAT( 72 | text, 73 | Catch::Matchers::SizeIs(10u)); 74 | } 75 | 76 | SECTION("StaticString is fully usable in compile-time context.") 77 | { 78 | STATIC_CHECK(std::ranges::equal(util::StaticString{"Hello, World!"}, std::string_view{"Hello, World!"})); 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /include/mimic++/utilities/StaticString.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_STATIC_STRING_HPP 7 | #define MIMICPP_UTILITIES_STATIC_STRING_HPP 8 | 9 | #include "mimic++/Fwd.hpp" 10 | #include "mimic++/config/Config.hpp" 11 | 12 | #ifndef MIMICPP_DETAIL_IS_MODULE 13 | #include 14 | #include 15 | #include 16 | #endif 17 | 18 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 19 | { 20 | template 21 | class StaticString 22 | { 23 | public: 24 | Char data[length]; 25 | 26 | [[nodiscard]] // 27 | explicit(false) consteval StaticString(Char const (&arr)[length + 1]) noexcept 28 | { 29 | std::ranges::copy_n(arr, length, std::ranges::begin(data)); 30 | } 31 | 32 | [[nodiscard]] 33 | static constexpr bool empty() noexcept 34 | { 35 | return false; 36 | } 37 | 38 | [[nodiscard]] 39 | static constexpr std::size_t size() noexcept 40 | { 41 | return length; 42 | } 43 | 44 | [[nodiscard]] 45 | constexpr auto begin() const noexcept 46 | { 47 | return std::ranges::begin(data); 48 | } 49 | 50 | [[nodiscard]] 51 | constexpr auto end() const noexcept 52 | { 53 | return std::ranges::end(data); 54 | } 55 | }; 56 | 57 | template 58 | class StaticString 59 | { 60 | public: 61 | [[nodiscard]] // 62 | explicit(false) consteval StaticString([[maybe_unused]] Char const (&arr)[1]) noexcept 63 | { 64 | } 65 | 66 | [[nodiscard]] 67 | static constexpr bool empty() noexcept 68 | { 69 | return true; 70 | } 71 | 72 | [[nodiscard]] 73 | static constexpr std::size_t size() noexcept 74 | { 75 | return 0u; 76 | } 77 | 78 | [[nodiscard]] 79 | static constexpr Char const* begin() noexcept 80 | { 81 | return nullptr; 82 | } 83 | 84 | [[nodiscard]] 85 | static constexpr Char const* end() noexcept 86 | { 87 | return nullptr; 88 | } 89 | }; 90 | 91 | template 92 | StaticString(Char const(&)[length]) -> StaticString; 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /test/stacktrace-tests/custom/CustomStacktrace.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "CustomStacktrace.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | "current_stacktrace prefers custom registrations, when present.", 12 | "[stacktrace]") 13 | { 14 | using trompeloeil::_; 15 | using trompeloeil::gt; 16 | 17 | using traits = util::stacktrace::backend_traits; 18 | 19 | std::shared_ptr const inner = std::make_shared(); 20 | REQUIRE_CALL(traits::currentMock, Invoke(_)) 21 | .WITH(_1 > 42) 22 | .LR_RETURN(CustomBackend{inner}); 23 | util::Stacktrace const stacktrace = util::stacktrace::current(42); 24 | 25 | SECTION("Testing empty.") 26 | { 27 | bool const empty = GENERATE(true, false); 28 | REQUIRE_CALL(inner->emptyMock, Invoke()) 29 | .RETURN(empty); 30 | 31 | REQUIRE(empty == stacktrace.empty()); 32 | } 33 | 34 | SECTION("Testing size.") 35 | { 36 | std::size_t const size = GENERATE(0u, 1u, 42u); 37 | REQUIRE_CALL(inner->sizeMock, Invoke()) 38 | .RETURN(size); 39 | 40 | REQUIRE(size == stacktrace.size()); 41 | } 42 | 43 | SECTION("Testing backend entries.") 44 | { 45 | std::size_t const at = GENERATE(0, 1, 42); 46 | 47 | SECTION("Testing description.") 48 | { 49 | std::string const description = GENERATE("", "Test", " Hello, World! "); 50 | REQUIRE_CALL(inner->descriptionMock, Invoke(at)) 51 | .RETURN(description); 52 | 53 | REQUIRE_THAT( 54 | stacktrace.description(at), 55 | Catch::Matchers::Equals(description)); 56 | } 57 | 58 | SECTION("Testing source_file.") 59 | { 60 | std::string const sourceFile = GENERATE("", "Test", " Hello, World! "); 61 | REQUIRE_CALL(inner->sourceMock, Invoke(at)) 62 | .RETURN(sourceFile); 63 | 64 | REQUIRE_THAT( 65 | stacktrace.source_file(at), 66 | Catch::Matchers::Equals(sourceFile)); 67 | } 68 | 69 | SECTION("Testing line.") 70 | { 71 | std::size_t const line = GENERATE(0u, 1u, 42u); 72 | REQUIRE_CALL(inner->lineMock, Invoke(at)) 73 | .RETURN(line); 74 | 75 | REQUIRE(line == stacktrace.source_line(at)); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /test/stacktrace-tests/custom/CustomStacktrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_TESTS_CUSTOM_STACKTRACE_HPP 7 | #define MIMICPP_TESTS_CUSTOM_STACKTRACE_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/utilities/Stacktrace.hpp" 12 | 13 | #include "../unit-tests/TestTypes.hpp" 14 | 15 | class CustomBackend 16 | { 17 | public: 18 | class Inner 19 | { 20 | public: 21 | InvocableMock sizeMock{}; 22 | InvocableMock emptyMock{}; 23 | InvocableMock descriptionMock{}; 24 | InvocableMock sourceMock{}; 25 | InvocableMock lineMock{}; 26 | }; 27 | 28 | std::shared_ptr inner{}; 29 | }; 30 | 31 | struct mimicpp::custom::find_stacktrace_backend 32 | { 33 | using type = CustomBackend; 34 | }; 35 | 36 | template <> 37 | struct mimicpp::util::stacktrace::backend_traits 38 | { 39 | using BackendT = CustomBackend; 40 | 41 | inline static InvocableMock currentMock{}; 42 | inline static InvocableMock currentMaxMock{}; 43 | 44 | [[nodiscard]] 45 | static BackendT current(std::size_t const skip, std::size_t const max) 46 | { 47 | return currentMaxMock.Invoke(skip, max); 48 | } 49 | 50 | [[nodiscard]] 51 | static BackendT current(std::size_t const skip) 52 | { 53 | return currentMock.Invoke(skip); 54 | } 55 | [[nodiscard]] 56 | static std::size_t size(BackendT const& backend) 57 | { 58 | return backend.inner->sizeMock.Invoke(); 59 | } 60 | 61 | [[nodiscard]] 62 | static bool empty(BackendT const& backend) 63 | { 64 | return backend.inner->emptyMock.Invoke(); 65 | } 66 | 67 | [[nodiscard]] 68 | static std::string description(BackendT const& backend, std::size_t const at) 69 | { 70 | return backend.inner->descriptionMock.Invoke(at); 71 | } 72 | 73 | [[nodiscard]] 74 | static std::string source_file(BackendT const& backend, std::size_t const at) 75 | { 76 | return backend.inner->sourceMock.Invoke(at); 77 | } 78 | 79 | [[nodiscard]] 80 | static std::size_t source_line(BackendT const& backend, std::size_t const at) 81 | { 82 | return backend.inner->lineMock.Invoke(at); 83 | } 84 | }; 85 | 86 | static_assert(mimicpp::util::stacktrace::backend); 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/mimic++/printing/PathPrinter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_PATH_PRINTER_HPP 7 | #define MIMICPP_PRINTING_PATH_PRINTER_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/printing/Format.hpp" 14 | 15 | #ifndef MIMICPP_DETAIL_IS_MODULE 16 | #include 17 | #include 18 | #include 19 | #include 20 | #endif 21 | 22 | namespace mimicpp::printing::detail 23 | { 24 | constexpr int maxPathElements{3}; 25 | 26 | class PathPrinterFn 27 | { 28 | public: 29 | template 30 | OutIter operator()(OutIter out, std::filesystem::path const& path) const 31 | { 32 | static constexpr CharT separator{std::filesystem::path::preferred_separator}; 33 | 34 | auto const pathString = path.lexically_normal().string(); 35 | auto const rend = pathString.crend(); 36 | auto iter = std::ranges::find(pathString.crbegin(), rend, separator); 37 | for (int i = 1; 38 | i < maxPathElements 39 | && iter != rend; 40 | ++i, iter = std::ranges::find(iter, rend, separator)) 41 | { 42 | ++iter; 43 | } 44 | 45 | return std::ranges::copy(iter.base(), pathString.cend(), std::move(out)).out; 46 | } 47 | 48 | [[nodiscard]] 49 | StringT operator()(std::filesystem::path const& path) const 50 | { 51 | StringStreamT stream{}; 52 | std::invoke( 53 | *this, 54 | std::ostreambuf_iterator{stream}, 55 | path); 56 | return std::move(stream).str(); 57 | } 58 | }; 59 | } 60 | 61 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp 62 | { 63 | /** 64 | * \defgroup PRINTING_PATH path 65 | * \ingroup PRINTING 66 | * \brief Printing paths in a specific format. 67 | * \details ``mimic++`` currently limits all paths to a level of 3. 68 | * E.g. ``/a/very/long/absolute/file.path`` will be printed as ``long/absolute/file.path``. 69 | * 70 | *\{ 71 | */ 72 | 73 | /** 74 | * \brief Functional object that outputs paths in a specific format. 75 | */ 76 | [[maybe_unused]] inline constexpr printing::detail::PathPrinterFn print_path{}; 77 | 78 | /** 79 | * \} 80 | */ 81 | } 82 | 83 | #endif 84 | -------------------------------------------------------------------------------- /test/unit-tests/config/Config.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #define MIMICPP_CONFIG_ONLY_PREFIXED_MACROS 7 | 8 | // ReSharper disable CppUnusedIncludeDirective 9 | #include "mimic++/ExpectationBuilder.hpp" 10 | #include "mimic++/Facade.hpp" 11 | #include "mimic++/utilities/AlwaysFalse.hpp" 12 | // ReSharper restore CppUnusedIncludeDirective 13 | 14 | #ifdef MAKE_OVERLOADED_FACADE_EXT 15 | static_assert( 16 | mimicpp::util::always_false<>::value, 17 | "MAKE_OVERLOADED_FACADE_EXT must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 18 | #endif 19 | 20 | #ifdef MAKE_FACADE_EXT 21 | static_assert( 22 | mimicpp::util::always_false<>::value, 23 | "MAKE_FACADE_EXT must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 24 | #endif 25 | 26 | #ifdef MAKE_OVERLOADED_MEMBER_MOCK 27 | static_assert( 28 | mimicpp::util::always_false<>::value, 29 | "MAKE_OVERLOADED_MEMBER_MOCK must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 30 | #endif 31 | 32 | #ifdef MAKE_MEMBER_MOCK 33 | static_assert( 34 | mimicpp::util::always_false<>::value, 35 | "MAKE_MEMBER_MOCK must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 36 | #endif 37 | 38 | #ifdef MAKE_OVERLOADED_MEMBER_MOCK_WITH_THIS 39 | static_assert( 40 | mimicpp::util::always_false<>::value, 41 | "MAKE_OVERLOADED_MEMBER_MOCK_WITH_THIS must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 42 | #endif 43 | 44 | #ifdef MAKE_MEMBER_MOCK_WITH_THIS 45 | static_assert( 46 | mimicpp::util::always_false<>::value, 47 | "MAKE_MEMBER_MOCK_WITH_THIS must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 48 | #endif 49 | 50 | #ifdef MOCK_METHOD 51 | static_assert( 52 | mimicpp::util::always_false<>::value, 53 | "MOCK_METHOD must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 54 | #endif 55 | 56 | #ifdef MOCK_OVERLOADED_METHOD 57 | static_assert( 58 | mimicpp::util::always_false<>::value, 59 | "MOCK_OVERLOADED_METHOD must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 60 | #endif 61 | 62 | #ifdef ADD_OVERLOAD 63 | static_assert( 64 | mimicpp::util::always_false<>::value, 65 | "ADD_OVERLOAD must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 66 | #endif 67 | 68 | #ifdef SCOPED_EXP 69 | static_assert( 70 | mimicpp::util::always_false<>::value, 71 | "SCOPED_EXP must be undefined when MIMICPP_CONFIG_ONLY_PREFIXED_MACROS is defined."); 72 | #endif 73 | -------------------------------------------------------------------------------- /examples/SideEffects.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/Mock.hpp" 7 | #include "mimic++/policies/SideEffectPolicies.hpp" 8 | 9 | TEST_CASE( 10 | "Side-effects can execute arbitrary actions.", 11 | "[example][example::side-effect]") 12 | { 13 | namespace then = mimicpp::then; 14 | 15 | mimicpp::Mock mock{}; 16 | 17 | std::string outText{}; 18 | SCOPED_EXP mock.expect_call(42) 19 | and then::invoke([&] { outText = "Hello, mimic++!"; }); 20 | 21 | mock(42); 22 | 23 | REQUIRE(outText == "Hello, mimic++!"); 24 | } 25 | 26 | TEST_CASE( 27 | "Side-effects can modify call params.", 28 | "[example][example::side-effect]") 29 | { 30 | namespace then = mimicpp::then; 31 | 32 | mimicpp::Mock mock{}; 33 | 34 | int value{42}; 35 | SCOPED_EXP mock.expect_call(42) 36 | and then::apply_arg<0>([](auto& v) { v = 1337; }); 37 | 38 | mock(value); 39 | 40 | REQUIRE(value == 1337); 41 | } 42 | 43 | TEST_CASE( 44 | "Side-effects can modify call params, which is observable by other side-effects.", 45 | "[example][example::side-effect]") 46 | { 47 | namespace then = mimicpp::then; 48 | 49 | mimicpp::Mock mock{}; 50 | 51 | int value{42}; 52 | SCOPED_EXP mock.expect_call(42) 53 | and then::apply_arg<0>([](auto& v) { v = 1337; }) 54 | and then::apply_arg<0>([](auto& v) { v = (v == 1337 ? -1337 : -42); }); 55 | 56 | mock(value); 57 | 58 | REQUIRE(value == -1337); 59 | } 60 | 61 | TEST_CASE( 62 | "Side-effects can apply the params in any order.", 63 | "[example][example::side-effect]") 64 | { 65 | namespace then = mimicpp::then; 66 | 67 | mimicpp::Mock mock{}; 68 | 69 | int outResult{}; 70 | SCOPED_EXP mock.expect_call(0, 1, 2) 71 | and then::apply_args<1, 2, 0>( // note the index order: 72 | // outResult is invoked as left-most param, but applied as right-most 73 | [](int lhs, int rhs, int& out) { out = lhs + rhs; }); 74 | 75 | mock(outResult, 1, 2); 76 | 77 | REQUIRE(outResult == 3); 78 | } 79 | 80 | TEST_CASE( 81 | "Side-effects can apply params multiple times.", 82 | "[example][example::side-effect]") 83 | { 84 | namespace then = mimicpp::then; 85 | 86 | mimicpp::Mock mock{}; 87 | 88 | int outResult{}; 89 | SCOPED_EXP mock.expect_call(0, 42) 90 | and then::apply_args<1, 1, 0>( // note the indices: second param is applied twice 91 | [](int lhs, int rhs, int& out) { out = lhs + rhs; }); 92 | 93 | mock(outResult, 42); 94 | 95 | REQUIRE(outResult == 84); 96 | } 97 | -------------------------------------------------------------------------------- /test/stacktrace-tests/custom/Printing.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "CustomStacktrace.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | "Stacktrace is printable.", 12 | "[stacktrace]") 13 | { 14 | using trompeloeil::_; 15 | auto&& [stacktrace, inner] = std::invoke( 16 | [] { 17 | const std::shared_ptr ptr = std::make_shared(); 18 | return std::tuple{ 19 | util::Stacktrace{CustomBackend{ptr}}, 20 | ptr}; 21 | }); 22 | 23 | SECTION("When stacktrace is empty") 24 | { 25 | REQUIRE_CALL(inner->emptyMock, Invoke()) 26 | .RETURN(true); 27 | 28 | const auto text = mimicpp::print(stacktrace); 29 | REQUIRE_THAT( 30 | text, 31 | Catch::Matchers::Equals("empty")); 32 | } 33 | 34 | SECTION("When stacktrace contains one entry.") 35 | { 36 | REQUIRE_CALL(inner->emptyMock, Invoke()) 37 | .RETURN(false); 38 | REQUIRE_CALL(inner->sizeMock, Invoke()) 39 | .TIMES(AT_LEAST(1u)) 40 | .RETURN(1u); 41 | REQUIRE_CALL(inner->sourceMock, Invoke(0u)) 42 | .RETURN("test.cpp"); 43 | REQUIRE_CALL(inner->lineMock, Invoke(0u)) 44 | .RETURN(1337u); 45 | REQUIRE_CALL(inner->descriptionMock, Invoke(0u)) 46 | .RETURN("test()"); 47 | 48 | const auto text = mimicpp::print(stacktrace); 49 | REQUIRE_THAT( 50 | text, 51 | Catch::Matchers::Equals("#0 `test.cpp:1337`, `test()`\n")); 52 | } 53 | 54 | SECTION("When stacktrace contains multiple entries.") 55 | { 56 | REQUIRE_CALL(inner->emptyMock, Invoke()) 57 | .RETURN(false); 58 | REQUIRE_CALL(inner->sizeMock, Invoke()) 59 | .TIMES(AT_LEAST(1u)) 60 | .RETURN(2u); 61 | REQUIRE_CALL(inner->sourceMock, Invoke(0u)) 62 | .RETURN("other-test.cpp"); 63 | REQUIRE_CALL(inner->lineMock, Invoke(0u)) 64 | .RETURN(42u); 65 | REQUIRE_CALL(inner->descriptionMock, Invoke(0u)) 66 | .RETURN("test_42()"); 67 | REQUIRE_CALL(inner->sourceMock, Invoke(1u)) 68 | .RETURN("test.cpp"); 69 | REQUIRE_CALL(inner->lineMock, Invoke(1u)) 70 | .RETURN(1337u); 71 | REQUIRE_CALL(inner->descriptionMock, Invoke(1u)) 72 | .RETURN("test()"); 73 | 74 | const auto text = mimicpp::print(stacktrace); 75 | REQUIRE_THAT( 76 | text, 77 | Catch::Matchers::Equals( 78 | "#0 `other-test.cpp:42`, `test_42()`\n" 79 | "#1 `test.cpp:1337`, `test()`\n")); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /examples/Times.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/Mock.hpp" 7 | 8 | TEST_CASE( 9 | "once() requires the expectation to be matched exactly once.", 10 | "[example][example::times]") 11 | { 12 | //! [once] 13 | namespace expect = mimicpp::expect; 14 | 15 | mimicpp::Mock mock{}; 16 | SCOPED_EXP mock.expect_call() 17 | and expect::once(); 18 | 19 | mock(); 20 | //! [once] 21 | } 22 | 23 | TEST_CASE( 24 | "twice() requires the expectation to be matched exactly twice.", 25 | "[example][example::times]") 26 | { 27 | //! [twice] 28 | namespace expect = mimicpp::expect; 29 | 30 | mimicpp::Mock mock{}; 31 | SCOPED_EXP mock.expect_call() 32 | and expect::twice(); 33 | 34 | mock(); // not enough 35 | mock(); // fine! 36 | //! [twice] 37 | } 38 | 39 | TEST_CASE( 40 | "at_least() requires the expectation to be matched at least the specified times.", 41 | "[example][example::times]") 42 | { 43 | //! [at_least] 44 | namespace expect = mimicpp::expect; 45 | 46 | mimicpp::Mock mock{}; 47 | SCOPED_EXP mock.expect_call() 48 | and expect::at_least(2u); 49 | 50 | mock(); // not enough 51 | mock(); // fine 52 | mock(); // also fine! 53 | //! [at_least] 54 | } 55 | 56 | TEST_CASE( 57 | "at_most() requires the expectation to be matched at most the specified times.", 58 | "[example][example::times]") 59 | { 60 | //! [at_most] 61 | namespace expect = mimicpp::expect; 62 | 63 | mimicpp::Mock mock{}; 64 | SCOPED_EXP mock.expect_call() 65 | and expect::at_most(2u); 66 | 67 | mock(); // fine 68 | mock(); // fine but exhausted! 69 | //! [at_most] 70 | } 71 | 72 | TEST_CASE( 73 | "times() supports a single limit.", 74 | "[example][example::times]") 75 | { 76 | //! [times single] 77 | namespace expect = mimicpp::expect; 78 | 79 | mimicpp::Mock mock{}; 80 | SCOPED_EXP mock.expect_call() 81 | and expect::times(2u); // equivalent to twice() 82 | 83 | mock(); // not enough 84 | mock(); // fine 85 | //! [times single] 86 | } 87 | 88 | TEST_CASE( 89 | "times() supports an upper and lower limit.", 90 | "[example][example::times]") 91 | { 92 | //! [times] 93 | namespace expect = mimicpp::expect; 94 | 95 | mimicpp::Mock mock{}; 96 | SCOPED_EXP mock.expect_call() 97 | and expect::times(1u, 3u); // between 1 and 3 matches 98 | 99 | mock(); // fine 100 | mock(); // fine 101 | mock(); // fine (exhausted) 102 | //! [times] 103 | } 104 | -------------------------------------------------------------------------------- /test/unit-tests/printing/PathPrinter.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/printing/PathPrinter.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | namespace 11 | { 12 | using PathT = std::filesystem::path; 13 | 14 | [[nodiscard]] 15 | PathT make_path(PathT path) 16 | { 17 | path.make_preferred(); 18 | return path; 19 | } 20 | } 21 | 22 | TEST_CASE( 23 | "print_path prints just the last 3 path elements.", 24 | "[print]") 25 | { 26 | SECTION("When empty path is given.") 27 | { 28 | REQUIRE_THAT( 29 | print_path(""), 30 | Catch::Matchers::Equals("")); 31 | } 32 | 33 | SECTION("When just the filename is given.") 34 | { 35 | REQUIRE_THAT( 36 | print_path("foo"), 37 | Catch::Matchers::Equals("foo")); 38 | REQUIRE_THAT( 39 | print_path("foo.cpp"), 40 | Catch::Matchers::Equals("foo.cpp")); 41 | } 42 | 43 | SECTION("When filename is preceded by directories.") 44 | { 45 | REQUIRE_THAT( 46 | print_path("abc/foo.cpp"), 47 | Catch::Matchers::Equals(make_path("abc/foo.cpp").string())); 48 | REQUIRE_THAT( 49 | print_path("/abc/foo.cpp"), 50 | Catch::Matchers::Equals(make_path("/abc/foo.cpp").string())); 51 | 52 | REQUIRE_THAT( 53 | print_path("abc/def/foo.cpp"), 54 | Catch::Matchers::Equals(make_path("abc/def/foo.cpp").string())); 55 | REQUIRE_THAT( 56 | print_path("/abc/def/foo.cpp"), 57 | Catch::Matchers::Equals(make_path("abc/def/foo.cpp").string())); 58 | 59 | REQUIRE_THAT( 60 | print_path("abc/def/g/h/i/foo.cpp"), 61 | Catch::Matchers::Equals(make_path("h/i/foo.cpp").string())); 62 | } 63 | 64 | SECTION("Multiple / are filtered.") 65 | { 66 | REQUIRE_THAT( 67 | print_path("abc//foo.cpp"), 68 | Catch::Matchers::Equals(make_path("abc/foo.cpp").string())); 69 | REQUIRE_THAT( 70 | print_path("//abc/foo.cpp"), 71 | Catch::Matchers::Equals(make_path("/abc/foo.cpp").string())); 72 | REQUIRE_THAT( 73 | print_path("//////////abc//////////foo.cpp"), 74 | Catch::Matchers::Equals(make_path("/abc/foo.cpp").string())); 75 | } 76 | 77 | #if MIMICPP_DETAIL_IS_WINDOWS 78 | SECTION("When some windows specific paths are given.") 79 | { 80 | REQUIRE_THAT( 81 | print_path("abc//def\\foo.cpp"), 82 | Catch::Matchers::Equals(make_path("abc/def/foo.cpp").string())); 83 | REQUIRE_THAT( 84 | print_path("C://abc/foo.cpp"), 85 | Catch::Matchers::Equals(make_path("C:/abc/foo.cpp").string())); 86 | } 87 | #endif 88 | } 89 | -------------------------------------------------------------------------------- /test/adapter-tests/gtest/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/Mock.hpp" 7 | #include "mimic++_ext/adapters/gtest.hpp" 8 | 9 | #include 10 | 11 | namespace 12 | { 13 | inline int g_SuccessCounter{0}; 14 | 15 | class SuccessListener final 16 | : public testing::EmptyTestEventListener 17 | { 18 | public: 19 | void OnTestPartResult(const testing::TestPartResult& result) override 20 | { 21 | if (result.passed()) 22 | { 23 | ++g_SuccessCounter; 24 | } 25 | } 26 | }; 27 | 28 | template 29 | class ScopedListener 30 | { 31 | public: 32 | ~ScopedListener() noexcept 33 | { 34 | mimicpp::settings::report_success().store(false); 35 | delete testing::UnitTest::GetInstance() 36 | ->listeners() 37 | .Release(m_Ptr); 38 | } 39 | 40 | [[nodiscard]] 41 | ScopedListener() 42 | : m_Ptr{new Listener{}} 43 | { 44 | mimicpp::settings::report_success().store(true); 45 | testing::UnitTest::GetInstance() 46 | ->listeners() 47 | .Append(m_Ptr); 48 | } 49 | 50 | private: 51 | Listener* m_Ptr{}; 52 | }; 53 | } 54 | 55 | TEST( 56 | GTestReporter, 57 | MatchReport) 58 | { 59 | const ScopedListener listener{}; 60 | 61 | g_SuccessCounter = 0; 62 | mimicpp::Mock mock{}; 63 | 64 | SCOPED_EXP mock.expect_call(42); 65 | 66 | ASSERT_EQ(g_SuccessCounter, 0); 67 | ASSERT_EQ(g_SuccessCounter, 0); // check, that ASSERT_EQ isn't reported 68 | mock(42); 69 | EXPECT_EQ(g_SuccessCounter, 1); 70 | } 71 | 72 | TEST( 73 | GTestReporter, 74 | NoMatchReport) 75 | { 76 | EXPECT_FATAL_FAILURE( 77 | mimicpp::Mock mock{}; 78 | EXPECT_ANY_THROW(mock(1337)), 79 | "Unmatched Call originated from "); 80 | } 81 | 82 | TEST( 83 | GTestReporter, 84 | ReportSuccess) 85 | { 86 | const ScopedListener listener{}; 87 | 88 | g_SuccessCounter = 0; 89 | 90 | mimicpp::reporting::detail::gtest::send_success("Test"); 91 | 92 | EXPECT_EQ(g_SuccessCounter, 1); 93 | } 94 | 95 | TEST( 96 | GTestReporter, 97 | ReportWarning) 98 | { 99 | mimicpp::reporting::detail::gtest::send_warning("Test"); 100 | 101 | // nothing to do 102 | } 103 | 104 | TEST( 105 | GTestReporter, 106 | ReportFail) 107 | { 108 | EXPECT_FATAL_FAILURE( 109 | EXPECT_ANY_THROW(mimicpp::reporting::detail::gtest::send_fail("Test")), 110 | "Test"); 111 | } 112 | -------------------------------------------------------------------------------- /include/mimic++/printing/state/C++23Backports.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_STATE_CXX23_BACKPORTS_HPP 7 | #define MIMICPP_PRINTING_STATE_CXX23_BACKPORTS_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | #include "mimic++/printing/Format.hpp" 13 | #include "mimic++/printing/state/Print.hpp" 14 | 15 | #ifndef MIMICPP_DETAIL_IS_MODULE 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | namespace mimicpp::printing::detail::state 24 | { 25 | template 26 | struct cxx23_backport_printer 27 | { 28 | template 29 | static OutIter print(OutIter out, auto& range) 30 | { 31 | out = format::format_to(std::move(out), "["); 32 | auto iter = std::ranges::begin(range); 33 | if (const auto end = std::ranges::end(range); 34 | iter != end) 35 | { 36 | out = mimicpp::print(std::move(out), *iter++); 37 | 38 | for (; iter != end; ++iter) 39 | { 40 | out = format::format_to(std::move(out), ", "); 41 | out = mimicpp::print(std::move(out), *iter); 42 | } 43 | } 44 | 45 | return format::format_to(std::move(out), "]"); 46 | } 47 | }; 48 | 49 | template 50 | OutIter print_tuple_element(OutIter out, auto& tuple) 51 | { 52 | if constexpr (0u != index) 53 | { 54 | out = format::format_to(std::move(out), ", "); 55 | } 56 | 57 | return mimicpp::print(std::move(out), std::get(tuple)); 58 | } 59 | 60 | template 61 | concept tuple_like = requires { 62 | typename std::tuple_size::type; 63 | { std::tuple_size_v } -> std::convertible_to; 64 | requires 0u <= std::tuple_size_v; 65 | }; 66 | 67 | template 68 | struct cxx23_backport_printer 69 | { 70 | template 71 | static OutIter print(OutIter out, auto& tuple) 72 | { 73 | out = format::format_to(std::move(out), "("); 74 | std::invoke( 75 | [&]([[maybe_unused]] const std::index_sequence) { 76 | (..., 77 | (out = state::print_tuple_element(std::move(out), tuple))); 78 | }, 79 | std::make_index_sequence>{}); 80 | 81 | return format::format_to(std::move(out), ")"); 82 | } 83 | }; 84 | } 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /include/mimic++/printing/type/Signature.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_PRINTING_TYPE_SIGNATURE_HPP 7 | #define MIMICPP_PRINTING_TYPE_SIGNATURE_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/TypeTraits.hpp" 13 | #include "mimic++/config/Config.hpp" 14 | #include "mimic++/printing/Format.hpp" 15 | #include "mimic++/printing/Fwd.hpp" 16 | #include "mimic++/printing/type/PrintType.hpp" 17 | #include "mimic++/utilities/Concepts.hpp" 18 | #include "mimic++/utilities/TypeList.hpp" 19 | 20 | #ifndef MIMICPP_DETAIL_IS_MODULE 21 | #include 22 | #include 23 | #include 24 | #include 25 | #endif 26 | 27 | namespace mimicpp::printing::type::detail 28 | { 29 | template 30 | constexpr OutIter print_separated(OutIter out, StringViewT const separator, util::type_list const ts) 31 | { 32 | if constexpr (0u < sizeof...(Ts)) 33 | { 34 | std::invoke( 35 | [&]([[maybe_unused]] util::type_list const) { 36 | out = mimicpp::print_type(std::move(out)); 37 | ((out = mimicpp::print_type(std::ranges::copy(separator, std::move(out)).out)), ...); 38 | }, 39 | ts); 40 | } 41 | 42 | return out; 43 | } 44 | 45 | template Signature> 46 | struct signature_type_printer 47 | { 48 | template 49 | static OutIter print(OutIter out) 50 | { 51 | out = mimicpp::print_type>(std::move(out)); 52 | out = format::format_to(std::move(out), "("); 53 | out = print_separated(out, ", ", signature_param_list_t{}); 54 | out = format::format_to(std::move(out), ")"); 55 | 56 | if constexpr (Constness::as_const == signature_const_qualification_v) 57 | { 58 | out = format::format_to(std::move(out), " const"); 59 | } 60 | 61 | if constexpr (ValueCategory::lvalue == signature_ref_qualification_v) 62 | { 63 | out = format::format_to(std::move(out), " &"); 64 | } 65 | else if constexpr (ValueCategory::rvalue == signature_ref_qualification_v) 66 | { 67 | out = format::format_to(std::move(out), " &&"); 68 | } 69 | 70 | if constexpr (signature_is_noexcept_v) 71 | { 72 | out = format::format_to(std::move(out), " noexcept"); 73 | } 74 | 75 | return out; 76 | } 77 | }; 78 | } 79 | 80 | #endif 81 | -------------------------------------------------------------------------------- /include/mimic++_ext/stacktrace/cpptrace.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_EXT_STACKTRACE_CPPTRACE_HPP 7 | #define MIMICPP_EXT_STACKTRACE_CPPTRACE_HPP 8 | 9 | #include "mimic++/Fwd.hpp" 10 | #include "mimic++/config/Config.hpp" 11 | 12 | #ifndef MIMICPP_DETAIL_IS_MODULE 13 | #if __has_include() 14 | #include 15 | #elif __has_include() 16 | // this is necessary for old cpptrace versions. 17 | // see: https://github.com/jeremy-rifkin/libassert/issues/110 18 | #include 19 | #else 20 | #error "The cpptrace stacktrace backend is explicitly enabled, but the the required include-file can not be found." 21 | #endif 22 | 23 | #include 24 | #include 25 | #endif 26 | 27 | struct mimicpp::util::stacktrace::find_backend 28 | { 29 | using type = cpptrace::stacktrace; 30 | }; 31 | 32 | template <> 33 | struct mimicpp::util::stacktrace::backend_traits 34 | { 35 | using Backend = cpptrace::stacktrace; 36 | 37 | [[nodiscard]] 38 | static Backend current(std::size_t const skip, std::size_t const max) noexcept 39 | { 40 | MIMICPP_ASSERT(skip < std::numeric_limits::max() - max, "Skip + max is too high."); 41 | 42 | return cpptrace::generate_trace(skip + 1, max); 43 | } 44 | 45 | [[nodiscard]] 46 | static Backend current(std::size_t const skip) 47 | { 48 | MIMICPP_ASSERT(skip < std::numeric_limits::max(), "Skip is too high."); 49 | 50 | return cpptrace::generate_trace(skip + 1); 51 | } 52 | 53 | [[nodiscard]] 54 | static MIMICPP_DETAIL_CONSTEXPR_VECTOR std::size_t size(Backend const& stacktrace) 55 | { 56 | return stacktrace.frames.size(); 57 | } 58 | 59 | [[nodiscard]] 60 | static MIMICPP_DETAIL_CONSTEXPR_VECTOR bool empty(Backend const& stacktrace) 61 | { 62 | return stacktrace.frames.empty(); 63 | } 64 | 65 | [[nodiscard]] 66 | static MIMICPP_DETAIL_CONSTEXPR_STRING std::string description(Backend const& stacktrace, std::size_t const at) 67 | { 68 | return frame(stacktrace, at).symbol; 69 | } 70 | 71 | [[nodiscard]] 72 | static MIMICPP_DETAIL_CONSTEXPR_STRING std::string source_file(Backend const& stacktrace, std::size_t const at) 73 | { 74 | return frame(stacktrace, at).filename; 75 | } 76 | 77 | [[nodiscard]] 78 | static MIMICPP_DETAIL_CONSTEXPR_VECTOR std::size_t source_line(Backend const& stacktrace, std::size_t const at) 79 | { 80 | return frame(stacktrace, at).line.value_or(0u); 81 | } 82 | 83 | [[nodiscard]] 84 | static MIMICPP_DETAIL_CONSTEXPR_VECTOR cpptrace::stacktrace_frame const& frame(Backend const& stacktrace, std::size_t const at) 85 | { 86 | return stacktrace.frames.at(at); 87 | } 88 | }; 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /.github/workflows/generate_docs.yml: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | name: generate docs 7 | 8 | on: 9 | push: 10 | branches: [ main, development ] 11 | pull_request: 12 | branches: [ main, development ] 13 | release: 14 | types: [ released ] 15 | 16 | jobs: 17 | create-documentation: 18 | runs-on: ubuntu-latest 19 | 20 | # this is required for the gh-pages deployment 21 | permissions: 22 | contents: write 23 | 24 | steps: 25 | - uses: actions/checkout@v5 26 | 27 | # we must configure, because the Doxyfile is generated via cmake 28 | - name: Configure 29 | run: | 30 | cmake \ 31 | -S . \ 32 | -B build \ 33 | --log-level=VERBOSE \ 34 | -DMIMICPP_CONFIGURE_DOXYGEN=ON \ 35 | -DMIMICPP_BUILD_TESTS=OFF \ 36 | -DMIMICPP_BUILD_EXAMPLES=OFF 37 | 38 | - name: Generate Doxygen Documentation 39 | uses: mattnotmitt/doxygen-action@edge 40 | with: 41 | doxyfile-path: build/docs/Doxyfile 42 | 43 | - name: Upload html documentation 44 | uses: actions/upload-artifact@v4 45 | with: 46 | name: HTML-Documentation 47 | path: build/docs/html 48 | 49 | # publish to main gh-pages, when main branch is pushed 50 | - name: Deploy to GitHub main Pages 51 | uses: peaceiris/actions-gh-pages@v4 52 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} 53 | with: 54 | github_token: ${{ secrets.GITHUB_TOKEN }} 55 | publish_dir: build/docs/html 56 | 57 | # publish to dev gh-pages, when development branch is pushed 58 | - name: Deploy to GitHub dev Pages 59 | uses: peaceiris/actions-gh-pages@v4 60 | if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }} 61 | with: 62 | github_token: ${{ secrets.GITHUB_TOKEN }} 63 | publish_dir: build/docs/html 64 | publish_branch: dev-gh-pages 65 | 66 | release-documentation: 67 | runs-on: ubuntu-latest 68 | needs: create-documentation 69 | if: ${{ github.event_name == 'release' }} 70 | 71 | # this is required for the asset attachment 72 | permissions: 73 | contents: write 74 | 75 | steps: 76 | - uses: actions/download-artifact@v5 77 | with: 78 | name: HTML-Documentation 79 | path: ./documentation 80 | 81 | - name: zip documentation 82 | uses: thedoctor0/zip-release@0.7.6 83 | with: 84 | type: 'zip' 85 | filename: "documentation.zip" 86 | path: ./documentation 87 | 88 | - name: attach release assets 89 | uses: ncipollo/release-action@v1 90 | with: 91 | artifacts: "documentation.zip" 92 | token: ${{ secrets.GITHUB_TOKEN }} 93 | allowUpdates: true 94 | artifactErrorsFailBuild: true 95 | omitBody: true 96 | omitName: true 97 | -------------------------------------------------------------------------------- /test/compile-errors/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | include(CTest) 7 | 8 | function(read_compile_error_definitions SOURCE_FILE OUT_ERROR_DEFINITIONS) 9 | file(READ ${SOURCE_FILE} FILE_CONTENT) 10 | if (NOT FILE_CONTENT) 11 | message(FATAL_ERROR "${MESSAGE_PREFIX} Unable to read source-file: `${SOURCE_FILE}`") 12 | endif () 13 | # matches everything between the tags and also newlines 14 | set(BEGIN_TOKEN "") 15 | string(LENGTH "${BEGIN_TOKEN}" BEGIN_TOKEN_LENGTH) 16 | string(FIND "${FILE_CONTENT}" "${BEGIN_TOKEN}" DEF_BEGIN) 17 | string(FIND "${FILE_CONTENT}" "" DEF_END) 18 | math(EXPR ERROR_START "${DEF_BEGIN} + ${BEGIN_TOKEN_LENGTH}") 19 | math(EXPR ERROR_LENGTH "${DEF_END} - ${ERROR_START}") 20 | string(SUBSTRING "${FILE_CONTENT}" ${ERROR_START} ${ERROR_LENGTH} ERROR_DEFINITIONS) 21 | string(STRIP "${ERROR_DEFINITIONS}" ERROR_DEFINITIONS) 22 | string(REGEX REPLACE "[\r\n]+" ";" ERROR_DEFINITIONS ${ERROR_DEFINITIONS}) 23 | 24 | if (NOT ERROR_DEFINITIONS) 25 | message(FATAL_ERROR "${MESSAGE_PREFIX} Could not read compile-error definition(s) from `${SOURCE_FILE}`.") 26 | endif () 27 | message(DEBUG "${MESSAGE_PREFIX} Expected compile-errors for case `${SOURCE_FILE}` are:\n\t`${ERROR_DEFINITIONS}`") 28 | 29 | set(${OUT_ERROR_DEFINITIONS} ${ERROR_DEFINITIONS} PARENT_SCOPE) 30 | endfunction() 31 | 32 | function(check_compile_error SOURCE_FILE) 33 | cmake_path(GET SOURCE_FILE STEM NAME) 34 | set(TARGET_NAME mimicpp-compile-error-${NAME}) 35 | set(TEST_NAME compile-error-${NAME}) 36 | read_compile_error_definitions(${SOURCE_FILE} EXPECTED_COMPILE_ERRORS) 37 | 38 | add_library(${TARGET_NAME} EXCLUDE_FROM_ALL 39 | ${SOURCE_FILE} 40 | ) 41 | 42 | target_link_libraries(${TARGET_NAME} PRIVATE 43 | mimicpp::header-only 44 | ) 45 | 46 | add_test(NAME ${TEST_NAME} 47 | COMMAND ${CMAKE_COMMAND} -E env "INCLUDE=${CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES};$ENV{INCLUDE}" 48 | ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} --target ${TARGET_NAME} 49 | ) 50 | 51 | set_tests_properties(${TEST_NAME} PROPERTIES 52 | PASS_REGULAR_EXPRESSION "${EXPECTED_COMPILE_ERRORS}" 53 | ) 54 | 55 | # On msvc, these manual compiled tests should not run in parallel, because they seem to create some lock-files. 56 | # error MSB3491: Could not write lines to file "[...]/ZERO_CHECK/ZERO_CHECK.tlog/ZERO_CHECK.lastbuildstate". 57 | # The process cannot access the file '...' because it is being used by another process. 58 | if (MSVC) 59 | set_tests_properties(${TEST_NAME} PROPERTIES 60 | RESOURCE_LOCK compile-error-test-lock 61 | ) 62 | endif () 63 | endfunction() 64 | 65 | check_compile_error("missing-finalizer-for-non-void.cpp") 66 | check_compile_error("multiple-times-policies.cpp") 67 | check_compile_error("multiple-finalize-policies.cpp") 68 | check_compile_error("manual-init-finalize-policy.cpp") 69 | -------------------------------------------------------------------------------- /test/adapter-tests/doctest/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN 7 | #include "mimic++_ext/adapters/Doctest.hpp" 8 | 9 | namespace 10 | { 11 | inline std::atomic_int g_SuccessCounter{0}; 12 | inline std::atomic_int g_WarningCounter{0}; 13 | 14 | class SuccessListener final 15 | : public doctest::IReporter 16 | { 17 | public: 18 | explicit SuccessListener([[maybe_unused]] const doctest::ContextOptions& in) 19 | { 20 | } 21 | 22 | void report_query([[maybe_unused]] const doctest::QueryData& in) override 23 | { 24 | } 25 | 26 | void test_run_start() override 27 | { 28 | } 29 | 30 | void test_run_end([[maybe_unused]] const doctest::TestRunStats& in) override 31 | { 32 | } 33 | 34 | void test_case_start([[maybe_unused]] const doctest::TestCaseData& in) override 35 | { 36 | } 37 | 38 | void test_case_reenter([[maybe_unused]] const doctest::TestCaseData& in) override 39 | { 40 | } 41 | 42 | void test_case_end([[maybe_unused]] const doctest::CurrentTestCaseStats& in) override 43 | { 44 | } 45 | 46 | void test_case_exception([[maybe_unused]] const doctest::TestCaseException& in) override 47 | { 48 | } 49 | 50 | void subcase_start([[maybe_unused]] const doctest::SubcaseSignature& in) override 51 | { 52 | } 53 | 54 | void subcase_end() override 55 | { 56 | } 57 | 58 | void log_assert(const doctest::AssertData& in) override 59 | { 60 | if (!in.m_failed) 61 | { 62 | ++g_SuccessCounter; 63 | } 64 | } 65 | 66 | void log_message(const doctest::MessageData& in) override 67 | { 68 | if (in.m_string == "Warning") 69 | { 70 | ++g_WarningCounter; 71 | } 72 | } 73 | 74 | void test_case_skipped([[maybe_unused]] const doctest::TestCaseData& in) override 75 | { 76 | } 77 | }; 78 | } 79 | 80 | REGISTER_LISTENER("SuccessListener", 1, SuccessListener); 81 | 82 | TEST_SUITE("adapter::doctest") 83 | { 84 | TEST_CASE("doctest::send_success notifies Doctest for success.") 85 | { 86 | g_SuccessCounter = 0; 87 | 88 | mimicpp::reporting::detail::doctest::send_success("Success"); 89 | 90 | REQUIRE(g_SuccessCounter == 1); 91 | } 92 | 93 | TEST_CASE("doctest::send_warning notifies Doctest.") 94 | { 95 | mimicpp::reporting::detail::doctest::send_warning("Warning"); 96 | 97 | REQUIRE(g_WarningCounter == 1); 98 | } 99 | 100 | TEST_CASE( 101 | "doctest::send_fail notifies Doctest for failures and aborts." 102 | * doctest::should_fail{}) 103 | { 104 | mimicpp::reporting::detail::doctest::send_fail("Fail"); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /include/mimic++/utilities/Concepts.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_UTILITIES_CONCEPTS_HPP 7 | #define MIMICPP_UTILITIES_CONCEPTS_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/config/Config.hpp" 12 | 13 | #ifndef MIMICPP_DETAIL_IS_MODULE 14 | #include 15 | #include 16 | #endif 17 | 18 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::util 19 | { 20 | /** 21 | * \defgroup UTIL_CONCEPTS concepts 22 | * \ingroup UTILITIES 23 | * \brief Contains common concept definitions. 24 | * 25 | * \{ 26 | */ 27 | 28 | /** 29 | * \brief Determines, whether `From` can be explicitly converted to `To`. 30 | * \note In fact, this is a more relaxed version of `std::convertible_to`, as this also requires implicit-convertibility. 31 | * \see https://en.cppreference.com/w/cpp/concepts/convertible_to 32 | */ 33 | template 34 | concept explicitly_convertible_to = 35 | requires { 36 | static_cast(std::declval()); 37 | }; 38 | 39 | /** 40 | * \brief Determines, whether `From` can be explicitly converted to `To`, without throwing. 41 | */ 42 | template 43 | concept nothrow_explicitly_convertible_to = 44 | explicitly_convertible_to 45 | && requires { 46 | { static_cast(std::declval()) } noexcept; 47 | }; 48 | 49 | /** 50 | * \brief Determines, whether `T` is the same as any type of the pack `Others`. 51 | */ 52 | template 53 | concept same_as_any = (... || std::same_as); 54 | 55 | /** 56 | * \brief Determines, whether `T` satisfies the specified trait type. 57 | */ 58 | template typename Trait> 59 | concept satisfies = Trait::value; 60 | 61 | /** 62 | * \brief Determines, whether `B` behaves as a the builtin type `bool`. 63 | * \see https://en.cppreference.com/w/cpp/concepts/boolean-testable 64 | */ 65 | template 66 | concept boolean_testable = 67 | std::convertible_to 68 | && requires(B&& b) { 69 | { !std::forward(b) } -> std::convertible_to; 70 | }; 71 | 72 | /** 73 | * \brief Determines, whether `T` can be equality compared with `U`. 74 | * \note In fact, this is a more relaxed version of the `std::equality_comparable_with` concept. 75 | * \see https://en.cppreference.com/w/cpp/concepts/equality_comparable 76 | */ 77 | template 78 | concept weakly_equality_comparable_with = 79 | requires(std::remove_reference_t const& t, std::remove_reference_t const& u) { 80 | { t == u } -> boolean_testable; 81 | { t != u } -> boolean_testable; 82 | { u == t } -> boolean_testable; 83 | { u != t } -> boolean_testable; 84 | }; 85 | 86 | /** 87 | * \} 88 | */ 89 | } 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | cmake_minimum_required(VERSION 3.15...3.31) 7 | set(MESSAGE_PREFIX "mimic++:") 8 | 9 | list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") 10 | 11 | include(Mimic++-ReadProjectVersion) 12 | mimicpp_read_project_version("include/mimic++/config/Version.hpp" MIMICPP_VERSION) 13 | 14 | project( 15 | mimicpp 16 | LANGUAGES CXX 17 | VERSION ${MIMICPP_VERSION} 18 | DESCRIPTION "A modern and (mostly) macro free mocking-framework" 19 | HOMEPAGE_URL "https://github.com/DNKpp/mimicpp" 20 | ) 21 | 22 | message(STATUS "${MESSAGE_PREFIX} version: v${PROJECT_VERSION} from: ${mimicpp_SOURCE_DIR}") 23 | if (CMAKE_SIZEOF_VOID_P EQUAL 8) 24 | message(STATUS "${MESSAGE_PREFIX} targeting 64-bit architecture") 25 | elseif (CMAKE_SIZEOF_VOID_P EQUAL 4) 26 | message(STATUS "${MESSAGE_PREFIX} targeting 32-bit architecture") 27 | else () 28 | message(WARNING "${MESSAGE_PREFIX} unable to determine architecture") 29 | endif () 30 | 31 | message(DEBUG "${MESSAGE_PREFIX} CXXFLAGS: $ENV{CXXFLAGS}") 32 | message(DEBUG "${MESSAGE_PREFIX} CMAKE_CXX_FLAGS: ${CMAKE_CXX_FLAGS}") 33 | message(DEBUG "${MESSAGE_PREFIX} CMAKE_CXX_FLAGS_INIT: ${CMAKE_CXX_FLAGS_INIT}") 34 | 35 | string(COMPARE EQUAL "${CMAKE_SOURCE_DIR}" "${mimicpp_SOURCE_DIR}" IS_TOP_LEVEL_PROJECT) 36 | 37 | set(CMAKE_CXX_STANDARD 20) 38 | if (MIMICPP_FORCED_CXX_STANDARD) 39 | message(DEBUG "${MESSAGE_PREFIX} forced c++-standard c++${MIMICPP_FORCED_CXX_STANDARD}") 40 | set(CMAKE_CXX_STANDARD ${MIMICPP_FORCED_CXX_STANDARD}) 41 | endif () 42 | 43 | include(Mimic++-EnableConfigOptions) 44 | 45 | add_library(mimicpp INTERFACE) 46 | add_library(mimicpp::header-only ALIAS mimicpp) 47 | add_library(mimicpp::mimicpp ALIAS mimicpp) 48 | 49 | include(GNUInstallDirs) 50 | target_include_directories(mimicpp INTERFACE 51 | "$" 52 | "$" 53 | ) 54 | 55 | target_compile_options(mimicpp INTERFACE 56 | # this option is required to make __VA_OPT__ work on msvc 57 | "$<$:/Zc:preprocessor>" 58 | ) 59 | 60 | target_compile_features(mimicpp INTERFACE 61 | cxx_std_${CMAKE_CXX_STANDARD} 62 | ) 63 | 64 | target_link_libraries(mimicpp INTERFACE 65 | mimicpp::internal::config-options 66 | ) 67 | 68 | if (MIMICPP_CONFIG_EXPERIMENTAL_ENABLE_CXX20_MODULES__UNPORTABLE__) 69 | add_subdirectory(module) 70 | endif () 71 | 72 | option(MIMICPP_BUILD_TESTS "Determines, whether the tests shall be built." ${IS_TOP_LEVEL_PROJECT}) 73 | if (MIMICPP_BUILD_TESTS) 74 | include(CTest) 75 | add_subdirectory("test") 76 | endif() 77 | 78 | option(MIMICPP_BUILD_EXAMPLES "Determines, whether the examples shall be built." ${IS_TOP_LEVEL_PROJECT}) 79 | if (MIMICPP_BUILD_EXAMPLES) 80 | include(CTest) 81 | add_subdirectory("examples") 82 | endif() 83 | 84 | option(MIMICPP_CONFIGURE_DOXYGEN "Determines, whether the doxyfile shall be configured." OFF) 85 | if (MIMICPP_CONFIGURE_DOXYGEN) 86 | option(MIMICPP_ENABLE_GENERATE_DOCS "Enable the doxygen documentation target." OFF) 87 | add_subdirectory("docs") 88 | endif() 89 | 90 | option(MIMICPP_ENABLE_AMALGAMATE_HEADERS "Enables the amalgamation target." OFF) 91 | if (MIMICPP_ENABLE_AMALGAMATE_HEADERS) 92 | add_subdirectory("tools/amalgamate-headers") 93 | endif() 94 | 95 | if(NOT CMAKE_SKIP_INSTALL_RULES) 96 | include(Mimic++-InstallRules) 97 | endif() 98 | -------------------------------------------------------------------------------- /include/mimic++/reporting/ExpectationReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_EXPECTATION_REPORT_HPP 7 | #define MIMICPP_REPORTING_EXPECTATION_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/reporting/SequenceReport.hpp" 14 | #include "mimic++/reporting/TargetReport.hpp" 15 | #include "mimic++/utilities/SourceLocation.hpp" 16 | 17 | #ifndef MIMICPP_DETAIL_IS_MODULE 18 | #include 19 | #include 20 | #include 21 | #endif 22 | 23 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 24 | { 25 | /** 26 | * \brief Denotes an inapplicable expectation state. 27 | * \ingroup REPORTING_REPORTS 28 | */ 29 | struct state_inapplicable 30 | { 31 | int min{}; 32 | int max{}; 33 | int count{}; 34 | std::vector sequences{}; 35 | std::vector inapplicableSequences{}; 36 | 37 | [[nodiscard]] 38 | friend bool operator==(state_inapplicable const&, state_inapplicable const&) = default; 39 | }; 40 | 41 | /** 42 | * \brief Denotes an applicable expectation state. 43 | * \ingroup REPORTING_REPORTS 44 | */ 45 | struct state_applicable 46 | { 47 | int min{}; 48 | int max{}; 49 | int count{}; 50 | std::vector sequenceRatings{}; 51 | 52 | [[nodiscard]] 53 | friend bool operator==(state_applicable const&, state_applicable const&) = default; 54 | }; 55 | 56 | /** 57 | * \brief Denotes a saturated expectation state. 58 | * \ingroup REPORTING_REPORTS 59 | */ 60 | struct state_saturated 61 | { 62 | int min{}; 63 | int max{}; 64 | int count{}; 65 | std::vector sequences{}; 66 | 67 | [[nodiscard]] 68 | friend bool operator==(state_saturated const&, state_saturated const&) = default; 69 | }; 70 | 71 | /** 72 | * \brief Denotes an expectation state. 73 | * \ingroup REPORTING_REPORTS 74 | */ 75 | using control_state_t = std::variant< 76 | state_inapplicable, 77 | state_applicable, 78 | state_saturated>; 79 | 80 | /** 81 | * \brief Contains the extracted info from a typed expectation. 82 | * \ingroup REPORTING_REPORTS 83 | */ 84 | class ExpectationReport 85 | { 86 | public: 87 | util::SourceLocation from{}; 88 | TargetReport target; 89 | control_state_t controlReport{}; 90 | std::optional finalizerDescription{}; 91 | std::vector> requirementDescriptions{}; 92 | 93 | [[nodiscard]] 94 | friend bool operator==(ExpectationReport const&, ExpectationReport const&) = default; 95 | }; 96 | 97 | /** 98 | * \brief Contains the boolean outcomes of a match-test. 99 | * \ingroup REPORTING_REPORTS 100 | */ 101 | class RequirementOutcomes 102 | { 103 | public: 104 | std::vector outcomes{}; 105 | 106 | [[nodiscard]] 107 | friend bool operator==(RequirementOutcomes const&, RequirementOutcomes const&) = default; 108 | }; 109 | } 110 | 111 | #endif 112 | -------------------------------------------------------------------------------- /examples/VariadicMocks.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/Facade.hpp" 7 | #include "mimic++/Mock.hpp" 8 | #include "mimic++/matchers/RangeMatchers.hpp" 9 | #include "mimic++/policies/FinalizerPolicies.hpp" 10 | 11 | namespace 12 | { 13 | //! [variadic mock def] 14 | template 15 | class VariadicClass 16 | { 17 | public: 18 | mimicpp::Mock myMock{}; 19 | }; 20 | 21 | //! [variadic mock def] 22 | } 23 | 24 | TEST_CASE( 25 | "Mock supports variadic template args.", 26 | "[example][example::mock]") 27 | { 28 | //! [variadic mock] 29 | VariadicClass myClass{}; 30 | SCOPED_EXP myClass.myMock.expect_call(); 31 | myClass.myMock(); 32 | 33 | VariadicClass myOtherClass{}; 34 | SCOPED_EXP myOtherClass.myMock.expect_call("Hello, World!", 1337); 35 | myOtherClass.myMock("Hello, World!", 1337); 36 | //! [variadic mock] 37 | } 38 | 39 | namespace 40 | { 41 | //! [variadic interface def] 42 | template 43 | class VariadicInterface 44 | { 45 | public: 46 | virtual ~VariadicInterface() = default; 47 | virtual void foo(Args...) = 0; 48 | virtual int bar(int, Args...) = 0; 49 | virtual std::string bar(Args..., int, Args...) const = 0; // you can go absolutely crazy! 50 | }; 51 | 52 | template 53 | class VariadicDerived final 54 | : public VariadicInterface 55 | { 56 | public: 57 | MAKE_MEMBER_MOCK(foo, void, (Args...), override); 58 | MAKE_OVERLOADED_MEMBER_MOCK( 59 | bar, 60 | ADD_OVERLOAD(int, (int, Args...), override), 61 | ADD_OVERLOAD(std::string, (Args..., int, Args...), const override)); 62 | }; 63 | 64 | //! [variadic interface def] 65 | } 66 | 67 | TEST_CASE( 68 | "MOCK_METHOD and MOCK_OVERLOADED_METHOD do support variadic templates, too.", 69 | "[example][example::mock][example::mock::interface]") 70 | { 71 | namespace finally = mimicpp::finally; 72 | namespace matches = mimicpp::matches; 73 | 74 | SECTION("Without template arguments.") 75 | { 76 | //! [variadic interface zero] 77 | VariadicDerived mock{}; 78 | 79 | SCOPED_EXP mock.foo_.expect_call(); // foo has no arguments 80 | mock.foo(); 81 | 82 | SCOPED_EXP mock.bar_.expect_call(42) // both bars have just an int parameter. This will select the non-const 83 | and finally::returns(1337); // version, which returns an int. 84 | SCOPED_EXP std::as_const(mock).bar_.expect_call(42) // to refer to the const version, just use a const ref 85 | and finally::returns(std::string{"Hello, World!"}); // this returns a std::string 86 | 87 | REQUIRE("Hello, World!" == std::as_const(mock).bar(42)); 88 | REQUIRE(1337 == mock.bar(42)); 89 | //! [variadic interface zero] 90 | } 91 | 92 | SECTION("With multiple template arguments.") 93 | { 94 | //! [variadic interface 2] 95 | VariadicDerived mock{}; 96 | 97 | SCOPED_EXP mock.foo_.expect_call(1337, matches::range::has_size(3)); 98 | mock.foo(1337, "Hey"); // second param size of 3 (without null-terminator). 99 | //! [variadic interface 2] 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /include/mimic++/reporting/BasicReporter.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_BASIC_REPORTER_HPP 7 | #define MIMICPP_REPORTING_BASIC_REPORTER_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Fwd.hpp" 12 | #include "mimic++/config/Config.hpp" 13 | #include "mimic++/reporting/CallReport.hpp" 14 | #include "mimic++/reporting/ExpectationReport.hpp" 15 | #include "mimic++/reporting/IReporter.hpp" 16 | #include "mimic++/reporting/NoMatchReport.hpp" 17 | #include "mimic++/reporting/StringifyReports.hpp" 18 | #include "mimic++/utilities/C++23Backports.hpp" 19 | 20 | #ifndef MIMICPP_DETAIL_IS_MODULE 21 | #include 22 | #include 23 | #include 24 | #endif 25 | 26 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 27 | { 28 | /** 29 | * \brief A reporter, which creates text messages and reports them via the provided callbacks. 30 | * \tparam successReporter The success reporter callback. 31 | * \tparam warningReporter The warning reporter callback. 32 | * \tparam failReporter The fail reporter callback. This reporter must never return! 33 | */ 34 | template < 35 | std::invocable auto successReporter, 36 | std::invocable auto warningReporter, 37 | std::invocable auto failReporter> 38 | class BasicReporter 39 | : public IReporter 40 | { 41 | public: 42 | [[noreturn]] 43 | void report_no_matches(CallReport call, std::vector noMatchReports) override 44 | { 45 | send_fail(stringify_no_matches(std::move(call), noMatchReports)); 46 | } 47 | 48 | [[noreturn]] 49 | void report_inapplicable_matches(CallReport call, std::vector expectationReports) override 50 | { 51 | send_fail(stringify_inapplicable_matches(std::move(call), expectationReports)); 52 | } 53 | 54 | void report_full_match(CallReport call, ExpectationReport expectationReport) noexcept override 55 | { 56 | send_success(stringify_full_match(std::move(call), std::move(expectationReport))); 57 | } 58 | 59 | void report_unfulfilled_expectation(const ExpectationReport expectationReport) override 60 | { 61 | if (0 == std::uncaught_exceptions()) 62 | { 63 | send_fail(stringify_unfulfilled_expectation(expectationReport)); 64 | } 65 | } 66 | 67 | void report_error(StringT const message) override 68 | { 69 | if (0 == std::uncaught_exceptions()) 70 | { 71 | send_fail(message); 72 | } 73 | } 74 | 75 | void report_unhandled_exception( 76 | CallReport const call, 77 | ExpectationReport const expectationReport, 78 | std::exception_ptr const exception) override 79 | { 80 | send_warning(stringify_unhandled_exception(call, expectationReport, exception)); 81 | } 82 | 83 | private: 84 | void send_success(StringT const& msg) 85 | { 86 | std::invoke(successReporter, msg); 87 | } 88 | 89 | void send_warning(StringT const& msg) 90 | { 91 | std::invoke(warningReporter, msg); 92 | } 93 | 94 | [[noreturn]] 95 | void send_fail(StringT const& msg) 96 | { 97 | // GCOVR_EXCL_START 98 | std::invoke(failReporter, msg); 99 | util::unreachable(); 100 | // GCOVR_EXCL_STOP 101 | } 102 | }; 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /include/mimic++/reporting/CallReport.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_REPORTING_CALL_REPORT_HPP 7 | #define MIMICPP_REPORTING_CALL_REPORT_HPP 8 | 9 | #pragma once 10 | 11 | #include "mimic++/Call.hpp" 12 | #include "mimic++/Fwd.hpp" 13 | #include "mimic++/config/Config.hpp" 14 | #include "mimic++/printing/StatePrinter.hpp" 15 | #include "mimic++/reporting/TargetReport.hpp" 16 | #include "mimic++/reporting/TypeReport.hpp" 17 | #include "mimic++/utilities/SourceLocation.hpp" 18 | #include "mimic++/utilities/Stacktrace.hpp" 19 | 20 | #ifndef MIMICPP_DETAIL_IS_MODULE 21 | #include 22 | #include 23 | #include 24 | #endif 25 | 26 | MIMICPP_DETAIL_MODULE_EXPORT namespace mimicpp::reporting 27 | { 28 | /** 29 | * \defgroup REPORTING_REPORTS reports 30 | * \ingroup REPORTING 31 | * \brief Contains reports of ``mimic++`` types. 32 | * \details Reports are simplified object representations of ``mimic++`` types. In fact, reports are used to communicate with 33 | * independent domains (e.g. unit-test frameworks) over the ``IReporter`` interface and are thus designed to provide as much 34 | * transparent information as possible, without requiring them to be a generic type. 35 | * 36 | * \{ 37 | */ 38 | 39 | /** 40 | * \brief Contains the extracted info from a typed ``call::Info``. 41 | */ 42 | class CallReport 43 | { 44 | public: 45 | class Arg 46 | { 47 | public: 48 | TypeReport typeInfo; 49 | StringT stateString; 50 | 51 | [[nodiscard]] 52 | friend bool operator==(const Arg&, const Arg&) = default; 53 | }; 54 | 55 | TargetReport target; 56 | TypeReport returnTypeInfo; 57 | std::vector argDetails{}; 58 | util::SourceLocation fromLoc{}; 59 | util::Stacktrace stacktrace{}; 60 | ValueCategory fromCategory{}; 61 | Constness fromConstness{}; 62 | 63 | [[nodiscard]] 64 | friend bool operator==(CallReport const&, CallReport const&) = default; 65 | }; 66 | 67 | /** 68 | * \brief Generates the call report for a given call info. 69 | * \tparam Return The function return type. 70 | * \tparam Params The function parameter types. 71 | * \param target The mock-target report. 72 | * \param callInfo The call info. 73 | * \param stacktrace The stacktrace, from where the call originates. 74 | * \return The call report. 75 | * \relatesalso CallReport 76 | */ 77 | template 78 | [[nodiscard]] 79 | CallReport make_call_report(TargetReport target, call::Info callInfo, util::Stacktrace stacktrace) 80 | { 81 | return CallReport{ 82 | .target{std::move(target)}, 83 | .returnTypeInfo{TypeReport::make()}, 84 | .argDetails = std::apply( 85 | [](auto&... args) { 86 | return std::vector{ 87 | CallReport::Arg{ 88 | .typeInfo = TypeReport::make(), 89 | .stateString = mimicpp::print(args.get())} 90 | ... 91 | }; 92 | }, 93 | callInfo.args), 94 | .fromLoc{std::move(callInfo.fromSourceLocation)}, 95 | .stacktrace{std::move(stacktrace)}, 96 | .fromCategory{callInfo.fromCategory}, 97 | .fromConstness{callInfo.fromConstness}}; 98 | } 99 | 100 | /** 101 | * \} 102 | */ 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | # Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | # Distributed under the Boost Software License, Version 1.0. 3 | # (See accompanying file LICENSE_1_0.txt or copy at 4 | # https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | name: "CodeQL" 7 | 8 | on: 9 | push: 10 | branches: [ main, development ] 11 | pull_request: 12 | branches: [ main, development ] 13 | schedule: 14 | - cron: '00 05 * * 1' # Monday 00:05 am 15 | 16 | jobs: 17 | analyze: 18 | name: Analyze (${{ matrix.language }}) 19 | runs-on: "ubuntu-latest" 20 | permissions: 21 | # required for all workflows 22 | security-events: write 23 | 24 | # required to fetch internal or private CodeQL packs 25 | packages: read 26 | 27 | strategy: 28 | fail-fast: false 29 | matrix: 30 | include: 31 | - language: c-cpp 32 | build-mode: manual 33 | # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' 34 | # Use `c-cpp` to analyze code written in C, C++ or both 35 | # Use 'java-kotlin' to analyze code written in Java, Kotlin or both 36 | # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both 37 | # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, 38 | # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. 39 | # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how 40 | # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages 41 | steps: 42 | - name: Checkout repository 43 | uses: actions/checkout@v4 44 | 45 | # Initializes the CodeQL tools for scanning. 46 | - name: Initialize CodeQL 47 | uses: github/codeql-action/init@v3 48 | with: 49 | languages: ${{ matrix.language }} 50 | build-mode: ${{ matrix.build-mode }} 51 | source-root: "include" 52 | 53 | # If you wish to specify custom queries, you can do so here or in a config file. 54 | # By default, queries listed here will override any specified in a config file. 55 | # Prefix the list here with "+" to use these queries and those in the config file. 56 | 57 | # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 58 | # queries: security-extended,security-and-quality 59 | 60 | # ℹ️ Command-line programs to run using the OS shell. 61 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 62 | - name: Configure 63 | shell: bash 64 | run: | 65 | cmake -S . \ 66 | -B build \ 67 | -D CMAKE_BUILD_TYPE="Release" \ 68 | -D MIMICPP_ENABLE_ADAPTER_TESTS=YES \ 69 | -D MIMICPP_ENABLE_STACKTRACE_TESTS=YES \ 70 | -D MIMICPP_CONFIG_EXPERIMENTAL_CATCH2_MATCHER_INTEGRATION=YES \ 71 | -D MIMICPP_CONFIG_EXPERIMENTAL_UNICODE_STR_MATCHER=YES \ 72 | -D MIMICPP_ENABLE_UNICODE_STR_MATCHER_TESTS=YES \ 73 | -D MIMICPP_CONFIG_EXPERIMENTAL_PRETTY_TYPES=YES \ 74 | -D MIMICPP_CONFIG_EXPERIMENTAL_STACKTRACE=cpptrace \ 75 | -D MIMICPP_CONFIG_EXPERIMENTAL_IMPORT_CPPTRACE=OFF 76 | 77 | - name: Build 78 | run: cmake --build build -j4 79 | 80 | - name: Perform CodeQL Analysis 81 | uses: github/codeql-action/analyze@v3 82 | with: 83 | category: "/language:${{matrix.language}}" 84 | -------------------------------------------------------------------------------- /test/stacktrace-tests/test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #include "mimic++/utilities/Stacktrace.hpp" 7 | 8 | using namespace mimicpp; 9 | 10 | TEST_CASE( 11 | TEST_CASE_PREFIX " - The active backend is the expected one.", 12 | "[stacktrace]") 13 | { 14 | using ExpectedBackend = EXPECTED_BACKEND_TYPE; 15 | STATIC_CHECK(std::same_as); 16 | } 17 | 18 | #ifndef NDEBUG 19 | 20 | TEST_CASE( 21 | TEST_CASE_PREFIX " - The active backend is fully functional.", 22 | "[stacktrace]") 23 | { 24 | util::Stacktrace const stacktrace = GENERATE( 25 | util::stacktrace::current(), 26 | util::stacktrace::current(0), 27 | util::stacktrace::current(0, 3)); 28 | CAPTURE(stacktrace); 29 | REQUIRE_FALSE(stacktrace.empty()); 30 | REQUIRE(0 < stacktrace.size()); 31 | 32 | // To keep my sanity, I relax the source-file and line requirement to just not failing, 33 | // because on macOS and boost::stacktrace nothing useful comes back. 34 | CHECK_THAT( 35 | stacktrace.description(0), 36 | !Catch::Matchers::IsEmpty()); 37 | CHECK_NOTHROW(stacktrace.source_file(0)); 38 | CHECK_NOTHROW(stacktrace.source_line(0)); 39 | 40 | for (std::size_t const i : std::views::iota(1u, stacktrace.size())) 41 | { 42 | CAPTURE(i); 43 | CHECK_NOTHROW(stacktrace.description(i)); 44 | CHECK_NOTHROW(stacktrace.source_file(i)); 45 | CHECK_NOTHROW(stacktrace.source_line(i)); 46 | } 47 | } 48 | 49 | TEST_CASE( 50 | TEST_CASE_PREFIX " - stacktrace::current's first frame is the from the source function.", 51 | "[stacktrace]") 52 | { 53 | auto const super = [] { return util::stacktrace::current(); }(); 54 | CAPTURE(super); 55 | REQUIRE(4u < super.size()); 56 | 57 | auto const stacktrace = util::stacktrace::current(); 58 | CAPTURE(stacktrace); 59 | 60 | // Comparing the current top-lvl frame is quite inconsistent with boost::stacktrace on msvc, 61 | // so let's head a few layers up. 62 | REQUIRE(3u < stacktrace.size()); 63 | CHECK(super.source_line(4u) == stacktrace.source_line(3u)); 64 | CHECK_THAT( 65 | stacktrace.source_file(3u), 66 | Catch::Matchers::Equals(super.source_file(4u))); 67 | CHECK_THAT( 68 | stacktrace.description(3u), 69 | Catch::Matchers::Equals(super.description(4u))); 70 | } 71 | 72 | TEST_CASE( 73 | TEST_CASE_PREFIX " - stacktrace::current supports skip.", 74 | "[stacktrace]") 75 | { 76 | auto const full = util::stacktrace::current(); 77 | CAPTURE(full); 78 | REQUIRE(3u < full.size()); 79 | 80 | auto const stacktrace = util::stacktrace::current(3u); 81 | CAPTURE(stacktrace); 82 | 83 | REQUIRE_FALSE(stacktrace.empty()); 84 | CHECK(full.source_line(3u) == stacktrace.source_line(0u)); 85 | CHECK_THAT( 86 | stacktrace.source_file(0u), 87 | Catch::Matchers::ContainsSubstring(std::string{full.source_file(3u)})); 88 | CHECK_THAT( 89 | stacktrace.description(0u), 90 | Catch::Matchers::ContainsSubstring(std::string{full.description(3u)})); 91 | } 92 | 93 | TEST_CASE( 94 | TEST_CASE_PREFIX " - stacktrace::current supports max.", 95 | "[stacktrace]") 96 | { 97 | auto const full = util::stacktrace::current(); 98 | CAPTURE(full); 99 | REQUIRE(3u < full.size()); 100 | 101 | auto const stacktrace = util::stacktrace::current(3u, 1u); 102 | CAPTURE(stacktrace); 103 | 104 | REQUIRE(1u == stacktrace.size()); 105 | CHECK(full.source_line(3u) == stacktrace.source_line(0u)); 106 | CHECK_THAT( 107 | stacktrace.source_file(0u), 108 | Catch::Matchers::ContainsSubstring(std::string{full.source_file(3u)})); 109 | CHECK_THAT( 110 | stacktrace.description(0u), 111 | Catch::Matchers::ContainsSubstring(std::string{full.description(3u)})); 112 | } 113 | 114 | #endif -------------------------------------------------------------------------------- /include/mimic++_ext/adapters/Catch2.hpp: -------------------------------------------------------------------------------- 1 | // Copyright Dominic (DNKpp) Koepke 2024 - 2025. 2 | // Distributed under the Boost Software License, Version 1.0. 3 | // (See accompanying file LICENSE_1_0.txt or copy at 4 | // https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #ifndef MIMICPP_ADAPTERS_CATCH2_HPP 7 | #define MIMICPP_ADAPTERS_CATCH2_HPP 8 | 9 | #pragma once 10 | 11 | #if __has_include("mimic++/Reporting.hpp") 12 | #include "mimic++/Reporting.hpp" 13 | #include "mimic++/utilities/C++23Backports.hpp" 14 | #elif not defined(MIMICPP_VERSION) 15 | #error "It appears that the test-adapter is not included in the mimic++ project or package." \ 16 | "If you plan to use it alongside the mimic++-amalgamated header, please ensure to include the adapter-header afterwards." 17 | #endif 18 | 19 | #if __has_include() 20 | #include 21 | #else 22 | #error "Unable to find catch2 includes." 23 | #endif 24 | 25 | namespace mimicpp::reporting::detail::catch2 26 | { 27 | inline void send_success(StringViewT const msg) 28 | { 29 | #ifdef CATCH_CONFIG_PREFIX_ALL 30 | CATCH_SUCCEED(msg); 31 | #else 32 | SUCCEED(msg); 33 | #endif 34 | } 35 | 36 | inline void send_warning(StringViewT const msg) 37 | { 38 | #ifdef CATCH_CONFIG_PREFIX_MESSAGES 39 | CATCH_WARN(msg); 40 | #else 41 | WARN(msg); 42 | #endif 43 | } 44 | 45 | [[noreturn]] 46 | inline void send_fail(StringViewT const msg) 47 | { 48 | /* This is a workaround because when there is a `noexcept` function somewhere in the current call-stack, 49 | * the error message will not be flushed to the actual output before the process termination. 50 | * So, we catch it here, write another message which seems to flush the current content, 51 | * so *mimic++* users can see the actual error-description. 52 | */ 53 | CATCH_TRY 54 | { 55 | #ifdef CATCH_CONFIG_PREFIX_ALL 56 | CATCH_FAIL(msg); 57 | #else 58 | FAIL(msg); 59 | #endif 60 | } 61 | CATCH_CATCH_ANON(Catch::TestFailureException const&) 62 | { 63 | send_warning("Fatal failure!"); 64 | throw; 65 | } 66 | } 67 | } 68 | 69 | namespace mimicpp::reporting 70 | { 71 | // GCOVR_EXCL_START 72 | 73 | /** 74 | * \brief Reporter for the integration into Catch2. 75 | * \ingroup REPORTING_ADAPTERS 76 | * \details This reporter enables the integration of ``mimic++`` into ``Catch2`` and prefixes the headers 77 | * of ``Catch2`` with ``catch2/``. 78 | * 79 | * This reporter installs itself by simply including this header file into any source file of the test executable. 80 | * 81 | * ## Experimental Matcher integration 82 | * 83 | * ``mimic++`` has an opt-in config, which lets users directly use ``catch2``-matchers everywhere, where a ``mimic++``-matcher 84 | * would be suitable. 85 | * \see \ref MIMICPP_CONFIG_EXPERIMENTAL_CATCH2_MATCHER_INTEGRATION 86 | */ 87 | using Catch2ReporterT = BasicReporter< 88 | &detail::catch2::send_success, 89 | &detail::catch2::send_warning, 90 | &detail::catch2::send_fail>; 91 | 92 | // GCOVR_EXCL_STOP 93 | } 94 | 95 | namespace mimicpp::reporting::detail::catch2 96 | { 97 | [[maybe_unused]] 98 | inline const ReporterInstaller installer{}; 99 | } 100 | 101 | #ifdef MIMICPP_CONFIG_EXPERIMENTAL_CATCH2_MATCHER_INTEGRATION 102 | 103 | #include 104 | 105 | template 106 | requires std::derived_from // new style 107 | || std::derived_from // old style 108 | struct mimicpp::custom::matcher_traits 109 | { 110 | template 111 | [[nodiscard]] 112 | static constexpr bool matches(const Matcher& matcher, T& value) 113 | requires requires { { matcher.match(value) } -> std::convertible_to; } 114 | { 115 | return matcher.match(value); 116 | } 117 | }; 118 | 119 | #endif 120 | 121 | #endif 122 | --------------------------------------------------------------------------------