├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── CMakeLists.txt ├── ChangeLog ├── LICENSE_1_0.txt ├── README.md ├── _config.yml ├── check_errors.sh ├── compilation_errors ├── address_of_illegal_argument.cpp ├── any_with_array_type.cpp ├── assign_illegal_argument.cpp ├── co_return_and_co_throw.cpp ├── co_return_empty_to_non_void_coroutine.cpp ├── co_return_from_non_coroutine.cpp ├── co_return_on_forbidden_call.cpp ├── co_return_value_to_void_coroutine.cpp ├── co_return_with_mismatching_type.cpp ├── co_throw_and_co_return.cpp ├── co_throw_from_non_coroutine.cpp ├── co_throw_on_forbidden_call.cpp ├── co_yield_from_non_coroutine.cpp ├── co_yield_to_promise_without_yield_value.cpp ├── co_yield_void.cpp ├── co_yield_with_mistamching_type.cpp ├── deathwatched_with_nonvirtual_destructor.cpp ├── dereference_illegal_argument.cpp ├── expectation_with_unknown_func_name.cpp ├── expectation_with_wrong_cardinality.cpp ├── expectation_with_wrong_type.cpp ├── illegal_move_mock.cpp ├── in_sequence_on_forbidden_call.cpp ├── make_mock_with_wrong_cardinality.cpp ├── missing_co_return_from_void_coroutine.cpp ├── missing_return_on_non_void_func.cpp ├── mixed_limits_with_rt_limits.cpp ├── mixed_rt_limits_with_limits.cpp ├── multiple_co_return.cpp ├── multiple_co_throw.cpp ├── multiple_late_return_on_non_void_func.cpp ├── multiple_limits.cpp ├── multiple_return_on_non_void_func.cpp ├── multiple_rt_limits.cpp ├── multiple_sequences.cpp ├── multiple_sequences_destruction.cpp ├── multiple_sequences_named_destruction.cpp ├── multiple_throws.cpp ├── negative_limit_interval_first.cpp ├── negative_limit_interval_second.cpp ├── ptr_to_member_from_nullptr_matcher.cpp ├── reference_from_duck_typed_matcher.cpp ├── reference_from_nullptr_matcher.cpp ├── reference_from_wildcard.cpp ├── return_address_of_illegal_argument.cpp ├── return_and_throw.cpp ├── return_first_from_void_func.cpp ├── return_from_coroutine.cpp ├── return_illegal_argument.cpp ├── return_on_forbidden_call.cpp ├── return_second_from_void_func.cpp ├── return_value_to_ref.cpp ├── return_wrong_pointer_constness.cpp ├── return_wrong_reference_constness.cpp ├── return_wrong_type_first.cpp ├── side_effect_on_forbidden_call.cpp ├── throw_and_return.cpp ├── throw_from_coroutine.cpp ├── throw_on_forbidden_call.cpp ├── times_0_after_return.cpp ├── times_0_after_sequence.cpp ├── times_0_after_side_effect.cpp ├── times_0_after_throw.cpp ├── use_illegal_argument.cpp ├── value_from_duck_typed_matcher.cpp ├── value_from_nullptr_matcher.cpp ├── value_from_typed_matcher.cpp └── value_from_wildcard.cpp ├── docs ├── Backward.md ├── CookBook.md ├── FAQ.md ├── PlatformsAndLibraries.md ├── reference.md ├── trompeloeil_cheat_sheet.odp └── trompeloeil_cheat_sheet.pdf ├── include ├── boost │ └── trompeloeil.hpp ├── cantata │ └── trompeloeil.hpp ├── catch2 │ └── trompeloeil.hpp ├── criterion │ └── trompeloeil.hpp ├── crpcut │ └── trompeloeil.hpp ├── cxxtest │ └── trompeloeil.hpp ├── doctest │ └── trompeloeil.hpp ├── gtest │ └── trompeloeil.hpp ├── trompeloeil.hpp └── trompeloeil │ ├── coro.hpp │ ├── cpp11_shenanigans.hpp │ ├── lifetime.hpp │ ├── matcher.hpp │ ├── matcher │ ├── any.hpp │ ├── compare.hpp │ ├── deref.hpp │ ├── member_is.hpp │ ├── not.hpp │ ├── range.hpp │ ├── re.hpp │ └── set_predicate.hpp │ ├── mock.hpp │ ├── sequence.hpp │ └── stream_tracer.hpp ├── install_libcxx.sh ├── test ├── CMakeLists.txt ├── compiling_tests.cpp ├── compiling_tests.hpp ├── compiling_tests_11.cpp ├── compiling_tests_14.cpp ├── custom_recursive_mutex.cpp ├── micro_coro.hpp ├── test_co_mock.cpp ├── test_reporter.hpp └── thread_terror.cpp ├── trompeloeil-config.cmake ├── trompeloeil-logo.png ├── trompeloeil-logo.svg └── verify_compilation_error.sh /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | *.sh eol=lf 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/c++,cmake,clion,visualstudio,visualstudiocode 3 | # Edit at https://www.gitignore.io/?templates=c++,cmake,clion,visualstudio,visualstudiocode 4 | 5 | ### C++ ### 6 | # Prerequisites 7 | *.d 8 | 9 | # Compiled Object files 10 | *.slo 11 | *.lo 12 | *.o 13 | *.obj 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Compiled Dynamic libraries 20 | *.so 21 | *.dylib 22 | *.dll 23 | 24 | # Fortran module files 25 | *.mod 26 | *.smod 27 | 28 | # Compiled Static libraries 29 | *.lai 30 | *.la 31 | *.a 32 | *.lib 33 | 34 | # Executables 35 | *.exe 36 | *.out 37 | *.app 38 | 39 | ### CLion ### 40 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 41 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 42 | 43 | # User-specific stuff 44 | .idea/**/workspace.xml 45 | .idea/**/tasks.xml 46 | .idea/**/usage.statistics.xml 47 | .idea/**/dictionaries 48 | .idea/**/shelf 49 | 50 | # Generated files 51 | .idea/**/contentModel.xml 52 | 53 | # Sensitive or high-churn files 54 | .idea/**/dataSources/ 55 | .idea/**/dataSources.ids 56 | .idea/**/dataSources.local.xml 57 | .idea/**/sqlDataSources.xml 58 | .idea/**/dynamic.xml 59 | .idea/**/uiDesigner.xml 60 | .idea/**/dbnavigator.xml 61 | 62 | # Gradle 63 | .idea/**/gradle.xml 64 | .idea/**/libraries 65 | 66 | # Gradle and Maven with auto-import 67 | # When using Gradle or Maven with auto-import, you should exclude module files, 68 | # since they will be recreated, and may cause churn. Uncomment if using 69 | # auto-import. 70 | # .idea/modules.xml 71 | # .idea/*.iml 72 | # .idea/modules 73 | # *.iml 74 | # *.ipr 75 | 76 | # CMake 77 | cmake-build-*/ 78 | 79 | # Mongo Explorer plugin 80 | .idea/**/mongoSettings.xml 81 | 82 | # File-based project format 83 | *.iws 84 | 85 | # IntelliJ 86 | out/ 87 | 88 | # mpeltonen/sbt-idea plugin 89 | .idea_modules/ 90 | 91 | # JIRA plugin 92 | atlassian-ide-plugin.xml 93 | 94 | # Cursive Clojure plugin 95 | .idea/replstate.xml 96 | 97 | # Crashlytics plugin (for Android Studio and IntelliJ) 98 | com_crashlytics_export_strings.xml 99 | crashlytics.properties 100 | crashlytics-build.properties 101 | fabric.properties 102 | 103 | # Editor-based Rest Client 104 | .idea/httpRequests 105 | 106 | # Android studio 3.1+ serialized cache file 107 | .idea/caches/build_file_checksums.ser 108 | 109 | ### CLion Patch ### 110 | # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 111 | 112 | # *.iml 113 | # modules.xml 114 | # .idea/misc.xml 115 | # *.ipr 116 | 117 | # Sonarlint plugin 118 | .idea/sonarlint 119 | 120 | ### CMake ### 121 | CMakeLists.txt.user 122 | CMakeCache.txt 123 | CMakeFiles 124 | CMakeScripts 125 | Testing 126 | Makefile 127 | cmake_install.cmake 128 | install_manifest.txt 129 | compile_commands.json 130 | CTestTestfile.cmake 131 | _deps 132 | 133 | ### CMake Patch ### 134 | # External projects 135 | *-prefix/ 136 | 137 | ### VisualStudioCode ### 138 | .vscode/* 139 | !.vscode/settings.json 140 | !.vscode/tasks.json 141 | !.vscode/launch.json 142 | !.vscode/extensions.json 143 | 144 | ### VisualStudioCode Patch ### 145 | # Ignore all local history of files 146 | .history 147 | 148 | ### VisualStudio ### 149 | ## Ignore Visual Studio temporary files, build results, and 150 | ## files generated by popular Visual Studio add-ons. 151 | ## 152 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 153 | 154 | # User-specific files 155 | *.rsuser 156 | *.suo 157 | *.user 158 | *.userosscache 159 | *.sln.docstates 160 | 161 | # User-specific files (MonoDevelop/Xamarin Studio) 162 | *.userprefs 163 | 164 | # Mono auto generated files 165 | mono_crash.* 166 | 167 | # Build results 168 | [Dd]ebug/ 169 | [Dd]ebugPublic/ 170 | [Rr]elease/ 171 | [Rr]eleases/ 172 | x64/ 173 | x86/ 174 | [Aa][Rr][Mm]/ 175 | [Aa][Rr][Mm]64/ 176 | bld/ 177 | [Bb]in/ 178 | [Oo]bj/ 179 | [Ll]og/ 180 | 181 | # Visual Studio 2015/2017 cache/options directory 182 | .vs/ 183 | # Uncomment if you have tasks that create the project's static files in wwwroot 184 | #wwwroot/ 185 | 186 | # Visual Studio 2017 auto generated files 187 | Generated\ Files/ 188 | 189 | # MSTest test Results 190 | [Tt]est[Rr]esult*/ 191 | [Bb]uild[Ll]og.* 192 | 193 | # NUnit 194 | *.VisualState.xml 195 | TestResult.xml 196 | nunit-*.xml 197 | 198 | # Build Results of an ATL Project 199 | [Dd]ebugPS/ 200 | [Rr]eleasePS/ 201 | dlldata.c 202 | 203 | # Benchmark Results 204 | BenchmarkDotNet.Artifacts/ 205 | 206 | # .NET Core 207 | project.lock.json 208 | project.fragment.lock.json 209 | artifacts/ 210 | 211 | # StyleCop 212 | StyleCopReport.xml 213 | 214 | # Files built by Visual Studio 215 | *_i.c 216 | *_p.c 217 | *_h.h 218 | *.ilk 219 | *.meta 220 | *.iobj 221 | *.pdb 222 | *.ipdb 223 | *.pgc 224 | *.pgd 225 | *.rsp 226 | *.sbr 227 | *.tlb 228 | *.tli 229 | *.tlh 230 | *.tmp 231 | *.tmp_proj 232 | *_wpftmp.csproj 233 | *.log 234 | *.vspscc 235 | *.vssscc 236 | .builds 237 | *.pidb 238 | *.svclog 239 | *.scc 240 | 241 | # Chutzpah Test files 242 | _Chutzpah* 243 | 244 | # Visual C++ cache files 245 | ipch/ 246 | *.aps 247 | *.ncb 248 | *.opendb 249 | *.opensdf 250 | *.sdf 251 | *.cachefile 252 | *.VC.db 253 | *.VC.VC.opendb 254 | 255 | # Visual Studio profiler 256 | *.psess 257 | *.vsp 258 | *.vspx 259 | *.sap 260 | 261 | # Visual Studio Trace Files 262 | *.e2e 263 | 264 | # TFS 2012 Local Workspace 265 | $tf/ 266 | 267 | # Guidance Automation Toolkit 268 | *.gpState 269 | 270 | # ReSharper is a .NET coding add-in 271 | _ReSharper*/ 272 | *.[Rr]e[Ss]harper 273 | *.DotSettings.user 274 | 275 | # JustCode is a .NET coding add-in 276 | .JustCode 277 | 278 | # TeamCity is a build add-in 279 | _TeamCity* 280 | 281 | # DotCover is a Code Coverage Tool 282 | *.dotCover 283 | 284 | # AxoCover is a Code Coverage Tool 285 | .axoCover/* 286 | !.axoCover/settings.json 287 | 288 | # Visual Studio code coverage results 289 | *.coverage 290 | *.coveragexml 291 | 292 | # NCrunch 293 | _NCrunch_* 294 | .*crunch*.local.xml 295 | nCrunchTemp_* 296 | 297 | # MightyMoose 298 | *.mm.* 299 | AutoTest.Net/ 300 | 301 | # Web workbench (sass) 302 | .sass-cache/ 303 | 304 | # Installshield output folder 305 | [Ee]xpress/ 306 | 307 | # DocProject is a documentation generator add-in 308 | DocProject/buildhelp/ 309 | DocProject/Help/*.HxT 310 | DocProject/Help/*.HxC 311 | DocProject/Help/*.hhc 312 | DocProject/Help/*.hhk 313 | DocProject/Help/*.hhp 314 | DocProject/Help/Html2 315 | DocProject/Help/html 316 | 317 | # Click-Once directory 318 | publish/ 319 | 320 | # Publish Web Output 321 | *.[Pp]ublish.xml 322 | *.azurePubxml 323 | # Note: Comment the next line if you want to checkin your web deploy settings, 324 | # but database connection strings (with potential passwords) will be unencrypted 325 | *.pubxml 326 | *.publishproj 327 | 328 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 329 | # checkin your Azure Web App publish settings, but sensitive information contained 330 | # in these scripts will be unencrypted 331 | PublishScripts/ 332 | 333 | # NuGet Packages 334 | *.nupkg 335 | # NuGet Symbol Packages 336 | *.snupkg 337 | # The packages folder can be ignored because of Package Restore 338 | **/[Pp]ackages/* 339 | # except build/, which is used as an MSBuild target. 340 | !**/[Pp]ackages/build/ 341 | # Uncomment if necessary however generally it will be regenerated when needed 342 | #!**/[Pp]ackages/repositories.config 343 | # NuGet v3's project.json files produces more ignorable files 344 | *.nuget.props 345 | *.nuget.targets 346 | 347 | # Microsoft Azure Build Output 348 | csx/ 349 | *.build.csdef 350 | 351 | # Microsoft Azure Emulator 352 | ecf/ 353 | rcf/ 354 | 355 | # Windows Store app package directories and files 356 | AppPackages/ 357 | BundleArtifacts/ 358 | Package.StoreAssociation.xml 359 | _pkginfo.txt 360 | *.appx 361 | *.appxbundle 362 | *.appxupload 363 | 364 | # Visual Studio cache files 365 | # files ending in .cache can be ignored 366 | *.[Cc]ache 367 | # but keep track of directories ending in .cache 368 | !?*.[Cc]ache/ 369 | 370 | # Others 371 | ClientBin/ 372 | ~$* 373 | *~ 374 | *.dbmdl 375 | *.dbproj.schemaview 376 | *.jfm 377 | *.pfx 378 | *.publishsettings 379 | orleans.codegen.cs 380 | 381 | # Including strong name files can present a security risk 382 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 383 | #*.snk 384 | 385 | # Since there are multiple workflows, uncomment next line to ignore bower_components 386 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 387 | #bower_components/ 388 | 389 | # RIA/Silverlight projects 390 | Generated_Code/ 391 | 392 | # Backup & report files from converting an old project file 393 | # to a newer Visual Studio version. Backup files are not needed, 394 | # because we have git ;-) 395 | _UpgradeReport_Files/ 396 | Backup*/ 397 | UpgradeLog*.XML 398 | UpgradeLog*.htm 399 | ServiceFabricBackup/ 400 | *.rptproj.bak 401 | 402 | # SQL Server files 403 | *.mdf 404 | *.ldf 405 | *.ndf 406 | 407 | # Business Intelligence projects 408 | *.rdl.data 409 | *.bim.layout 410 | *.bim_*.settings 411 | *.rptproj.rsuser 412 | *- [Bb]ackup.rdl 413 | *- [Bb]ackup ([0-9]).rdl 414 | *- [Bb]ackup ([0-9][0-9]).rdl 415 | 416 | # Microsoft Fakes 417 | FakesAssemblies/ 418 | 419 | # GhostDoc plugin setting file 420 | *.GhostDoc.xml 421 | 422 | # Node.js Tools for Visual Studio 423 | .ntvs_analysis.dat 424 | node_modules/ 425 | 426 | # Visual Studio 6 build log 427 | *.plg 428 | 429 | # Visual Studio 6 workspace options file 430 | *.opt 431 | 432 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 433 | *.vbw 434 | 435 | # Visual Studio LightSwitch build output 436 | **/*.HTMLClient/GeneratedArtifacts 437 | **/*.DesktopClient/GeneratedArtifacts 438 | **/*.DesktopClient/ModelManifest.xml 439 | **/*.Server/GeneratedArtifacts 440 | **/*.Server/ModelManifest.xml 441 | _Pvt_Extensions 442 | 443 | # Paket dependency manager 444 | .paket/paket.exe 445 | paket-files/ 446 | 447 | # FAKE - F# Make 448 | .fake/ 449 | 450 | # CodeRush personal settings 451 | .cr/personal 452 | 453 | # Python Tools for Visual Studio (PTVS) 454 | __pycache__/ 455 | *.pyc 456 | 457 | # Cake - Uncomment if you are using it 458 | # tools/** 459 | # !tools/packages.config 460 | 461 | # Tabs Studio 462 | *.tss 463 | 464 | # Telerik's JustMock configuration file 465 | *.jmconfig 466 | 467 | # BizTalk build output 468 | *.btp.cs 469 | *.btm.cs 470 | *.odx.cs 471 | *.xsd.cs 472 | 473 | # OpenCover UI analysis results 474 | OpenCover/ 475 | 476 | # Azure Stream Analytics local run output 477 | ASALocalRun/ 478 | 479 | # MSBuild Binary and Structured Log 480 | *.binlog 481 | 482 | # NVidia Nsight GPU debugger configuration file 483 | *.nvuser 484 | 485 | # MFractors (Xamarin productivity tool) working folder 486 | .mfractor/ 487 | 488 | # Local History for Visual Studio 489 | .localhistory/ 490 | 491 | # BeatPulse healthcheck temp database 492 | healthchecksdb 493 | 494 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 495 | MigrationBackup/ 496 | 497 | # End of https://www.gitignore.io/api/c++,cmake,clion,visualstudio,visualstudiocode 498 | 499 | ######################################## 500 | ## TROMPELOEIL-SPECIFIC IGNORE PATTERNS 501 | ######################################## 502 | 503 | build/ 504 | 505 | # CLion 506 | .idea 507 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14) 2 | project(trompeloeil CXX) 3 | 4 | include(GNUInstallDirs) 5 | include(ExternalProject) 6 | include(CMakePackageConfigHelpers) 7 | include(CheckCXXCompilerFlag) 8 | 9 | option(TROMPELOEIL_BUILD_TESTS "Build self test programs" off) 10 | 11 | write_basic_package_version_file( 12 | "${CMAKE_CURRENT_BINARY_DIR}/trompeloeil/trompeloeil-config-version.cmake" 13 | VERSION 49 14 | COMPATIBILITY AnyNewerVersion 15 | ARCH_INDEPENDENT) 16 | 17 | add_library(trompeloeil INTERFACE) 18 | add_library(trompeloeil::trompeloeil ALIAS trompeloeil) 19 | 20 | set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) 21 | 22 | target_include_directories( 23 | trompeloeil 24 | INTERFACE 25 | $ 26 | ) 27 | 28 | target_include_directories( 29 | trompeloeil 30 | INTERFACE 31 | $/include> 32 | ) 33 | 34 | set(MASTER_PROJECT OFF) 35 | if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) 36 | set(MASTER_PROJECT ON) 37 | endif() 38 | 39 | option(TROMPELOEIL_INSTALL_TARGETS "Sets whether trompeloeil should be installed" ${MASTER_PROJECT}) 40 | option(TROMPELOEIL_INSTALL_DOCS "Install documentation" ${TROMPELOEIL_INSTALL_TARGETS}) 41 | 42 | if (MASTER_PROJECT AND TROMPELOEIL_BUILD_TESTS) 43 | add_subdirectory(test) 44 | endif() 45 | 46 | if (TROMPELOEIL_INSTALL_TARGETS) 47 | install( 48 | TARGETS 49 | trompeloeil 50 | EXPORT 51 | trompeloeil-targets 52 | INCLUDES DESTINATION 53 | include 54 | ) 55 | 56 | install( 57 | EXPORT 58 | trompeloeil-targets 59 | NAMESPACE 60 | trompeloeil:: 61 | DESTINATION 62 | ${CMAKE_INSTALL_LIBDIR}/cmake/trompeloeil 63 | ) 64 | install( 65 | FILES 66 | trompeloeil-config.cmake 67 | "${CMAKE_CURRENT_BINARY_DIR}/trompeloeil/trompeloeil-config-version.cmake" 68 | DESTINATION 69 | ${CMAKE_INSTALL_LIBDIR}/cmake/trompeloeil 70 | COMPONENT 71 | Devel 72 | ) 73 | 74 | install( 75 | DIRECTORY 76 | include/ 77 | DESTINATION 78 | ${CMAKE_INSTALL_INCLUDEDIR} 79 | ) 80 | endif(TROMPELOEIL_INSTALL_TARGETS) 81 | 82 | if(TROMPELOEIL_INSTALL_DOCS) 83 | install( 84 | FILES 85 | LICENSE_1_0.txt 86 | DESTINATION 87 | ${CMAKE_INSTALL_DOCDIR} 88 | ) 89 | 90 | install( 91 | DIRECTORY 92 | docs 93 | DESTINATION 94 | ${CMAKE_INSTALL_DOCDIR} 95 | ) 96 | endif() 97 | -------------------------------------------------------------------------------- /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. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # *Trompeloeil* 2 | 3 | ![trompeloeil logo](trompeloeil-logo.png) 4 | 5 | 6 | ![CI](https://github.com/rollbear/trompeloeil/workflows/CI/badge.svg) 7 | [![codecov](https://codecov.io/gh/rollbear/trompeloeil/branch/master/graph/badge.svg?token=PCUO4knwdU)](https://codecov.io/gh/rollbear/trompeloeil) 8 | 9 | Get: [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/trompeloeil) 10 | 11 | Buy me a coffee 12 | 13 | > *trompe l'oeil* noun (Concise Encyclopedia) 14 | > Style of representation in which a painted object is intended 15 | > to deceive the viewer into believing it is the object itself... 16 | 17 | # What is it? 18 | 19 | A thread-safe header-only mocking framework for C++11/14 using the Boost Software License 1.0 20 | 21 | # Documentation 22 | 23 | - [Integrating with unit test frame works](docs/CookBook.md/#unit_test_frameworks) 24 | - [Introduction](https://playfulprogramming.blogspot.com/2014/12/introducing-trompeloeil-c-mocking.html) 25 | - [Building and running the self test suite](#self_test) 26 | - [How to contribute](#contribute) 27 | - [Compiler compatibility](#compilers) 28 | - [External tools](#tools) 29 | - [Presentation videos](#videos) 30 | - [Trompeloeil on CppCast](http://cppcast.com/2017/02/bjorn-fahller/) 31 | - [Cheat Sheet (2*A4)](docs/trompeloeil_cheat_sheet.pdf) 32 | - [Cook Book](docs/CookBook.md) 33 | - [FAQ](docs/FAQ.md) 34 | - [Backward compatibility with earlier versions of C++](docs/Backward.md) 35 | - [Platform and library support for Trompeloeil](docs/PlatformsAndLibraries.md) 36 | - [Reference](docs/reference.md) 37 | 38 | Also, follow up with the post on 39 | [sequencing]( 40 | https://playfulprogramming.blogspot.se/2015/01/sequence-control-with-trompeloeil-c.html 41 | ) for examples on how to restrict or relax allowed sequences of matching calls. 42 | 43 | # Teaser 44 | 45 | ```Cpp 46 | #include 47 | 48 | class Interface 49 | { 50 | public: 51 | virtual ~Interface() = default; 52 | virtual bool foo(int, std::string& s) = 0; 53 | virtual bool bar(int) = 0; 54 | virtual bool bar(std::string) = 0; 55 | }; 56 | 57 | void interface_func(Interface*); // function to test 58 | 59 | class Mock : public Interface 60 | { 61 | public: 62 | MAKE_MOCK(foo, auto (int, std::string&) -> bool, override); 63 | MAKE_MOCK(bar, auto (int) -> bool, override); 64 | MAKE_MOCK(bar, auto (std::string) -> bool, override); 65 | MAKE_MOCK0(baz, void()); // not from Interface 66 | }; 67 | 68 | TEST(exercise_interface_func) 69 | { 70 | using trompeloeil::_; // wild card for matching any value 71 | using trompeloeil::gt; // greater-than match 72 | 73 | Mock m; 74 | 75 | trompeloeil::sequence seq1, seq2; // control order of matching calls 76 | 77 | int local_var = 0; 78 | 79 | REQUIRE_CALL(m, bar(ANY(int))) // expect call to m.bar(int) 80 | .LR_SIDE_EFFECT(local_var = _1) // set captured variable to value of param 81 | .RETURN(_1 > 0) // return value depending on param value 82 | .IN_SEQUENCE(seq1) // must be first match for seq1 83 | .TIMES(AT_LEAST(1)); // can be called several times 84 | 85 | FORBID_CALL(m, bar(0)); // but m.bar(0) is not allowed 86 | 87 | REQUIRE_CALL(m, bar("word")) // expect one call to m.bar(std::string) 88 | .RETURN(true) 89 | .IN_SEQUENCE(seq2); // must be first match for seq2 90 | 91 | REQUIRE_CALL(m, foo(gt(2), _)) // expect call to foo(int,std::string&) 92 | .WITH(_2 == "") // with int > 2 and empty string 93 | .IN_SEQUENCE(seq1, seq2) // last for both seq1 and seq2 94 | .SIDE_EFFECT(_2 = "cat") // and set param string to "cat" 95 | .RETURN(true); 96 | 97 | interface_func(&m); 98 | 99 | // all the above expectations must be fulfilled here 100 | } 101 | ``` 102 | 103 | # Building and running the self test suite 104 | 105 | To build the self test suite run `cmake` with `-DTROMPELOEIL_BUILD_TESTS=yes`. 106 | Use the options `CXX_STANDARD` to select which C++ standard to test, and 107 | `SANITIZE` to select sanitizers to build with. Note that the self tests needs a 108 | reasonably modern version of CMake. Example: 109 | 110 | ``` 111 | cmake -B build_dir \ 112 | -D TROMPELOEIL_BUILD_TESTS=yes \ 113 | -D CMAKE_BUILD_TYPE=Debug \ 114 | -D CXX_STANDARD=17 \ 115 | -D SANITIZE=Address,Undefined \ 116 | 117 | ``` 118 | 119 | If the build finds a CMake package for `Catch2` it will use that, otherwise it 120 | will download a header-only version of Catch2 v2.x. 121 | 122 | ``` 123 | cmake --build build_dir -t self_test thread_terror custom_recursive_mutex 124 | ``` 125 | 126 | Then run the built binaries: 127 | 128 | ``` 129 | ./build_dir/self_test && ./build_dir/thread_terror && ./build_dir/custom_recursive_mutex 130 | ``` 131 | 132 | # How to contribute 133 | 134 | Contributions are most welcome. For new functionality, please file an issue as 135 | an enhancement request first, to get a discussion going about how to best 136 | implement it. Also for bugfixes, it is good to file an issue, so that others can 137 | see what the problem is and when it's solved. Internal changes are normally not 138 | mentioned in the ChangeLog - it should typically reflect what a user can see 139 | (however, performance improvements and silencing warnings are visible for 140 | users.) Feel free to add your name to the copyright blurb. 141 | 142 | |Change | PR to | 143 | |-----------------------------|----------------| 144 | |Documentation |master branch | 145 | |Trivial bugfixes |master branch | 146 | |Non trivial bugfixes |develop branch | 147 | |Simple new functionality |develop branch | 148 | |Non-trivial new functionality|new topic branch| 149 | 150 | # Compiler compatibility 151 | 152 | Trompeloeil is known to work with: 153 | 154 | - GCC [4.8.4](docs/Backward.md#gxx48x_limitations)+, 4.9.3+, 5, 6, 7, 8, 9, 10, 11, 12, 13 155 | - Clang 3.5, 3.6, 3.7, 3.8, 3.9, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 156 | - Visual Studio 2015, 2017, 2019 157 | 158 | Latest patch level releases are assumed in the versions listed above. 159 | 160 | Further details on C++11 support, platform and library limitations, may 161 | be found in 162 | 163 | - [Backward compatibility with earlier versions of C++](docs/Backward.md) 164 | - [Platform and library support for Trompeloeil](docs/PlatformsAndLibraries.md) 165 | 166 | # External Tools 167 | 168 | - [ReSharperC++](https://www.jetbrains.com/resharper-cpp/) extension to 169 | [VisualStudio](https://visualstudio.microsoft.com/) has a mock generator for 170 | *Trompeloeil* since [2016.2](https://blog.jetbrains.com/rscpp/2016/09/14/whats-new-in-resharper-c-2016-2/) 171 | 172 | # Videos 173 | | | | 174 | |--|--| 175 | | [![Mocking Modern C++ with Trompeloeil](https://img.youtube.com/vi/mPYNsARvTDk/mqdefault.jpg)](https://www.youtube.com/watch?v=mPYNsARvTDk)| *Mocking Modern C++ with Trompeloeil*, introduction to Trompeloeil by Björn Fahller from from from Stockholm C++ UG (34m)| [(Slides)](https://speakerdeck.com/rollbear/mocking-modern-c-plus-plus-with-trompeloeil) | 176 | | [![Using Trompeloeil, a Mocking Framework for Modern C++](https://img.youtube.com/vi/vvQ-kK4coYM/mqdefault.jpg)](https://www.youtube.com/watch?v=vvQ-kK4coYM)| *Using Trompeloeil, a Mocking Framework for Modern C++*, by Björn Fahller from NDC{Oslo} 2017 (52m) [(Slides)](https://speakerdeck.com/rollbear/ndc-oslo-using-trompeloeil-a-mocking-framework-for-modern-c-plus-plus) | 177 | | [![Using Trompeloeil, a Mocking Framework for Modern C++](https://img.youtube.com/vi/HCh6cs9nXt0/mqdefault.jpg)](https://www.youtube.com/watch?v=HCh6cs9nXt0) | *Using Trompeloeil, a Mocking Framework for Modern C++*, Detailed presentation by Björn Fahller from ACCU 2017 (1h25m) [(Slides with extra material)](https://speakerdeck.com/rollbear/using-trompeloeil-a-mocking-framework-for-modern-c-plus-plus) | 178 | | [![Packporting to the future](https://img.youtube.com/vi/KKvSVyZ4_5k/mqdefault.jpg)](https://www.youtube.com/watch?v=KKvSVyZ4_5k) | *Backporting to the Future*, Detailing the C++11 API and how it came to be, by Andrew Paxie from Pacific++ 2018 (53m) [(Slides)](https://github.com/pacificplusplus/conference/blob/master/slides-2018/backporting-to-the-future/slides.pdf) | 179 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-modernist -------------------------------------------------------------------------------- /check_errors.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Trompeloeil C++ mocking framework 5 | # 6 | # Copyright Björn Fahller 7 | # 8 | # Use, modification and distribution is subject to the 9 | # Boost Software License, Version 1.0. (See accompanying 10 | # file LICENSE_1_0.txt or copy at 11 | # http://www.boost.org/LICENSE_1_0.txt) 12 | # 13 | # Project home: https://github.com/rollbear/trompeloeil 14 | # 15 | 16 | echo "CXX=$CXX" 17 | echo "CXXFLAGS=$CXXFLAGS" 18 | echo "CPPFLAGS=$CPPFLAGS" 19 | 20 | # Default CXXFLAGS to -std=c++14 if not set in the environment 21 | # for backward compatibility. 22 | #CXXFLAGS=${CXXFLAGS:-"-std=c++14"} 23 | 24 | #echo "CXXFLAGS is now $CXXFLAGS" 25 | 26 | failfile=`mktemp` 27 | #${CXX} --version 28 | cd compilation_errors 29 | files=`ls *.cpp` 30 | parallel ../verify_compilation_error.sh ::: $files | tee $failfile 31 | FAILURES=`cat $failfile | grep FAIL | wc -l` 32 | rm $failfile 33 | exit $FAILURES 34 | -------------------------------------------------------------------------------- /compilation_errors/address_of_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, void(int)); 21 | }; 22 | 23 | void func(const void*); 24 | 25 | int main() 26 | { 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(ANY(int)), 32 | .SIDE_EFFECT(func(&_2))); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f(ANY(int))) 37 | .SIDE_EFFECT(func(&_2)); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/any_with_array_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: array parameter type decays to pointer type for ANY 15 | 16 | #include 17 | 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK1(f, void(int [3])); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(ANY(int[3]))); 31 | 32 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | REQUIRE_CALL(obj, f(ANY(int[3]))); 35 | 36 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 37 | } 38 | -------------------------------------------------------------------------------- /compilation_errors/assign_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, void(int)); 21 | }; 22 | 23 | void func(const int&); 24 | 25 | int main() 26 | { 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(ANY(int)), 32 | .SIDE_EFFECT(_2 = 1)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f(ANY(int))) 37 | .SIDE_EFFECT(_2 = 1); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/co_return_and_co_throw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_THROW and CO_RETURN does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | }; 29 | 30 | struct MS 31 | { 32 | MAKE_MOCK0(f, task()); 33 | }; 34 | 35 | int main() 36 | { 37 | MS obj; 38 | 39 | REQUIRE_CALL(obj, f()) 40 | .CO_RETURN(0) 41 | .CO_THROW("foo"); 42 | } 43 | -------------------------------------------------------------------------------- /compilation_errors/co_return_empty_to_non_void_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Expression type does not match the coroutine promise type 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .CO_RETURN(); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/co_return_from_non_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_RETURN when return type is not a coroutine 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, int()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | REQUIRE_CALL(obj, f()) 29 | .CO_RETURN(0); 30 | } 31 | -------------------------------------------------------------------------------- /compilation_errors/co_return_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_RETURN for forbidden call does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | FORBID_CALL(obj, f()) 38 | .CO_RETURN(0); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/co_return_value_to_void_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Expression type does not match the coroutine promise type 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_void(); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .CO_RETURN(0); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/co_return_with_mismatching_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Expression type does not match the coroutine promise type 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(void*); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .CO_RETURN(0); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/co_throw_and_co_return.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_THROW and CO_RETURN does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | REQUIRE_CALL(obj, f()) 41 | .CO_THROW("foo") 42 | .CO_RETURN(0); 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/co_throw_from_non_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Do not use CO_THROW from a normal function, use THROW 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, int()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | REQUIRE_CALL(obj, f()) 29 | .CO_THROW(0); 30 | } 31 | -------------------------------------------------------------------------------- /compilation_errors/co_throw_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_THROW for forbidden call does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | FORBID_CALL(obj, f()) 41 | .CO_THROW(0); 42 | } 43 | -------------------------------------------------------------------------------- /compilation_errors/co_yield_from_non_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_YIELD when return type is not a coroutine 16 | 17 | #include 18 | 19 | 20 | struct MS 21 | { 22 | MAKE_MOCK0(f, int()); 23 | }; 24 | 25 | int main() 26 | { 27 | MS obj; 28 | 29 | REQUIRE_CALL(obj, f()) 30 | .RETURN(1) 31 | .CO_YIELD(1); 32 | 33 | } 34 | -------------------------------------------------------------------------------- /compilation_errors/co_yield_to_promise_without_yield_value.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_YIELD is incompatible with the promise type 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | REQUIRE_CALL(obj, f()) 41 | .CO_YIELD(1) 42 | .CO_RETURN(0); 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/co_yield_void.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: You cannot CO_YIELD void 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_void(); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | REQUIRE_CALL(obj, f()) 41 | .CO_YIELD() 42 | .CO_RETURN(); 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/co_yield_with_mistamching_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_YIELD is incompatible with the promise type 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | std::suspend_always yield_value(int); 27 | task get_return_object(); 28 | }; 29 | int await_resume(); 30 | }; 31 | 32 | struct MS 33 | { 34 | MAKE_MOCK0(f, task()); 35 | }; 36 | 37 | int main() 38 | { 39 | MS obj; 40 | 41 | REQUIRE_CALL(obj, f()) 42 | .CO_YIELD("foo") 43 | .CO_RETURN(0); 44 | } 45 | -------------------------------------------------------------------------------- /compilation_errors/deathwatched_with_nonvirtual_destructor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: virtual destructor is a necessity for deathwatched to work 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | auto obj = new trompeloeil::deathwatched(); 26 | } 27 | -------------------------------------------------------------------------------- /compilation_errors/dereference_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, void(int)); 21 | }; 22 | 23 | void func(const int&); 24 | 25 | int main() 26 | { 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(ANY(int)), 32 | .SIDE_EFFECT(*_2 = 1)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f(ANY(int))) 37 | .SIDE_EFFECT(*_2 = 1); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/expectation_with_unknown_func_name.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: no member named.*x 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, int(int)); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, x(1), 30 | .RETURN(_2)); 31 | 32 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | REQUIRE_CALL(obj, x(1)) 35 | .RETURN(_2); 36 | 37 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/expectation_with_wrong_cardinality.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: function.*call 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, int(int)); 21 | }; 22 | using trompeloeil::_; 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(_,_), 30 | .RETURN(_2)); 31 | 32 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | REQUIRE_CALL(obj, f(_,_)) 35 | .RETURN(_2); 36 | 37 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/expectation_with_wrong_type.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: (cannot (initialize|convert)|no known conversion).*trompeloeil::param_list_t 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK3(f, int(int,int,int)); 21 | }; 22 | using trompeloeil::_; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(1,nullptr,_), 31 | .RETURN(_2)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f(1,nullptr,_)) 36 | .RETURN(_2); 37 | 38 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/illegal_move_mock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: make a mock object movable, see: 15 | 16 | #include 17 | 18 | 19 | struct M 20 | { 21 | MAKE_MOCK1(f, void(int)); 22 | }; 23 | 24 | template 25 | T ident(T t) 26 | { 27 | return t; 28 | } 29 | 30 | int main() 31 | { 32 | auto obj = ident(M{}); 33 | } 34 | -------------------------------------------------------------------------------- /compilation_errors/in_sequence_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: IN_SEQUENCE for forbidden call does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, void()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | trompeloeil::sequence s; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .TIMES(0) 32 | .IN_SEQUENCE(s)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f()) 37 | .TIMES(0) 38 | .IN_SEQUENCE(s); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/make_mock_with_wrong_cardinality.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Function signature does not have 2 parameters 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK2(f, void(int)); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /compilation_errors/missing_co_return_from_void_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: CO_RETURN missing for coroutine 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_void(); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()); 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/missing_return_on_non_void_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: RETURN missing for non-void function 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f()); 30 | 31 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 32 | 33 | REQUIRE_CALL(obj, f()); 34 | 35 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 36 | } 37 | -------------------------------------------------------------------------------- /compilation_errors/mixed_limits_with_rt_limits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Only one RT_TIMES call limit is allowed, but it can express an interval 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | MS obj; 25 | 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | 28 | REQUIRE_CALL_V(obj, f(), 29 | .TIMES(AT_LEAST(1)) 30 | .RT_TIMES(AT_MOST(3)) 31 | .RETURN(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .TIMES(AT_LEAST(1)) 37 | .RT_TIMES(AT_MOST(3)) 38 | .RETURN(0); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/mixed_rt_limits_with_limits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Only one TIMES call limit is allowed, but it can express an interval 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | MS obj; 25 | 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | 28 | REQUIRE_CALL_V(obj, f(), 29 | .RT_TIMES(AT_LEAST(1)) 30 | .TIMES(AT_MOST(3)) 31 | .RETURN(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RT_TIMES(AT_LEAST(1)) 37 | .TIMES(AT_MOST(3)) 38 | .RETURN(0); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/multiple_co_return.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Multiple CO_RETURN does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | REQUIRE_CALL(obj, f()) 41 | .CO_RETURN(1) 42 | .CO_RETURN(2); 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/multiple_co_throw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Multiple CO_THROW does not make sense 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | void unhandled_exception(); 26 | task get_return_object(); 27 | }; 28 | int await_resume(); 29 | }; 30 | 31 | struct MS 32 | { 33 | MAKE_MOCK0(f, task()); 34 | }; 35 | 36 | int main() 37 | { 38 | MS obj; 39 | 40 | REQUIRE_CALL(obj, f()) 41 | .CO_THROW("one") 42 | .CO_THROW("two"); 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/multiple_late_return_on_non_void_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple RETURN does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | int n; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .LR_SIDE_EFFECT(n = 1) 32 | .RETURN(1) 33 | .RETURN(2)); 34 | 35 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .LR_SIDE_EFFECT(n = 1) 39 | .RETURN(1) 40 | .RETURN(2); 41 | 42 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 43 | } 44 | -------------------------------------------------------------------------------- /compilation_errors/multiple_limits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Only one TIMES call limit is allowed, but it can express an interval 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | MS obj; 25 | 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | 28 | REQUIRE_CALL_V(obj, f(), 29 | .TIMES(AT_LEAST(1)) 30 | .TIMES(AT_MOST(3)) 31 | .RETURN(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .TIMES(AT_LEAST(1)) 37 | .TIMES(AT_MOST(3)) 38 | .RETURN(0); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/multiple_return_on_non_void_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple RETURN does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .RETURN(1) 31 | .RETURN(2)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(1) 37 | .RETURN(2); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/multiple_rt_limits.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Only one RT_TIMES call limit is allowed, but it can express an interval 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | MS obj; 25 | 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | 28 | REQUIRE_CALL_V(obj, f(), 29 | .RT_TIMES(AT_LEAST(1)) 30 | .RT_TIMES(AT_MOST(3)) 31 | .RETURN(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RT_TIMES(AT_LEAST(1)) 37 | .RT_TIMES(AT_MOST(3)) 38 | .RETURN(0); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/multiple_sequences.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | trompeloeil::sequence seq; 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .IN_SEQUENCE(seq) 31 | .RETURN(0) 32 | .IN_SEQUENCE(seq)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f()) 37 | .IN_SEQUENCE(seq) 38 | .RETURN(0) 39 | .IN_SEQUENCE(seq); 40 | 41 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 42 | } 43 | -------------------------------------------------------------------------------- /compilation_errors/multiple_sequences_destruction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | trompeloeil::sequence seq; 25 | MS obj; 26 | REQUIRE_DESTRUCTION(obj) 27 | .IN_SEQUENCE(seq) 28 | .IN_SEQUENCE(seq); 29 | } 30 | -------------------------------------------------------------------------------- /compilation_errors/multiple_sequences_named_destruction.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | trompeloeil::sequence seq; 25 | MS obj; 26 | auto d = NAMED_REQUIRE_DESTRUCTION(obj) 27 | .IN_SEQUENCE(seq) 28 | .IN_SEQUENCE(seq); 29 | } 30 | -------------------------------------------------------------------------------- /compilation_errors/multiple_throws.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: Multiple THROW does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .THROW(3) 31 | .THROW('a')); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .THROW(3) 37 | .THROW('a'); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/negative_limit_interval_first.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: In TIMES the first value must not exceed the second 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | trompeloeil::sequence seq; 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .RETURN(0) 31 | .TIMES(3,2)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(0) 37 | .TIMES(3,2); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/negative_limit_interval_second.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: In TIMES the first value must not exceed the second 15 | #include 16 | 17 | struct MS 18 | { 19 | MAKE_MOCK0(f, int()); 20 | }; 21 | 22 | int main() 23 | { 24 | trompeloeil::sequence seq; 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .RETURN(0) 31 | .TIMES(3,2)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(0) 37 | .TIMES(3,2); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/ptr_to_member_from_nullptr_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from a typed matcher 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | using memptr = int S::*; 21 | MAKE_MOCK0(f, memptr()); 22 | }; 23 | 24 | int main() 25 | { 26 | S s; 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | REQUIRE_CALL_V(s, f(), 29 | .RETURN(ANY(std::nullptr_t))); 30 | #else 31 | REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); 32 | #endif 33 | } 34 | -------------------------------------------------------------------------------- /compilation_errors/reference_from_duck_typed_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from a duck typed matcher 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | MAKE_MOCK0(f, bool&()); 21 | }; 22 | 23 | int main() 24 | { 25 | S s; 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | REQUIRE_CALL_V(s, f(), 28 | .RETURN(trompeloeil::eq(0))); 29 | #else 30 | REQUIRE_CALL(s, f()).RETURN(trompeloeil::eq(0)); 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /compilation_errors/reference_from_nullptr_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from a typed matcher 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | MAKE_MOCK0(f, void*&()); 21 | }; 22 | 23 | int main() 24 | { 25 | S s; 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | REQUIRE_CALL_V(s, f(), 28 | .RETURN(ANY(std::nullptr_t))); 29 | #else 30 | REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /compilation_errors/reference_from_wildcard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from wildcard 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | MAKE_MOCK0(f, int&()); 21 | }; 22 | 23 | int main() 24 | { 25 | S s; 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | REQUIRE_CALL_V(s, f(), 28 | .RETURN(trompeloeil::_)); 29 | #else 30 | REQUIRE_CALL(s, f()).RETURN(trompeloeil::_); 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /compilation_errors/return_address_of_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, const void*(int)); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(ANY(int)), 30 | .RETURN(&_2)); 31 | 32 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | REQUIRE_CALL(obj, f(ANY(int))) 35 | .RETURN(&_2); 36 | 37 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/return_and_throw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: THROW and RETURN does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .RETURN(0) 31 | .THROW(3)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(0) 37 | .THROW(3); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/return_first_from_void_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: RETURN does not make sense for void-function 15 | 16 | #include 17 | 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, void()); 22 | }; 23 | 24 | int main() 25 | { 26 | int n; 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(), 32 | .RETURN(1) 33 | .LR_SIDE_EFFECT(n = 0)); 34 | 35 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .RETURN(1) 39 | .LR_SIDE_EFFECT(n = 0); 40 | 41 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 42 | } 43 | -------------------------------------------------------------------------------- /compilation_errors/return_from_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Do not use RETURN from a coroutine, use CO_RETURN 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .RETURN(0); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/return_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, int(int)); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(ANY(int)), 30 | .RETURN(_2)); 31 | 32 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | REQUIRE_CALL(obj, f(ANY(int))) 35 | .RETURN(_2); 36 | 37 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/return_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: RETURN for forbidden call does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | FORBID_CALL_V(obj, f(), 30 | .RETURN(0)); 31 | 32 | #else /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 33 | 34 | FORBID_CALL(obj, f()) 35 | .RETURN(0); 36 | 37 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 38 | } 39 | -------------------------------------------------------------------------------- /compilation_errors/return_second_from_void_func.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: RETURN does not make sense for void-function 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, void()); 21 | }; 22 | 23 | int main() 24 | { 25 | int n; 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .LR_SIDE_EFFECT(n = 0) 32 | .RETURN(1)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f()) 37 | .LR_SIDE_EFFECT(n = 0) 38 | .RETURN(1); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/return_value_to_ref.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: c++11 15 | // pass: RETURN non-reference from function returning reference 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, char&()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .RETURN('a')); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN('a'); 37 | 38 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/return_wrong_pointer_constness.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: c++11 15 | // pass: RETURN const\* from function returning pointer to non-const 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, char*()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .RETURN("")); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(""); 37 | 38 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/return_wrong_reference_constness.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: c++11 15 | // pass: RETURN const\& from function returning non-const reference 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, char&()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .RETURN(*"")); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(*""); 37 | 38 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/return_wrong_type_first.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: c++11 15 | // pass: RETURN value is not convertible to the return type of the function 16 | 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, int()); 22 | }; 23 | 24 | int main() 25 | { 26 | int n; 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(), 32 | .RETURN("") 33 | .LR_SIDE_EFFECT(n = 0)); 34 | 35 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .RETURN("") 39 | .LR_SIDE_EFFECT(n = 0); 40 | 41 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 42 | } 43 | -------------------------------------------------------------------------------- /compilation_errors/side_effect_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: SIDE_EFFECT for forbidden call does not make sense 15 | 16 | #include 17 | #include 18 | 19 | struct MS 20 | { 21 | MAKE_MOCK0(f, int()); 22 | }; 23 | 24 | int main() 25 | { 26 | MS obj; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | FORBID_CALL_V(obj, f(), 31 | .SIDE_EFFECT(std::cout << 3)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | FORBID_CALL(obj, f()) 36 | .SIDE_EFFECT(std::cout << 3); 37 | 38 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/throw_and_return.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: THROW and RETURN does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .THROW(3) 31 | .RETURN(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .THROW(3) 37 | .RETURN(0); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/throw_from_coroutine.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] 15 | // pass: Do not use THROW from a coroutine, use CO_THROW 16 | 17 | #include 18 | 19 | struct task 20 | { 21 | struct promise_type { 22 | std::suspend_never initial_suspend() noexcept { return {};} 23 | std::suspend_always final_suspend() noexcept { return {};} 24 | void return_value(int); 25 | }; 26 | }; 27 | 28 | struct MS 29 | { 30 | MAKE_MOCK0(f, task()); 31 | }; 32 | 33 | int main() 34 | { 35 | MS obj; 36 | 37 | REQUIRE_CALL(obj, f()) 38 | .THROW(std::runtime_error("")); 39 | } 40 | -------------------------------------------------------------------------------- /compilation_errors/throw_on_forbidden_call.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: THROW for forbidden call does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .TIMES(0) 31 | .THROW(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .TIMES(0) 37 | .THROW(0); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/times_0_after_return.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: RETURN and TIMES\(0\) does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .RETURN(0) 31 | .TIMES(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .RETURN(0) 37 | .TIMES(0); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/times_0_after_sequence.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: IN_SEQUENCE and TIMES\(0\) does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, void()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | trompeloeil::sequence s; 27 | 28 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 29 | 30 | REQUIRE_CALL_V(obj, f(), 31 | .IN_SEQUENCE(s) 32 | .TIMES(0)); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f()) 37 | .IN_SEQUENCE(s) 38 | .TIMES(0); 39 | 40 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 41 | } 42 | -------------------------------------------------------------------------------- /compilation_errors/times_0_after_side_effect.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: SIDE_EFFECT and TIMES\(0\) does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | int m = 0; 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .SIDE_EFFECT(m = 3) 31 | .TIMES(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .SIDE_EFFECT(m = 3) 37 | .TIMES(0); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/times_0_after_throw.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: THROW and TIMES\(0\) does not make sense 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | MS obj; 26 | 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | 29 | REQUIRE_CALL_V(obj, f(), 30 | .THROW(0) 31 | .TIMES(0)); 32 | 33 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 34 | 35 | REQUIRE_CALL(obj, f()) 36 | .THROW(0) 37 | .TIMES(0); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/use_illegal_argument.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: illegal argument 15 | 16 | #include 17 | 18 | struct MS 19 | { 20 | MAKE_MOCK1(f, void(int)); 21 | }; 22 | 23 | void func(const int&); 24 | 25 | int main() 26 | { 27 | MS obj; 28 | 29 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 30 | 31 | REQUIRE_CALL_V(obj, f(ANY(int)), 32 | .SIDE_EFFECT(func(_2))); 33 | 34 | #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ 35 | 36 | REQUIRE_CALL(obj, f(ANY(int))) 37 | .SIDE_EFFECT(func(_2)); 38 | 39 | #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ 40 | } 41 | -------------------------------------------------------------------------------- /compilation_errors/value_from_duck_typed_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: clang++-3 15 | // pass: value from a duck typed matcher 16 | 17 | #include 18 | 19 | struct S 20 | { 21 | MAKE_MOCK0(f, bool()); 22 | }; 23 | 24 | int main() 25 | { 26 | S s; 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | REQUIRE_CALL_V(s, f(), 29 | .RETURN(trompeloeil::eq(3))); 30 | #else 31 | REQUIRE_CALL(s, f()).RETURN(trompeloeil::eq(3)); 32 | #endif 33 | } 34 | -------------------------------------------------------------------------------- /compilation_errors/value_from_nullptr_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from a typed matcher 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | MAKE_MOCK0(f, void*()); 21 | }; 22 | 23 | int main() 24 | { 25 | S s; 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | REQUIRE_CALL_V(s, f(), 28 | .RETURN(ANY(std::nullptr_t))); 29 | #else 30 | REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /compilation_errors/value_from_typed_matcher.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // pass: value from a typed matcher 15 | 16 | #include 17 | 18 | struct S 19 | { 20 | MAKE_MOCK0(f, int()); 21 | }; 22 | 23 | int main() 24 | { 25 | S s; 26 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 27 | REQUIRE_CALL_V(s, f(), 28 | .RETURN(ANY(int))); 29 | #else 30 | REQUIRE_CALL(s, f()).RETURN(ANY(int)); 31 | #endif 32 | } 33 | -------------------------------------------------------------------------------- /compilation_errors/value_from_wildcard.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | // exception: g++-[678] 15 | // pass: value from wildcard 16 | 17 | #include 18 | 19 | struct S 20 | { 21 | MAKE_MOCK0(f, int()); 22 | }; 23 | 24 | int main() 25 | { 26 | S s; 27 | #if (TROMPELOEIL_CPLUSPLUS == 201103L) 28 | REQUIRE_CALL_V(s, f(), 29 | .RETURN(trompeloeil::_)); 30 | #else 31 | REQUIRE_CALL(s, f()).RETURN(trompeloeil::_); 32 | #endif 33 | } 34 | -------------------------------------------------------------------------------- /docs/trompeloeil_cheat_sheet.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbear/trompeloeil/2a633b923f32cebc336dc8a6a77e4c04f2238106/docs/trompeloeil_cheat_sheet.odp -------------------------------------------------------------------------------- /docs/trompeloeil_cheat_sheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbear/trompeloeil/2a633b923f32cebc336dc8a6a77e4c04f2238106/docs/trompeloeil_cheat_sheet.pdf -------------------------------------------------------------------------------- /include/boost/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | 15 | #ifndef TROMPELOEIL_BOOST_HPP_ 16 | #define TROMPELOEIL_BOOST_HPP_ 17 | 18 | #ifndef BOOST_TEST 19 | #error " must be included before " 20 | #endif 21 | 22 | #include "../trompeloeil.hpp" 23 | 24 | namespace trompeloeil 25 | { 26 | template <> 27 | inline void reporter::send( 28 | severity s, 29 | char const *file, 30 | unsigned long line, 31 | const char* msg) 32 | { 33 | std::ostringstream os; 34 | if (line != 0U) os << file << ':' << line << '\n'; 35 | auto text = os.str() + msg; 36 | if (s == severity::fatal) 37 | BOOST_FAIL(text); 38 | else 39 | BOOST_ERROR(text); 40 | } 41 | } 42 | 43 | 44 | #endif //TROMPELOEIL_BOOST_HPP_ 45 | -------------------------------------------------------------------------------- /include/cantata/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2023 5 | * Copyright Andreas Schätti 2023 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy at 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_CANTATA_HPP_ 16 | #define TROMPELOEIL_CANTATA_HPP_ 17 | 18 | #ifndef INCLUDED_CANTPP_H 19 | #error " must be included before " 20 | #endif 21 | 22 | #include "../trompeloeil.hpp" 23 | 24 | namespace trompeloeil 25 | { 26 | template <> 27 | inline void reporter::send( 28 | severity s, 29 | char const *file, 30 | unsigned long line, 31 | const char* msg) 32 | { 33 | std::ostringstream os; 34 | if (line != 0U) os << file << ':' << line << '\n'; 35 | auto text = os.str() + msg; 36 | if (s == severity::fatal) 37 | { 38 | text += "\nseverity: fatal\n"; 39 | CHECK_NAMED(text.c_str(), true, false); 40 | throw expectation_violation("severity: fatal"); 41 | } 42 | else 43 | { 44 | CHECK_NAMED(text.c_str(), true, false); 45 | } 46 | } 47 | 48 | template <> 49 | inline void reporter::sendOk( 50 | const char* trompeloeil_mock_calls_done_correctly) 51 | { 52 | CHECK_NAMED(trompeloeil_mock_calls_done_correctly, true, true); 53 | } 54 | } 55 | 56 | #endif //TROMPELOEIL_CANTATA_HPP_ 57 | -------------------------------------------------------------------------------- /include/catch2/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * Copyright Tore Martin Hagen 2019 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy at 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | 16 | #ifndef TROMPELOEIL_CATCH2_HPP_ 17 | #define TROMPELOEIL_CATCH2_HPP_ 18 | 19 | #if !((defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CHECK)) \ 20 | || (!defined(CATCH_CONFIG_PREFIX_ALL) && defined(CHECK))) 21 | #error "Catch2 macros must be defined before including " 22 | #endif 23 | 24 | #include "../trompeloeil.hpp" 25 | 26 | namespace trompeloeil 27 | { 28 | template <> 29 | inline void reporter::send( 30 | severity s, 31 | const char* file, 32 | unsigned long line, 33 | const char* msg) 34 | { 35 | std::ostringstream os; 36 | if (line) os << file << ':' << line << '\n'; 37 | os << msg; 38 | auto failure = os.str(); 39 | if (s == severity::fatal) 40 | { 41 | #ifdef CATCH_CONFIG_PREFIX_ALL 42 | CATCH_FAIL(failure); 43 | #else 44 | FAIL(failure); 45 | #endif 46 | } 47 | else 48 | { 49 | #ifdef CATCH_CONFIG_PREFIX_ALL 50 | CATCH_CAPTURE(failure); 51 | CATCH_CHECK(failure.empty()); 52 | #else 53 | CAPTURE(failure); 54 | CHECK(failure.empty()); 55 | #endif 56 | } 57 | } 58 | 59 | template <> 60 | inline void reporter::sendOk( 61 | const char* trompeloeil_mock_calls_done_correctly) 62 | { 63 | #ifdef CATCH_CONFIG_PREFIX_ALL 64 | CATCH_REQUIRE(trompeloeil_mock_calls_done_correctly != 0); 65 | #else 66 | REQUIRE(trompeloeil_mock_calls_done_correctly != 0); 67 | #endif 68 | } 69 | } 70 | 71 | 72 | #endif //TROMPELOEIL_CATCH2_HPP_ 73 | -------------------------------------------------------------------------------- /include/criterion/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * Copyright Etienne Barbier 2020 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy at 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | 16 | #ifndef TROMPELOEIL_CRITERION_HPP_ 17 | #define TROMPELOEIL_CRITERION_HPP_ 18 | 19 | #ifndef CRITERION_H_ 20 | #error " must be included before " 21 | #endif 22 | 23 | #include "../trompeloeil.hpp" 24 | 25 | namespace trompeloeil 26 | { 27 | template <> 28 | inline void reporter::send( 29 | severity s, 30 | char const *file, 31 | unsigned long line, 32 | const char* msg) 33 | { 34 | struct criterion_assert_stats cr_stat__; 35 | cr_stat__.passed = false; 36 | cr_stat__.file = file; 37 | cr_stat__.line = line; 38 | cr_stat__.message = msg; 39 | if (s == severity::fatal) 40 | { 41 | criterion_send_assert(&cr_stat__); 42 | CR_FAIL_ABORT_(); 43 | } 44 | else 45 | { 46 | criterion_send_assert(&cr_stat__); 47 | CR_FAIL_CONTINUES_(); 48 | } 49 | } 50 | 51 | template <> 52 | inline void reporter::sendOk( 53 | const char* trompeloeil_mock_calls_done_correctly) 54 | { 55 | cri_asserts_passed_incr(); 56 | } 57 | } 58 | 59 | 60 | 61 | #endif //TROMPELOEIL_CRITERION_HPP_ 62 | -------------------------------------------------------------------------------- /include/crpcut/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | 15 | #ifndef TROMPELOEIL_CRPCUT_HPP_ 16 | #define TROMPELOEIL_CRPCUT_HPP_ 17 | 18 | #ifndef CRPCUT_HERE 19 | #error " must be included before " 20 | #endif 21 | 22 | #include "../trompeloeil.hpp" 23 | 24 | namespace trompeloeil 25 | { 26 | template <> 27 | inline void reporter::send( 28 | severity, 29 | char const *file, 30 | unsigned long line, 31 | const char* msg) 32 | { 33 | std::ostringstream os; 34 | os << file << ':' << line; 35 | auto loc = os.str(); 36 | auto location = line == 0U 37 | ? ::crpcut::crpcut_test_monitor::current_test()->get_location() 38 | : ::crpcut::datatypes::fixed_string::make(loc.c_str(), loc.length()); 39 | ::crpcut::comm::report(::crpcut::comm::exit_fail, 40 | std::ostringstream(msg), 41 | location); 42 | } 43 | } 44 | 45 | 46 | #endif //TROMPELOEIL_CRPCUT_HPP_ 47 | -------------------------------------------------------------------------------- /include/cxxtest/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * Copyright (C) 2019 Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy at 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | 16 | #ifndef TROMPELOEIL_CXXTEST_HPP_ 17 | #define TROMPELOEIL_CXXTEST_HPP_ 18 | 19 | #ifndef CXXTEST_FLAGS 20 | #error " must be included before " 21 | #endif 22 | 23 | #include "../trompeloeil.hpp" 24 | 25 | #include 26 | #include 27 | 28 | namespace trompeloeil 29 | { 30 | template <> 31 | inline void reporter::send( 32 | severity s, 33 | const char* file, 34 | unsigned long line, 35 | const char* msg) 36 | { 37 | std::ostringstream os; 38 | if (line) os << file << ':' << line << '\n'; 39 | os << msg; 40 | auto failure = os.str(); 41 | if (s == severity::fatal) 42 | { 43 | // Must not return normally i.e. must throw, abort or terminate. 44 | TS_FAIL(failure); 45 | } 46 | else 47 | { 48 | // nonfatal: violation occurred during stack rollback. 49 | // Must not throw an exception. 50 | TS_WARN(failure); 51 | } 52 | } 53 | } /* namespace trompeloeil */ 54 | 55 | #endif //TROMPELOEIL_CXXTEST_HPP_ 56 | -------------------------------------------------------------------------------- /include/doctest/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2022 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | 15 | #ifndef TROMPELOEIL_DOCTEST_HPP_ 16 | #define TROMPELOEIL_DOCTEST_HPP_ 17 | 18 | #ifndef DOCTEST_VERSION_MAJOR 19 | #error " must be included before " 20 | #endif 21 | 22 | #include "../trompeloeil.hpp" 23 | 24 | namespace trompeloeil 25 | { 26 | template <> 27 | inline void reporter::send( 28 | severity s, 29 | const char* file, 30 | unsigned long line, 31 | const char* msg) 32 | { 33 | doctest::String msgstr(msg); 34 | auto f = line ? file : "[file/line unavailable]"; 35 | if (s == severity::fatal) 36 | { 37 | DOCTEST_ADD_FAIL_AT(f, line, msgstr); 38 | } 39 | else 40 | { 41 | DOCTEST_ADD_FAIL_CHECK_AT(f, line, msgstr); 42 | } 43 | } 44 | 45 | template <> 46 | inline void reporter::sendOk( 47 | const char* trompeloeil_mock_calls_done_correctly) 48 | { 49 | #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 50 | DOCTEST_REQUIRE_UNARY(trompeloeil_mock_calls_done_correctly); 51 | #else 52 | DOCTEST_REQUIRE_NE(doctest::String(trompeloeil_mock_calls_done_correctly), ""); 53 | #endif 54 | } 55 | } 56 | 57 | 58 | #endif //TROMPELOEIL_DOCTEST_HPP_ 59 | -------------------------------------------------------------------------------- /include/gtest/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2019 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy at 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | 15 | #ifndef TROMPELOEIL_GTEST_HPP_ 16 | #define TROMPELOEIL_GTEST_HPP_ 17 | 18 | #ifndef GTEST_TEST 19 | #error " must be included before " 20 | #endif 21 | 22 | #include "../trompeloeil.hpp" 23 | 24 | namespace trompeloeil 25 | { 26 | template <> 27 | inline void reporter::send( 28 | severity s, 29 | char const *file, 30 | unsigned long line, 31 | const char* msg) 32 | { 33 | if (s == severity::fatal) 34 | { 35 | std::ostringstream os; 36 | if (line != 0U) 37 | { 38 | os << file << ':' << line << '\n'; 39 | } 40 | throw expectation_violation(os.str() + msg); 41 | } 42 | 43 | ADD_FAILURE_AT(file, line) << msg; 44 | } 45 | } 46 | 47 | 48 | #endif //TROMPELOEIL_GTEST_HPP_ 49 | -------------------------------------------------------------------------------- /include/trompeloeil.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 2014-2021 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy atl 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | #ifndef TROMPELOEIL_HPP_ 15 | #define TROMPELOEIL_HPP_ 16 | 17 | 18 | // trompe l'oeil noun (Concise Encyclopedia) 19 | // Style of representation in which a painted object is intended 20 | // to deceive the viewer into believing it is the object itself... 21 | 22 | // project home: https://github.com/rollbear/trompeloeil 23 | 24 | 25 | // Deficiencies and missing features 26 | // * Mocking function templates is not supported 27 | // * If a macro kills a kitten, this threatens extinction of all felines! 28 | 29 | #include "trompeloeil/mock.hpp" 30 | #include "trompeloeil/lifetime.hpp" 31 | #include "trompeloeil/matcher.hpp" 32 | #include "trompeloeil/matcher/any.hpp" 33 | #include "trompeloeil/matcher/compare.hpp" 34 | #include "trompeloeil/matcher/deref.hpp" 35 | #if TROMPELOEIL_CPLUSPLUS >= 201402L 36 | #include "trompeloeil/matcher/member_is.hpp" 37 | #endif 38 | #include "trompeloeil/matcher/not.hpp" 39 | #if TROMPELOEIL_CPLUSPLUS >= 201402L 40 | #include "trompeloeil/matcher/range.hpp" 41 | #endif 42 | #include "trompeloeil/matcher/re.hpp" 43 | #include "trompeloeil/matcher/set_predicate.hpp" 44 | #include "trompeloeil/sequence.hpp" 45 | #include "trompeloeil/stream_tracer.hpp" 46 | #ifdef __cpp_impl_coroutine 47 | #include "trompeloeil/coro.hpp" 48 | #endif 49 | #endif // include guard 50 | -------------------------------------------------------------------------------- /include/trompeloeil/cpp11_shenanigans.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_CPP11_SHENANIGANS_HPP 16 | #define TROMPELOEIL_CPP11_SHENANIGANS_HPP 17 | 18 | namespace trompeloeil { 19 | namespace detail 20 | { 21 | template 22 | struct unwrap_type 23 | { 24 | using type = T; 25 | }; 26 | template 27 | struct unwrap_type> 28 | { 29 | using type = T&; 30 | }; 31 | 32 | /* Implement C++14 features using only C++11 entities. */ 33 | 34 | /* */ 35 | 36 | /* Implementation of make_unique is from 37 | * 38 | * Stephan T. Lavavej, "make_unique (Revision 1)," 39 | * ISO/IEC JTC1 SC22 WG21 N3656, 18 April 2013. 40 | * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3656.htm 41 | * Accessed: 14 June 2017 42 | * 43 | * Renamed types to avoid the use of reserved identifiers. 44 | */ 45 | template 46 | struct unique_if 47 | { 48 | typedef std::unique_ptr single_object; 49 | }; 50 | 51 | template 52 | struct unique_if 53 | { 54 | typedef std::unique_ptr unknown_bound; 55 | }; 56 | 57 | template 58 | struct unique_if 59 | { 60 | typedef void known_bound; 61 | }; 62 | 63 | template 64 | typename unique_if::single_object 65 | make_unique(Args&&... args) 66 | { 67 | return std::unique_ptr(new T(std::forward(args)...)); 68 | } 69 | 70 | template 71 | typename unique_if::unknown_bound 72 | make_unique(size_t n) 73 | { 74 | typedef typename std::remove_extent::type U; 75 | return std::unique_ptr(new U[n]()); 76 | } 77 | 78 | template 79 | typename unique_if::known_bound 80 | make_unique(Args&&...) = delete; 81 | 82 | /* */ 83 | 84 | /* The implementation of these is from 85 | * 86 | * Walter E. Brown, "TransformationTraits Redux, v2," 87 | * ISO/IEC JTC1 SC22 WG21 N3655, 18 April 2013. 88 | * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3655.pdf 89 | * Accessed: 2 November 2017 90 | * 91 | * Minor changes to capitalize template parameter `bool B` has been made. 92 | * 93 | * See also: 94 | * http://en.cppreference.com/w/cpp/types/conditional 95 | * http://en.cppreference.com/w/cpp/types/decay 96 | * http://en.cppreference.com/w/cpp/types/enable_if 97 | * http://en.cppreference.com/w/cpp/types/remove_pointer 98 | * http://en.cppreference.com/w/cpp/types/remove_reference 99 | * Accessed: 17 May 2017 100 | */ 101 | template 102 | using conditional_t = typename std::conditional::type; 103 | 104 | template 105 | using decay_t = typename std::decay::type; 106 | 107 | template 108 | using enable_if_t = typename std::enable_if::type; 109 | 110 | template 111 | using remove_pointer_t = typename std::remove_pointer::type; 112 | 113 | template 114 | using remove_reference_t = typename std::remove_reference::type; 115 | 116 | /* */ 117 | 118 | /* This implementation of exchange is from 119 | * 120 | * Jeffrey Yasskin, "exchange() utility function, revision 3," 121 | * ISO/IEC JTC1 SC22 WG21 N3688, 19 April 2013. 122 | * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3668.html 123 | * Accessed: 2 November 2017 124 | * 125 | * See also: 126 | * http://en.cppreference.com/w/cpp/utility/exchange 127 | * Accessed: 17 May 2017 128 | */ 129 | template 130 | inline 131 | T 132 | exchange( 133 | T& obj, 134 | U&& new_value) 135 | { 136 | T old_value = std::move(obj); 137 | obj = std::forward(new_value); 138 | return old_value; 139 | } 140 | 141 | /* integer_sequence and index_sequence implementations are from 142 | * 143 | * Jonathan Wakely, "Compile-time integer sequences," 144 | * ISO/IEC JTC1 SC22 WG21 N3658, 18 April 2013. 145 | * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html 146 | * Accessed: 2 November 2017 147 | * 148 | * See also: 149 | * http://en.cppreference.com/w/cpp/utility/integer_sequence 150 | * Accessed: 17 May 2017 151 | */ 152 | template 153 | struct integer_sequence 154 | { 155 | // Replaces a typedef used in the definition found in N3658. 156 | using value_type = T; 157 | 158 | static constexpr size_t size() noexcept 159 | { 160 | return sizeof...(I); 161 | } 162 | }; 163 | 164 | template 165 | using index_sequence = integer_sequence; 166 | 167 | /* This implementation of make_integer_sequence is from boost/mp11, 168 | * 169 | * Copyright 2015, 2017 Peter Dimov 170 | * 171 | * Distributed under the Boost Software License, Version 1.0. 172 | * 173 | * Implemented here: 174 | * 175 | * https://github.com/pdimov/mp11/blob/master/include/boost/ 176 | * integer_sequence.hpp 177 | * Accessed: 17 May 2017 178 | * 179 | * (now missing) and here: 180 | * 181 | * https://github.com/boostorg/mp11/blob/develop/include/boost/ 182 | * mp11/integer_sequence.hpp 183 | * Accessed: 13 August 2017 184 | */ 185 | namespace impl 186 | { 187 | // iseq_if_c 188 | template 189 | struct iseq_if_c_impl; 190 | 191 | template 192 | struct iseq_if_c_impl 193 | { 194 | using type = T; 195 | }; 196 | 197 | template 198 | struct iseq_if_c_impl 199 | { 200 | using type = E; 201 | }; 202 | 203 | template 204 | using iseq_if_c = typename iseq_if_c_impl::type; 205 | 206 | // iseq_identity 207 | template 208 | struct iseq_identity 209 | { 210 | using type = T; 211 | }; 212 | 213 | template 214 | struct append_integer_sequence; 215 | 216 | template 217 | struct append_integer_sequence, integer_sequence> 218 | { 219 | using type = integer_sequence; 220 | }; 221 | 222 | template 223 | struct make_integer_sequence_impl; 224 | 225 | template 226 | struct make_integer_sequence_impl_ 227 | { 228 | private: 229 | 230 | static_assert( N >= 0, "make_integer_sequence: N must not be negative" ); 231 | 232 | static T const M = N / 2; 233 | static T const R = N % 2; 234 | 235 | using S1 = typename make_integer_sequence_impl::type; 236 | using S2 = typename append_integer_sequence::type; 237 | using S3 = typename make_integer_sequence_impl::type; 238 | using S4 = typename append_integer_sequence::type; 239 | 240 | public: 241 | 242 | using type = S4; 243 | }; 244 | 245 | template 246 | struct make_integer_sequence_impl: 247 | iseq_if_c>, 249 | iseq_if_c>, 251 | make_integer_sequence_impl_>> 252 | { 253 | }; 254 | } 255 | 256 | template 257 | using make_integer_sequence = typename impl::make_integer_sequence_impl::type; 258 | 259 | template 260 | using make_index_sequence = make_integer_sequence; 261 | 262 | template 263 | using index_sequence_for = make_index_sequence; 264 | 265 | } /* namespace detail */ 266 | 267 | } 268 | 269 | #define TROMPELOEIL_WITH_(capture, arg_s, ...) \ 270 | template action( \ 271 | arg_s, \ 272 | [capture] \ 273 | (typename trompeloeil_e_t::trompeloeil_call_params_type_t const& trompeloeil_x)\ 274 | { \ 275 | auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ 276 | auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ 277 | auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ 278 | auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ 279 | auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ 280 | auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ 281 | auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ 282 | auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ 283 | auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ 284 | auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ 285 | auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ 286 | auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ 287 | auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ 288 | auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ 289 | auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ 290 | ::trompeloeil::ignore( \ 291 | _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ 292 | return __VA_ARGS__; \ 293 | }) 294 | 295 | #define TROMPELOEIL_SIDE_EFFECT_(capture, ...) \ 296 | template action( \ 297 | [capture] \ 298 | (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ 299 | { \ 300 | auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ 301 | auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ 302 | auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ 303 | auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ 304 | auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ 305 | auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ 306 | auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ 307 | auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ 308 | auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ 309 | auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ 310 | auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ 311 | auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ 312 | auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ 313 | auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ 314 | auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ 315 | ::trompeloeil::ignore( \ 316 | _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ 317 | __VA_ARGS__; \ 318 | }) 319 | 320 | #define TROMPELOEIL_RETURN_(capture, ...) \ 321 | template action( \ 322 | [capture] \ 323 | (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ 324 | -> typename trompeloeil_e_t::trompeloeil_return_of_t \ 325 | { \ 326 | auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ 327 | auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ 328 | auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ 329 | auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ 330 | auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ 331 | auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ 332 | auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ 333 | auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ 334 | auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ 335 | auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ 336 | auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ 337 | auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ 338 | auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ 339 | auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ 340 | auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ 341 | ::trompeloeil::ignore( \ 342 | _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ 343 | return ::trompeloeil::decay_return_type(__VA_ARGS__); \ 344 | }) 345 | #define TROMPELOEIL_THROW_(capture, ...) \ 346 | template action( \ 347 | [capture] \ 348 | (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ 349 | { \ 350 | auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ 351 | auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ 352 | auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ 353 | auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ 354 | auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ 355 | auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ 356 | auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ 357 | auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ 358 | auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ 359 | auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ 360 | auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ 361 | auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ 362 | auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ 363 | auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ 364 | auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ 365 | ::trompeloeil::ignore( \ 366 | _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ 367 | throw __VA_ARGS__; \ 368 | }) 369 | 370 | #endif //TROMPELOEIL_CPP11_SHENANIGANS_HPP 371 | -------------------------------------------------------------------------------- /include/trompeloeil/lifetime.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_LIFETIME_HPP 16 | #define TROMPELOEIL_LIFETIME_HPP 17 | 18 | #ifndef TROMPELOEIL_MOCK_HPP_ 19 | #include "mock.hpp" 20 | #endif 21 | 22 | #if defined(__cxx_rtti) || defined(__GXX_RTTI) || defined(_CPPRTTI) 23 | # define TROMPELOEIL_TYPE_ID_NAME(x) typeid(x).name() 24 | #else 25 | # define TROMPELOEIL_TYPE_ID_NAME(x) "object" 26 | #endif 27 | 28 | namespace trompeloeil 29 | { 30 | struct lifetime_monitor; 31 | 32 | template 33 | class deathwatched : public T 34 | { 35 | static_assert(std::has_virtual_destructor::value, 36 | "virtual destructor is a necessity for deathwatched to work"); 37 | public: 38 | template ::value>> 40 | deathwatched( 41 | U&& ...u) 42 | noexcept(noexcept(T(std::declval()...))) 43 | : T(std::forward(u)...) 44 | {} 45 | 46 | ~deathwatched() override; 47 | 48 | trompeloeil::lifetime_monitor*& 49 | trompeloeil_expect_death( 50 | trompeloeil::lifetime_monitor* monitor) 51 | const 52 | noexcept 53 | { 54 | auto lock = get_lock(); 55 | trompeloeil_lifetime_monitor = monitor; 56 | return trompeloeil_lifetime_monitor.leak(); 57 | } 58 | private: 59 | mutable null_on_move trompeloeil_lifetime_monitor; 60 | }; 61 | 62 | struct lifetime_monitor : public expectation 63 | { 64 | template 65 | lifetime_monitor( 66 | ::trompeloeil::deathwatched const &obj, 67 | char const* obj_name_, 68 | char const* invocation_name_, 69 | char const* call_name_, 70 | location loc_) 71 | noexcept 72 | : object_monitor(obj.trompeloeil_expect_death(this)) 73 | , loc(loc_) 74 | , object_name(obj_name_) 75 | , invocation_name(invocation_name_) 76 | , call_name(call_name_) 77 | { 78 | } 79 | 80 | bool is_satisfied() const noexcept override 81 | { 82 | return died; 83 | } 84 | 85 | bool is_saturated() const noexcept override 86 | { 87 | return died; 88 | } 89 | 90 | lifetime_monitor(lifetime_monitor const&) = delete; 91 | 92 | ~lifetime_monitor() override 93 | { 94 | auto lock = get_lock(); 95 | if (!died) 96 | { 97 | std::ostringstream os; 98 | os << "Object " << object_name << " is still alive"; 99 | send_report(severity::nonfatal, loc, os.str()); 100 | object_monitor = nullptr; // prevent its death poking this cadaver 101 | } 102 | } 103 | 104 | lifetime_monitor& operator=(lifetime_monitor const&) = delete; 105 | 106 | void 107 | notify() 108 | noexcept 109 | { 110 | died = true; 111 | sequences->validate(severity::nonfatal, call_name, loc); 112 | 113 | sequences->increment_call(); 114 | if (sequences->is_satisfied()) 115 | { 116 | sequences->retire_predecessors(); 117 | } 118 | } 119 | 120 | template 121 | void 122 | set_sequence( 123 | T&& ... t) 124 | { 125 | using handler = sequence_handler; 126 | auto seq = detail::make_unique(*sequences, 127 | invocation_name, 128 | loc, 129 | std::forward(t)...); 130 | sequences = std::move(seq); 131 | } 132 | private: 133 | atomic died{false}; 134 | lifetime_monitor *&object_monitor; 135 | location loc; 136 | char const *object_name; 137 | char const *invocation_name; 138 | char const *call_name; 139 | std::unique_ptr sequences = detail::make_unique>(); 140 | }; 141 | 142 | template 143 | deathwatched::~deathwatched() 144 | { 145 | auto lock = get_lock(); 146 | if (trompeloeil_lifetime_monitor) 147 | { 148 | trompeloeil_lifetime_monitor->notify(); 149 | return; 150 | } 151 | std::ostringstream os; 152 | os << "Unexpected destruction of " 153 | << TROMPELOEIL_TYPE_ID_NAME(T) << "@" << this << '\n'; 154 | send_report(severity::nonfatal, 155 | location{}, 156 | os.str()); 157 | } 158 | 159 | template 160 | struct lifetime_monitor_modifier : std::unique_ptr 161 | { 162 | explicit 163 | lifetime_monitor_modifier( 164 | std::unique_ptr&& p) 165 | noexcept 166 | : unique_ptr(std::move(p)) 167 | {} 168 | 169 | template 170 | auto 171 | in_sequence(T&& ... t) 172 | -> lifetime_monitor_modifier 173 | { 174 | static_assert(!b, 175 | "Multiple IN_SEQUENCE does not make sense." 176 | " You can list several sequence objects at once"); 177 | std::unique_ptr& m = *this; 178 | m->set_sequence(std::forward(t)...); 179 | return lifetime_monitor_modifier{std::move(m)}; 180 | } 181 | }; 182 | 183 | struct lifetime_monitor_releaser 184 | { 185 | template 186 | std::unique_ptr 187 | operator+( 188 | lifetime_monitor_modifier&& m) 189 | const 190 | { 191 | return std::move(m); 192 | } 193 | }; 194 | 195 | } 196 | 197 | #define TROMPELOEIL_REQUIRE_DESTRUCTION(obj) \ 198 | TROMPELOEIL_REQUIRE_DESTRUCTION_(obj, #obj) 199 | 200 | #define TROMPELOEIL_REQUIRE_DESTRUCTION_(obj, obj_s) \ 201 | std::unique_ptr \ 202 | TROMPELOEIL_CONCAT(trompeloeil_death_monitor_, __LINE__) \ 203 | = TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_(,obj, obj_s) 204 | 205 | #define TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION(obj) \ 206 | TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_("NAMED_", obj, #obj) 207 | 208 | #define TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_(prefix, obj, obj_s) \ 209 | trompeloeil::lifetime_monitor_releaser{} + \ 210 | trompeloeil::lifetime_monitor_modifier{ \ 211 | ::trompeloeil::detail::make_unique( \ 212 | obj, \ 213 | obj_s, \ 214 | prefix "REQUIRE_DESTRUCTION(" obj_s ")", \ 215 | "destructor for " obj_s, \ 216 | ::trompeloeil::location{__FILE__, \ 217 | static_cast(__LINE__)}) \ 218 | } 219 | 220 | #ifndef TROMPELOEIL_LONG_MACROS 221 | #define REQUIRE_DESTRUCTION TROMPELOEIL_REQUIRE_DESTRUCTION 222 | #define NAMED_REQUIRE_DESTRUCTION TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION 223 | #endif 224 | 225 | #endif //TROMPELOEIL_LIFETIME_HPP 226 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_MATCHER_HPP 16 | #define TROMPELOEIL_MATCHER_HPP 17 | 18 | #ifndef TROMPELOEIL_MOCK_HPP_ 19 | #include "mock.hpp" 20 | #endif 21 | 22 | namespace trompeloeil 23 | { 24 | template 25 | struct typed_matcher : matcher 26 | { 27 | template 28 | operator T() const { 29 | static_assert(b, 30 | "Getting a value from a typed matcher is not allowed.\n" 31 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 32 | "and https://github.com/rollbear/trompeloeil/issues/290"); 33 | return {}; 34 | } 35 | }; 36 | 37 | template <> 38 | struct typed_matcher : matcher 39 | { 40 | template < 41 | typename T, 42 | typename = decltype(std::declval() == nullptr) 43 | > 44 | operator T&&() const 45 | { 46 | static_assert(std::is_same{}, 47 | "Getting a value from a typed matcher is not allowed.\n" 48 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 49 | "https://github.com/rollbear/trompeloeil/issues/290"); 50 | return *this; 51 | } 52 | 53 | template < 54 | typename T, 55 | typename = decltype(std::declval() == nullptr) 56 | > 57 | operator T&()const volatile 58 | { 59 | static_assert(std::is_same{}, 60 | "Getting a value from a typed matcher is not allowed.\n" 61 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 62 | "and https://github.com/rollbear/trompeloeil/issues/290"); 63 | return *this; 64 | } 65 | 66 | template 67 | operator T C::*() const 68 | { 69 | static_assert(std::is_same{}, 70 | "Getting a value from a typed matcher is not allowed.\n" 71 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 72 | "and https://github.com/rollbear/trompeloeil/issues/290"); 73 | return *this; 74 | } 75 | }; 76 | 77 | template 78 | class duck_typed_matcher : public matcher 79 | { 80 | public: 81 | #if (!TROMPELOEIL_GCC) || \ 82 | (TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 40900) 83 | 84 | // g++ 4.8 gives a "conversion from to is ambiguous" error 85 | // if this operator is defined. 86 | template < 87 | typename V, 88 | typename = detail::enable_if_t{}>, 89 | typename = invoke_result_type 90 | > 91 | operator V&&() const { 92 | #if !TROMPELOEIL_CLANG || TROMPELOEIL_CLANG_VERSION >= 40000 93 | // clang 3.x instantiates the function even when it's only used 94 | // for compile time signature checks and never actually called. 95 | static_assert(std::is_same{}, 96 | "Getting a value from a duck typed matcher is not allowed.\n" 97 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 98 | "and https://github.com/rollbear/trompeloeil/issues/290"); 99 | #endif 100 | return *this; 101 | } 102 | 103 | #endif 104 | 105 | template < 106 | typename V, 107 | typename = detail::enable_if_t{}>, 108 | typename = invoke_result_type 109 | > 110 | operator V&() const volatile 111 | { 112 | static_assert(std::is_same{}, 113 | "Getting a value from a duck typed matcher is not allowed.\n" 114 | "See https://github.com/rollbear/trompeloeil/issues/270\n" 115 | "and https://github.com/rollbear/trompeloeil/issues/290"); 116 | 117 | return *this; 118 | } 119 | }; 120 | 121 | template 122 | struct matcher_kind 123 | { 124 | using type = typed_matcher; 125 | }; 126 | 127 | template 128 | struct matcher_kind 129 | { 130 | using type = duck_typed_matcher; 131 | }; 132 | 133 | template 134 | using matcher_kind_t = 135 | typename matcher_kind::type; 136 | 137 | template 138 | class predicate_matcher 139 | : private Predicate 140 | , private Printer 141 | , public MatcherType 142 | { 143 | public: 144 | template 145 | constexpr 146 | predicate_matcher( 147 | Predicate&& pred, 148 | Printer&& printer, 149 | U&& ... v) 150 | noexcept(noexcept(std::tuple(std::declval()...)) && noexcept(Predicate(std::declval())) && noexcept(Printer(std::declval()))) 151 | : Predicate(std::move(pred)) 152 | , Printer(std::move(printer)) 153 | , value(std::forward(v)...) 154 | {} 155 | 156 | template 157 | constexpr 158 | bool 159 | matches( 160 | V&& v) 161 | const 162 | noexcept(noexcept(std::declval()(std::declval(), std::declval()...))) 163 | { 164 | return matches_(std::forward(v), detail::make_index_sequence{}); 165 | } 166 | 167 | friend 168 | std::ostream& 169 | operator<<( 170 | std::ostream& os, 171 | predicate_matcher const& v) 172 | { 173 | return v.print_(os, detail::make_index_sequence{}); 174 | } 175 | private: 176 | // The below function call operator must be declared to 177 | // work around gcc bug 78446 178 | // 179 | // For some reason microsoft compiler from VS2015 update 3 180 | // requires the function call operator to be private to avoid 181 | // ambiguities. 182 | template 183 | void operator()(U&&...) const = delete; 184 | 185 | template 186 | bool matches_(V&& v, detail::index_sequence) const 187 | { 188 | return Predicate::operator()(std::forward(v), std::get(value)...); 189 | } 190 | 191 | template 192 | std::ostream& print_(std::ostream& os_, detail::index_sequence) const 193 | { 194 | Printer::operator()(os_, std::get(value)...); 195 | return os_; 196 | } 197 | 198 | std::tuple value; 199 | }; 200 | 201 | template 202 | using make_matcher_return = 203 | predicate_matcher...>, 206 | detail::decay_t...>; 207 | 208 | 209 | template 210 | inline 211 | make_matcher_return 212 | make_matcher(Predicate pred, Printer print, T&& ... t) 213 | { 214 | return {std::move(pred), std::move(print), std::forward(t)...}; 215 | } 216 | 217 | 218 | 219 | } 220 | 221 | #endif //TROMPELOEIL_MATCHER_HPP 222 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/any.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_ANY_HPP 16 | #define TROMPELOEIL_ANY_HPP 17 | 18 | #ifndef TROMPELOEIL_MATCHER_HPP 19 | #include "../matcher.hpp" 20 | #endif 21 | 22 | 23 | namespace trompeloeil 24 | { 25 | namespace lambdas { 26 | 27 | struct any_predicate 28 | { 29 | template 30 | bool 31 | operator()( 32 | T&&) 33 | const 34 | { 35 | return true; 36 | } 37 | }; 38 | 39 | 40 | // Define `struct` with `operator()` to replace generic lambdas. 41 | struct any_printer 42 | { 43 | explicit 44 | any_printer( 45 | char const* type_name_) 46 | : type_name(type_name_) 47 | {} 48 | 49 | void 50 | operator()( 51 | std::ostream& os) 52 | const 53 | { 54 | os << " matching ANY(" << type_name << ")"; 55 | } 56 | 57 | private: 58 | char const* type_name; 59 | }; 60 | 61 | } 62 | 63 | template < 64 | typename T, 65 | typename R = make_matcher_return> 66 | inline 67 | auto 68 | any_matcher_impl(char const* type_name, std::false_type) 69 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 70 | { 71 | return make_matcher(lambdas::any_predicate(), lambdas::any_printer(type_name)); 72 | } 73 | 74 | template 75 | wildcard 76 | any_matcher_impl(char const*, std::true_type); 77 | 78 | template 79 | inline 80 | auto 81 | any_matcher(char const* name) 82 | TROMPELOEIL_TRAILING_RETURN_TYPE(decltype(any_matcher_impl(name, std::is_array{}))) 83 | { 84 | static_assert(!std::is_array::value, 85 | "array parameter type decays to pointer type for ANY()" 86 | " matcher. Please rephrase as pointer instead"); 87 | return any_matcher_impl(name, std::is_array{}); 88 | } 89 | 90 | } 91 | 92 | #define TROMPELOEIL_ANY(type) ::trompeloeil::any_matcher(#type) 93 | 94 | #ifndef TROMPELOEIL_LONG_MACROS 95 | #define ANY TROMPELOEIL_ANY 96 | #endif 97 | 98 | #endif //TROMPELOEIL_ANY_HPP 99 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/compare.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_COMPARE_HPP 16 | #define TROMPELOEIL_COMPARE_HPP 17 | 18 | #ifndef TROMPELOEIL_MATCHER_HPP 19 | #include "../matcher.hpp" 20 | #endif 21 | 22 | namespace trompeloeil 23 | { 24 | 25 | namespace lambdas { 26 | // The below must be classes/structs to work with VS 2015 update 3 27 | // since it doesn't respect the trailing return type declaration on 28 | // the lambdas of template deduction context 29 | 30 | #define TROMPELOEIL_MK_PRED_BINOP(name, op) \ 31 | struct name { \ 32 | template \ 33 | auto operator()(X const& x, Y const& y) const -> decltype(x op y) \ 34 | { \ 35 | ::trompeloeil::ignore(x,y); \ 36 | return x op y; \ 37 | } \ 38 | } 39 | TROMPELOEIL_MK_PRED_BINOP(equal, ==); 40 | TROMPELOEIL_MK_PRED_BINOP(not_equal, !=); 41 | TROMPELOEIL_MK_PRED_BINOP(less, <); 42 | TROMPELOEIL_MK_PRED_BINOP(less_equal, <=); 43 | TROMPELOEIL_MK_PRED_BINOP(greater, >); 44 | TROMPELOEIL_MK_PRED_BINOP(greater_equal, >=); 45 | #undef TROMPELOEIL_MK_PRED_BINOP 46 | 47 | #define TROMPELOEIL_MK_OP_PRINTER(name, op_string) \ 48 | struct name ## _printer \ 49 | { \ 50 | template \ 51 | void \ 52 | operator()( \ 53 | std::ostream& os, \ 54 | T const& value) \ 55 | const \ 56 | { \ 57 | os << op_string; \ 58 | ::trompeloeil::print(os, value); \ 59 | } \ 60 | } 61 | TROMPELOEIL_MK_OP_PRINTER(equal, " == "); 62 | TROMPELOEIL_MK_OP_PRINTER(not_equal, " != "); 63 | TROMPELOEIL_MK_OP_PRINTER(less, " < "); 64 | TROMPELOEIL_MK_OP_PRINTER(less_equal, " <= "); 65 | TROMPELOEIL_MK_OP_PRINTER(greater, " > "); 66 | TROMPELOEIL_MK_OP_PRINTER(greater_equal, " >= "); 67 | #undef TROMPELOEIL_MK_OP_PRINTER 68 | 69 | 70 | } 71 | template < 72 | typename T = wildcard, 73 | typename V, 74 | typename R = make_matcher_return> 75 | inline 76 | auto 77 | eq( 78 | V&& v) 79 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 80 | { 81 | return make_matcher(lambdas::equal(), 82 | lambdas::equal_printer(), 83 | std::forward(v)); 84 | } 85 | 86 | template < 87 | typename T = wildcard, 88 | typename V, 89 | typename R = make_matcher_return> 90 | inline 91 | auto 92 | ne( 93 | V&& v) 94 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 95 | { 96 | return make_matcher(lambdas::not_equal(), 97 | lambdas::not_equal_printer(), 98 | std::forward(v)); 99 | } 100 | 101 | template < 102 | typename T = wildcard, 103 | typename V, 104 | typename R = make_matcher_return> 105 | inline 106 | auto 107 | ge( 108 | V&& v) 109 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 110 | { 111 | return make_matcher(lambdas::greater_equal(), 112 | lambdas::greater_equal_printer(), 113 | std::forward(v)); 114 | } 115 | 116 | template < 117 | typename T = wildcard, 118 | typename V, 119 | typename R = make_matcher_return> 120 | inline 121 | auto 122 | gt( 123 | V&& v) 124 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 125 | { 126 | return make_matcher(lambdas::greater(), 127 | lambdas::greater_printer(), 128 | std::forward(v)); 129 | } 130 | 131 | template < 132 | typename T = wildcard, 133 | typename V, 134 | typename R = make_matcher_return> 135 | inline 136 | auto 137 | lt( 138 | V&& v) 139 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 140 | { 141 | return make_matcher(lambdas::less(), 142 | lambdas::less_printer(), 143 | std::forward(v)); 144 | } 145 | 146 | template < 147 | typename T = wildcard, 148 | typename V, 149 | typename R = make_matcher_return> 150 | inline 151 | auto 152 | le( 153 | V&& v) 154 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 155 | { 156 | return make_matcher(lambdas::less_equal(), 157 | lambdas::less_equal_printer(), 158 | std::forward(v)); 159 | } 160 | 161 | } 162 | 163 | #endif //TROMPELOEIL_COMPARE_HPP 164 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/deref.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | 16 | #ifndef TROMPELOEIL_DEREF_HPP 17 | #define TROMPELOEIL_DEREF_HPP 18 | 19 | #ifndef TROMPELOEIL_MATCHER_HPP 20 | #include "../matcher.hpp" 21 | #endif 22 | 23 | namespace trompeloeil { 24 | 25 | template 26 | class ptr_deref : public matcher 27 | { 28 | public: 29 | template ())>>(std::declval()))> 31 | operator U() const; 32 | 33 | template 34 | explicit 35 | ptr_deref( 36 | U&& m_) 37 | : m( std::forward(m_) ) 38 | {} 39 | 40 | template 41 | bool 42 | matches( 43 | const U& u) 44 | const 45 | noexcept(noexcept(std::declval().matches(*u))) 46 | { 47 | return (u != nullptr) && m.matches(*u); 48 | } 49 | 50 | friend 51 | std::ostream& 52 | operator<<( 53 | std::ostream& os, 54 | ptr_deref const& p) 55 | { 56 | return os << p.m; 57 | } 58 | friend 59 | std::string 60 | param_name_prefix( 61 | const ptr_deref*) 62 | { 63 | return "*" + param_name_prefix(static_cast(nullptr)); 64 | } 65 | 66 | private: 67 | M m; 68 | }; 69 | 70 | 71 | template ::value>> 73 | inline 74 | ::trompeloeil::ptr_deref> 75 | operator*( 76 | M&& m) 77 | { 78 | return ::trompeloeil::ptr_deref>{std::forward(m)}; 79 | } 80 | 81 | 82 | } 83 | #endif //TROMPELOEIL_DEREF_HPP 84 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/member_is.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_MEMBER_IS_HPP 16 | #define TROMPELOEIL_MEMBER_IS_HPP 17 | 18 | #ifndef TROMPELOEIL_MATCHER_HPP 19 | #include "../matcher.hpp" 20 | #endif 21 | 22 | namespace trompeloeil 23 | { 24 | 25 | namespace impl { 26 | template 27 | struct member_is_matcher 28 | { 29 | template 30 | bool operator()(const V& v, const C& c) const 31 | { 32 | return trompeloeil::param_matches(c, std::ref(m(v))); 33 | } 34 | M m; 35 | }; 36 | } 37 | 38 | template 39 | auto match_member_is(M m, const char* name, C&& c) 40 | { 41 | return trompeloeil::make_matcher( 42 | impl::member_is_matcher{m}, 43 | [name](std::ostream& os, const C& compare) { 44 | os << ' ' << name << compare; 45 | }, 46 | std::forward(c) 47 | ); 48 | } 49 | } 50 | 51 | #define TROMPELOEIL_MEMBER_IS(member_name, compare) \ 52 | trompeloeil::match_member_is( \ 53 | std::mem_fn(member_name), \ 54 | #member_name, \ 55 | compare) 56 | 57 | #ifndef TROMPELOEIL_LONG_MACROS 58 | #define MEMBER_IS TROMPELOEIL_MEMBER_IS 59 | #endif 60 | 61 | #endif // TROMPELOEIL_MEMBER_IS_HPP 62 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/not.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_NOT_HPP 16 | #define TROMPELOEIL_NOT_HPP 17 | 18 | #ifndef TROMPELOEIL_MATCHER_HPP 19 | #include "../matcher.hpp" 20 | #endif 21 | 22 | namespace trompeloeil 23 | { 24 | 25 | template 26 | class not_matcher : public matcher 27 | { 28 | public: 29 | template ())>>(std::declval()))> 31 | operator U() const { return {}; } 32 | 33 | template 34 | explicit 35 | not_matcher( 36 | U&& m_) 37 | : m( std::forward(m_) ) 38 | {} 39 | 40 | template 41 | bool 42 | matches( 43 | const U& u) 44 | const 45 | noexcept(noexcept(!std::declval().matches(u))) 46 | { 47 | return !m.matches(u); 48 | } 49 | 50 | friend 51 | std::ostream& 52 | operator<<( 53 | std::ostream& os, 54 | not_matcher const& p) 55 | { 56 | return os << p.m; 57 | } 58 | friend 59 | std::string 60 | param_name_prefix( 61 | const not_matcher*) 62 | { 63 | return "not " + param_name_prefix(static_cast(nullptr)); 64 | } 65 | 66 | private: 67 | M m; 68 | }; 69 | 70 | 71 | template ::value>> 73 | inline 74 | ::trompeloeil::not_matcher> 75 | operator!( 76 | M&& m) 77 | { 78 | return ::trompeloeil::not_matcher>{std::forward(m)}; 79 | } 80 | 81 | } 82 | #endif //TROMPELOEIL_NOT_HPP 83 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/re.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_RE_HPP 16 | #define TROMPELOEIL_RE_HPP 17 | 18 | #ifndef TROMPELOEIL_MATCHER_HPP 19 | #include "../matcher.hpp" 20 | #endif 21 | 22 | #include 23 | #include 24 | 25 | namespace trompeloeil 26 | { 27 | namespace lambdas { 28 | struct regex_check 29 | { 30 | 31 | class string_helper // a vastly simplified string_view type of class 32 | { 33 | public: 34 | template < 35 | typename S, 36 | typename = decltype(std::declval() = std::declval().data()), 37 | typename = decltype(std::declval().length()) 38 | > 39 | string_helper( 40 | const S& s) 41 | noexcept 42 | : begin_(s.data()) 43 | , end_(begin_ + s.length()) 44 | {} 45 | 46 | constexpr 47 | string_helper( 48 | char const* s) 49 | noexcept 50 | : begin_(s) 51 | , end_(s ? begin_ + strlen(s) : nullptr) 52 | { 53 | } 54 | 55 | constexpr 56 | explicit 57 | operator bool() const 58 | { 59 | return begin_; 60 | } 61 | constexpr 62 | char const * 63 | begin() 64 | const 65 | { 66 | return begin_; 67 | } 68 | constexpr 69 | char const * 70 | end() 71 | const 72 | { 73 | return end_; 74 | } 75 | private: 76 | char const* begin_; 77 | char const* end_; 78 | }; 79 | 80 | regex_check( 81 | std::regex&& re_, 82 | std::regex_constants::match_flag_type match_type_) 83 | : re(std::move(re_)), 84 | match_type(match_type_) 85 | {} 86 | 87 | template 88 | bool 89 | operator()( 90 | string_helper str, 91 | T const&) 92 | const 93 | { 94 | return str && std::regex_search(str.begin(), str.end(), re, match_type); 95 | } 96 | 97 | private: 98 | std::regex re; 99 | std::regex_constants::match_flag_type match_type; 100 | }; 101 | 102 | struct regex_printer 103 | { 104 | template 105 | void 106 | operator()( 107 | std::ostream& os, 108 | T const& str) 109 | const 110 | { 111 | os << " matching regular expression /" << str << "/"; 112 | } 113 | }; 114 | } 115 | 116 | template < 117 | typename Kind = wildcard, 118 | typename R = make_matcher_return> 119 | auto 120 | re( 121 | std::string s, 122 | std::regex_constants::syntax_option_type opt = std::regex_constants::ECMAScript, 123 | std::regex_constants::match_flag_type match_type = std::regex_constants::match_default) 124 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 125 | { 126 | return make_matcher(lambdas::regex_check(std::regex(s, opt), 127 | match_type), 128 | lambdas::regex_printer(), 129 | std::move(s)); 130 | } 131 | 132 | template < 133 | typename Kind = wildcard, 134 | typename R = make_matcher_return> 135 | auto 136 | re( 137 | std::string s, 138 | std::regex_constants::match_flag_type match_type) 139 | TROMPELOEIL_TRAILING_RETURN_TYPE(R) 140 | { 141 | return make_matcher(lambdas::regex_check(std::regex(s), match_type), 142 | lambdas::regex_printer(), 143 | std::move(s)); 144 | } 145 | 146 | 147 | } 148 | #endif //TROMPELOEIL_RE_HPP 149 | -------------------------------------------------------------------------------- /include/trompeloeil/matcher/set_predicate.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy atl 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | #ifndef TROMPELOEIL_SET_PREDICATE_HPP 15 | #define TROMPELOEIL_SET_PREDICATE_HPP 16 | 17 | #ifndef TROMPELOEIL_MATCHER_HPP 18 | #include "../matcher.hpp" 19 | #endif 20 | 21 | namespace trompeloeil { 22 | namespace impl { 23 | struct any_of_checker 24 | { 25 | template 26 | bool operator()(const T& t, const Cs& ... compare) const 27 | { 28 | bool any_true = false; 29 | trompeloeil::ignore(std::initializer_list{ 30 | (any_true = any_true || trompeloeil::param_matches(compare, std::ref(t)))... 31 | }); 32 | return any_true; 33 | } 34 | }; 35 | struct any_of_printer 36 | { 37 | template 38 | void operator()(std::ostream& os, const Cs& ... compare) const 39 | { 40 | os << " to be any of {"; 41 | const char* sep = " "; 42 | trompeloeil::ignore(std::initializer_list{ 43 | ((os << detail::exchange(sep, ", ") << compare),0)... 44 | }); 45 | os << " }"; 46 | } 47 | }; 48 | } 49 | 50 | template < 51 | typename Type = trompeloeil::wildcard, 52 | typename ... Cs, 53 | typename R = make_matcher_return< 54 | Type, 55 | impl::any_of_checker, 56 | impl::any_of_printer, 57 | Cs... 58 | > 59 | > 60 | R any_of(Cs&& ... cs) 61 | { 62 | return trompeloeil::make_matcher( 63 | impl::any_of_checker{}, 64 | impl::any_of_printer{}, 65 | std::forward(cs)...); 66 | } 67 | 68 | namespace impl { 69 | struct none_of_checker 70 | { 71 | template 72 | bool operator()(const T& t, const Cs& ... compare) const 73 | { 74 | bool any_true = false; 75 | trompeloeil::ignore(std::initializer_list{ 76 | (any_true = any_true || trompeloeil::param_matches(compare, std::ref(t)))... 77 | }); 78 | return !any_true; 79 | } 80 | }; 81 | struct none_of_printer 82 | { 83 | template 84 | void operator()(std::ostream& os, const Cs& ... compare) const 85 | { 86 | os << " to be none of {"; 87 | const char* sep = " "; 88 | trompeloeil::ignore(std::initializer_list{ 89 | ((os << detail::exchange(sep, ", ") << compare),0)... 90 | }); 91 | os << " }"; 92 | } 93 | }; 94 | } 95 | 96 | template < 97 | typename Type = trompeloeil::wildcard, 98 | typename ... Cs, 99 | typename R = make_matcher_return< 100 | Type, 101 | impl::none_of_checker, 102 | impl::none_of_printer, 103 | Cs... 104 | > 105 | > 106 | R none_of(Cs&& ... cs) 107 | { 108 | return trompeloeil::make_matcher( 109 | impl::none_of_checker{}, 110 | impl::none_of_printer{}, 111 | std::forward(cs)...); 112 | } 113 | 114 | namespace impl { 115 | struct all_of_checker 116 | { 117 | template 118 | bool operator()(const T& t, const Cs& ... compare) const 119 | { 120 | bool all_true = true; 121 | trompeloeil::ignore(std::initializer_list{ 122 | (all_true = all_true && trompeloeil::param_matches(compare, std::ref(t)))... 123 | }); 124 | return all_true; 125 | } 126 | }; 127 | struct all_of_printer 128 | { 129 | template 130 | void operator()(std::ostream& os, const Cs& ... compare) const 131 | { 132 | os << " to be all of {"; 133 | const char* sep = " "; 134 | trompeloeil::ignore(std::initializer_list{ 135 | ((os << detail::exchange(sep, ", ") << compare),0)... 136 | }); 137 | os << " }"; 138 | } 139 | }; 140 | } 141 | 142 | template < 143 | typename Type = trompeloeil::wildcard, 144 | typename ... Cs, 145 | typename R = make_matcher_return< 146 | Type, 147 | impl::all_of_checker, 148 | impl::all_of_printer, 149 | Cs... 150 | > 151 | > 152 | R all_of(Cs&& ... cs) 153 | { 154 | return trompeloeil::make_matcher( 155 | impl::all_of_checker{}, 156 | impl::all_of_printer{}, 157 | std::forward(cs)...); 158 | } 159 | 160 | } 161 | #endif // TROMPELOEIL_SET_PREDICATE_HPP 162 | -------------------------------------------------------------------------------- /include/trompeloeil/sequence.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * Copyright (C) Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy atl 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #ifndef TROMPELOEIL_SEQUENCE_HPP 16 | #define TROMPELOEIL_SEQUENCE_HPP 17 | 18 | #ifndef TROMPELOEIL_MOCK_HPP_ 19 | #include "mock.hpp" 20 | #endif 21 | 22 | namespace trompeloeil { 23 | 24 | class sequence_type 25 | { 26 | public: 27 | sequence_type() = default; 28 | sequence_type(sequence_type&&) = delete; 29 | sequence_type(const sequence_type&) = delete; 30 | sequence_type& operator=(sequence_type&&) = delete; 31 | sequence_type& operator=(const sequence_type&) = delete; 32 | ~sequence_type(); 33 | 34 | bool 35 | is_completed() 36 | const 37 | noexcept; 38 | 39 | bool 40 | is_first( 41 | sequence_matcher const *m) 42 | const 43 | noexcept; 44 | 45 | unsigned 46 | cost( 47 | sequence_matcher const *m) 48 | const 49 | noexcept; 50 | 51 | void 52 | retire_until( 53 | sequence_matcher const* m) 54 | noexcept; 55 | 56 | void 57 | add_last( 58 | sequence_matcher *m) 59 | noexcept; 60 | 61 | void 62 | validate_match( 63 | severity s, 64 | sequence_matcher const *matcher, 65 | char const *seq_name, 66 | char const *match_name, 67 | location loc) 68 | const; 69 | 70 | private: 71 | list matchers{}; 72 | }; 73 | 74 | class sequence 75 | { 76 | public: 77 | sequence_type& operator*() { return *obj; } 78 | bool is_completed() const { return obj->is_completed(); } 79 | private: 80 | std::unique_ptr obj{detail::make_unique()}; 81 | }; 82 | 83 | class sequence_matcher : public list_elem 84 | { 85 | public: 86 | using init_type = std::pair; 87 | 88 | sequence_matcher( 89 | char const *exp, 90 | location loc, 91 | const sequence_handler_base& handler, 92 | init_type i) 93 | noexcept 94 | : seq_name(i.first) 95 | , exp_name(exp) 96 | , exp_loc(loc) 97 | , sequence_handler(handler) 98 | , seq(*i.second) 99 | { 100 | auto lock = get_lock(); 101 | seq.add_last(this); 102 | } 103 | 104 | sequence_matcher(const sequence_matcher&) = delete; 105 | sequence_matcher(sequence_matcher&&) = default; 106 | sequence_matcher& operator=(sequence_matcher const&) = delete; 107 | 108 | void 109 | validate_match( 110 | severity s, 111 | char const *match_name, 112 | location loc) 113 | const 114 | { 115 | seq.validate_match(s, this, seq_name, match_name, loc); 116 | } 117 | 118 | unsigned 119 | cost() 120 | const 121 | noexcept 122 | { 123 | return seq.cost(this); 124 | } 125 | 126 | bool 127 | is_satisfied() 128 | const 129 | noexcept; 130 | 131 | bool 132 | is_optional() 133 | const 134 | noexcept; 135 | 136 | void 137 | retire() 138 | noexcept 139 | { 140 | this->unlink(); 141 | } 142 | 143 | void 144 | retire_predecessors() 145 | noexcept 146 | { 147 | seq.retire_until(this); 148 | } 149 | 150 | void 151 | print_expectation(std::ostream& os) 152 | const 153 | { 154 | os << exp_name << " at " << exp_loc; 155 | } 156 | 157 | char const* 158 | sequence_name() 159 | const 160 | noexcept 161 | { 162 | return seq_name; 163 | } 164 | private: 165 | char const *seq_name; 166 | char const *exp_name; 167 | location exp_loc; 168 | const sequence_handler_base& sequence_handler; 169 | sequence_type& seq; 170 | }; 171 | 172 | inline 173 | bool 174 | sequence_type::is_completed() 175 | const 176 | noexcept 177 | { 178 | for (const auto& matcher : matchers) 179 | { 180 | if (!matcher.is_satisfied()) 181 | { 182 | return false; 183 | } 184 | } 185 | return true; 186 | } 187 | 188 | inline 189 | bool 190 | sequence_type::is_first( 191 | sequence_matcher const *m) 192 | const 193 | noexcept 194 | { 195 | return !matchers.empty() && &*matchers.begin() == m; 196 | } 197 | 198 | inline 199 | unsigned 200 | sequence_type::cost( 201 | sequence_matcher const* m) 202 | const 203 | noexcept 204 | { 205 | unsigned sequence_cost = 0U; 206 | for (auto const& e : matchers) 207 | { 208 | if (&e == m) return sequence_cost; 209 | if (!e.is_satisfied()) 210 | { 211 | return ~0U; 212 | } 213 | ++sequence_cost; 214 | } 215 | return ~0U; 216 | } 217 | 218 | inline 219 | void 220 | sequence_type::retire_until( 221 | sequence_matcher const* m) 222 | noexcept 223 | { 224 | while (!matchers.empty()) 225 | { 226 | auto first = &*matchers.begin(); 227 | if (first == m) return; 228 | first->retire(); 229 | } 230 | } 231 | 232 | inline 233 | void 234 | sequence_type::validate_match( 235 | severity s, 236 | sequence_matcher const *matcher, 237 | char const* seq_name, 238 | char const* match_name, 239 | location loc) 240 | const 241 | { 242 | if (is_first(matcher)) return; 243 | if (matchers.empty()) 244 | { 245 | std::ostringstream os; 246 | os << "Sequence mismatch for sequence \"" << seq_name 247 | << "\" with matching call of " << match_name 248 | << " at " << loc 249 | << ". Sequence \"" << seq_name 250 | << "\" has no more pending expectations\n"; 251 | send_report(s, loc, os.str()); 252 | } 253 | bool first = true; 254 | std::ostringstream os; 255 | os << "Sequence mismatch for sequence \"" << seq_name 256 | << "\" with matching call of " << match_name 257 | << " at " << loc << ".\n"; 258 | for (auto const& m : matchers) 259 | { 260 | if (first || !m.is_optional()) 261 | { 262 | if (first) 263 | { 264 | os << "Sequence \"" << seq_name << "\" has "; 265 | } 266 | else 267 | { 268 | os << "and has "; 269 | } 270 | m.print_expectation(os); 271 | if (m.is_optional()) 272 | { 273 | os << " first in line\n"; 274 | } 275 | else 276 | { 277 | os << " as first required expectation\n"; 278 | break; 279 | } 280 | } 281 | first = false; 282 | } 283 | send_report(s, loc, os.str()); 284 | } 285 | 286 | inline 287 | sequence_type::~sequence_type() 288 | { 289 | bool touched = false; 290 | std::ostringstream os; 291 | while (!matchers.empty()) 292 | { 293 | auto m = matchers.begin(); 294 | if (!touched) 295 | { 296 | os << "Sequence expectations not met at destruction of sequence object \"" 297 | << m->sequence_name() << "\":"; 298 | touched = true; 299 | } 300 | os << "\n missing "; 301 | m->print_expectation(os); 302 | m->unlink(); 303 | } 304 | if (touched) 305 | { 306 | os << "\n"; 307 | send_report(severity::nonfatal, location{}, os.str()); 308 | } 309 | } 310 | 311 | inline 312 | void 313 | sequence_type::add_last( 314 | sequence_matcher *m) 315 | noexcept 316 | { 317 | matchers.push_back(m); 318 | } 319 | 320 | inline 321 | bool 322 | sequence_matcher::is_satisfied() 323 | const 324 | noexcept 325 | { 326 | return sequence_handler.is_satisfied(); 327 | } 328 | 329 | inline 330 | bool 331 | sequence_matcher::is_optional() 332 | const 333 | noexcept 334 | { 335 | return sequence_handler.get_min_calls() == 0; 336 | } 337 | 338 | template 339 | struct sequence_matchers 340 | { 341 | void 342 | validate( 343 | severity s, 344 | char const *match_name, 345 | location loc) 346 | { 347 | for (auto& e : matchers) 348 | { 349 | e.validate_match(s, match_name, loc); 350 | } 351 | } 352 | 353 | unsigned 354 | order() 355 | const 356 | noexcept 357 | { 358 | unsigned highest_order = 0U; 359 | for (auto &m: matchers) { 360 | auto cost = m.cost(); 361 | if (cost > highest_order) { 362 | highest_order = cost; 363 | } 364 | } 365 | return highest_order; 366 | } 367 | void 368 | retire() 369 | noexcept 370 | { 371 | for (auto& e : matchers) 372 | { 373 | e.retire(); 374 | } 375 | } 376 | void 377 | retire_predecessors() 378 | noexcept 379 | { 380 | for (auto& e : matchers) 381 | { 382 | e.retire_predecessors(); 383 | } 384 | } 385 | 386 | std::array matchers; 387 | }; 388 | } 389 | 390 | #define TROMPELOEIL_IN_SEQUENCE(...) \ 391 | in_sequence(TROMPELOEIL_INIT_WITH_STR(::trompeloeil::sequence_matcher::init_type, __VA_ARGS__)) 392 | 393 | #ifndef TROMPELOEIL_LONG_MACRCOS 394 | #define IN_SEQUENCE TROMPELOEIL_IN_SEQUENCE 395 | #endif 396 | 397 | #endif //TROMPELOEIL_SEQUENCE_HPP 398 | -------------------------------------------------------------------------------- /include/trompeloeil/stream_tracer.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy atl 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | #ifndef TROMPELOEIL_STREAM_TRACER_HPP 15 | #define TROMPELOEIL_STREAM_TRACER_HPP 16 | 17 | #ifndef TROMPELOEIL_MOCK_HPP_ 18 | #include "mock.hpp" 19 | #endif 20 | 21 | namespace trompeloeil { 22 | 23 | class stream_tracer : public tracer 24 | { 25 | public: 26 | explicit 27 | stream_tracer( 28 | std::ostream& stream_) 29 | : stream(stream_) {} 30 | void 31 | trace( 32 | char const *file, 33 | unsigned long line, 34 | std::string const &call) 35 | override 36 | { 37 | stream << location{file, line} << '\n' << call << '\n'; 38 | } 39 | private: 40 | std::ostream& stream; 41 | }; 42 | 43 | } 44 | #endif //TROMPELOEIL_STREAM_TRACER_HPP 45 | -------------------------------------------------------------------------------- /install_libcxx.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | TRUNK_VERSION="14.0.1" 4 | 5 | set -e 6 | 7 | # The pattern of clang --version is: clang version X.Y.Z (sometimes, see below). 8 | COMPILER_VERSION_OUTPUT="$($CXX --version)" 9 | arr=(${COMPILER_VERSION_OUTPUT// / }) 10 | 11 | COMPILER="${arr[0]}" 12 | VERSION="${arr[2]}" 13 | 14 | case $COMPILER in 15 | "clang") 16 | # Some Ubuntu clang builds are advertised as "just clang", but the 17 | # Version still follows the pattern: 3.6.2-svn240577-1~exp1 18 | # echo "Compiler is clang :)" 19 | arr2=(${VERSION//-/ }) 20 | VERSION="${arr2[0]}" 21 | ;; 22 | "Ubuntu") 23 | # Ubuntu renames _some_ (not all) of its clang compilers, the pattern of 24 | # clang --version is then: 25 | # Ubuntu clang version 3.6.2-svn240577-1~exp1 26 | COMPILER="${arr[1]}" 27 | VERSION="${arr[3]}" 28 | arr2=(${VERSION//-/ }) 29 | VERSION="${arr2[0]}" 30 | ;; 31 | *) 32 | echo "case did not match: compiler: ${COMPILER}" 33 | exit 1 34 | ;; 35 | esac 36 | 37 | if [ ${COMPILER} != "clang" ]; then 38 | echo "Error: trying to install libc++ for a compiler that is not clang: ${COMPILER}" 39 | exit 1 40 | fi 41 | 42 | if [ -z ${VERSION+x} ]; then 43 | echo "Malformed libc++ version - I give up." 44 | exit 4 45 | fi 46 | 47 | MAJOR=$(echo $VERSION | sed 's/\..*//') 48 | if [ ${VERSION} == $TRUNK_VERSION ]; then 49 | echo "Fetching libc++ and libc++abi tip-of-trunk..." 50 | 51 | # Checkout LLVM sources 52 | git clone --depth=1 https://github.com/llvm-mirror/llvm.git llvm-source 53 | git clone --depth=1 https://github.com/llvm-mirror/libcxx.git llvm-source/projects/libcxx 54 | git clone --depth=1 https://github.com/llvm-mirror/libcxxabi.git llvm-source/projects/libcxxabi 55 | else 56 | echo "Fetching libc++/libc++abi version: ${VERSION}..." 57 | if [ ${MAJOR} -ge 8 ]; then 58 | BASE_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-" 59 | else 60 | BASE_URL="https://releases.llvm.org/" 61 | fi 62 | LLVM_URL="${BASE_URL}${VERSION}/llvm-${VERSION}.src.tar.xz" 63 | LIBCXX_URL="${BASE_URL}${VERSION}/libcxx-${VERSION}.src.tar.xz" 64 | LIBCXXABI_URL="${BASE_URL}${VERSION}/libcxxabi-${VERSION}.src.tar.xz" 65 | echo wget $LLVM_URL 66 | echo wget $LIBCXX_URL 67 | echo wget $LIBCXXABI_URL 68 | wget $LLVM_URL 69 | wget $LIBCXX_URL 70 | wget $LIBCXXABI_URL 71 | mkdir llvm-source 72 | mkdir llvm-source/projects 73 | mkdir llvm-source/projects/libcxx 74 | mkdir llvm-source/projects/libcxxabi 75 | 76 | tar -xf llvm-${VERSION}.src.tar.xz -C llvm-source --strip-components=1 77 | tar -xf libcxx-${VERSION}.src.tar.xz -C llvm-source/projects/libcxx --strip-components=1 78 | tar -xf libcxxabi-${VERSION}.src.tar.xz -C llvm-source/projects/libcxxabi --strip-components=1 79 | fi 80 | 81 | SOURCE=`pwd`/llvm-source 82 | TARGET=`pwd`/llvm 83 | mkdir "${TARGET}" 84 | mkdir llvm-build 85 | cd llvm-build 86 | 87 | # - libc++ versions < 4.x do not have the install-cxxabi and install-cxx targets 88 | # - only ASAN is enabled for clang/libc++ versions < 4.x 89 | if [[ $VERSION == *"3."* ]]; then 90 | cmake -DCMAKE_C_COMPILER=${CC} -DCMAKE_CXX_COMPILER=${CXX} \ 91 | -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX="${TARGET}" \ 92 | ../llvm-source 93 | if [[ $SANITIZER == "Address;Undefined" ]]; then 94 | ASAN_FLAGS="-fsanitize=address" 95 | cmake -DCMAKE_CXX_FLAGS="${ASAN_FLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${ASAN_FLAGS}" ../llvm-source 96 | fi 97 | make cxx -j4 VERBOSE=1 98 | mkdir "${TARGET}/lib" 99 | mkdir "${TARGET}/include" 100 | cp -r lib/* "${TARGET}/lib" 101 | cp -r include/c++ "${TARGET}/include" 102 | else 103 | cmake -DCMAKE_C_COMPILER=${CC} -DCMAKE_CXX_COMPILER=${CXX} \ 104 | -DCMAKE_BUILD_TYPE=RelWithDebInfo -DCMAKE_INSTALL_PREFIX="${TARGET}" \ 105 | -DLIBCXX_ABI_UNSTABLE=ON \ 106 | -DCMAKE_BUILD_WITH_INSTALL_RPATH=1 \ 107 | -DLLVM_USE_SANITIZER=${SANITIZER} \ 108 | -DCMAKE_MODULE_PATH=${SOURCE}/Modules \ 109 | -DLLVM_INCLUDE_BENCHMARKS=no \ 110 | -DLIBCXX_INCLUDE_BENCHMARKS=no \ 111 | ../llvm-source 112 | make cxx -j4 VERBOSE=1 113 | make install-cxxabi install-cxx 114 | fi 115 | 116 | exit 0 117 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.19) 2 | 3 | option(TROMPELOEIL_CATCH2_PREBUILT "Major version of prebuilt catch2") 4 | option(TROMPELOEIL_CATCH2_PREFIX "Path to catch2 installation") 5 | 6 | if (${CXX_STANDARD}) 7 | set(CMAKE_CXX_STANDARD ${CXX_STANDARD}) 8 | else() 9 | set(CMAKE_CXX_STANDARD 14) 10 | endif() 11 | set(CMAKE_CXX_STANDARD_REQUIRED YES) 12 | set(CMAKE_CXX_EXTENSIONS OFF) 13 | 14 | if (${CMAKE_CXX_STANDARD} GREATER 11) 15 | find_package(Catch2 3 QUIET) 16 | endif() 17 | if (NOT Catch2_FOUND) 18 | find_package(Catch2 2...<3 QUIET) 19 | if (NOT Catch2_FOUND) 20 | set(CATCH_DIR ${CMAKE_CURRENT_BINARY_DIR}/catch) 21 | if (NOT EXISTS "${CATCH_DIR}/catch2/catch.hpp") 22 | if (NOT EXISTS ${CATCH_DIR}) 23 | FILE(MAKE_DIRECTORY "${CATCH_DIR}/catch2") 24 | endif() 25 | file( 26 | DOWNLOAD 27 | https://github.com/catchorg/Catch2/releases/download/v2.13.7/catch.hpp ${CATCH_DIR}/catch2/catch.hpp 28 | STATUS 29 | status 30 | LOG 31 | log 32 | ) 33 | list(GET status 0 status_code) 34 | list(GET status 1 status_string) 35 | 36 | if(NOT status_code EQUAL 0) 37 | message(FATAL_ERROR "error downloading catch: ${status_string}" 38 | "${log}") 39 | endif() 40 | endif() 41 | add_library(Catch2 INTERFACE) 42 | add_library(Catch2::Catch2 ALIAS Catch2) 43 | target_include_directories(Catch2 INTERFACE "${CATCH_DIR}") 44 | set(Catch2_VERSION_MAJOR 2) 45 | endif() 46 | endif() 47 | if (TARGET Catch2::Catch2WithMain) 48 | set(CATCH2_MAIN Catch2::Catch2WithMain) 49 | add_compile_definitions(CATCH2_MAIN) 50 | endif() 51 | add_compile_definitions(CATCH2_VERSION=${Catch2_VERSION_MAJOR}) 52 | 53 | # Assumptions: 54 | # Clang and GNU compilers run on Linux or Linux-like platforms. 55 | # MSVC compilers run on Windows platforms. 56 | 57 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") 58 | 59 | set( 60 | LIBCXX_PREFIX_PATH 61 | "/usr/lib/llvm-8" 62 | CACHE 63 | PATH 64 | "Path prefix to libc++" 65 | ) 66 | 67 | # Interpret CXX_STDLIB, if specified 68 | if (NOT "${CXX_STDLIB}" STREQUAL "") 69 | 70 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 71 | 72 | # Emulate -stdlib for g++ 73 | if ("${CXX_STDLIB}" STREQUAL "libc++") 74 | 75 | # Disable standard library and 76 | # set include path to appropriate libc++ headers 77 | string(CONCAT 78 | LIBCXX_INCLUDE_PATH 79 | "-isystem" 80 | "${LIBCXX_PREFIX_PATH}" 81 | "/include/c++/v1") 82 | string(CONCAT 83 | STDLIB_COMPILE_FLAGS 84 | "-nostdinc++" 85 | " " 86 | "${LIBCXX_INCLUDE_PATH}") 87 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${STDLIB_COMPILE_FLAGS}") 88 | 89 | elseif ("${CXX_STDLIB}" STREQUAL "libstdc++") 90 | 91 | # This is the default library for g++, nothing to do. 92 | 93 | else() 94 | 95 | # Unknown CXX_STDLIB option 96 | message(FATAL_ERROR 97 | "CXX_STDLIB only understands libc++ and libstdc++, not " 98 | "'${CXX_STDLIB}'") 99 | 100 | endif() 101 | 102 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 103 | 104 | if (("${CXX_STDLIB}" STREQUAL "libc++") OR 105 | ("${CXX_STDLIB}" STREQUAL "libstdc++")) 106 | 107 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=${CXX_STDLIB}") 108 | 109 | else() 110 | 111 | # Unknown CXX_STDLIB option 112 | message(FATAL_ERROR 113 | "CXX_STDLIB only understands libc++ and libstdc++, not " 114 | "'${CXX_STDLIB}'") 115 | 116 | endif() 117 | 118 | else() 119 | 120 | message(FATAL_ERROR 121 | "Only g++ and Clang++ compilers support CXX_STDLIB") 122 | 123 | endif() 124 | 125 | endif() 126 | 127 | if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") 128 | string(CONCAT 129 | WARN_FLAGS 130 | "-Weverything" 131 | " -Wno-c++98-compat-pedantic" 132 | " -Wno-padded" 133 | " -Wno-weak-vtables" 134 | " -Wno-exit-time-destructors" 135 | " -Wno-global-constructors") 136 | 137 | # Disable for Catch2. 138 | # See 139 | check_cxx_compiler_flag("-Wno-extra-semi-stmt" WARN_SEMI_STMT) 140 | 141 | if (WARN_SEMI_STMT) 142 | string(APPEND 143 | WARN_FLAGS 144 | " -Wno-extra-semi-stmt") 145 | endif() 146 | 147 | # Disable for Catch2. 148 | # See 149 | check_cxx_compiler_flag("-Wno-reserved-identifier" WARN_RESERVED_ID) 150 | 151 | if (WARN_RESERVED_ID) 152 | string(APPEND 153 | WARN_FLAGS 154 | " -Wno-reserved-identifier") 155 | endif() 156 | 157 | elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") 158 | string(CONCAT 159 | WARN_FLAGS 160 | "-Wall" 161 | " -Wextra" 162 | " -pedantic" 163 | " -Wshadow" 164 | " -Wconversion") 165 | check_cxx_compiler_flag("-Wnonnull" WARN_NONNULL) 166 | 167 | if (WARN_NONNULL) 168 | string(APPEND 169 | WARN_FLAGS 170 | " -Wnonnull") 171 | endif() 172 | endif() 173 | 174 | set(WARN_FLAGS "${WARN_FLAGS} -Werror") 175 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WARN_FLAGS}") 176 | 177 | # Default sanitizer target properties. 178 | set(TSAN "-fsanitize=undefined,thread") 179 | set(SSAN "-fsanitize=undefined,address") 180 | 181 | # Exceptions to sanitizer target properties based on compiler and compiler version. 182 | if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") 183 | 184 | if (NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.0")) 185 | set(SSAN "-fsanitize=undefined,address -fsanitize-address-use-after-scope") 186 | else() 187 | set(SSAN "-fsanitize=undefined,address") 188 | endif() 189 | 190 | elseif (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 191 | 192 | if ((NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.8")) AND 193 | (CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.9")) 194 | set(TSAN "-fsanitize=thread") 195 | set(SSAN "-fsanitize=address") 196 | endif() 197 | 198 | endif() 199 | 200 | endif() # Clang or GNU 201 | 202 | if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC") 203 | 204 | add_compile_options(/W4) 205 | add_compile_options(/bigobj) 206 | add_compile_options(/EHsc) 207 | 208 | check_cxx_compiler_flag(/permissive HAS_PERMISSIVE_FLAG) 209 | if(HAS_PERMISSIVE_FLAG) 210 | add_compile_options(/permissive-) 211 | endif() 212 | 213 | add_compile_definitions(NOMINMAX) 214 | 215 | endif() # MSVC 216 | 217 | if (${CMAKE_CXX_STANDARD} GREATER_EQUAL 20) 218 | set(CXX20TESTS "test_co_mock.cpp") 219 | else () 220 | set(CXX20TESTS "") 221 | endif () 222 | 223 | add_executable( 224 | self_test 225 | compiling_tests.cpp 226 | compiling_tests_11.cpp 227 | compiling_tests_14.cpp 228 | ${CXX20TESTS}) 229 | 230 | 231 | if (SANITIZE AND NOT APPLE) 232 | set_target_properties( 233 | self_test 234 | PROPERTIES 235 | LINK_FLAGS 236 | ${SSAN} 237 | COMPILE_FLAGS 238 | ${SSAN} 239 | ) 240 | endif() 241 | 242 | target_link_libraries( 243 | self_test 244 | PUBLIC 245 | trompeloeil 246 | ${CATCH2_MAIN} 247 | Catch2::Catch2 248 | ) 249 | 250 | 251 | find_package(Threads REQUIRED) 252 | 253 | add_executable( 254 | thread_terror 255 | thread_terror.cpp 256 | ) 257 | 258 | target_link_libraries( 259 | thread_terror 260 | PUBLIC 261 | trompeloeil 262 | Threads::Threads 263 | ) 264 | 265 | if (SANITIZE) 266 | set_target_properties( 267 | thread_terror 268 | PROPERTIES 269 | LINK_FLAGS 270 | ${TSAN} 271 | COMPILE_FLAGS 272 | ${TSAN} 273 | ) 274 | endif() 275 | 276 | add_executable( 277 | custom_recursive_mutex 278 | custom_recursive_mutex.cpp 279 | ) 280 | 281 | target_link_libraries( 282 | custom_recursive_mutex 283 | PUBLIC 284 | trompeloeil 285 | Threads::Threads 286 | ) 287 | 288 | if (SANITIZE AND NOT APPLE) 289 | set_target_properties( 290 | custom_recursive_mutex 291 | PROPERTIES 292 | LINK_FLAGS 293 | "${SSAN}" 294 | COMPILE_FLAGS 295 | ${SSAN} 296 | ) 297 | endif() 298 | 299 | # Linker support for CXX_STDLIB argument 300 | if (NOT ("${CXX_STDLIB}" STREQUAL "")) 301 | 302 | if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") 303 | 304 | if ("${CXX_STDLIB}" STREQUAL "libc++") 305 | 306 | set(LIBCXX_LIBRARY_PATH "${LIBCXX_PREFIX_PATH}/lib") 307 | set(STDLIB_LINK_FLAGS 308 | -nodefaultlibs 309 | -L${LIBCXX_LIBRARY_PATH} 310 | -Wl,-rpath,${LIBCXX_LIBRARY_PATH} 311 | ) 312 | set(STDLIB_LINK_LIBRARIES 313 | "-lc++" 314 | "-lc++abi" 315 | "-lm" 316 | "-lc" 317 | "-lgcc_s" 318 | "-lgcc" 319 | ) 320 | 321 | set_target_properties( 322 | self_test 323 | PROPERTIES 324 | LINK_FLAGS 325 | ${STDLIB_LINK_FLAGS} 326 | ) 327 | 328 | target_link_libraries( 329 | self_test 330 | PUBLIC 331 | ${STDLIB_LINK_LIBRARIES} 332 | ) 333 | 334 | set_target_properties( 335 | thread_terror 336 | PROPERTIES 337 | LINK_FLAGS 338 | ${STDLIB_LINK_FLAGS} 339 | ) 340 | 341 | target_link_libraries( 342 | thread_terror 343 | PUBLIC 344 | ${STDLIB_LINK_LIBRARIES} 345 | ) 346 | 347 | set_target_properties( 348 | custom_recursive_mutex 349 | PROPERTIES 350 | LINK_FLAGS 351 | ${STDLIB_LINK_FLAGS} 352 | ) 353 | 354 | target_link_libraries( 355 | custom_recursive_mutex 356 | PUBLIC 357 | ${STDLIB_LINK_LIBRARIES} 358 | ) 359 | 360 | endif() 361 | 362 | endif() 363 | 364 | endif() 365 | -------------------------------------------------------------------------------- /test/compiling_tests.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright Björn Fahller 2014-2018 5 | * Copyright (C) 2017 Andrew Paxie 6 | * 7 | * Use, modification and distribution is subject to the 8 | * Boost Software License, Version 1.0. (See accompanying 9 | * file LICENSE_1_0.txt or copy at 10 | * http://www.boost.org/LICENSE_1_0.txt) 11 | * 12 | * Project home: https://github.com/rollbear/trompeloeil 13 | */ 14 | 15 | #define TROMPELOEIL_SANITY_CHECKS 16 | 17 | #if defined(_WIN32) 18 | #include 19 | #undef interface 20 | #endif 21 | 22 | #include 23 | #if not defined(CATCH2_VERSION) || CATCH2_VERSION == 2 24 | #ifndef CATCH2_MAIN 25 | #define CATCH_CONFIG_MAIN 26 | #endif 27 | #include 28 | #else 29 | #if CATCH2_VERSION == 3 30 | #include 31 | #endif 32 | #endif 33 | 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | 43 | #include "compiling_tests.hpp" 44 | #include "test_reporter.hpp" 45 | 46 | std::vector reports; 47 | std::vector okReports; 48 | 49 | int 50 | intfunc(int i) 51 | { 52 | return i; 53 | } 54 | 55 | int global_n = 0; 56 | 57 | char carr[4] = "foo"; 58 | -------------------------------------------------------------------------------- /test/custom_recursive_mutex.cpp: -------------------------------------------------------------------------------- 1 | #define TROMPELOEIL_CUSTOM_RECURSIVE_MUTEX 2 | #include 3 | 4 | namespace trompeloeil { 5 | 6 | std::unique_ptr create_custom_recursive_mutex() { 7 | 8 | class custom : public custom_recursive_mutex { 9 | void lock() override { mtx.lock(); } 10 | void unlock() override { mtx.unlock(); } 11 | 12 | private: 13 | std::recursive_mutex mtx; 14 | }; 15 | 16 | return std::unique_ptr(new custom); 17 | } 18 | 19 | } // namespace trompeloeil 20 | 21 | class C { 22 | public: 23 | MAKE_MOCK0(func, int(void)); 24 | }; 25 | 26 | int main() { 27 | C c; 28 | std::puts("Pass! (the program compiled)"); 29 | } 30 | -------------------------------------------------------------------------------- /test/micro_coro.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy atl 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | #ifndef TROMPELOEIL_MICRO_CORO_HPP 15 | #define TROMPELOEIL_MICRO_CORO_HPP 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | namespace coro 23 | { 24 | template 25 | struct task; 26 | 27 | template 28 | struct promise 29 | { 30 | promise() = default; 31 | 32 | promise &operator=(promise &&) = delete; 33 | 34 | std::suspend_never 35 | initial_suspend() 36 | const 37 | noexcept 38 | { 39 | return {}; 40 | } 41 | 42 | std::suspend_always 43 | final_suspend() 44 | const 45 | noexcept 46 | { 47 | return {}; 48 | } 49 | 50 | template 51 | std::coroutine_handle<> 52 | await_suspend(std::coroutine_handle

p) 53 | noexcept 54 | { 55 | if (p.promise().continuation_) 56 | { 57 | return p.promise().continuation_; 58 | } 59 | return std::noop_coroutine(); 60 | } 61 | 62 | task 63 | get_return_object() 64 | noexcept; 65 | 66 | bool has_data() const 67 | { 68 | return !std::holds_alternative(data_); 69 | } 70 | 71 | void 72 | return_value(T t) 73 | { 74 | data_.template emplace(std::move(t)); 75 | if (continuation_) 76 | { 77 | continuation_.resume(); 78 | } 79 | } 80 | 81 | auto 82 | yield_value(T t) 83 | { 84 | data_.template emplace(std::move(t)); 85 | if (continuation_) 86 | { 87 | continuation_.resume(); 88 | } 89 | return std::suspend_always{}; 90 | } 91 | 92 | void 93 | unhandled_exception() 94 | noexcept 95 | { 96 | data_.template emplace(std::current_exception()); 97 | } 98 | 99 | T 100 | result() 101 | { 102 | struct cleaner_ { 103 | promise* p; 104 | ~cleaner_() { p->data_.template emplace();} 105 | }; 106 | cleaner_ c{this}; 107 | if (auto v = std::get_if(&data_)) 108 | { 109 | return std::move(v->value); 110 | } 111 | else if (auto e = std::get_if(&data_)) 112 | { 113 | std::rethrow_exception(*e); 114 | } 115 | else 116 | { 117 | abort(); 118 | } 119 | } 120 | 121 | void 122 | continuation(std::coroutine_handle<> next) 123 | noexcept 124 | { 125 | continuation_ = next; 126 | } 127 | private: 128 | struct data 129 | { 130 | data(T&& t) : value(std::move(t)) {} 131 | T value; 132 | }; 133 | std::variant data_; 134 | std::coroutine_handle<> continuation_{nullptr}; 135 | }; 136 | 137 | template<> 138 | struct promise 139 | { 140 | promise() = default; 141 | promise &operator=(promise &&) = delete; 142 | 143 | std::suspend_never 144 | initial_suspend() 145 | const 146 | noexcept 147 | { 148 | return {}; 149 | } 150 | 151 | std::suspend_always 152 | final_suspend() 153 | const 154 | noexcept 155 | { 156 | return {}; 157 | } 158 | 159 | template 160 | std::coroutine_handle<> 161 | await_suspend(std::coroutine_handle

p) 162 | noexcept 163 | { 164 | if (p.promise().continuation_) 165 | { 166 | return p.promise().continuation_; 167 | } 168 | return std::noop_coroutine(); 169 | } 170 | 171 | task 172 | get_return_object() 173 | noexcept; 174 | 175 | bool 176 | has_data() 177 | const 178 | { 179 | return has_data_; 180 | } 181 | void 182 | return_void() 183 | { 184 | has_data_ = true; 185 | exception_ = nullptr; 186 | } 187 | 188 | void 189 | unhandled_exception() 190 | noexcept 191 | { 192 | has_data_ = true; 193 | exception_ = std::current_exception(); 194 | } 195 | 196 | void 197 | result() 198 | { 199 | has_data_ = false; 200 | if (exception_) 201 | { 202 | std::rethrow_exception(exception_); 203 | } 204 | } 205 | 206 | void 207 | continuation(std::coroutine_handle<> next) 208 | noexcept 209 | { 210 | continuation_ = next; 211 | } 212 | private: 213 | std::exception_ptr exception_ = nullptr; 214 | std::coroutine_handle<> continuation_{nullptr}; 215 | bool has_data_ = false; 216 | }; 217 | 218 | template 219 | struct task { 220 | using promise_type = coro::promise; 221 | 222 | explicit task(std::coroutine_handle h = nullptr) : coroutine_(h) {} 223 | 224 | task(task &&h) : coroutine_(std::exchange(h.coroutine_, nullptr)) {} 225 | 226 | ~task() { 227 | if (coroutine_) { 228 | coroutine_.destroy(); 229 | } 230 | } 231 | 232 | bool 233 | is_ready() 234 | const 235 | noexcept 236 | { 237 | return !coroutine_ || coroutine_.done(); 238 | } 239 | 240 | bool 241 | resume() 242 | { 243 | if (!coroutine_.done()) 244 | { 245 | coroutine_.resume(); 246 | } 247 | return !coroutine_.done(); 248 | } 249 | 250 | bool 251 | destroy() 252 | { 253 | if (coroutine_) 254 | { 255 | coroutine_.destroy(); 256 | coroutine_ = nullptr; 257 | return true; 258 | } 259 | return false; 260 | } 261 | 262 | struct awaitable_base 263 | { 264 | bool 265 | await_ready() 266 | const 267 | noexcept 268 | { 269 | return coroutine_.promise().has_data(); 270 | } 271 | 272 | std::coroutine_handle<> 273 | await_suspend(std::coroutine_handle<> next) 274 | noexcept 275 | { 276 | coroutine_.promise().continuation(next); 277 | return coroutine_; 278 | } 279 | 280 | 281 | std::coroutine_handle coroutine_; 282 | }; 283 | 284 | auto 285 | operator co_await() 286 | const & 287 | noexcept 288 | 289 | { 290 | struct awaitable : awaitable_base { 291 | decltype(auto) 292 | await_resume() 293 | { 294 | return awaitable_base::coroutine_.promise().result(); 295 | } 296 | 297 | }; 298 | return awaitable{coroutine_}; 299 | } 300 | 301 | auto 302 | operator co_await() 303 | const && 304 | noexcept 305 | 306 | { 307 | struct awaitable : awaitable_base { 308 | decltype(auto) 309 | await_resume() 310 | { 311 | return std::move(awaitable_base::coroutine_.promise()).result(); 312 | } 313 | 314 | }; 315 | return awaitable{coroutine_}; 316 | } 317 | 318 | promise_type& 319 | promise() 320 | const 321 | { 322 | return coroutine_.promise(); 323 | } 324 | 325 | private: 326 | std::coroutine_handle coroutine_; 327 | }; 328 | 329 | template 330 | task 331 | promise::get_return_object() 332 | noexcept 333 | { 334 | return task{std::coroutine_handle::from_promise(*this)}; 335 | } 336 | 337 | task 338 | promise::get_return_object() 339 | noexcept 340 | { 341 | return task{std::coroutine_handle::from_promise(*this)}; 342 | } 343 | 344 | template 345 | struct generator; 346 | 347 | template 348 | struct generator_promise 349 | { 350 | generator_promise() = default; 351 | 352 | generator_promise &operator=(generator_promise &&) = delete; 353 | 354 | std::suspend_never 355 | initial_suspend() 356 | const 357 | noexcept 358 | { 359 | return {}; 360 | } 361 | 362 | std::suspend_always 363 | final_suspend() 364 | const 365 | noexcept 366 | { 367 | return {}; 368 | } 369 | 370 | template 371 | std::coroutine_handle<> 372 | await_suspend(std::coroutine_handle

p) 373 | noexcept 374 | { 375 | if (p.promise().continuation_) 376 | { 377 | return p.promise().continuation_; 378 | } 379 | return std::noop_coroutine(); 380 | } 381 | 382 | generator 383 | get_return_object() 384 | noexcept; 385 | 386 | bool has_data() const 387 | { 388 | return !std::holds_alternative(data_); 389 | } 390 | 391 | void 392 | return_void() 393 | { 394 | if (continuation_) 395 | { 396 | continuation_.resume(); 397 | } 398 | } 399 | 400 | auto 401 | yield_value(T t) 402 | { 403 | data_.template emplace(std::move(t)); 404 | if (continuation_) 405 | { 406 | continuation_.resume(); 407 | } 408 | return std::suspend_always{}; 409 | } 410 | 411 | void 412 | unhandled_exception() 413 | noexcept 414 | { 415 | data_.template emplace(std::current_exception()); 416 | } 417 | 418 | T 419 | result() 420 | { 421 | struct cleaner_ 422 | { 423 | generator_promise *p; 424 | 425 | ~cleaner_() 426 | { p->data_.template emplace(); } 427 | }; 428 | cleaner_ c{this}; 429 | if (auto v = std::get_if(&data_)) 430 | { 431 | return std::move(v->value); 432 | } else if (auto e = std::get_if(&data_)) 433 | { 434 | std::rethrow_exception(*e); 435 | } else 436 | { 437 | abort(); 438 | } 439 | } 440 | void 441 | continuation(std::coroutine_handle<> next) 442 | noexcept 443 | { 444 | continuation_ = next; 445 | } 446 | private: 447 | struct data 448 | { 449 | data(T&& t) : value(std::move(t)) {} 450 | T value; 451 | }; 452 | std::variant data_; 453 | std::coroutine_handle<> continuation_{nullptr}; 454 | }; 455 | 456 | template 457 | struct generator 458 | { 459 | using promise_type = coro::generator_promise; 460 | 461 | explicit generator(std::coroutine_handle h = nullptr) : coroutine_(h) {} 462 | 463 | generator(generator &&h) : coroutine_(std::exchange(h.coroutine_, nullptr)) {} 464 | 465 | ~generator() { 466 | if (coroutine_) { 467 | coroutine_.destroy(); 468 | } 469 | } 470 | 471 | bool 472 | is_ready() 473 | const 474 | noexcept 475 | { 476 | return !coroutine_ || coroutine_.done(); 477 | } 478 | 479 | bool 480 | resume() 481 | { 482 | if (!coroutine_.done()) 483 | { 484 | coroutine_.resume(); 485 | } 486 | return !coroutine_.done(); 487 | } 488 | 489 | bool 490 | destroy() 491 | { 492 | if (coroutine_) 493 | { 494 | coroutine_.destroy(); 495 | coroutine_ = nullptr; 496 | return true; 497 | } 498 | return false; 499 | } 500 | 501 | struct awaitable_base 502 | { 503 | bool 504 | await_ready() 505 | const 506 | noexcept 507 | { 508 | return coroutine_.promise().has_data(); 509 | } 510 | 511 | std::coroutine_handle<> 512 | await_suspend(std::coroutine_handle<> next) 513 | noexcept 514 | { 515 | coroutine_.promise().continuation(next); 516 | return coroutine_; 517 | } 518 | 519 | 520 | std::coroutine_handle coroutine_; 521 | }; 522 | 523 | auto 524 | operator co_await() 525 | const & 526 | noexcept 527 | 528 | { 529 | struct awaitable : awaitable_base { 530 | decltype(auto) 531 | await_resume() 532 | { 533 | return awaitable_base::coroutine_.promise().result(); 534 | } 535 | 536 | }; 537 | return awaitable{coroutine_}; 538 | } 539 | 540 | auto 541 | operator co_await() 542 | const && 543 | noexcept 544 | 545 | { 546 | struct awaitable : awaitable_base { 547 | decltype(auto) 548 | await_resume() 549 | { 550 | return std::move(awaitable_base::coroutine_.promise()).result(); 551 | } 552 | 553 | }; 554 | return awaitable{coroutine_}; 555 | } 556 | 557 | promise_type& 558 | promise() 559 | const 560 | { 561 | return coroutine_.promise(); 562 | } 563 | 564 | private: 565 | std::coroutine_handle coroutine_; 566 | 567 | }; 568 | 569 | template 570 | generator generator_promise::get_return_object() noexcept 571 | { 572 | return generator{std::coroutine_handle::from_promise(*this)}; 573 | } 574 | } // namespace coro 575 | 576 | #endif //TROMPELOEIL_MICRO_CORO_HPP 577 | -------------------------------------------------------------------------------- /test/test_co_mock.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Trompeloeil C++ mocking framework 3 | * 4 | * Copyright (C) Björn Fahller 5 | * 6 | * Use, modification and distribution is subject to the 7 | * Boost Software License, Version 1.0. (See accompanying 8 | * file LICENSE_1_0.txt or copy atl 9 | * http://www.boost.org/LICENSE_1_0.txt) 10 | * 11 | * Project home: https://github.com/rollbear/trompeloeil 12 | */ 13 | 14 | #ifdef __cpp_impl_coroutine 15 | 16 | #include 17 | #include 18 | 19 | #if defined(CATCH2_VERSION) && CATCH2_VERSION == 3 20 | #include 21 | #else 22 | #include 23 | #endif 24 | #include "micro_coro.hpp" 25 | #include "test_reporter.hpp" 26 | #include 27 | 28 | #include 29 | #ifdef __cpp_lib_generator 30 | #include 31 | #endif 32 | 33 | using trompeloeil::_; 34 | 35 | namespace { 36 | using iptr = std::unique_ptr; 37 | 38 | struct co_mock { 39 | MAKE_MOCK0 (intret, coro::task()); 40 | MAKE_MOCK0 (voidret, coro::task()); 41 | MAKE_MOCK1 (unique, coro::task(iptr)); 42 | MAKE_MOCK0 (gen, coro::generator()); 43 | 44 | #ifdef __cpp_lib_generator 45 | MAKE_MOCK0 (stdgen, std::generator()); 46 | #endif // __cpp_lib_generator 47 | }; 48 | } 49 | 50 | TEST_CASE_METHOD( 51 | Fixture, 52 | "A CO_RETURNed value is obtained from co_await", 53 | "[coro]") 54 | { 55 | co_mock m; 56 | REQUIRE_CALL(m, intret()).CO_RETURN(3); 57 | 58 | int x = 0; 59 | std::invoke([&]()->coro::task{ x = co_await m.intret();}); 60 | 61 | REQUIRE(x == 3); 62 | 63 | REQUIRE(reports.empty()); 64 | } 65 | 66 | TEST_CASE_METHOD( 67 | Fixture, 68 | "The coroutine can be executed after the expectation has been retired", 69 | "[coro]") 70 | { 71 | co_mock m; 72 | std::optional> t; 73 | { 74 | REQUIRE_CALL(m, intret()).CO_RETURN(3); 75 | t.emplace(m.intret()); 76 | } 77 | 78 | int x = 0; 79 | std::invoke([&]()->coro::task{ x = co_await *t;}); 80 | 81 | REQUIRE(x == 3); 82 | REQUIRE(reports.empty()); 83 | } 84 | 85 | TEST_CASE_METHOD( 86 | Fixture, 87 | "A void co_routine is CO_RETURNed", 88 | "[coro]") 89 | { 90 | co_mock m; 91 | REQUIRE_CALL(m, voidret()).CO_RETURN(); 92 | 93 | int x = 0; 94 | std::invoke([&]()->coro::task{ co_await m.voidret(); x = 3;}); 95 | 96 | REQUIRE(x == 3); 97 | REQUIRE(reports.empty()); 98 | } 99 | 100 | TEST_CASE_METHOD( 101 | Fixture, 102 | "If the CO_RETURN expression throws, the exception is thrown from co_await", 103 | "[coro]") 104 | { 105 | co_mock m; 106 | std::optional> t; 107 | { 108 | REQUIRE_CALL(m, intret()).CO_RETURN(false ? 0 : throw "foo"); 109 | t.emplace(m.intret()); 110 | } 111 | int x = 0; 112 | std::invoke([&]()->coro::task{ 113 | REQUIRE_THROWS(co_await *t); 114 | x = 1; 115 | }); 116 | REQUIRE(x == 1); 117 | REQUIRE(reports.empty()); 118 | } 119 | 120 | TEST_CASE_METHOD( 121 | Fixture, 122 | "Exception from CO_THROW is thrown from co_await", 123 | "[coro]") 124 | { 125 | co_mock m; 126 | REQUIRE_CALL(m, intret()).CO_THROW("foo"); 127 | auto p = m.intret(); 128 | int x = 0; 129 | std::invoke([&]()->coro::task{ 130 | REQUIRE_THROWS(co_await p); 131 | x = 1; 132 | }); 133 | REQUIRE(x == 1); 134 | REQUIRE(reports.empty()); 135 | } 136 | 137 | TEST_CASE_METHOD( 138 | Fixture, 139 | "A move-only type can be CO_RETURNed from the argument", 140 | "[coro]") 141 | { 142 | co_mock m; 143 | REQUIRE_CALL(m, unique(_)).CO_RETURN(std::move(_1)); 144 | auto p = m.unique(std::make_unique(3)); 145 | iptr x; 146 | std::invoke([&]() -> coro::task { x = co_await p; }); 147 | REQUIRE(x); 148 | REQUIRE(*x == 3); 149 | REQUIRE(reports.empty()); 150 | } 151 | 152 | TEST_CASE_METHOD( 153 | Fixture, 154 | "SIDE_EFFECT runs on the call to co-routine function, not when the coro runs", 155 | "[coro]") 156 | { 157 | co_mock m; 158 | int x = 0; 159 | int y = 0; 160 | REQUIRE_CALL(m, intret()).LR_SIDE_EFFECT(x=1).CO_RETURN(5); 161 | auto p = m.intret(); 162 | REQUIRE(x == 1); 163 | REQUIRE(y == 0); 164 | x = 0; 165 | std::invoke([&]() -> coro::task { y = co_await p;}); 166 | REQUIRE(x == 0); 167 | REQUIRE(y == 5); 168 | REQUIRE(reports.empty()); 169 | } 170 | 171 | TEST_CASE_METHOD( 172 | Fixture, 173 | "CO_YIELDed values are co_await:ed in order with CO_RETURN last", 174 | "[coro]") 175 | { 176 | co_mock m; 177 | REQUIRE_CALL(m, intret()).CO_YIELD(1).CO_YIELD(2).CO_RETURN(0); 178 | auto p = m.intret(); 179 | int v = 0; 180 | std::invoke([&]() -> coro::task { v = co_await p;}); 181 | REQUIRE(v == 1); 182 | std::invoke([&]() -> coro::task { v = co_await p;}); 183 | REQUIRE(v == 2); 184 | std::invoke([&]() -> coro::task { v = co_await p;}); 185 | REQUIRE(v == 0); 186 | REQUIRE(reports.empty()); 187 | } 188 | 189 | TEST_CASE_METHOD( 190 | Fixture, 191 | "Empty CO_RETURN can end a generator with yield and return_void", 192 | "[coro]") 193 | { 194 | co_mock m; 195 | REQUIRE_CALL(m, gen()) 196 | .CO_YIELD(5) 197 | .CO_YIELD(8) 198 | .CO_YIELD(3) 199 | .CO_RETURN(); 200 | auto p = m.gen(); 201 | int v = 0; 202 | std::invoke([&]() -> coro::task { v = co_await p;}); 203 | REQUIRE(v == 5); 204 | std::invoke([&]() -> coro::task { v = co_await p;}); 205 | REQUIRE(v == 8); 206 | std::invoke([&]() -> coro::task { v = co_await p;}); 207 | REQUIRE(v == 3); 208 | REQUIRE(reports.empty()); 209 | } 210 | 211 | #ifdef __cpp_lib_generator 212 | TEST_CASE_METHOD( 213 | Fixture, 214 | "CO_YIELD with std::generator", 215 | "[coro]") 216 | { 217 | co_mock m; 218 | REQUIRE_CALL(m, stdgen()) 219 | .CO_YIELD(5) 220 | .CO_YIELD(8) 221 | .CO_YIELD(3) 222 | .CO_YIELD(0) 223 | .CO_RETURN(); 224 | 225 | auto gen = m.stdgen(); 226 | 227 | SECTION("as iterator") 228 | { 229 | auto it = std::ranges::begin(gen); 230 | REQUIRE(*it == 5); 231 | ++it; 232 | REQUIRE(it != std::ranges::end(gen)); 233 | REQUIRE(*it == 8); 234 | ++it; 235 | REQUIRE(it != std::ranges::end(gen)); 236 | REQUIRE(*it == 3); 237 | ++it; 238 | REQUIRE(it != std::ranges::end(gen)); 239 | REQUIRE(*it == 0); 240 | ++it; 241 | REQUIRE(it == std::ranges::end(gen)); 242 | } 243 | 244 | SECTION("as range") 245 | { 246 | REQUIRE(std::ranges::equal(gen, std::array{5, 8, 3, 0})); 247 | } 248 | 249 | REQUIRE(reports.empty()); 250 | } 251 | #endif // __cpp_lib_generator 252 | #endif 253 | -------------------------------------------------------------------------------- /test/test_reporter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef TROMPELOEIL_TEST_REPORTER_HPP 2 | #define TROMPELOEIL_TEST_REPORTER_HPP 3 | 4 | #include 5 | 6 | namespace detail 7 | { 8 | /* 9 | * Use compiler-version independent make_unique. 10 | */ 11 | using ::trompeloeil::detail::make_unique; 12 | 13 | // std::uncaught_exception() is deprecated in C++17. 14 | inline 15 | bool 16 | there_are_uncaught_exceptions() 17 | { 18 | /* 19 | * GCC 5.x supports specifying -std=c++17 but libstdc++-v3 for 20 | * GCC 5.x doesn't declare std::uncaught_exceptions(). 21 | * Rather than detect what version of C++ Standard Library 22 | * is in use, we equate the compiler version with the library version. 23 | * 24 | * Some day this test will based on __cpp_lib_uncaught_exceptions. 25 | */ 26 | # if (TROMPELOEIL_CPLUSPLUS > 201402L) && \ 27 | ((!TROMPELOEIL_GCC) || \ 28 | (TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 60000)) 29 | 30 | return std::uncaught_exceptions() > 0; 31 | 32 | # else 33 | 34 | return std::uncaught_exception(); 35 | 36 | # endif 37 | } 38 | 39 | } /* namespace detail */ 40 | 41 | class reported {}; 42 | 43 | struct report 44 | { 45 | trompeloeil::severity s; 46 | const char *file; 47 | unsigned long line; 48 | std::string msg; 49 | }; 50 | 51 | extern std::vector reports; 52 | extern std::vector okReports; 53 | 54 | namespace trompeloeil 55 | { 56 | template <> 57 | struct reporter 58 | { 59 | static void send(severity s, 60 | char const* file, 61 | unsigned long line, 62 | char const* msg) 63 | { 64 | reports.push_back(report{s, file, line, msg}); 65 | if (s == severity::fatal && !::detail::there_are_uncaught_exceptions()) 66 | { 67 | throw reported{}; 68 | } 69 | } 70 | 71 | static void sendOk(char const* msg) 72 | { 73 | okReports.push_back(msg); 74 | } 75 | }; 76 | } 77 | 78 | struct Fixture 79 | { 80 | Fixture() { 81 | reports.clear(); 82 | okReports.clear(); 83 | } 84 | }; 85 | 86 | #endif //TROMPELOEIL_TEST_REPORTER_HPP 87 | -------------------------------------------------------------------------------- /test/thread_terror.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class C 9 | { 10 | public: 11 | MAKE_MOCK0(func, unsigned(void)); 12 | std::unique_ptr allow; 13 | }; 14 | 15 | static std::mutex ptr_mutex; 16 | inline std::unique_lock get_lock() 17 | { 18 | return std::unique_lock{ ptr_mutex }; 19 | } 20 | 21 | static std::shared_ptr obj; 22 | 23 | inline std::shared_ptr get_obj() 24 | { 25 | auto lock = get_lock(); 26 | return obj; 27 | } 28 | 29 | static std::array, 7> call_count; 30 | static std::array, 7> ret_count; 31 | 32 | static void init_obj() 33 | { 34 | auto m = std::make_shared(); 35 | m->allow = NAMED_ALLOW_CALL(*m, func()) 36 | .SIDE_EFFECT(++call_count[0]) 37 | .RETURN(0U); 38 | auto lock = get_lock(); 39 | obj = m; 40 | } 41 | 42 | static void make(size_t count) 43 | { 44 | while (count--) 45 | { 46 | init_obj(); 47 | } 48 | } 49 | 50 | static void call(size_t count) 51 | { 52 | while (count--) 53 | { 54 | if (auto m = get_obj()) 55 | { 56 | std::size_t idx = m->func(); 57 | assert(idx < ret_count.size()); 58 | ret_count[idx]++; 59 | } 60 | } 61 | } 62 | 63 | static void allow(size_t count, unsigned id) 64 | { 65 | std::unique_ptr exp; 66 | while (count--) 67 | { 68 | if (auto m = get_obj()) 69 | { 70 | exp = NAMED_ALLOW_CALL(*m, func()) 71 | .SIDE_EFFECT(++call_count[id]) 72 | .RETURN(id); 73 | assert(exp->is_satisfied()); 74 | assert(!exp->is_saturated()); 75 | } 76 | } 77 | } 78 | 79 | int main() 80 | { 81 | trompeloeil::set_reporter([](auto , auto , auto, auto&) 82 | { 83 | abort(); 84 | }); 85 | init_obj(); 86 | 87 | size_t count = 100000; 88 | std::vector allowers; 89 | std::vector callers; 90 | allowers.reserve(6); 91 | callers.reserve(6); 92 | auto maker = std::thread(make, count); 93 | for (int i = 1; i <= 6; ++i) 94 | { 95 | allowers.emplace_back(allow, count, i); 96 | callers.emplace_back(call, count); 97 | } 98 | for (auto& t : callers) t.join(); 99 | for (auto& t : allowers) t.join(); 100 | maker.join(); 101 | std::cout << "calls "; 102 | std::copy(std::begin(call_count), std::end(call_count), 103 | std::ostream_iterator(std::cout, " ")); 104 | std::cout << "\nreturns "; 105 | std::copy(std::begin(ret_count), std::end(ret_count), 106 | std::ostream_iterator(std::cout, " ")); 107 | std::cout << "\n"; 108 | assert(std::equal(std::begin(call_count), std::end(call_count), 109 | std::begin(ret_count), std::end(ret_count))); 110 | obj.reset(); 111 | } 112 | -------------------------------------------------------------------------------- /trompeloeil-config.cmake: -------------------------------------------------------------------------------- 1 | include( "${CMAKE_CURRENT_LIST_DIR}/trompeloeil-targets.cmake" ) 2 | 3 | -------------------------------------------------------------------------------- /trompeloeil-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rollbear/trompeloeil/2a633b923f32cebc336dc8a6a77e4c04f2238106/trompeloeil-logo.png -------------------------------------------------------------------------------- /trompeloeil-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 20 | 22 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 61 | 67 | Ceci n'est pas un objet. 80 | 89 | 98 | obj : Mock 111 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /verify_compilation_error.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Trompeloeil C++ mocking framework 5 | # 6 | # Copyright Björn Fahller 2022 7 | # 8 | # Use, modification and distribution is subject to the 9 | # Boost Software License, Version 1.0. (See accompanying 10 | # file LICENSE_1_0.txt or copy at 11 | # http://www.boost.org/LICENSE_1_0.txt) 12 | # 13 | # Project home: https://github.com/rollbear/trompeloeil 14 | # 15 | 16 | get_rule () 17 | { 18 | SCRIPT=' 19 | s|^// '$1': \(.*\)$|\1|g 20 | t print 21 | b 22 | :print 23 | P 24 | ' 25 | sed -n "$SCRIPT" < $2 26 | } 27 | PASS="\033[32mPASS\033[0m" 28 | FAIL="\033[1;31mFAIL\033[0m" 29 | 30 | f=$1 31 | EXCEPTION_RE=`get_rule "exception" $f` 32 | COMPILER="${CXX} ${CXXFLAGS} ${CPPFLAGS}" 33 | 34 | [ -n "$EXCEPTION_RE" ] && echo "{$RUNNER_OS} ${COMPILER}" | grep -q -e "$EXCEPTION_RE" && exit 0 35 | PASS_RE=`get_rule "pass" $f` 36 | failfile=`mktemp` 37 | (${COMPILER} -I ../include $f -c 2>&1) > $failfile 38 | cat $failfile | egrep -q "${PASS_RE}" && printf "%-45s ${PASS}\n" $f && continue || { printf "%-45s ${FAIL}\n" $f; cat $failfile; } && false 39 | RET=$? 40 | rm $failfile 41 | exit $RET 42 | --------------------------------------------------------------------------------