pax_global_header00006660000000000000000000000064145445246130014522gustar00rootroot0000000000000052 comment=ad9bc41b1e01ae92802de59a12d19cf7c8683d6d trompeloeil-47/000077500000000000000000000000001454452461300136515ustar00rootroot00000000000000trompeloeil-47/.gitattributes000066400000000000000000000000301454452461300165350ustar00rootroot00000000000000* text=auto *.sh eol=lf trompeloeil-47/.github/000077500000000000000000000000001454452461300152115ustar00rootroot00000000000000trompeloeil-47/.github/workflows/000077500000000000000000000000001454452461300172465ustar00rootroot00000000000000trompeloeil-47/.github/workflows/ci.yml000066400000000000000000001416021454452461300203700ustar00rootroot00000000000000name: CI # Trigger on pushes to all branches and for all pull-requests on: [push, pull_request] jobs: build: name: ${{ matrix.config.name }} runs-on: ${{ matrix.config.os }} container: ${{ matrix.config.container }} strategy: fail-fast: false matrix: config: # GCC-4.8 - { name: "Linux GCC 4.8 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:4.8" }, #cc: "gcc-4.8", cxx: "g++-4.8", compiler: gcc, cxx_standard: 11, cxx_asan: true, } # GCC-4.9 - { name: "Linux GCC 4.9 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:4.9" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 4.9 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:4.9" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } # GCC-5 - { name: "Linux GCC 5 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:5" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 5 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:5" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 5 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:5" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } # GCC-6 - { name: "Linux GCC 6 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:6" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 6 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:6" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 6 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:6" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } # GCC-7 - { name: "Linux GCC 7 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:7" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 7 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:7" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 7 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:7" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } # GCC-8 - { name: "Linux GCC 8 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:8" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 8 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:8" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 8 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:8" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } # GCC-9 - { name: "Linux GCC 9 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:9" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 9 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:9" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 9 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:9" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } # GCC-10 - { name: "Linux GCC 10 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:10" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 10 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:10" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 10 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:10" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } - { name: "Linux GCC 10 C++20", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:10" }, compiler: gcc, cxx_standard: 20, cxx_asan: true, } # GCC-11 - { name: "Linux GCC 11 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:11" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 11 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:11" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 11 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:11" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } - { name: "Linux GCC 11 C++20", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:11" }, compiler: gcc, cxx_standard: 20, cxx_asan: true, } # GCC-12 - { name: "Linux GCC 12 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:12" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 12 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:12" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 12 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:12" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } - { name: "Linux GCC 12 C++20", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:12" }, compiler: gcc, cxx_standard: 20, cxx_asan: true, } - { name: "Linux GCC 12 C++23", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:12" }, compiler: gcc, cxx_standard: 23, cxx_asan: true, } # GCC-13 - { name: "Linux GCC 13 C++11", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:13" }, compiler: gcc, cxx_standard: 11, cxx_asan: true, } - { name: "Linux GCC 13 C++14", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:13" }, compiler: gcc, cxx_standard: 14, cxx_asan: true, } - { name: "Linux GCC 13 C++17", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:13" }, compiler: gcc, cxx_standard: 17, cxx_asan: true, } - { name: "Linux GCC 13 C++20", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:13" }, compiler: gcc, cxx_standard: 20, cxx_asan: true, } - { name: "Linux GCC 13 C++23", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/gcc:13" }, compiler: gcc, cxx_standard: 23, cxx_asan: true, } # Clang-3.5 - { name: "Linux Clang 3.5 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.5" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } #- { # name: "Linux Clang 3.5 C++14 / libstdc++", # os: ubuntu-latest, # container: { image: "ghcr.io/rollbear/clang:3.5" }, # compiler: clang, # cxx_standard: 14, # cxx_asan: false, # libcxx: false #} - { name: "Linux Clang 3.5 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.5" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 3.5 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.5" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, no_coverage: true, } # Clang-3.6 - { name: "Linux Clang 3.6 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.6" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 3.6 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.6" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, no_coverage: true } - { name: "Linux Clang 3.6 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.6" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 3.6 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.6" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, no_coverage: true } # Clang-3.7 - { name: "Linux Clang 3.7 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.7" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: false, } - { name: "Linux Clang 3.7 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.7" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: false, } - { name: "Linux Clang 3.7 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.7" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 3.7 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.7" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, } # Clang-3.8 - { name: "Linux Clang 3.8 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.8" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 3.8 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.8" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 3.8 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.8" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 3.8 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.8" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, } # Clang-3.9 - { name: "Linux Clang 3.9 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.9" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 3.9 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.9" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 3.9 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.9" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 3.9 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:3.9" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, no_coverage: true } # Clang-4.0 - { name: "Linux Clang 4.0 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:4.0" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 4.0 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:4.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 4.0 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:4.0" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 4.0 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:4.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, no_coverage: true } # Clang-5.0 - { name: "Linux Clang 5.0 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 5.0 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 5.0 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 5.0 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 5.0 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 5.0 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:5.0" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } # Clang-6.0 - { name: "Linux Clang 6.0 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 6.0 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 6.0 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 6.0 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 6.0 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 6.0 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:6.0" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } # Clang-7 - { name: "Linux Clang 7 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 7 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 7 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 7 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 7 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 7 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:7" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } # Clang-8 - { name: "Linux Clang 8 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: false, } - { name: "Linux Clang 8 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 8 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 8 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 8 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 8 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:8" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } # Clang-9 - { name: "Linux Clang 9 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 9 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 9 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 9 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 9 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 9 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:9" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } # Clang-10 - { name: "Linux Clang 10 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 10 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 10 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 10 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 10 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 10 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 10 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 10 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:10" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: true, } # Clang-11 - { name: "Linux Clang 11 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 11 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 11 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 11 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 11 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 11 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 11 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 11 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:11" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: true, } # Clang-12 - { name: "Linux Clang 12 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 12 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 12 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 12 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 12 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 12 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 12 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 12 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:12" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: true, } # Clang-13 - { name: "Linux Clang 13 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 13 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 13 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 13 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 13 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 13 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 13 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 13 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:13" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: true, } # Clang-14 - { name: "Linux Clang 14 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 14 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 14 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 14 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 14 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 14 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 14 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: true, } - { name: "Linux Clang 14 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:14" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: true, } # Clang-15 - { name: "Linux Clang 15 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 15 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 15 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 15 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 15 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 15 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 15 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 17, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 15 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:15" }, compiler: clang, cxx_standard: 20, cxx_asan: false, libcxx: true, } # Clang-16 - { name: "Linux Clang 16 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 16 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 16 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 16 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 16 C++23 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 2b, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 16 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 16 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 16 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 17, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 16 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 20, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 16 C++23 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:16" }, compiler: clang, cxx_standard: 2b, cxx_asan: false, libcxx: true, } # clang-17 - { name: "Linux Clang 17 C++11 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 11, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 17 C++14 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 14, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 17 C++17 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 17, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 17 C++20 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 20, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 17 C++23 / libstdc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 23, cxx_asan: true, libcxx: false, } - { name: "Linux Clang 17 C++11 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 11, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 17 C++14 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 14, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 17 C++17 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 17, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 17 C++20 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 20, cxx_asan: false, libcxx: true, } - { name: "Linux Clang 17 C++23 / libc++", os: ubuntu-latest, container: { image: "ghcr.io/rollbear/clang:17" }, compiler: clang, cxx_standard: 23, cxx_asan: false, libcxx: true, } # AppleClang - { name: "macOS Clang C++11", os: macos-latest, cc: "clang", cxx: "clang++", cxx_standard: 11, cxx_asan: true } - { name: "macOS Clang C++14", os: macos-latest, cc: "clang", cxx: "clang++", cxx_standard: 14, cxx_asan: true } - { name: "macOS Clang C++17", os: macos-latest, cc: "clang", cxx: "clang++", cxx_standard: 17, cxx_asan: true } - { name: "macOS Clang C++20", os: macos-latest, cc: "clang", cxx: "clang++", cxx_standard: 20, cxx_asan: true } - { name: "macOS Clang C++23", os: macos-latest, cc: "clang", cxx: "clang++", cxx_standard: 2b, cxx_asan: true } # MSVC 2022 - { name: "Windows MSVC 2022 C++11", os: windows-2022, cc: "cl", cxx: "cl", cxx_standard: 11, } - { name: "Windows MSVC 2022 C++14", os: windows-2022, cc: "cl", cxx: "cl", cxx_standard: 14, } - { name: "Windows MSVC 2022 C++17", os: windows-2022, cc: "cl", cxx: "cl", cxx_standard: 17, } - { name: "Windows MSVC 2022 C++20", os: windows-2022, cc: "cl", cxx: "cl", cxx_standard: 20, } # MSVC 2019 - { name: "Windows MSVC 2019 C++11", os: windows-2019, cc: "cl", cxx: "cl", cxx_standard: 11, } - { name: "Windows MSVC 2019 C++14", os: windows-2019, cc: "cl", cxx: "cl", cxx_standard: 14, } - { name: "Windows MSVC 2019 C++17", os: windows-2019, cc: "cl", cxx: "cl", cxx_standard: 17, } - { name: "Windows MSVC 2019 C++20", os: windows-2019, cc: "cl", cxx: "cl", cxx_standard: 20, } steps: - uses: actions/checkout@v3 - name: Configure MSVC console (Windows) if: startsWith(matrix.config.os, 'windows') uses: ilammy/msvc-dev-cmd@v1 - name: Set MacOS compiler env id: set_macos_cc_cxx if: startsWith(matrix.config.os, 'macos') shell: bash run: | env brew install parallel ninja echo "CC=clang" >> $GITHUB_ENV echo "CXX=clang++" >> $GITHUB_ENV - name: Verify compilation errors if: (!startsWith(matrix.config.os, 'windows')) shell: bash run: | CXXFLAGS="-std=c++${{ matrix.config.cxx_standard }}" ./check_errors.sh - name: Configure shell: bash run: | STD=${{ matrix.config.cxx_standard }} if [ "x${{ matrix.config.libcxx }}" == "xtrue" ] then cxx_flags="${cxx_flags} -stdlib=libc++ -Wno-unused-command-line-argument" link_flags="${link_flags} -lc++abi" STDLIB="libc++" fi if [ "x${{ matrix.config.cxx_asan }}" == "xtrue" ] then cxx_flags="${cxx_flags} -fno-omit-frame-pointer" fi [ -n "${{ matrix.config.no_coverage }}" ] || { echo ${{ matrix.config.name }} | grep -q -e '^Windows' || cxx_flags="${cxx_flags} --coverage" } cmake \ -S . \ -B build \ -D TROMPELOEIL_BUILD_TESTS=yes \ -D CMAKE_BUILD_TYPE=Debug \ -D CMAKE_VERBOSE_MAKEFILE=ON \ -D CXX_STANDARD:STRING=${STD} \ -D CMAKE_PREFIX_PATH="/usr/local/lib/c++${STD}${STDLIB}" \ -D CMAKE_CXX_FLAGS:STRING="${cxx_flags}" \ -D CMAKE_EXE_LINKER_FLAGS:STRING="${link_flags}" \ -D SANITIZE=${{matrix.config.cxx_asan}} \ ${{ matrix.config.cmake_args }} \ ${extra_cmake_args} \ -G Ninja - name: Build shell: bash run: | cmake --build build --target self_test - name: Run tests shell: bash run: | ./build/test/self_test - name: Collect coverage if: (!startsWith(matrix.config.name, 'windows') && !matrix.config.no_coverage) run: | COV=`echo "${{ matrix.config.name }}}" | grep -q -e "Linux.*Clang" && echo "llvm-cov gcov"|| echo gcov` ${COV} -abcfup `find build/test -name "*.gcno"` ls *.gcov| grep -v 'include#trompeloeil'|xargs rm - name: Upload coverage if: (!startsWith(matrix.config.name, 'windows') && !matrix.config.no_coverage) && github.repository == 'rollbear/trompeloeil' uses: codecov/codecov-action@v3 with: gcov_include: "include/trompeloeil" name: "${{ matrix.config.name }}" fail_ci_if_error: false verbose: true trompeloeil-47/.gitignore000066400000000000000000000210741454452461300156450ustar00rootroot00000000000000 # Created by https://www.gitignore.io/api/c++,cmake,clion,visualstudio,visualstudiocode # Edit at https://www.gitignore.io/?templates=c++,cmake,clion,visualstudio,visualstudiocode ### C++ ### # Prerequisites *.d # Compiled Object files *.slo *.lo *.o *.obj # Precompiled Headers *.gch *.pch # Compiled Dynamic libraries *.so *.dylib *.dll # Fortran module files *.mod *.smod # Compiled Static libraries *.lai *.la *.a *.lib # Executables *.exe *.out *.app ### CLion ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 # User-specific stuff .idea/**/workspace.xml .idea/**/tasks.xml .idea/**/usage.statistics.xml .idea/**/dictionaries .idea/**/shelf # Generated files .idea/**/contentModel.xml # Sensitive or high-churn files .idea/**/dataSources/ .idea/**/dataSources.ids .idea/**/dataSources.local.xml .idea/**/sqlDataSources.xml .idea/**/dynamic.xml .idea/**/uiDesigner.xml .idea/**/dbnavigator.xml # Gradle .idea/**/gradle.xml .idea/**/libraries # Gradle and Maven with auto-import # When using Gradle or Maven with auto-import, you should exclude module files, # since they will be recreated, and may cause churn. Uncomment if using # auto-import. # .idea/modules.xml # .idea/*.iml # .idea/modules # *.iml # *.ipr # CMake cmake-build-*/ # Mongo Explorer plugin .idea/**/mongoSettings.xml # File-based project format *.iws # IntelliJ out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Cursive Clojure plugin .idea/replstate.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties # Editor-based Rest Client .idea/httpRequests # Android studio 3.1+ serialized cache file .idea/caches/build_file_checksums.ser ### CLion Patch ### # Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721 # *.iml # modules.xml # .idea/misc.xml # *.ipr # Sonarlint plugin .idea/sonarlint ### CMake ### CMakeLists.txt.user CMakeCache.txt CMakeFiles CMakeScripts Testing Makefile cmake_install.cmake install_manifest.txt compile_commands.json CTestTestfile.cmake _deps ### CMake Patch ### # External projects *-prefix/ ### VisualStudioCode ### .vscode/* !.vscode/settings.json !.vscode/tasks.json !.vscode/launch.json !.vscode/extensions.json ### VisualStudioCode Patch ### # Ignore all local history of files .history ### VisualStudio ### ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. ## ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files *.rsuser *.suo *.user *.userosscache *.sln.docstates # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs # Mono auto generated files mono_crash.* # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ [Rr]eleases/ x64/ x86/ [Aa][Rr][Mm]/ [Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ [Ll]og/ # Visual Studio 2015/2017 cache/options directory .vs/ # Uncomment if you have tasks that create the project's static files in wwwroot #wwwroot/ # Visual Studio 2017 auto generated files Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* # NUnit *.VisualState.xml TestResult.xml nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ # .NET Core project.lock.json project.fragment.lock.json artifacts/ # StyleCop StyleCopReport.xml # Files built by Visual Studio *_i.c *_p.c *_h.h *.ilk *.meta *.iobj *.pdb *.ipdb *.pgc *.pgd *.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj *_wpftmp.csproj *.log *.vspscc *.vssscc .builds *.pidb *.svclog *.scc # Chutzpah Test files _Chutzpah* # Visual C++ cache files ipch/ *.aps *.ncb *.opendb *.opensdf *.sdf *.cachefile *.VC.db *.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx *.sap # Visual Studio Trace Files *.e2e # TFS 2012 Local Workspace $tf/ # Guidance Automation Toolkit *.gpState # ReSharper is a .NET coding add-in _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user # JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in _TeamCity* # DotCover is a Code Coverage Tool *.dotCover # AxoCover is a Code Coverage Tool .axoCover/* !.axoCover/settings.json # Visual Studio code coverage results *.coverage *.coveragexml # NCrunch _NCrunch_* .*crunch*.local.xml nCrunchTemp_* # MightyMoose *.mm.* AutoTest.Net/ # Web workbench (sass) .sass-cache/ # Installshield output folder [Ee]xpress/ # DocProject is a documentation generator add-in DocProject/buildhelp/ DocProject/Help/*.HxT DocProject/Help/*.HxC DocProject/Help/*.hhc DocProject/Help/*.hhk DocProject/Help/*.hhp DocProject/Help/Html2 DocProject/Help/html # Click-Once directory publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, # but database connection strings (with potential passwords) will be unencrypted *.pubxml *.publishproj # Microsoft Azure Web App publish settings. Comment the next line if you want to # checkin your Azure Web App publish settings, but sensitive information contained # in these scripts will be unencrypted PublishScripts/ # NuGet Packages *.nupkg # NuGet Symbol Packages *.snupkg # The packages folder can be ignored because of Package Restore **/[Pp]ackages/* # except build/, which is used as an MSBuild target. !**/[Pp]ackages/build/ # Uncomment if necessary however generally it will be regenerated when needed #!**/[Pp]ackages/repositories.config # NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets # Microsoft Azure Build Output csx/ *.build.csdef # Microsoft Azure Emulator ecf/ rcf/ # Windows Store app package directories and files AppPackages/ BundleArtifacts/ Package.StoreAssociation.xml _pkginfo.txt *.appx *.appxbundle *.appxupload # Visual Studio cache files # files ending in .cache can be ignored *.[Cc]ache # but keep track of directories ending in .cache !?*.[Cc]ache/ # Others ClientBin/ ~$* *~ *.dbmdl *.dbproj.schemaview *.jfm *.pfx *.publishsettings orleans.codegen.cs # Including strong name files can present a security risk # (https://github.com/github/gitignore/pull/2483#issue-259490424) #*.snk # Since there are multiple workflows, uncomment next line to ignore bower_components # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) #bower_components/ # RIA/Silverlight projects Generated_Code/ # Backup & report files from converting an old project file # to a newer Visual Studio version. Backup files are not needed, # because we have git ;-) _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm ServiceFabricBackup/ *.rptproj.bak # SQL Server files *.mdf *.ldf *.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings *.rptproj.rsuser *- [Bb]ackup.rdl *- [Bb]ackup ([0-9]).rdl *- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ # GhostDoc plugin setting file *.GhostDoc.xml # Node.js Tools for Visual Studio .ntvs_analysis.dat node_modules/ # Visual Studio 6 build log *.plg # Visual Studio 6 workspace options file *.opt # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) *.vbw # Visual Studio LightSwitch build output **/*.HTMLClient/GeneratedArtifacts **/*.DesktopClient/GeneratedArtifacts **/*.DesktopClient/ModelManifest.xml **/*.Server/GeneratedArtifacts **/*.Server/ModelManifest.xml _Pvt_Extensions # Paket dependency manager .paket/paket.exe paket-files/ # FAKE - F# Make .fake/ # CodeRush personal settings .cr/personal # Python Tools for Visual Studio (PTVS) __pycache__/ *.pyc # Cake - Uncomment if you are using it # tools/** # !tools/packages.config # Tabs Studio *.tss # Telerik's JustMock configuration file *.jmconfig # BizTalk build output *.btp.cs *.btm.cs *.odx.cs *.xsd.cs # OpenCover UI analysis results OpenCover/ # Azure Stream Analytics local run output ASALocalRun/ # MSBuild Binary and Structured Log *.binlog # NVidia Nsight GPU debugger configuration file *.nvuser # MFractors (Xamarin productivity tool) working folder .mfractor/ # Local History for Visual Studio .localhistory/ # BeatPulse healthcheck temp database healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ # End of https://www.gitignore.io/api/c++,cmake,clion,visualstudio,visualstudiocode ######################################## ## TROMPELOEIL-SPECIFIC IGNORE PATTERNS ######################################## build/ # CLion .idea trompeloeil-47/CMakeLists.txt000066400000000000000000000036721454452461300164210ustar00rootroot00000000000000cmake_minimum_required(VERSION 3.14) project(trompeloeil CXX) include(GNUInstallDirs) include(ExternalProject) include(CMakePackageConfigHelpers) include(CheckCXXCompilerFlag) option(TROMPELOEIL_BUILD_TESTS "Build self test programs" off) write_basic_package_version_file( "${CMAKE_CURRENT_BINARY_DIR}/trompeloeil/trompeloeil-config-version.cmake" VERSION 47 COMPATIBILITY AnyNewerVersion ARCH_INDEPENDENT) add_library(trompeloeil INTERFACE) add_library(trompeloeil::trompeloeil ALIAS trompeloeil) set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories( trompeloeil INTERFACE $ ) target_include_directories( trompeloeil INTERFACE $/include> ) set(MASTER_PROJECT OFF) if (${CMAKE_CURRENT_SOURCE_DIR} STREQUAL ${CMAKE_SOURCE_DIR}) set(MASTER_PROJECT ON) endif() option(TROMPELOEIL_INSTALL_TARGETS "Sets whether trompeloeil should be installed" ${MASTER_PROJECT}) option(TROMPELOEIL_INSTALL_DOCS "Install documentation" ${TROMPELOEIL_INSTALL_TARGETS}) if (MASTER_PROJECT AND TROMPELOEIL_BUILD_TESTS) add_subdirectory(test) endif() if (TROMPELOEIL_INSTALL_TARGETS) install( TARGETS trompeloeil EXPORT trompeloeil-targets INCLUDES DESTINATION include ) install( EXPORT trompeloeil-targets NAMESPACE trompeloeil:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/trompeloeil ) install( FILES trompeloeil-config.cmake "${CMAKE_CURRENT_BINARY_DIR}/trompeloeil/trompeloeil-config-version.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/trompeloeil COMPONENT Devel ) install( DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} ) endif(TROMPELOEIL_INSTALL_TARGETS) if(TROMPELOEIL_INSTALL_DOCS) install( FILES LICENSE_1_0.txt DESTINATION ${CMAKE_INSTALL_DOCDIR} ) install( DIRECTORY docs DESTINATION ${CMAKE_INSTALL_DOCDIR} ) endif() trompeloeil-47/ChangeLog000066400000000000000000000627401454452461300154340ustar00rootroot00000000000000v47 2024-01-01 * Coroutines are conditionally supported by the __cpp_impl_coroutine feature test macro. There is no longer any need to define the TROMPELOEIL_EXPERIMENTAL_COROUTINES macro in order to use coroutines with Trompeloeil. * Split the monolithic "trompeloeil.hpp" into several smaller headers. You can continue to #include as usual, but you can also do more fine grained #include:s, which may improve build times. E.g.: #include // basic mock functionality #include // REQUIRE_DESTRUCTION etc. #include // regular expressions The reference manual says which header to include to get the functionality for each item. If no header is mentioned, it is in v46 2023-11-06 * Experimental support for coroutines. Use CO_RETURN (or LR_CO_RETURN) for a member function that has a coroutine return type. Use CO_THROW (or LR_CO_THROW) to throw from a coroutine. Use as many CO_YIELD (or LR_CO_YIELD) from a coroutine function as you like, as long as the promise type supports it. The experimental support must be explicitly enabled with #define TROMPELOEIL_EXPERIMENTAL_COROUTINES #include alternatively #define TROMPELOEIL_EXPERIMENTAL_COROUTINES #include #include trompeloeil::stream_tracer does not produce correct result for coroutines * Corrected output of input-range like types. Thank you Dominic Koepke for the fix. * The self test program "custom_recursive_mutex" now says that it's succeeded. Thank you @yurivict for reporting the confusion. * Self test programs are only build when explicitly setting -DTROMPELOEIL_BUILD_TESTS=yes to the CMake command line. * The self test programs require a higher version of CMake (3.19 currently) v45 2023-07-21 * Support matching regular expressions to std::string view * Added adapter for QA Systems Cantata. Thank you Andreas Schätti v44 2023-04-10 * Fixed issue 293: Wildcard _ could not match types that can be constructed from any type. This fix unfortunately turns off conversion warnings for REQUIRE_CALL and friends when building with gcc. Thank you @TimonNoethlichs for reporting. * Fixed issue 296: Improved sequence violation message when ALLOW_CALL is involved. Thank you Sigurður Sveinn Halldórsson for reporting. * Fixed -Wunsafe-buffer-usage warning from clang-16 * static_assert() when trying to get a runtime value from any matcher * Bumped required CMake version to 3.14 or later. Thank you Luke Dennis for reporting. v43 2022-10-26 * Added static_assert to duck_typed_matcher's templatized conversion function explaining why it should never be instantiated. Issue 270. * Added gcc-12 and clang++-15 to the CI build matrix * Fixed issue 272: Support Catch2 piecemeal headers. * Fix issue #279 where the doctest adapter showed violation messages as hex addresses for most recent releases of doctest. Thanks @SimonKagstrom for reporting. * Fixed an obscure bug where an expectation could match with a sequence object that has run to completion. * Specify ARCH_INDEPENDENT when creating package version file in CMake. v42 2021-12-07 * Fixed issue 264: Sequence objects did not correctly report is_complete() when there were living, but satisfied, expectations remaining. Thank you Václav Kubernát for reporting. * Fixed issue 259 where CMakeFiles.txt wrongly installed trompeloeil for projects that includes it. It is now an option. See FAQ for details. Thank you Ismail Pazarbasi for reporting and fixing. * Updated Catch2 to version 2.13.7 to compile unit tests on systems with glibc >= 2.34. * Fixed issue 255: Hex dumps showed byte values <= 15(dec) wrong. Thank you Stuart Dootson for reporting. * Fixed issue 253: Resolve lingering warnings in early Clang compilers and enable -Wzero-as-null-pointer-constant when compiling unit tests with GCC and Clang. * Fixed issue 250: Warnings about zero argument variadic macros with clang-msvc. Thank you u3shit for reporting and fixing. * Fixed issue 251: trompeloeil::printer<> customization point now supports SFINAE expressions to constrain partial specializations. Thank you Christian Morales Vega for reporting. * Fixed issue 245: Modify cmake to build thread_terror on Windows with MSVC. * Use CMake internal Threads::Threads target where needed. Thank you Martin Hořeňovský for reporting. * For CI builds, use github actions cacheing of built libc++ to shorten build times. * Added CMake install namespace. Thank you offa * Fixed bug where an expectation end of life was reported as an error if it was included in a satisfied sequence. Thank you Andy Saul. v41 2021-06-15 * catch2 adapter works with CATCH_CONFIG_PREFIX_ALL. thanks Christian Morales Vega * Silenced -Wreserved-identifier from Clang "latest" (13.0.0). * Silenced (again) the MSVC C4702 warning from the default_return<>() function template. * Introduced type trompeloeil::printer as a customization point or formatting data to strings in reports. This has the advantage of allowing partial specializations. The old technique of specializing the function template trompeloeil::print(ostream&, const T&) still works. v40 2021-03-14 * Silenced -Wnonnull warning from GCC 9 and newer. Thank you Tony Neubert. * Fixed custom reported documentation bug. Thanks Matt Godbolt. * Added CMake alias target trompeloeil::trompeloeil. Thank you Leon De Andrade. * Documentation markdown fixes. Thank you offa. * Moved all CI builds to github actions. travis-ci and appveyor are no longer used. * Moved CI coverage collection to codecov.io * Conan recipe is now on https://conan.io/center/trompeloeil the old rollbear/stable channel is defunct. Thank you Florian Berchtold. v39 2020-10-31 * Fix issue 204: ALLOW_CALL was not respected in sequences. Now ALLOW_CALL in sequence may be skipped, but making a call out of sequence is a violation. NOTE! This fix is likely to break some existing test code! * Fix issue 211: #include before #include caused compilation failure for all expectations. * Fix minor spelling errors and markdownlint warnings. * Issue 207: Extend cmake script to allow use of libc++ with g++ * Fix issue 129: Wildcard _ does not match pass-by-value tuple of only one type. * Fix issue 197: Add override to virtual destructors to avoid -Wsuggest-destructor-override warnings. v38 2020-06-08 * Fixed bug where ALLOW_CALL only worked with sequences if called at least once * Fixed bug to support IMPLEMENT_MOCKx and IMPLEMENT_CONST_MOCKx constexpr * More fixes to Conan packaging. Thank you Kai Bernhard. * Support OK-reporters from the runtime reporter registration API. Thank you Moritz Haase. * Rewrites to not trigger deprecation warnings in C++17 builds. Thank you Kasper Laudrup. v37 2020-02-09 * Added adapter for the Criterion unit testing framework. Thanks you Etienne Barbier * Fixes to Conan packaging. Thank you kert * Fix issue 180 for GCC and MSVC, where the presence of a type like Qt5/QChar broke compilation of unrelated mock signatures. * Fix TROMPELOEIL_CONCAT macro issue to restore compiling with MSVC when traditional preprocessor is enabled. * Fix issue 173 for GCC 4.x by performing testing to confirm correctness of existing code. v36 2019-12-29 * Status reporting of passed expectation calls as successful assertions in DOCTEST and Catch2. Thanks to: Tore Martin Hagen for Catch2 Cristian Morales Vega for DOCTEST You get the support via the provided headers #include #include See the CookBook for information about adding such hooks for other unit testing frame works. * Fixed issue 172 where THROW() would not compile if the function returns a type that is not default constructible. * Partially fixed issue 173, where an object constructible from nullptr but not comparable with nullptr, would be constructed when printed (for example when an expectation failed.) Unfortunately this fix does not work for gcc versions 4.x or MSVC 14. v35 2019-04-01 * Improvements to documentation. Thanks to: Robert Dailey Yuri Timenkov Viatorus * Improved DocTest integration. Thanks to: Cristian Morales Vega * CMakeLists.txt honours CMAKE_INSTALL_LIBDIR. Thanks to: Cristian Morales Vega * Partially fixed issue 155, where an unfulfilled expectation, when built with the default throwing reporter, terminated without a message when compiled with gcc and optimization. With the partial fix the program still terminates, but with the correct violation message displayed. * Fixed issue 157 where it was impossible to place an expectation on a reference to a non-copyable type. This fix also resolved a number of problems with older compilers. See docs/Backward.md for details. * Fixed clang-tidy warning, misc-non-private-member-variables-in-classes that leaks into application code from the Trompeloeil header. v34 2019-04-01 * Rearranged include directory structure to make it easier to use, and to write, adapters for unit test frame works. Now, if you want to use Trompeloeil with, for example, the 'doctest' unit testing frame work, you include #include #include The old adaptation mechanisms still work. See issue #118 * Support compilation without RTTI support. This makes error reporting from deathwatched<> violations less informative (it cannot mention the name of the type of the object) but has no other impact on functionality. * Silenced g++-4.9 -Wmissing-field-initializers warning with libc++. * Fixed issue #121 where mutexes were created in each translation unit * Fixed issue #124 where sequence objects were not properly protected against access from several threads. * Silenced several warnings in the Trompeloeil self test programs. v33 2019-01-21 * Silenced noisy g++-7 -Wuseless-cast warning * Fixed a bug where a mocked function would not compile if a parameter had an operator==(nullptr) returning a type that is not convertible to bool. * Fixed a bug where a mocked function would not compile if a parameter was a range with iterators to rvalue proxy objects, like vector. * Mock objects can be move constructed if they have a static constexpr bool member named trompeloeil_movable_mock with value = true. * ANY() matcher gives a short descriptive compilation error message when the type is an array type (it would silently decay into a pointer type, which can be very confusing.) * When compiled with preprocessor macro TROMPELOEIL_USER_DEFINED_COMPILE_TIME_REPORTER, a `extern` `trompeloeil::reporter` is declared from `trompeloeil.hpp`. Thanks @rcdailey * Minor documentation updates. * Update pattern in expectation_with_wrong_type.cpp to match new error message from GCC '9' at svn revision 264700. v32 2018-07-23 * Fix issue #95: check_errors.sh typo and detect failure in Travis * Update unit test framework to Catch 2.2.3. * Fix documentation of sanitize flags * Enable destructor override warning in self_test build for Clang 5.0 or later * Update unit test framework to Catch 2.2.1. * Worked around clang++-6 bugs 38010 and 38033 * Improve support for compiler modes: GCC and Clang: -std=c++17; MSVC: /std:c++17 GCC and Clang: -std=c++2a; MSVC: /std:c++latest * Fix issue #87: C4355 warning from VS Release builds. Thanks @Neargye * Fix issue #69: work around C4702 warning from VS Release builds. * Fix issue #88: work around C2066 error from VS 2017 15.7.1. v31 2018-05-11 * Issue #83: Add AppVeyor support for VS 2015 and VS 2017 * Fix issue #82: restore compilation with VS 2015. v30 2018-04-02 * mock_interface provides a convenient short cut when implementing mocks from interfaces. It is used together with the macros IMPLEMENT_MOCKn(func_name) and IMPLEMENT_CONST_MOCKn(func_name). The signature of the function is deduced. It is not possible to use mock_interface with multiple inheritance, and it is not possible to mock overloads with IMPLEMENT_MOCKn(func_name) or IMPLEMENT_CONST_MOCKn(func_name) * Used markdownlint to make documentation more consistent. Thanks @AndrewPaxie * Silenced 2 clang++-5 warnings about missing "override" Back ported Trompeloeil to C++11. Thanks @AndrewPaxie! Changes by file and directory: * Cleaned up `.travis.yml` * Cleaned up `CMakeLists.txt` and bumped kcov for travis builds * `README.md` * Updated supported compiler list. * Added link to `docs/Backward.md`. * Added link to `docs/PlatformAndLibraries.md`. * `check_errors.sh` require `CXXFLAGS` with either `-std=c++11` or `-std=c++14`. * `docs/FAQ.md` * Updated supported compilers list. * Updated answer regarding C++11 support. * `docs/` * New: "Backward compatibility with earlier versions of C++". * New: "Platform and library support for Trompeloeil". * `compilation_errors/` * Support for C++11 expectation syntax in test cases. * `test/` * Split `compiling_tests.cpp` into separately compilable files, for Catch main, C++11 test cases and C++14 test cases. * Fixed whitespace and a minor spelling error in trompeloeil.hpp. * Tidy up test cases in compilation_errors. v29 2017-07-23 * Fix Issue #54: Exception thrown exit - fixed static dtor fiasco * Fix Issue #48: Move "re" in lambda capture list in "regex_check". * Fix Issue #55: Restore warnings for Clang builds. * Correct spelling of SANITIZE for clang Xcode builds. * Fix Issue #57: Avoid unneeded-member-function warning from Clang. * Allow only standard C++ dialects in Trompeloeil test programs. * Lightly edited documentation. v28 2017-07-24 * You can place expectations on types multiply inheriting several mock types. * Changed directory structure. "trompeloeil.hpp" now resides in directory "include". Self test programs "compiling_tests.cpp" and "thread_terror.cpp" resides in directory "test". * Major work on CMake support - "make install" - works as before and also includes a package - For CMake based project you can use . "find_package(trompeloeil 28 REQUIRED)" and add "target_link_libraries( trompeloeil)" for your test target . use "add_subdirectory(trompeloeil)" if you prefer to track the trompeloeil git repository and also here add "target_link_libraries( trompeloeil)" for your test target - "cmake -DBUILD_TYPE=Debug " enables the test targets "self_test" and "thread_terror" . "-DSANITIZE" enables ASAN and UBSAN for "self_test", and TSAN and UBSAN for "thread_terror" v27 2017-06-27 * Fixed a regression where NAMED_REQUIRE_DESTRUCTION(obj) accidentally resulted in a std::unique_ptr instead of std::unique_ptr as documented. * Added a rudimentary CMakeLists.txt file. Thanks Harald Achitz. v26 2017-06-12 * Support for threaded semi-integration tests by allowing queries if a sequence object "is_completed()", if an expectation objet "is_satisfied()" or "is_saturated()". See FAQ and reference manual for details. * Internal restructuring for reduced code size. v25 2017-04-17 * Changed the expectation macros such that you can now have a macro that expands into several REQUIRE_CALL() (and the likes) * Fixed macro expansion bugs causing name clashes. * Documented clang++ 4 compatibility * Sequence objects are now movable and can, for example, be returned from functions. v24 2017-03-10 * Worked around VS2017 bug. Thanks mlimber and xiangfan-ms v23 2017-01-29 * Matchers can be negated using the logical not operator !. Example: struct Mock { MAKE_MOCK1(func, void(const std::string&)); }; TEST(...) { using trompeloeil::re; // match regular expressions Mock m; REQUIRE_CALL(m, func(!re("^foo"))); // calls to func with strings not matching the regex /^foo/ ... } * Made sequence and its dependencies moveable. (mlimber) This means it's now possible to use tha Almost Always Auto style for sequence objects: auto seq = trompeloeil::sequence{}; * Internal refactoring for substantially reduced compilation time. v22 2016-12-13 * Messages from violations of expectations now print collections member wise. This goes for std::pair<>, std::tuple<> and any data type for which a range based for loop is possible. This is done recursively for the contents of the collections. * Worked around gcc bug 78446 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=78446 * Cleaned up -Wshadow warnings from gcc v21 2016-11-13 * Tracing now includes return values and exceptions thrown. For exception types inherited from std::exception, the what() string is printed. * Fixed a bug when a member function in a mocked class calls a mocked function. This is now explicitly allowed, even when an expectation recursively calls the same function as a side effect. * Worked around VisualStudio 2015 update 3 issue where trailing return type for lambdas is not respected in template deduction context. This caused compilation errors when using matchers in expectations to overloaded functions. * Worked around VisualStudio 2015 update 3 issue with evaluating regex_search() in trailing return type spec for auto deduced string type. v20 2016-10-05 * Fixed harmless but very very annoying warning from clang++ v19 2016-10-03 * Fixed obscure bug when placing an expectation using a value implicitly convertible to the target type, but not equal comparable with it. Example: struct S { S(const char* s_) : s(s_) {} bool operator(const char*) = delete; bool operator==(const S& rh) const { return s == rh.s; } std::string s; }; struct mock { MAKE_MOCK1(func, void(S)); }; TEST(...) { mock m; REQUIRE_CALL(m, func("string")); // now compiles and compares the function call parameter value // with S("string") } * Improved compilation error messages for type-mismatch situations in .RETURN() v18 2016-08-18 * Writing custom matchers is much simplified through the use of function template make_matcher<>, which accepts lambdas for predicate and printing error message. The old technique of inheriting form trompeloeil::matcher or trompeloeil::typed_matcher still works. * Further internal restructuring for yet reduced test program build time. v17 2016-06-11 * Use template specialization when writing adapter code for unit testing frame works. * Internal restructuring for shorter compilation times. v16 2016-05-16 * class trompeloeil::lifetime_monitor now inherits from class trompeloeil::expectation, so using std::unique_ptr p = NAMED_REQUIRE_DESTRUCTION(obj); instead of std::unique_ptr p = NAMED_REQUIRE_DESTRUCTION(obj); works equally well, reduces the cognitive load a bit, and seems to build slightly faster. * .IN_SEQUENCE(...) can now be used with REQUIRE_DESTRUCTION(...) and NAMED_REQUIRE_DESTRUCTION(...) to ensure objects are destroyed in the intended order. Example: auto p1 = new trompeloeil::deathwatched; auto p2 = new trompeloeil::deathwatched; trompeloeil::sequence s; REQUIRE_DESTRUCTION(*p1) .IN_SEQUENCE(s); REQUIRE_DESTRUCTION(*p2) .IN_SEQUENCE(s); call_destroyer(p1, p2); // both must be destroyed, p1 before p2. v15 2016-04-29 * Fixed macro bug that caused warnings with g++ and clang++ when compiling with strict C++ standards compliance. v14 2016-04-27 * Fixed bug when the destruction of a sequence object with still living expectations caused call to abort(). * You can now add extra trailing specifiers to a mock function, such as the "override" context sensitive specifier, and/or the keyword "noexcept" (careful with the latter if your registered reporter can/does throw.) Example: struct D : public B { MAKE_MOCK1(func, int(int), override); }; v13 2016-03-07 * Mock functions and their expectations are thread safe, using a global recursive mutex. * Silenced warnings from g++ -Wshadow. v12 2016-02-01 * Built in matchers are duck typed by default, i.e. eq, ne, gt, ge, lt, le do by default match any parameter that supports operators ==, !=, >, >=, <, <= with the value provided. If needed for disambiguation of overloads an explicit type can be provided. Example: REQUIRE_CALL(obj, numfunc(gt(3))); REQUIRE_CALL(obj, strfunc(eq("foo"))); The expectation on numfunc will match a function numfunc with any parameter type that can be compared as > 3. The expectation on strfunc will only match an overload with std::string& (if there are competing overloads, e.g. strfunc(const char*) and strfunc(const std::string).) * Fixed a bug with return type deduction where an array type expression was used. E.g. returning a string literal when the return type was const char* or std::string caused a compilation error. * Fixed a bug when the eq(nullptr) matcher actually checked if != comparison with nullptr was allowed. * Reluctantly reverted use of std::tuple_element_t<> for typename tuple_element<>::type, to support g++ 4.9.0 (4.9.1 does have std::tuple_element_t<>.) v11 2016-01-04 * Added regular expression matcher for std::string and c-strings * Added specialization eq for pointer-like parameters and pointer-to-member parameters. This is mostly useful for pointer to pointer parameters, e.g.: REQUIRE_CALL(obj, func(*trompeloeil::eq(nullptr))); * Improved accuracy of compilation error message when attempting to place expectation that does not uniquely match any function signature. * Added specialization eq for pointer-like parameters and v10 2015-12-11 * Fixed bug when wildcard _ could not match std::ostream& * Fixed ADL bugs * Added functionality to use the dereference operator (prefix operator*) on any matcher to instead match a pointer to the value to check. * Documented adapter for VisualStudio MSTest * Corrected documentation bug for how to write report formatting function trompeloeil::print<>(std::ostream&, T const&). v9 2015-11-29 * Fixed bug with accepting std::unique_ptr<> by value. * Signed/unsigned compilation warnings in expectations are attributed to correct file/line with clang++ and VisualStudio 2015 * Complete documentation overhaul. Now with: - Cook book - FAQ - reference manual * Better compilation error message when illegal argument is used in expectation. * Addressed clang++ and VisualStudio warnings v8 2015-10-30 * Fixed bug when mock object was destroyed with a saturated expectation in scope. * Further improved compilation error messages. v7 2015-10-24 * Report error if live expectations remain when a mock object is destroyed * Reduced clutter in compilation errors * Allow mock objects to be templates. E.g. template struct mock { MAKE_MOCK1(func, void(T)); }; Note that member function templates are still not supported. v6 2015-09-22 * Verified support for released Visual Studio 2015 * trompeloeil::ne(nullptr) works for all pointer types * Fixed a few issues reported by clang 3.7 sanitizers * line number in reporter_func is unsigned long to match type of __LINE__ v5 2015-06-19 * Support for Visual Studio 2015 RC * 5 parameter value matchers are included. These are (in namespace trompeloeil): - ne(x) - not equal to x - lt(x) - less than x - le(x) - less than or equal to x - gt(x) - greater than x - ge(x) - greater than or equal to x These are used in expectations as e.g.: REQUIRE_CALL(obj, foo(ne(5))); which matches calls to foo with a value not equal to 5. * Support and documentation for how to write custom matchers. * The function registered to set_reporter() now must accept the source location as file, line instead of location as a combined string. Apologies for breaking existing code, but since this is more in line with how other frame works refers to source code locations, it improves compatibility. v4 2015-05-01 * Expectations of death do not follow move-constructed and copy-constructed deathwatched objects. * Internal rewrites to reduce compilation times v3 2015-04-02 * Fixed compiler dependent reference binding SNAFU v2 2015-04-02 * Improved compilation time performance. 20% drop in compilation time has been seen in some test programs. * Improved the compiler's chance to provide good warning messages when values in expectations don't quite the types used in the function signature (for example signed/unsigned mismatch.) * Added support for tracing matching calls. This is an aid when doing exploratory tests of legacy code. A trace can often drastically reduce the time required to understand how the legacy code works. To use it, create an object of a tracer type, for example: TEST(atest) { trompeloeil::stream_tracer trace(std::cout); // normal test code } v1 2015-01-10 First official release. trompeloeil-47/LICENSE_1_0.txt000066400000000000000000000024721454452461300161400ustar00rootroot00000000000000Boost Software License - Version 1.0 - August 17th, 2003 Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. trompeloeil-47/README.md000066400000000000000000000173111454452461300151330ustar00rootroot00000000000000# *Trompeloeil* ![trompeloeil logo](trompeloeil-logo.png) ![CI](https://github.com/rollbear/trompeloeil/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/rollbear/trompeloeil/branch/master/graph/badge.svg?token=PCUO4knwdU)](https://codecov.io/gh/rollbear/trompeloeil) Get: [![Conan](https://img.shields.io/badge/on-conan-blue.svg)](https://conan.io/center/trompeloeil) Buy me a coffee > *trompe l'oeil* noun (Concise Encyclopedia) > Style of representation in which a painted object is intended > to deceive the viewer into believing it is the object itself... # What is it? A thread-safe header-only mocking framework for C++11/14 using the Boost Software License 1.0 # Documentation - [Integrating with unit test frame works](docs/CookBook.md/#unit_test_frameworks) - [Introduction](https://playfulprogramming.blogspot.com/2014/12/introducing-trompeloeil-c-mocking.html) - [Building and running the self test suite](#self_test) - [How to contribute](#contribute) - [Compiler compatibility](#compilers) - [External tools](#tools) - [Presentation videos](#videos) - [Trompeloeil on CppCast](http://cppcast.com/2017/02/bjorn-fahller/) - [Cheat Sheet (2*A4)](docs/trompeloeil_cheat_sheet.pdf) - [Cook Book](docs/CookBook.md) - [FAQ](docs/FAQ.md) - [Backward compatibility with earlier versions of C++](docs/Backward.md) - [Platform and library support for Trompeloeil](docs/PlatformsAndLibraries.md) - [Reference](docs/reference.md) Also, follow up with the post on [sequencing]( https://playfulprogramming.blogspot.se/2015/01/sequence-control-with-trompeloeil-c.html ) for examples on how to restrict or relax allowed sequences of matching calls. # Teaser ```Cpp #include class Interface { public: virtual ~Interface() = default; virtual bool foo(int, std::string& s) = 0; virtual bool bar(int) = 0; virtual bool bar(std::string) = 0; }; void interface_func(Interface*); // function to test class Mock : public Interface { public: MAKE_MOCK2(foo, bool(int, std::string&),override); MAKE_MOCK1(bar, bool(int),override); MAKE_MOCK1(bar, bool(std::string),override); MAKE_MOCK0(baz, void()); // not from Interface }; TEST(exercise_interface_func) { using trompeloeil::_; // wild card for matching any value using trompeloeil::gt; // greater-than match Mock m; trompeloeil::sequence seq1, seq2; // control order of matching calls int local_var = 0; REQUIRE_CALL(m, bar(ANY(int))) // expect call to m.bar(int) .LR_SIDE_EFFECT(local_var = _1) // set captured variable to value of param .RETURN(_1 > 0) // return value depending on param value .IN_SEQUENCE(seq1) // must be first match for seq1 .TIMES(AT_LEAST(1)); // can be called several times FORBID_CALL(m, bar(0)); // but m.bar(0) is not allowed REQUIRE_CALL(m, bar("word")) // expect one call to m.bar(std::string) .RETURN(true) .IN_SEQUENCE(seq2); // must be first match for seq2 REQUIRE_CALL(m, foo(gt(2), _)) // expect call to foo(int,std::string&) .WITH(_2 == "") // with int > 2 and empty string .IN_SEQUENCE(seq1, seq2) // last for both seq1 and seq2 .SIDE_EFFECT(_2 = "cat") // and set param string to "cat" .RETURN(true); interface_func(&m); // all the above expectations must be fulfilled here } ``` # Building and running the self test suite To build the self test suite run `cmake` with `-DTROMPELOEIL_BUILD_TESTS=yes`. Use the options `CXX_STANDARD` to select which C++ standard to test, and `SANITIZE` to select sanitizers to build with. Note that the self tests needs a reasonably modern version of CMake. Example: ``` cmake -B build_dir \ -D TROMPELOEIL_BUILD_TESTS=yes \ -D CMAKE_BUILD_TYPE=Debug \ -D CXX_STANDARD=17 \ -D SANITIZE=Address,Undefined \ ``` If the build finds a CMake package for `Catch2` it will use that, otherwise it will download a header-only version of Catch2 v2.x. ``` cmake --build build_dir -t self_test thread_terror custom_recursive_mutex ``` Then run the built binaries: ``` ./build_dir/self_test && ./build_dir/thread_terror && ./build_dir/custom_recursive_mutex ``` # How to contribute Contributions are most welcome. For new functionality, please file an issue as an enhancement request first, to get a discussion going about how to best implement it. Also for bugfixes, it is good to file an issue, so that others can see what the problem is and when it's solved. Internal changes are normally not mentioned in the ChangeLog - it should typically reflect what a user can see (however, performance improvements and silencing warnings are visible for users.) Feel free to add your name to the copyright blurb. |Change | PR to | |-----------------------------|----------------| |Documentation |master branch | |Trivial bugfixes |master branch | |Non trivial bugfixes |develop branch | |Simple new functionality |develop branch | |Non-trivial new functionality|new topic branch| # Compiler compatibility Trompeloeil is known to work with: - GCC [4.8.4](docs/Backward.md#gxx48x_limitations)+, 4.9.3+, 5, 6, 7, 8, 9, 10, 11, 12, 13 - 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 - Visual Studio 2015, 2017, 2019 Latest patch level releases are assumed in the versions listed above. Further details on C++11 support, platform and library limitations, may be found in - [Backward compatibility with earlier versions of C++](docs/Backward.md) - [Platform and library support for Trompeloeil](docs/PlatformsAndLibraries.md) # External Tools - [ReSharperC++](https://www.jetbrains.com/resharper-cpp/) extension to [VisualStudio](https://visualstudio.microsoft.com/) has a mock generator for *Trompeloeil* since [2016.2](https://blog.jetbrains.com/rscpp/2016/09/14/whats-new-in-resharper-c-2016-2/) # Videos | | | |--|--| | [![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) | | [![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) | | [![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) | | [![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) | trompeloeil-47/_config.yml000066400000000000000000000000351454452461300157760ustar00rootroot00000000000000theme: jekyll-theme-modernisttrompeloeil-47/check_errors.sh000077500000000000000000000014141454452461300166610ustar00rootroot00000000000000#!/bin/sh # # Trompeloeil C++ mocking framework # # Copyright Björn Fahller # # Use, modification and distribution is subject to the # Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) # # Project home: https://github.com/rollbear/trompeloeil # echo "CXX=$CXX" echo "CXXFLAGS=$CXXFLAGS" echo "CPPFLAGS=$CPPFLAGS" # Default CXXFLAGS to -std=c++14 if not set in the environment # for backward compatibility. #CXXFLAGS=${CXXFLAGS:-"-std=c++14"} #echo "CXXFLAGS is now $CXXFLAGS" failfile=`mktemp` #${CXX} --version cd compilation_errors files=`ls *.cpp` parallel ../verify_compilation_error.sh ::: $files | tee $failfile FAILURES=`cat $failfile | grep FAIL | wc -l` rm $failfile exit $FAILURES trompeloeil-47/compilation_errors/000077500000000000000000000000001454452461300175635ustar00rootroot00000000000000trompeloeil-47/compilation_errors/address_of_illegal_argument.cpp000066400000000000000000000013551454452461300257770ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, void(int)); }; void func(const void*); int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .SIDE_EFFECT(func(&_2))); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .SIDE_EFFECT(func(&_2)); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/any_with_array_type.cpp000066400000000000000000000013111454452461300243440ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: array parameter type decays to pointer type for ANY #include struct MS { MAKE_MOCK1(f, void(int [3])); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int[3]))); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int[3]))); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/assign_illegal_argument.cpp000066400000000000000000000013461454452461300251520ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, void(int)); }; void func(const int&); int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .SIDE_EFFECT(_2 = 1)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .SIDE_EFFECT(_2 = 1); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/co_return_and_co_throw.cpp000066400000000000000000000015411454452461300250160ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_THROW and CO_RETURN does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(0) .CO_THROW("foo"); } trompeloeil-47/compilation_errors/co_return_empty_to_non_void_coroutine.cpp000066400000000000000000000014341454452461300301730ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Expression type does not match the coroutine promise type #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(); } trompeloeil-47/compilation_errors/co_return_from_non_coroutine.cpp000066400000000000000000000011061454452461300262510ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_RETURN when return type is not a coroutine #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_return_on_forbidden_call.cpp000066400000000000000000000014231454452461300257720ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_RETURN for forbidden call does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; FORBID_CALL(obj, f()) .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_return_value_to_void_coroutine.cpp000066400000000000000000000014311454452461300272740ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Expression type does not match the coroutine promise type #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_void(); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_return_with_mismatching_type.cpp000066400000000000000000000014371454452461300267530ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Expression type does not match the coroutine promise type #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(void*); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_throw_and_co_return.cpp000066400000000000000000000015671454452461300250260ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_THROW and CO_RETURN does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_THROW("foo") .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_throw_from_non_coroutine.cpp000066400000000000000000000011151454452461300260750ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Do not use CO_THROW from a normal function, use THROW #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_THROW(0); } trompeloeil-47/compilation_errors/co_throw_on_forbidden_call.cpp000066400000000000000000000015451454452461300256230ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_THROW for forbidden call does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; FORBID_CALL(obj, f()) .CO_THROW(0); } trompeloeil-47/compilation_errors/co_yield_from_non_coroutine.cpp000066400000000000000000000011251454452461300260410ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_YIELD when return type is not a coroutine #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .RETURN(1) .CO_YIELD(1); } trompeloeil-47/compilation_errors/co_yield_to_promise_without_yield_value.cpp000066400000000000000000000015671454452461300304740ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_YIELD is incompatible with the promise type #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_YIELD(1) .CO_RETURN(0); } trompeloeil-47/compilation_errors/co_yield_void.cpp000066400000000000000000000015331454452461300231010ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: You cannot CO_YIELD void #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_void(); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_YIELD() .CO_RETURN(); } trompeloeil-47/compilation_errors/co_yield_with_mistamching_type.cpp000066400000000000000000000016451454452461300265430ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_YIELD is incompatible with the promise type #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); std::suspend_always yield_value(int); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_YIELD("foo") .CO_RETURN(0); } trompeloeil-47/compilation_errors/deathwatched_with_nonvirtual_destructor.cpp000066400000000000000000000010271454452461300305060ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: virtual destructor is a necessity for deathwatched to work #include struct MS { MAKE_MOCK0(f, int()); }; int main() { auto obj = new trompeloeil::deathwatched(); } trompeloeil-47/compilation_errors/dereference_illegal_argument.cpp000066400000000000000000000013501454452461300261300ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, void(int)); }; void func(const int&); int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .SIDE_EFFECT(*_2 = 1)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .SIDE_EFFECT(*_2 = 1); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/expectation_with_unknown_func_name.cpp000066400000000000000000000012571454452461300274440ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: no member named.*x #include struct MS { MAKE_MOCK1(f, int(int)); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, x(1), .RETURN(_2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, x(1)) .RETURN(_2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/expectation_with_wrong_cardinality.cpp000066400000000000000000000013041454452461300274420ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: function.*call #include struct MS { MAKE_MOCK1(f, int(int)); }; using trompeloeil::_; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(_,_), .RETURN(_2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(_,_)) .RETURN(_2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/expectation_with_wrong_type.cpp000066400000000000000000000014701454452461300261240ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: (cannot (initialize|convert)|no known conversion).*trompeloeil::param_list_t #include struct MS { MAKE_MOCK3(f, int(int,int,int)); }; using trompeloeil::_; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(1,nullptr,_), .RETURN(_2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(1,nullptr,_)) .RETURN(_2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/illegal_move_mock.cpp000066400000000000000000000010341454452461300237350ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: make a mock object movable, see: #include struct M { MAKE_MOCK1(f, void(int)); }; template T ident(T t) { return t; } int main() { auto obj = ident(M{}); } trompeloeil-47/compilation_errors/in_sequence_on_forbidden_call.cpp000066400000000000000000000014121454452461300262660ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: IN_SEQUENCE for forbidden call does not make sense #include struct MS { MAKE_MOCK0(f, void()); }; int main() { MS obj; trompeloeil::sequence s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .TIMES(0) .IN_SEQUENCE(s)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .TIMES(0) .IN_SEQUENCE(s); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/make_mock_with_wrong_cardinality.cpp000066400000000000000000000007141454452461300270510ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Function signature does not have 2 parameters #include struct MS { MAKE_MOCK2(f, void(int)); }; trompeloeil-47/compilation_errors/missing_co_return_from_void_coroutine.cpp000066400000000000000000000013551454452461300301570ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: CO_RETURN missing for coroutine #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_void(); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()); } trompeloeil-47/compilation_errors/missing_return_on_non_void_func.cpp000066400000000000000000000012331454452461300267400ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: RETURN missing for non-void function #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f()); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/multiple_co_return.cpp000066400000000000000000000015601454452461300242040ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Multiple CO_RETURN does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_RETURN(1) .CO_RETURN(2); } trompeloeil-47/compilation_errors/multiple_co_throw.cpp000066400000000000000000000015651454452461300240350ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Multiple CO_THROW does not make sense #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); void unhandled_exception(); task get_return_object(); }; int await_resume(); }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .CO_THROW("one") .CO_THROW("two"); } trompeloeil-47/compilation_errors/multiple_late_return_on_non_void_func.cpp000066400000000000000000000014261454452461300301330ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple RETURN does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; int n; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .LR_SIDE_EFFECT(n = 1) .RETURN(1) .RETURN(2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .LR_SIDE_EFFECT(n = 1) .RETURN(1) .RETURN(2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/multiple_limits.cpp000066400000000000000000000014671454452461300235130ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Only one TIMES call limit is allowed, but it can express an interval #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .TIMES(AT_LEAST(1)) .TIMES(AT_MOST(3)) .RETURN(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .TIMES(AT_LEAST(1)) .TIMES(AT_MOST(3)) .RETURN(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/multiple_return_on_non_void_func.cpp000066400000000000000000000013271454452461300271260ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple RETURN does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(1) .RETURN(2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(1) .RETURN(2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/multiple_sequences.cpp000066400000000000000000000015211454452461300241740ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence #include struct MS { MAKE_MOCK0(f, int()); }; int main() { trompeloeil::sequence seq; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .IN_SEQUENCE(seq) .RETURN(0) .IN_SEQUENCE(seq)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .IN_SEQUENCE(seq) .RETURN(0) .IN_SEQUENCE(seq); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/multiple_sequences_destruction.cpp000066400000000000000000000011401454452461300266140ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence #include struct MS { MAKE_MOCK0(f, int()); }; int main() { trompeloeil::sequence seq; MS obj; REQUIRE_DESTRUCTION(obj) .IN_SEQUENCE(seq) .IN_SEQUENCE(seq); } trompeloeil-47/compilation_errors/multiple_sequences_named_destruction.cpp000066400000000000000000000011571454452461300277700ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple IN_SEQUENCE does not make sense. You can list several sequence #include struct MS { MAKE_MOCK0(f, int()); }; int main() { trompeloeil::sequence seq; MS obj; auto d = NAMED_REQUIRE_DESTRUCTION(obj) .IN_SEQUENCE(seq) .IN_SEQUENCE(seq); } trompeloeil-47/compilation_errors/multiple_throws.cpp000066400000000000000000000013271454452461300235330ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: Multiple THROW does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .THROW(3) .THROW('a')); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .THROW(3) .THROW('a'); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/negative_limit_interval_first.cpp000066400000000000000000000014051454452461300264020ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: In TIMES the first value must not exceed the second #include struct MS { MAKE_MOCK0(f, int()); }; int main() { trompeloeil::sequence seq; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(0) .TIMES(3,2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(0) .TIMES(3,2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/negative_limit_interval_second.cpp000066400000000000000000000014051454452461300265260ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: In TIMES the first value must not exceed the second #include struct MS { MAKE_MOCK0(f, int()); }; int main() { trompeloeil::sequence seq; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(0) .TIMES(3,2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(0) .TIMES(3,2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/ptr_to_member_from_nullptr_matcher.cpp000066400000000000000000000012151454452461300274320ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from a typed matcher #include struct S { using memptr = int S::*; MAKE_MOCK0(f, memptr()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(ANY(std::nullptr_t))); #else REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); #endif } trompeloeil-47/compilation_errors/reference_from_duck_typed_matcher.cpp000066400000000000000000000011641454452461300271700ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from a duck typed matcher #include struct S { MAKE_MOCK0(f, bool&()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(trompeloeil::eq(0))); #else REQUIRE_CALL(s, f()).RETURN(trompeloeil::eq(0)); #endif } trompeloeil-47/compilation_errors/reference_from_nullptr_matcher.cpp000066400000000000000000000011621454452461300265330ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from a typed matcher #include struct S { MAKE_MOCK0(f, void*&()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(ANY(std::nullptr_t))); #else REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); #endif } trompeloeil-47/compilation_errors/reference_from_wildcard.cpp000066400000000000000000000011371454452461300251230ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from wildcard #include struct S { MAKE_MOCK0(f, int&()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(trompeloeil::_)); #else REQUIRE_CALL(s, f()).RETURN(trompeloeil::_); #endif } trompeloeil-47/compilation_errors/return_address_of_illegal_argument.cpp000066400000000000000000000013051454452461300273710ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, const void*(int)); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .RETURN(&_2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .RETURN(&_2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_and_throw.cpp000066400000000000000000000013261454452461300236550ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: THROW and RETURN does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(0) .THROW(3)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(0) .THROW(3); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_first_from_void_func.cpp000066400000000000000000000014031454452461300260720ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: RETURN does not make sense for void-function #include struct MS { MAKE_MOCK0(f, void()); }; int main() { int n; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(1) .LR_SIDE_EFFECT(n = 0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(1) .LR_SIDE_EFFECT(n = 0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_from_coroutine.cpp000066400000000000000000000014221454452461300247170ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Do not use RETURN from a coroutine, use CO_RETURN #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .RETURN(0); } trompeloeil-47/compilation_errors/return_illegal_argument.cpp000066400000000000000000000012731454452461300252040ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, int(int)); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .RETURN(_2)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .RETURN(_2); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_on_forbidden_call.cpp000066400000000000000000000013021454452461300253050ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: RETURN for forbidden call does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) FORBID_CALL_V(obj, f(), .RETURN(0)); #else /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ FORBID_CALL(obj, f()) .RETURN(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_second_from_void_func.cpp000066400000000000000000000014021454452461300262150ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: RETURN does not make sense for void-function #include struct MS { MAKE_MOCK0(f, void()); }; int main() { int n; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .LR_SIDE_EFFECT(n = 0) .RETURN(1)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .LR_SIDE_EFFECT(n = 0) .RETURN(1); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_value_to_ref.cpp000066400000000000000000000013461454452461300243440ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: c++11 // pass: RETURN non-reference from function returning reference #include struct MS { MAKE_MOCK0(f, char&()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN('a')); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN('a'); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_wrong_pointer_constness.cpp000066400000000000000000000013511454452461300266610ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: c++11 // pass: RETURN const\* from function returning pointer to non-const #include struct MS { MAKE_MOCK0(f, char*()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN("")); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(""); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_wrong_reference_constness.cpp000066400000000000000000000013521454452461300271400ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: c++11 // pass: RETURN const\& from function returning non-const reference #include struct MS { MAKE_MOCK0(f, char&()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(*"")); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(*""); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/return_wrong_type_first.cpp000066400000000000000000000014551454452461300252770ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: c++11 // pass: RETURN value is not convertible to the return type of the function #include struct MS { MAKE_MOCK0(f, int()); }; int main() { int n; MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN("") .LR_SIDE_EFFECT(n = 0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN("") .LR_SIDE_EFFECT(n = 0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/side_effect_on_forbidden_call.cpp000066400000000000000000000013761454452461300262410ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: SIDE_EFFECT for forbidden call does not make sense #include #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) FORBID_CALL_V(obj, f(), .SIDE_EFFECT(std::cout << 3)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ FORBID_CALL(obj, f()) .SIDE_EFFECT(std::cout << 3); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/throw_and_return.cpp000066400000000000000000000013261454452461300236550ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: THROW and RETURN does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .THROW(3) .RETURN(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .THROW(3) .RETURN(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/throw_from_coroutine.cpp000066400000000000000000000014441454452461300245470ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: macOS\|g++-10\|clang++-1[0-3]\|c++1[147] // pass: Do not use THROW from a coroutine, use CO_THROW #include struct task { struct promise_type { std::suspend_never initial_suspend() noexcept { return {};} std::suspend_always final_suspend() noexcept { return {};} void return_value(int); }; }; struct MS { MAKE_MOCK0(f, task()); }; int main() { MS obj; REQUIRE_CALL(obj, f()) .THROW(std::runtime_error("")); } trompeloeil-47/compilation_errors/throw_on_forbidden_call.cpp000066400000000000000000000013341454452461300251360ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: THROW for forbidden call does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .TIMES(0) .THROW(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .TIMES(0) .THROW(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/times_0_after_return.cpp000066400000000000000000000013331454452461300244070ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: RETURN and TIMES\(0\) does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .RETURN(0) .TIMES(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .RETURN(0) .TIMES(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/times_0_after_sequence.cpp000066400000000000000000000014061454452461300247010ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: IN_SEQUENCE and TIMES\(0\) does not make sense #include struct MS { MAKE_MOCK0(f, void()); }; int main() { MS obj; trompeloeil::sequence s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .IN_SEQUENCE(s) .TIMES(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .IN_SEQUENCE(s) .TIMES(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/times_0_after_side_effect.cpp000066400000000000000000000013741454452461300253350ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: SIDE_EFFECT and TIMES\(0\) does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int m = 0; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .SIDE_EFFECT(m = 3) .TIMES(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .SIDE_EFFECT(m = 3) .TIMES(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/times_0_after_throw.cpp000066400000000000000000000013301454452461300242300ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: THROW and TIMES\(0\) does not make sense #include struct MS { MAKE_MOCK0(f, int()); }; int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(), .THROW(0) .TIMES(0)); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f()) .THROW(0) .TIMES(0); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/use_illegal_argument.cpp000066400000000000000000000013521454452461300244570ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: illegal argument #include struct MS { MAKE_MOCK1(f, void(int)); }; void func(const int&); int main() { MS obj; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(obj, f(ANY(int)), .SIDE_EFFECT(func(_2))); #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ REQUIRE_CALL(obj, f(ANY(int))) .SIDE_EFFECT(func(_2)); #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ } trompeloeil-47/compilation_errors/value_from_duck_typed_matcher.cpp000066400000000000000000000012131454452461300263410ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: clang++-3 // pass: value from a duck typed matcher #include struct S { MAKE_MOCK0(f, bool()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(trompeloeil::eq(3))); #else REQUIRE_CALL(s, f()).RETURN(trompeloeil::eq(3)); #endif } trompeloeil-47/compilation_errors/value_from_nullptr_matcher.cpp000066400000000000000000000011611454452461300257100ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from a typed matcher #include struct S { MAKE_MOCK0(f, void*()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(ANY(std::nullptr_t))); #else REQUIRE_CALL(s, f()).RETURN(ANY(std::nullptr_t)); #endif } trompeloeil-47/compilation_errors/value_from_typed_matcher.cpp000066400000000000000000000011311454452461300253320ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // pass: value from a typed matcher #include struct S { MAKE_MOCK0(f, int()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(ANY(int))); #else REQUIRE_CALL(s, f()).RETURN(ANY(int)); #endif } trompeloeil-47/compilation_errors/value_from_wildcard.cpp000066400000000000000000000011661454452461300243030ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ // exception: g++-[678] // pass: value from wildcard #include struct S { MAKE_MOCK0(f, int()); }; int main() { S s; #if (TROMPELOEIL_CPLUSPLUS == 201103L) REQUIRE_CALL_V(s, f(), .RETURN(trompeloeil::_)); #else REQUIRE_CALL(s, f()).RETURN(trompeloeil::_); #endif } trompeloeil-47/docs/000077500000000000000000000000001454452461300146015ustar00rootroot00000000000000trompeloeil-47/docs/Backward.md000066400000000000000000000353221454452461300166460ustar00rootroot00000000000000# Backward compatibility with earlier versions of C\+\+ - [Introduction](#introduction) - [C\+\+11 compromises](#cxx11_compromises) - [C\+\+11 API](#cxx11_api) - [`REQUIRE_CALL` example](#cxx11_require_call) - [`NAMED_REQUIRE_CALL` example](#cxx11_named_require_call) - [`ALLOW_CALL` example](#cxx11_allow_call) - [`NAMED_ALLOW_CALL` example](#cxx11_named_allow_call) - [`FORBID_CALL` example](#cxx11_forbid_call) - [`NAMED_FORBID_CALL` example](#cxx11_named_forbid_call) - [Migrating from C\+\+11 API to C\+\+14 API](#migrate_to_cxx14) - [Implicit conversion of `RETURN` modifier expression](#cxx11_return_implicit_conversion) - [Macro expansion of `ANY` matcher before stringizing](#cxx11_any_stringizing) - [G\+\+ 4.8.x limitations](#gxx48x_limitations) - [Compiler defects](#gxx48x_compiler) - [Rvalue reference failures](gxx48x_compiler_rvalue_ref) - [Overload failures](#gxx48x_compiler_overload) - [! matcher failures](#gxx48x_compiler_neg_matcher) - [ANY matcher failures](#gxx48x_compiler_any_matcher) - [Summary of compiler matcher failures](#gxx48x_compiler_matcher_summary) - [Standard library defects](#gxx48x_library) - [Regular expressions](#gxx48x_library_regex) - [``](#gxx48x_library_tuple) ## Introduction Trompeloeil is a C\+\+14-first library and looks forward to the future where C\+\+17-and-beyond language features and standard library further improve its utility and performance. Sometimes though, a project comes along where instead of looking forward one has to look backward. How far backward? All the way back to `g++-4.8.4` with a vintage `libstdc++-v3` library and requirements for compliance with the features available in the C\+\+11 standard without compiler extensions. (Indeed, it might be much worse: you might have a project forced to use `g++-4.8.3` with further constraints.) To allow you to consider Trompeloeil as your mock object framework for a project with these constraints, we have back ported Trompeloeil to `g++-4.8.4` (C\+\+11, `libstdc++-v3`) with an API that may be used with a C\+\+11 dialect selected. The C\+\+11 API remains supported when a C\+\+14 (or later) dialect is selected. ## C\+\+11 compromises Two major changes to functionality occur when compiling with the C\+\+11 dialect. First, the API for defining expectations is different from the API used in C\+\+14 and later dialects. Second, the argument to a [**`RETURN`**](reference.md/#RETURN) modifier undergoes an implicit conversion before semantic analysis. This results in a different error message when the expression cannot be implicitly converted to the return type of the function for which the expectation is being defined. A minor change is that the expansion of the [**`ANY`**](reference.md/#ANY) matcher in arguments to expectations is stringized differently in the C\+\+11 API when compared to the C\+\+14 API. ### C\+\+11 API It has not been possible to replicate the macro syntax that is used in the C\+\+14 API. The cause is an inability to find a mechanism to communicate sufficient type information between expectation macros and modifier macros. Our approach has been to redefine expectation macros as taking the modifiers, if any, as an argument to the expectation macro. The C\+\+11 API has a similar name to the corresponding C\+\+14 API ```text C++14 API C++11 API ------------------------------ -------------------------------- TROMPELOEIL_REQUIRE_CALL TROMPELOEIL_REQUIRE_CALL_V TROMPELOEIL_NAMED_REQUIRE_CALL TROMPELOEIL_NAMED_REQUIRE_CALL_V TROMPELOEIL_ALLOW_CALL TROMPELOEIL_ALLOW_CALL_V TROMPELOEIL_NAMED_ALLOW_CALL TROMPELOEIL_NAMED_ALLOW_CALL_V TROMPELOEIL_FORBID_CALL TROMPELOEIL_FORBID_CALL_V TROMPELOEIL_NAMED_FORBID_CALL TROMPELOEIL_NAMED_FORBID_CALL_V ``` Short names for these macros have also been defined. ```text Short macro name Long macro name -------------------- -------------------------------- REQUIRE_CALL_V TROMPELOEIL_REQUIRE_CALL_V NAMED_REQUIRE_CALL_V TROMPELOEIL_NAMED_REQUIRE_CALL_V ALLOW_CALL_V TROMPELOEIL_ALLOW_CALL_V NAMED_ALLOW_CALL_V TROMPELOEIL_NAMED_ALLOW_CALL_V FORBID_CALL_V TROMPELOEIL_FORBID_CALL_V NAMED_FORBID_CALL_V TROMPELOEIL_NAMED_FORBID_CALL_V ``` In the C\+\+11 API, the expectation macros accept two or more arguments, the first two being object and function and the remainder being the modifiers, if any. Therefore the `_V` suffix may be read as an abbreviation of the word "variadic". All documentation in Trompeloeil outside of this note uses the C\+\+14 API. The examples below show how to translate from the C\+\+14 API to the C\+\+11 API. #### `REQUIRE_CALL` example Given mock class `mock_c` with mock function `int getter(int)`, ```cpp struct mock_c { MAKE_MOCK1(getter, int(int)); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; // Two macros adjacent to each other in the program text. REQUIRE_CALL(obj, getter(ANY(int))) .RETURN(_1); ``` the corresponding expectation implemented using the C\+\+11 API is ```cpp mock_c obj; // One macro with three arguments. REQUIRE_CALL_V(obj, getter(ANY(int)), .RETURN(_1)); ``` See also: [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL). #### `NAMED_REQUIRE_CALL` example Given mock class `mock_c` with mock function `int getter(int)`, ```cpp struct mock_c { MAKE_MOCK1(getter, int(int)); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; // Two macros adjacent to each other in the program text. auto e = NAMED_REQUIRE_CALL(obj, getter(ANY(int))) .RETURN(0); ``` the corresponding expectation implemented using the C\+\+11 API is ```cpp mock_c obj; // One macro with three arguments. auto e = NAMED_REQUIRE_CALL_V(obj, getter(ANY(int)), .RETURN(0)); ``` See also: [**`NAMED_REQUIRE_CALL(...)`**](reference.md/#NAMED_REQUIRE_CALL). #### `ALLOW_CALL` example Given mock class `mock_c` with mock function `int count()`, ```cpp struct mock_c { MAKE_MOCK0(count, int()); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; // Two macros adjacent to each other in the program text. ALLOW_CALL(obj, count()) .RETURN(1); ``` the corresponding expectation implemented using the C\+\+11 API is, ```cpp mock_c obj; // One macro with three arguments. ALLOW_CALL_V(obj, count(), .RETURN(1)); ``` See also: [**`ALLOW_CALL(...)`**](reference.md/#ALLOW_CALL). #### `NAMED_ALLOW_CALL` example Given mock class `mock_c` with mock function `int count()`, ```cpp struct mock_c { MAKE_MOCK0(count, int()); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; // Two macros adjacent to each other in the program text. auto e = NAMED_ALLOW_CALL(obj, count()) .RETURN(1); ``` the corresponding expectation implemented using the C\+\+11 API is, ```cpp mock_c obj; // One macro with three arguments. auto e = NAMED_ALLOW_CALL_V(obj, count(), .RETURN(1)); ``` See also: [**`NAMED_ALLOW_CALL(...)`**](reference.md/#NAMED_ALLOW_CALL). #### `FORBID_CALL` example Given mock class `mock_c` with mock function `int count()`, ```cpp struct mock_c { MAKE_MOCK0(count, int()); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; FORBID_CALL(obj, count()); ``` the corresponding expectation implemented using the C\+\+11 API is, ```cpp mock_c obj; FORBID_CALL_V(obj, count()); ``` See also: [**`FORBID_CALL(...)`**](reference.md/#FORBID_CALL). #### `NAMED_FORBID_CALL` example Given mock class `mock_c` with mock function `int count()`, ```cpp struct mock_c { MAKE_MOCK0(count, int()); }; ``` and this expectation defined using the C\+\+14 API, ```cpp mock_c obj; auto e = NAMED_FORBID_CALL(obj, count()); ``` the corresponding expectation implemented using the C\+\+11 API is, ```cpp mock_c obj; auto e = NAMED_FORBID_CALL_V(obj, count()); ``` See also: [**`NAMED_FORBID_CALL(...)`**](reference.md/#NAMED_FORBID_CALL). #### Migrating from C\+\+11 API to C\+\+14 API The C\+\+11 API remains available when changing your C\+\+ dialect to C\+\+14 or later. Therefore existing test cases may be migrated incrementally to the C\+\+14 API while using the C\+\+14 API for new test cases. Steps: - Remove the `_V` suffix from the expectation macro. - Move the modifiers, if any, outside the argument list of the expectation macro. - Remove workarounds such as - Changes to regular expressions that may be testing messages generated with the `ANY` matcher. - Any of the workarounds required to use Trompeloeil with `g++ 4.8.3`. For example, given this expectation using the C\+\+11 API, ```cpp trompeloeil::sequence seq; auto thrown = false; REQUIRE_CALL_V(obj, getter(ANY(int)), .IN_SEQUENCE(seq) .LR_SIDE_EFFECT(thrown = true) .THROW(_1)); ``` the corresponding C\+\+14 API implementation is, ```cpp trompeloeil::sequence seq; auto thrown = false; REQUIRE_CALL(obj, getter(ANY(int))) .IN_SEQUENCE(seq) .LR_SIDE_EFFECT(thrown = true) .THROW(_1); ``` ### Implicit conversion of `RETURN` modifier expression In the C\+\+14 API, the [**`RETURN(...)`**](reference.md/#RETURN) modifier stores the expression passed as an argument to the modifier and forwards it to the Trompeloeil implementation for semantic analysis. In the C\+\+11 API, not only is the expression stored but also an implicit conversion to the return type of the mocked function is performed. This implicit conversion may fail before semantic checks are performed. The result is that instead of a helpful message generated by a `static_assert`, a less helpful error message is generated by the compiler. For example, ```cpp struct MS { MAKE_MOCK0(f, char&()); }; int main() { MS obj; REQUIRE_CALL_V(obj, f(), .RETURN('a')); } ``` The C\+\+11 error message is, ```text error: invalid initialization of non-const reference of type ‘MS::trompeloeil_l_tag_type_trompeloeil_20::return_of_t {aka char&}’ from an rvalue of type ‘char’ ``` The C\+\+14 error message is, ```text error: static assertion failed: RETURN non-reference from function returning reference ``` Other error messages that may not be generated while compiling using a C\+\+11 dialect include: ```text RETURN const* from function returning pointer to non-const RETURN const& from function returning non-const reference RETURN value is not convertible to the return type of the function ``` This is a quality of implementation issue that wasn't resolved before the C\+\+11 API became available. ### Macro expansion of `ANY` matcher before stringizing Macro expansion differences between C\+\+11 and C\+\+14 expectation macros mean macros like the [**`ANY(...)`**](reference.md/#ANY_MACRO) matcher used in the parameter list of the function to match are expanded in C\+\+11 before they are stringized. For example, a regular expression written in a C\+\+14 dialect, or later, ```cpp auto re = R":(Sequence expectations not met at destruction of sequence object "s": missing obj\.getter\(ANY\(int\)\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* missing obj\.foo\(_\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* ):"; ``` won't match the string generated when running in a C\+\+11 dialect. The `ANY(int)` matcher is actually expanded to some Trompeloeil-internal data. A helper macro, such as `CXX11_AS_STRING()`, may be defined to give a stringized form correct for C\+\+11: ```cpp #define CXX11_AS_STRING_IMPL(x) #x #define CXX11_AS_STRING(x) CXX11_AS_STRING_IMPL(x) ``` It may be used in constructing larger strings. Rewriting the example above illustrates its use: ```cpp auto re = R":(Sequence expectations not met at destruction of sequence object "s": missing obj\.getter\():" + escape_parens(CXX11_AS_STRING(ANY(int))) + R":(\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* missing obj\.foo\(_\) at [A-Za-z0-9_ ./:\]*:[0-9]*.* ):"; ``` where `escape_parens()` performs escaping of parentheses in the input string, ```cpp std::string escape_parens(const std::string& s) { constexpr auto backslash = '\\'; std::string tmp; for (auto& c : s) { if (c == '(' || c == ')') { tmp += backslash; } tmp += c; } return tmp; } ``` This is a quality of implementation issue that wasn't resolved before the C\+\+11 API became available. ## G\+\+ 4.8.x limitations Trompeloeil's support for `g++ 4.8.x` is limited by compiler and standard library defects. ### Compiler defects `g++-4.8.3` and older suffers from [bug 58714]( https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58714) which causes the wrong overload to be selected when overloads for mock functions exists for both `T&&` and `const T&` parameters. Example: ```Cpp struct S { MAKE_MOCK1(func, void(const int&)); MAKE_MOCK1(func, void(int&&)); }; void test() { S s; REQUIRE_CALL_V(s, func(ANY(const int&))); const int i = 0; s.func(i); } ``` With `g++-4.8.3` and older, this is reported as: ```text No match for call of func with signature void(const int&) with. param _1 == 1 ``` because the expectation is wrongly placed on the `int&&` overload. Consider moving to a more modern compiler. ### Standard library defects #### Regular expressions `g++ 4.8.x` lacks support for regular expressions in `libstdc++-v3`. As Jonathan Wakely said, > *sigh* \ is not implemented prior to GCC 4.9.0, > I thought the whole world was aware of that by now. See: GCC Bugzilla, "Bug 61582 - C\+\+11 regex memory corruption," 23 June 2014. \ Available: \ Accessed: 9 November 2017 As a consequence, avoid the [**`re(...)`**](reference.md/#re) matcher in test cases when compiling with a C\+\+11 dialect. #### `` `g++-4.8.3` has a defect in `` in `libstdc++-v3`. See: GCC Bugzilla, "Bug 61947 - [4.8/4.9 Regression] Ambiguous calls when constructing std::tuple," 29 July 2014. \ Available: \ Accessed: 8 November 2017 This is fixed in `g++-4.8.4`, `g++-4.9.3` and later releases. One workaround for this defect is to copy a version of `` from a release of `g++-4.8.4` or `g++-4.8.5` and arrange to include it ahead of the buggy version. Then work hard to move forward to a more recent compiler release. trompeloeil-47/docs/CookBook.md000066400000000000000000002212721454452461300166370ustar00rootroot00000000000000# *Trompeloeil* cook book - [Integrating with unit test frame works](#unit_test_frameworks) - [Creating Mock Classes](#creating_mock_classes) - [Mocking private or protected member functions](#mocking_non_public) - [Mocking overloaded member functions](#mocking_overloaded) - [Mocking operator()](#mocking_call_operator) - [Mocking a class template](#mocking_class_template) - [Mocking non-virtual member functions](#mocking_non_virtual) - [Mocking free functions](#mocking_free_functions) - [Mocking functions which return a template](#mocking_return_template) - [Setting Expectations](#setting_expectations) - [Matching exact values](#matching_exact_values) - [Matching values with conditions](#matching_conditions) - [Matching strings with regular expressions](#matching_regular_expressions) - [Matching pointers to values](#matching_pointers) - [Matching the opposite of a matcher](#negating_matchers) - [Matching calls with conditions depending on several parameters](#matching_multiconditions) - [Matching `std::unique_ptr` and other non-copyable values](#matching_non_copyable) - [Matching calls to overloaded member functions](#matching_overloads) - [Define side effects for matching calls](#side_effects) - [Return values from matching calls](#return_values) - [Return references from matching calls](#return_references) - [Throwing exceptions from matching calls](#throw) - [Allowing any call](#allowing_any) - [Temporarily disallowing matching calls](#temporary_disallow) - [Expecting several matching calls in some sequences](#sequences) - [Expecting matching calls a certain number of times](#match_count) - [Controlling lifetime of mock objects](#lifetime) - [Customize output format of values](#custom_formatting) - [Tracing mocks](#tracing) - [Using `trompeloeil::stream_tracer`](#stream_tracer) - [Writing custom tracers](#custom_tracer) - [Writing custom matchers](#custom_matchers) - [Typed matchers](#typed_matcher) - [Duck-typed matchers](#duck_typed_matcher) - [Legacy matchers](#legacy_matcher) ## Integrating with unit test frame works By default, *Trompeloeil* reports violations by throwing an exception, explaining the problem in the [`what()`](http://en.cppreference.com/w/cpp/error/exception/what) string. Depending on your test frame work and your runtime environment, this may, or may not, suffice. *Trompeloeil* offers support for adaptation to any test frame work. Some sample adaptations are: - [Catch!](#adapt_catch) - [crpcut](#adapt_crpcut) - [CxxTest](#adapt_cxxtest) - [doctest](#adapt_doctest) - [gtest](#adapt_gtest) - [lest](#adapt_lest) - [boost Unit Test Framework](#adapt_boost_unit_test_framework) - [MSTest](#adapt_mstest) - [Criterion](#adapt_criterion) There are two mechanisms for adapting to a testing frame work. The compile time adapter and the run time adapter. The compile time adapter is easier to use, especially if you write several test programs, but the runtime adapter allows for more flexibility, for example if you need run-time data like CLI arguments. ### Compile time adapter If you have a unit testing framework named *my_test*, create a header file ``. This header file must include ``, and provide an inline specialization of the `trompeloeil::reporter::send()` function. Below, as an example, is the adapter for the [*doctest*](https://github.com/onqtam/doctest) unit testing frame work, in the file `` ```Cpp #ifndef TROMPELOEIL_DOCTEST_HPP_ #define TROMPELOEIL_DOCTEST_HPP_ #ifndef DOCTEST_VERSION_MAJOR //** 1 **// #error " must be included before " #endif #include "../trompeloeil.hpp" //** 2 **// namespace trompeloeil { template <> inline void reporter::send( //** 3 **// severity s, char const* file, unsigned long line, std::string const& msg) { auto f = line ? file : "[file/line unavailable]"; if (s == severity::fatal) { ADD_FAIL_AT(f, line, msg); //** 4 **// } else { ADD_FAIL_CHECK_AT(f, line, msg); //** 4 **// } } } #endif //TROMPELOEIL_DOCTEST_HPP_ ``` The preprocessor check at `//** 1 **//` is not necessary, but it gives a friendly hint about what's missing. The function uses *doctest* macros at `//** 4 **//`, so `` must be included for this to compile. At `//** 2 **//` the include path is relative, since this is the file from the *Trompeloeil* distribution, where the main `trompeloeil.hpp` file is known to be in the parent directory of `doctest/trompeloeil.hpp`. At `//** 3 **//` the specialized function is marked `inline`, so as not to cause linker errors if your test program consists of several translation units, each including ``. At `//** 4 **//` the violations are reported in a *doctest* specific manner. It is important to understand the first parameter `trompeloeil::severity`. It is an enum with the values `trompeloeil::severity::fatal` and `trompeloeil::severity::nonfatal`. The value `severity::nonfatal` is used when reporting violations during stack rollback, typically during the destruction of an [expectation]( reference.md/#expectation ). In this case it is vital that no exception is thrown, or the process will terminate. If the value is `severity::fatal`, it is instead imperative that the function does not return. It may throw or abort. **NOTE!** There are some violations that cannot be attributed to a source code location. An example is an unexpected call to a [mock function](reference.md/#mock_function) for which there are no expectations. In these cases `file` will be `""` string and `line` == 0. Please contribute your adapter, so that others can enjoy your unit testing framework together with *Trompeloeil*. ### Run time adapter Run time adaptation to unit test frame works is done with this function: ```Cpp using reporter_func = std::function; using ok_reporter_func = std::function; reporter_func trompeloeil::set_reporter(reporter_func new_reporter); std::pair trompeloeil::set_reporter( reporter_func new_reporter, ok_reporter_func new_ok_reporter) ``` Call it with the adapter to your test frame work. The return value is the old adapter. The overload is provided to allow you to also set an 'OK reporter' at the same time (it also returns the old 'OK reporter') See the next section for details. It is important to understand the first parameter `trompeloeil::severity`. It is an enum with the values `trompeloeil::severity::fatal` and `trompeloeil::severity::nonfatal`. The value `severity::nonfatal` is used when reporting violations during stack rollback, typically during the destruction of an [expectation](reference.md/#expectation). In this case it is vital that no exception is thrown, or the process will terminate. If the value is `severity::fatal`, it is instead imperative that the function does not return. It may throw or abort. **NOTE!** There are some violations that cannot be attributed to a source code location. An example is an unexpected call to a [mock function](reference.md/#mock_function) for which there are no expectations. In these cases `file` will be `""` string and `line` == 0. ### Status OK reporting It is possible to make an adaption to the reporter that will be called if a positive expectation is met. This can be useful for correct counting and reporting from the testing framework. Negative expectations like `FORBID_CALL` and `.TIMES(0)` are not counted. Either provide your adapter as an inline specialization of the `trompeloeil::reporter::sendOk()` function at compile time or as the second argument to `trompeloeil::set_reporter(new_reporter, new_ok_reporter)` at runtime. The function should call a matcher in the testing framework that always yields true. Below, as an example, is the compile time adapter for the Catch2 unit testing frame work, in the file `` ```Cpp template <> inline void reporter::sendOk( const char* trompeloeil_mock_calls_done_correctly) { REQUIRE(trompeloeil_mock_calls_done_correctly); } ``` If you roll your own `main()`, you may prefer a runtime adapter instead. Please note that the first param given to `set_reporter()` here is a dummy - see the sections below for implementation examples for your unit testing framework of choice. ```Cpp trompeloeil::set_reporter( [](auto, auto, auto, auto) {}, // Not relevant here [](const char* trompeloeil_mock_calls_done_correctly) { // Example for Catch2 REQUIRE(trompeloeil_mock_calls_done_correctly); } ); ``` Below is a simple example for *Catch2*: ```Cpp class MockFoo { public: MAKE_MOCK0(func, void()); }; TEST_CASE("Foo test") { MockFoo foo; REQUIRE_CALL(foo, func()).TIMES(2,4); foo.func(); foo.func(); } ``` When the test is executed we get the following output ```sh $ ./footest =============================================================================== All tests passed (2 assertions in 1 test case) ``` ### Use *Trompeloeil* with [Catch2](https://github.com/catchorg/Catch2) The easiest way to use *Trompeloeil* with *Catch2* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include TEST_CASE("... ``` If you roll your own `main()`, you may prefer a runtime adapter instead. Before running any tests, make sure to call: ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { std::ostringstream os; if (line) os << file << ':' << line << '\n'; os << msg; auto failure = os.str(); if (s == trompeloeil::severity::fatal) { FAIL(failure); } else { CAPTURE(failure); CHECK(failure.empty()); } }); ``` ### Use *Trompeloeil* with [CxxTest](https://www.cxxtest.com) The easiest way to use *Trompeloeil* with *CxxTest* is to `#include ` in your test `.hpp` files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include class TestClass: public CxxTest::TestSuite { public: void TestXXX() { // ... } }; ``` If you roll your own `main()`, you may prefer a runtime adapter instead. Before running any tests, make sure to call: ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { std::ostringstream os; if (line) os << file << ':' << line << '\n'; os << msg; auto failure = os.str(); if (s == severity::fatal) { // Must not return normally i.e. must throw, abort or terminate. TS_FAIL(failure); } else { // nonfatal: violation occurred during stack rollback. // Must not throw an exception. TS_WARN(failure); } }); ``` ### Use *Trompeloeil* with [crpcut](http://crpcut.sourceforge.net) The easiest way to use *Trompeloeil* with *crpcut* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include TEST(... ``` If you instead prefer a runtime adapter, make sure to call ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity, const char* file, unsigned long line, std::string const& msg) { std::ostringstream os; os << file << ':' << line; auto loc = os.str(); auto location = line == 0U ? ::crpcut::crpcut_test_monitor::current_test()->get_location() : ::crpcut::datatypes::fixed_string::make(loc.c_str(), loc.length()); ::crpcut::comm::report(::crpcut::comm::exit_fail, std::ostringstream(msg), location); }); ``` before any tests are run. ### Use *Trompeloeil* with [doctest](https://github.com/onqtam/doctest) - [doctest 1.2 or newer](#doctest12) - [doctest < 1.2](#doctest_old) #### doctest 1.2 or newer The easiest way to use *Trompeloeil* with *doctest* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include TEST_CASE("... ``` If you roll your own `main()`, you may prefer a runtime adapter instead. Before running any tests, make sure to call: ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { auto f = line ? file : "[file/line unavailable]"; if (s == severity::fatal) { ADD_FAIL_AT(f, line, msg); } else { ADD_FAIL_CHECK_AT(f, line, msg); } }); ``` #### doctest < 1.2 Create a simple `doctest_violation` type by pasting the below code into the file containing `main()`. ```Cpp struct doctest_violation : std::ostringstream { friend std::ostream& operator<<(std::ostream& os, doctest_violation const& v) { return os << v.str(); } }; ``` Then, before running any tests, make sure to call: ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { ::doctest_violation violation; if (line) violation << file << ':' << line << '\n'; violation << msg; if (s == trompeloeil::severity::fatal) { REQUIRE_FALSE(violation); } else { CHECK_FALSE(violation); } }); ``` ### Use *Trompeloeil* with [gtest](https://code.google.com/p/googletest/) The easiest way to use *Trompeloeil* with *gtest* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include TEST("... ``` If you instead prefer a runtime adapter, make sure to call ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { if (s == trompeloeil::severity::fatal) { std::ostringstream os; if (line != 0U) { os << file << ':' << line << '\n'; } throw trompeloeil::expectation_violation(os.str() + msg); } ADD_FAILURE_AT(file, line) << msg; }); ``` before running any tests. ### Use *Trompeloeil* with [lest](https://github.com/martinmoene/lest) With *lest*, you always provide your own `main()`. In it, provide a runtime adapter like the one below. ```Cpp int main(int argc, char *argv[]) { std::ostream& stream = std::cout; trompeloeil::set_reporter([&stream]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { if (s == trompeloeil::severity::fatal) { throw lest::message{"", lest::location{ line ? file : "[file/line unavailable]", int(line) }, "", msg }; } else { stream << lest::location{ line ? file : "[file/line unavailable]", int(line) } << ": " << msg; } }); return lest::run(specification, argc, argv, stream); } ``` ### Use *Trompeloeil* with [boost Unit Test Framework](http://www.boost.org/doc/libs/1_59_0/libs/test/doc/html/index.html) The easiest way to use *Trompeloeil* with *boost::unit_test* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include BOOST_AUTO_TEST_CASE("... ``` If you instead prefer a runtime adapter, make sure to call ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { std::ostringstream os; if (line != 0U) os << file << ':' << line << '\n'; auto text = os.str() + msg; if (s == trompeloeil::severity::fatal) BOOST_FAIL(text); else BOOST_ERROR(text); }); ``` before running any tests. ### Use *Trompeloeil* with [MSTest](https://msdn.microsoft.com/en-us/library/hh694602.aspx) Place the below code snippet in, for example, your `TEST_CLASS_INITIALIZE(...)` ```Cpp using namespace trompeloeil; set_reporter([]( severity, char const* file, unsigned long line, std::string const& msg) { std::wstring wideMsg(msg.begin(), msg.end()); std::wstring wfile; if (line > 0) wfile.append(file, file + strlen(file)); __LineInfo loc(wfile.c_str(), "", line); Assert::Fail(wideMsg.c_str(), line == 0 ? nullptr : &loc); }); ``` ### Use *Trompeloeil* with [Criterion](https://github.com/Snaipe/Criterion) The easiest way to use *Trompeloeil* with *Criterion* is to `#include ` in your test .cpp files. Note that the inclusion order is important. `` must be included before ``. Like this: ```Cpp #include #include Test(... ``` If you instead prefer a runtime adapter, make sure to call ```Cpp trompeloeil::set_reporter([]( trompeloeil::severity s, const char* file, unsigned long line, std::string const& msg) { struct criterion_assert_stats cr_stat__; cr_stat__.passed = false; cr_stat__.file = file; cr_stat__.line = line; cr_stat__.message = msg; if (s == severity::fatal) { criterion_send_assert(&cr_stat__); CR_FAIL_ABORT_(); } else { criterion_send_assert(&cr_stat__); CR_FAIL_CONTINUES_(); } }); ``` before running any tests. ## Creating Mock Classes A Mock class is any class that [mocks](reference.md/#mock_function) member functions. There are two ways to create mocks. A very frequently seen situation is when inheriting from an interface (i.e. an abstract base class with pure virtual functions). When this is the case, the easiest route is to inherit the interface via [`trompeloeil::mock_interface`](#reference.md/mock_interface) and implement the mock functions with the macros [**`IMPLEMENT_MOCKn(...)`**](reference.md/#IMPLEMENT_MOCKn) and [**`IMPLEMENT_CONST_MOCKn(...)`**](reference.md/#IMPLEMENT_CONST_MOCKn). These only work when implementing to an interface, do not handle multiple inheritance and do not handle overloads. A more generic technique is to implement free mocks as members of any `struct` or `class` using the macros [**`MAKE_MOCKn`**]( reference.md/#MAKE_MOCKn ) and [**`MAKE_CONST_MOCKn`**]( reference.md/#MAKE_CONST_MOCKn ), where `n` is the number of parameters in the function. Example: ```Cpp class Dictionary { public: virtual ~Dictionary() = default; virtual std::string& lookup(int n) const = 0; virtual void add(int n, std::string&&) = 0; }; class MockDictionary : public trompeloeil::mock_interface { IMPLEMENT_CONST_MOCK1(lookup); IMPLEMENT_MOCK2(add); }; struct Logger { MAKE_MOCK2(log, void(int severity, const std::string& msg)); }; ``` In the example above, `MockDictionary` is, as the name implies, a mock class for the pure virtual class `Dictionary`. The line `IMPLEMENT_CONST_MOCK1(lookup);` implements the function `std::string& lookup(int) const` and the line `IMPLEMENT_MOCK2(add);` implements the function `void add(int, std::string&&)`. The line `MAKE_MOCK2(log, void(int severity, const std::string& msg))` creates a mock function `void Logger::log(int, const std::string&)`. If [**`MAKE_MOCKn(...)`**](reference.md/#MAKE_MOCKn) or [**`MAKE_CONST_MOCKn(...)`**](reference.md/#MAKE_CONST_MOCKn) are used to implement a virtual function from a base class, it is always recommended to add a third macro parameter `override` since it gives the compiler an ability to complain about mistakes. ### Mocking private or protected member functions Mocking private or protected member functions using [**`MAKE_MOCKn(...)`**](reference.md/#MAKE_MOCKn) or [**`MAKE_CONST_MOCKn(...)`**](reference.md/#MAKE_CONST_MOCKn) is no different from mocking public member functions. Just make them public in the mock class. It may seem strange that you can change access rights of a member function through inheritance, but C\+\+ allows it. Example: ```Cpp class Base { private: virtual void secret(int); }; class Mock : public Base { public: MAKE_MOCK1(secret, void(int), override); // not so secret now }; ``` The [mock functions](reference.md/#mock_function) must be public for you to be able to set [expectations](#setting_expectations) on them, but there is nothing preventing a public function from implementing a private virtual function in a base class. **NOTE!** Mocking private or protected functions does not work with [**`IMPLEMENT_MOCKn(...)`**](reference.md/#IMPLEMENT_MOCKn) or [**`IMPLEMENT_CONST_MOCKn(...)`**](reference.md/#IMPLEMENT_CONST_MOCKn), since these need full visibility of the function in the base class. ### Mocking overloaded member functions *Trompeloeil* matches [mock functions](reference.md/#mock_function) by their name and their signature, so there is nothing special about adding several overloads of mocked functions. Example: ```Cpp class Mock { public: MAKE_MOCK1(overload, void(int)); MAKE_MOCK1(overload, int(const std::string&)); MAKE_MOCK2(overload, int(const char*, size_t)); }; ``` Above there are three [mock functions](reference.md/#mock_function) named `overload`, with different signatures. See [Matching calls to overloaded member functions](#matching_overloads) for how to place [expectations](reference.md/#expectation) on them. **NOTE!** Overloaded member functions cannot be mocked using the macros [**`IMPLEMENT_MOCKn(...)`**](reference.md/IMPLEMENT_MOCKn) or [**`IMPLEMENT_CONST_MOCKn(...)`**](reference.md/IMPLEMENT_CONST_MOCKn)`. ### Mocking operator() The *Trompeloeil* macros cannot handle `operator()` directly, so to mock the function call operator you have to go via an indirection, where you implement a trivial `operator()` that calls a function that you can mock. Example: ```Cpp class Mock { public: int operator()(int x) const { return function_call(x); } MAKE_CONST_MOCK1(function_call, int(int)); }; ``` ### Mocking a class template Unlike some *C\+\+* mocking frame works, *Trompeloeil* does not make a distinction between mocks in class templates and mocks in concrete classes. Example: ```Cpp template class Mock { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK2(tfunc, int(const T&, size_t)); }; ``` Above, `Mock` is a mock class template with two member functions. The member function `void func(int)` does not depend on the template parameter, whereas the member function `int tfunc(const T&, size_t)` does. This will work for any type `T`. ### Mocking non-virtual member functions While it is often the case that mocks are used to implement interfaces, there is no such requirement. Just add the [mock functions][mockfun] that are needed. Example: ```Cpp class ConcreteMock { public: MAKE_MOCK2(func, bool(size_t, const char*)); }; ``` Above `ConcreteMock` is a mock class that implements a non-virtual [mock function][mockfun] `bool func(size_t, const char*)`. > **REMINDER**: Non-virtual functions may not be dispatched via polymorphism at > runtime. This feature doesn't alter the underlying semantic rules for virtual > methods. If you upcast to a base type, the mock class implementations of these > methods will _not_ be invoked. [mockfun]: reference.md/#mock_function ### Mocking free functions Free functions on their own cannot be mocked, the calls to them needs to be dispatched to [mock objects](reference.md/#mock_object). Often there are several free functions that together form an API, and then it makes sense to implement one mock class for the API, with [mock functions](reference.md/#mock_function) for each. Example, assume a simple C-API ```Cpp // C-API.h #ifdef __cplusplus extern "C" { #endif struct c_api_cookie; struct c_api_cookie* c_api_init(); int c_api_func1(struct c_api_cookie* cookie, const char* str, size_t len); void c_api_end(struct c_api_cookie*); #ifdef __cplusplus } #endif ``` ```Cpp // unit-test-C-API.h -- example using Catch2 #include #include /* this should go last */ #include "C-API.h" class API { public: MAKE_MOCK0(c_api_init, c_api_cookie*()); MAKE_MOCK3(c_api_func1, int(c_api_cookie*, const char*, size_t)); MAKE_MOCK1(c_api_end, void(c_api_cookie*)); }; extern API c_api_mock; ``` Then implement the functions in a test version of the API, which uses the mock. ```Cpp // unit-test_c_api.cpp #include "unit-test-C-API.h" API c_api_mock; extern "C" { c_api_cookie c_api_init() { return c_api_mock.c_api_init(); } int c_api_func1(c_api_cookie* cookie, const char* str, size_t len) { return c_api_mock.c_api_func1(cookie, str, len); } void c_api_end(c_api_cookie* cookie) { c_api_mock.c_api_end(cookie); } } ``` A test program can place [expectations](reference.md/#expectation) on the mock object, and the tested functionality calls the C-API functions which dispatch to the mock object. ```Cpp #include "unit-test-C-API.h" void a_test() { REQUIRE_CALL(c_api_mock, c_api_init()) .RETURN(nullptr); REQUIRE_CALL(c_api_mock, c_api_end(nullptr)); function_under_test(); } ``` ### Mocking functions which return a template To use template as return type you have to put the signature into parentheses like this: ```Cpp struct M { MAKE_MOCK2(make, (std::pair)(int,int)); }; ``` ## Setting Expectations It is with [expectations](reference.md/#expectation) you define the behaviour of your test. By default all calls to [mock functions](reference.md/#mock_function) are illegal and will be reported as violations. You use expectations, long or short lived, wide or narrow, to make some calls legal and define what happens. There are three basic types of expectations. - [**`ALLOW_CALL(...)`**](reference.md/#ALLOW_CALL) - [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL) - [**`FORBID_CALL(...)`**](reference.md/#FORBID_CALL) **`ALLOW_CALL(...)`** is often used for a default. It can match any number of times. **`REQUIRE_CALL(...)`** is stricter and defaults to match exactly once, although you can change that and control exactly [how many times](#match_count) you want the expectation to match. **`FORBID_CALL(...)`** may seem unnecessary since calls are forbidden by default, but it is useful in combination with **`ALLOW_CALL(...)`** or **`REQUIRE_CALL(...)`** to forbid something that would otherwise be accepted. If several expectations match a call, it is the last matching expectation created that is used. **`ALLOW_CALL(...)`**, **`REQUIRE_CALL(...)`** and **`FORBID_CALL(...)`** are active until the end of the scope. This means that you can place a wide default, and use temporary special expectations in local scopes, for example to temporarily forbid a call that is otherwise allowed. If the scoped lifetime rules are unsuitable, there are also thee named versions of the expectations. - [**`NAMED_ALLOW_CALL(...)`**](reference.md/#NAMED_ALLOW_CALL) - [**`NAMED_REQUIRE_CALL(...)`**](reference.md/#NAMED_REQUIRE_CALL) - [**`NAMED_FORBID_CALL(...)`**](reference.md/#NAMED_FORBID_CALL) These do the same, but they create a `std::unique_ptr`, which you can bind to variables that you control the life time of. ### Matching exact values The simplest [expectations](reference.md/#expectation) are for calls with exact expected parameter values. You just provide the expected values in the parameter list of the expectation. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK2(func, void(const char*)); }; void test() { Mock m; ALLOW_CALL(m, func(1)); // int version any number of times REQUIRE_CALL(m, func(nullptr)); // const char * version exactly once func(&m); // expectations must be met before end of scope } ``` ### Matching values with conditions Instead of using exact values of parameters to match calls with, *Trompeloeil* provides a set of [matchers](reference.md/#matcher). Simple value matchers are: - [**`eq(`** *value* **`)`**](reference.md/#eq) matches value equal (using `operator==()`) - [**`ne(`** *value* **`)`**](reference.md/#ne) matches value not equal (using `operator!=()`) - [**`gt(`** *value* **`)`**](reference.md/#gt) matches value greater than (using `operator>()`) - [**`ge(`** *value* **`)`**](reference.md/#ge) matches value greater than or equal (using `operator>=()`) - [**`lt(`** *value* **`)`**](reference.md/#lt) matches value less than (using `operator<()`) - [**`le(`** *value* **`)`**](reference.md/#le) matches value less than or equal (using `operator<=()`) By default, the matchers are [*duck typed*]( https://en.wikipedia.org/wiki/Duck_typing ), i.e. they match a parameter that supports the operation. If disambiguation is necessary to resolve overloads, an explicit type can be specified. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(const char*)); MAKE_MOCK1(func, void(const std::string&)) }; void test() { Mock m; ALLOW_CALL(m, func(trompeloeil::gt(1))); // int version any number of times REQUIRE_CALL(m, func(trompeloeil::ne(""))); // const std::string& version once func(&m); // expectations must be met before end of scope } ``` ### Matching strings with regular expressions Matching string parameters to regular expressions is convenient with *Trompeloeil* [**`re(`** *expression* **`)`**](reference.md/#re) regular expression matchers. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(const char*)); }; void test() { Mock m; REQUIRE_CALL(m, func(trompeloeil::re("^begin.*end$"))); func(&m); // expectation must be met before end of scope } ``` **TIP!** Using `C++` [raw string literals]( http://www.stroustrup.com/C++11FAQ.html#raw-strings ) can massively help getting regular expression escapes right. ### Matching pointers to values All [matchers](reference.md/#matcher) can be converted to a pointer matcher by using the dereference prefix operator [**`*`**](reference.md/#deref_matcher). This works for smart pointers too. These pointer matchers fail if the pointer parameter is `nullptr`. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int*)); MAKE_MOCK2(func, void(std::unique_ptr*)); }; using trompeloeil::eq; using trompeloeil::gt; void test() { Mock m; ALLOW_CALL(m, func(*eq(1))); // pointer to int value 1 any number of times REQUIRE_CALL(m, func(*gt(5))); // unique_ptr to >5 once func(&m); // expectations must be met before end of scope } ``` ### Matching the opposite of a matcher All [matchers](reference.md/#matcher) can be negated, allowing what the matcher disallows and disallowing what the matcher allows, using the operator [**`!`**](reference.md/#negate_matcher) on the matcher. Example: ```Cpp struct Mock { MAKE_MOCK1(func, void(const std::string&)); }; using trompeloeil::re; // matching regular expressions TEST(atest) { Mock m; REQUIRE_CALL(m, func(!re("^foo"))); func(&m); // m.func() must've been called with a string not beginning with "foo" } ``` ### Matching calls with conditions depending on several parameters Some times a matching call cannot be judged for individual parameter values alone, but together they work. Assume for example a C-string API where you have a `const char*` and a length. Example: ```Cpp class Mock { public: MAKE_MOCK2(func, void(const char*, size_t len)); }; using trompeloeil::ne; using trompeloeil::_; void test() { Mock m; REQUIRE_CALL(m, func(ne(nullptr), _))) // once .WITH(std::string(_1, _2) == "meow")); func(&m); // expectations must be met before end of scope } ``` [**`_`**](reference.md/#wildcard) is a special matcher that matches everything. [**`.WITH(...)`**](reference.md/#WITH) is a construction used for when simple matchers aren't enough. If a call is made which matches the values given in the [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL), the selection process continues in [**`.WITH(std::string(_1, _2) == "meow")`**](reference.md/#WITH). **`_1`** and **`_2`** are the parameters to the call, so in this case a `std::string` is constructed using the non-null `const char*` and the length, and its value is compared with `"meow"`. The expression in [**`.WITH(...)`**](reference.md/#WITH) can be anything at all that returns a boolean value. It can refer to global variables, for example. It is important to understand that [**`.WITH(...)`**](reference.md/#WITH) accesses any local variable used in the expression as a copy. If you want to refer to a local variable by reference, use [**`.LR_WITH(...)`**](reference.md/#LR_WITH) instead (`LR_` for "local reference"). ### Matching `std::unique_ptr` and other non-copyable values Matching parameter values that you cannot copy, or do not want to copy, requires a bit of thought. The wildcards [**`_`**](reference.md/#wildcard) and [**`ANY(...)`**](reference.md/#ANY) works. For `std::unique_ptr` and `std::shared_ptr`, the matcher [**`ne(nullptr)`**](reference.md/#ne) also works. If you want to be more specific, you will need to use [**`.WITH(...)`**](reference.md/#WITH) or [**`.LR_WITH(...)`**](reference.md/#LR_WITH) Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(std::unique_ptr)); }; using trompeloeil::ne; void test() { Mock m; REQUIRE_CALL(m, func(ne(nullptr))) .WITH(*_1 == 3); func(&m); // expectations must be met before end of scope } ``` Above there is a requirement that the function is called with a non-null `std::unique_ptr`, which points to a value of `3`. If the signature of the function is to a reference, you can also use [`std::ref()`](https://en.cppreference.com/w/cpp/utility/functional/ref) to bind a reference in the expectation. ```Cpp class Mock { public: MAKE_MOCK1(func, void(std::unique_ptr&)); }; void func_to_test(Mock& m, std::unique_ptr& ptr); void test() { Mock m; auto p = std::make_unique(3); { REQUIRE_CALL(m, func(std::ref(p))) .LR_WITH(&_1 == &p); // ensure same object, not just equal value func_to_test(m, p); } } ``` Note that the check for a matching parameter defaults to using `operator==`. If you want to ensure that it is the exact same object, not just one with the same value, you need to compare the addresses of the parameter and the expected value, as shown in the example above. ### Matching calls to overloaded member functions Distinguishing between overloads is simple when using exact values to match since the type follows the values. It is more difficult when you want to use wildcards and other [matchers](reference.md/#matcher). One useful matcher is [**`ANY(...)`**](reference.md/#ANY), which behaves like the open wildcard [**`_`**](reference.md/#wildcard), but has a type. It is also possible to specify types in the matchers. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int*)); MAKE_MOCK1(func, void(char*)); }; using namespace trompeloeil; void test() { Mock m; REQUIRE_CALL(m, func(ANY(int*))); REQUIRE_CALL(m, func(ne(nullptr))); func(&m); } ``` Above, each of the `func` overloads must be called once, the `int*` version with any pointer value at all, and the `char*` version with a non-null value. Matching overloads on constness is done by placing the expectation on a const or non-const object. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); MAKE_CONST_MOCK1(func, void(int)); }; void test() { Mock m; REQUIRE_CALL(m, func(3)); // non-const overload const Mock& mc = m; REQUIRE_CALL(mc, func(-3)); // const overload m.func(3); // calls non-const overload mc.func(-3); // calls const overload } ``` ### Define side effects for matching calls A side effect, in *Trompeloeil* parlance, is something that is done after a match has been made for an [expectation](reference.md/#expectation), and before returning (or throwing). Typical side effects are: - Setting out parameters - Capturing in parameters - Calling other functions Example: ```Cpp class Dispatcher { public: MAKE_MOCK1(subscribe, void(std::function)); }; using trompeloeil::_; void test() { Dispatcher d; std::vector> clients; { REQUIRE_CALL(d, subscribe(_)) .LR_SIDE_EFFECT(clients.push_back(std::move(_1))) .TIMES(AT_LEAST(1)); func(&d); } for (auto& cb : clients) cb("meow"); } ``` Above, any call to `d.subscribe(...)` will have the side effect that the parameter value is stored in the local vector `clients`. The test then goes on to call all subscribers. [**`LR_SIDE_EFFECT(...)`**](reference.md/#LR_SIDE_EFFECT) accesses references to local variables. There is also [**`SIDE_EFFECT(...)`**](reference.md/#SIDE_EFFECT), which accesses copies of local variables. ### Return values from matching calls An [expectation](reference.md/#expectation) on a non-void function must return something or [throw](#throw) an exception. There are no default values. Returning is easy, however. Just use a [**`.RETURN(...)`**](reference.md/#RETURN) or [**`.LR_RETURN(...)`**](reference.md/#LR_RETURN) with an expression of the right type. Example: ```Cpp class Dictionary { public: using id_t = size_t; MAKE_MOCK1(lookup, std::string(id_t)); }; using trompeloeil::ge; // greater than or equal using trompeloeil::lt; // less than void test() { Dictionary d; std::vector dict{...}; ALLOW_CALL(d, lookup(ge(dict.size()))) .RETURN(""); // create std::string from "" ALLOW_CALL(d, lookup(lt(dict.size()))) .LR_RETURN(dict[_1]); // access element in vector func(&d); } ``` Above, the [matchers](reference.md/#matcher) [**`lt(...)`**](reference.md/#lt) and [**`ge(...)`**](reference.md/#ge) are used to ensure that the indexing in the local variable `dict` can be made safely. Note that the first [expectation](reference.md/#expectation) does not match the return type exactly, but is something that can be implicitly converted. [**`LR_RETURN(...)`**](reference.md/#LR_RETURN) is used in the second to avoid copying the vector, since [**`RETURN(...)`**](reference.md/#RETURN) always accesses copies of local variables. ### Return references from matching calls Returning references from matching [expectations](reference.md/#expectation) exposes some peculiarities in the language. Specifically, it is not allowed to return a captured local variable as a reference in [**`RETURN(...)`**](reference.md/#RETURN), and in [**`LR_RETURN(...)`**](reference.md/#LR_RETURN) a returned variable must be decorated to ensure that a reference is intended. Example: ```Cpp class Dictionary { public: using id_t = size_t; MAKE_MOCK1(lookup, const std::string&(id_t)); }; using trompeloeil::gt; // greater than or equal using trompeloeil::lt; // less than std::string global_empty; void test() { Dictionary d; std::vector dict{...}; std::string empty; ALLOW_CALL(d, lookup(gt(dict.size()))) .LR_RETURN((empty)); // extra () -> reference to local variable ALLOW_CALL(d, lookup(dict.size())) .LR_RETURN(std::ref(empty)); // reference to local variable ALLOW_CALL(d, lookup(lt(dict.size()))) .LR_RETURN(dict[_1]); // result of function call ALLOW_CALL(d, lookup(0)) .RETURN(std::ref(global_empty)); // reference to global variable func(&d); } ``` Captured variables that are returned as references must either be enclosed in extra parenthesis, or [`std::ref()`](http://en.cppreference.com/w/cpp/utility/functional/ref). Returning a reference obtained from a function call, however, does not require any extra decoration, as the third [expectation](reference.md/#expectation) above, which looks up values in `dict` shows. ### Throwing exceptions from matching calls To throw an exception, just add a [**`.THROW(...)`**](reference.md/#THROW) or [**`.LR_THROW(...)`**](reference.md/#LR_THROW), with the value to throw. For non-void functions, [**`.LR_THROW(...)`**](reference.md/#LR_THROW) and [**`.THROW(...)`**](reference.md/#THROW) takes the place of a [**`.RETURN(...)`**](reference.md/#RETURN) or [**`.LR_RETURN(...)`**](reference.md/#LR_RETURN). Example: ```Cpp class Dictionary { public: using id_t = size_t; MAKE_CONST_MOCK1(lookup, const std::string&(id_t)); }; using trompeloeil::_; // matches anything void test() { Dictionary d; std::vector dict{...}; ALLOW_CALL(d, lookup(_)) .LR_WITH(_1 >= dict.size()) .THROW(std::out_of_range("index too large for dictionary")); ALLOW_CALL(d, lookup(_)) .LR_WITH(_1 < dict.size()) .LR_RETURN(dict[_1]); func(&d); } ``` Above, any call to `d.lookup(...)` with an index within the size of the vector will return the string reference, while any call with an index outside the size of the vector will throw a `std::out_of_range` exception. ### Allowing any call By default it is illegal to call any [mock function](reference.md/#mock_function) and you provide narrow specific expectations according to the needs of your test. However, sometimes it makes sense to have a wide-open default. That is done with the [expectations](reference.md/#expectation) [**`ALLOW_CALL(...)`**](reference.md/#ALLOW_CALL) and [**`NAMED_ALLOW_CALL(...)`**](reference.md/#NAMED_ALLOW_CALL). The difference between them is that **`ALLOW_CALL`** is local in nature and is only valid until the end of the scope, while **`NAMED_ALLOW_CALL(...)`** can be bound to a `std::unique_ptr`, which you can control the lifetime of. Example: ```Cpp template class Allocator { public: MAKE_MOCK1(allocate, T*(size_t)); MAKE_MOCK1(deallocate, void(T*)); }; using trompeloeil::_; void test_no_mem() { Allocator ai; ALLOW_CALL(ai, allocate(_)) .RETURN(nullptr); ALLOW_CALL(ai, deallocate(nullptr)); hairy_int_job(&ai); } ``` The simplistic allocator above is rigged to allow any attempts to allocate memory, but always return `nullptr`, and only allow deallocation of `nullptr`. ### Temporarily disallowing matching calls Just as it is sometimes convenient to provide a blanket default behaviour, it is sometimes desirable to temporarily ban calls. Example: ```Cpp #include "hairy_job.h" template class Allocator { public: MAKE_MOCK1(allocate, T*(size_t)); MAKE_MOCK1(deallocate, void(T*)); }; using trompeloeil::_; void test_restricted_mem() { Allocator ai; ALLOW_CALL(ai, allocate(_)) .RETURN(new int[_1]); ALLOW_CALL(ai, deallocate(_)) .SIDE_EFFECT(delete[] _1); hairy_job> job(ai, initial_data); { FORBID_CALL(ai, allocate(_)); job.churn(); // must not allocate memory } job.get_result(); // may allocate memory } ``` Above we see a simplistic Allocator that by default allocates and deallocates arrays. The `hairy_job` uses the Allocator for its setup, and is expected to allocate all memory it needs for `churn()` in its constructor. That `churn()` doesn't use the allocator is ensured by the local scope, in which all calls to `allocate(...)` are forbidden. This pattern is quite common when writing tests with *Trompeloeil*. Use wide defaults in the scope of the test case (or in a fixture), and use local scopes with specifics, be they forbidden or exact requirements. ### Expecting several matching calls in some sequences By default all [expectations](reference.md/#expectation) are equal, and the only sequencing relationship is that if several match a call, the one last created is the one matched. This means that [expectations](reference.md/#expectation) that do not compete for matching the same call have no ordering relationship at all, they are logically parallel. Often this is exactly what you want. When you poke an object, you want this and that thing to happen and the order between them is irrelevant. For example, if calling callbacks stored in a hash table, you don't want to impose an order of those calls. There are two very different reasons for using sequence control with *Trompeloeil*. One is hinted at above, to impose an order between [expectations](reference.md/#expectation) that are logically parallel. The other is to set an exact order of indistinguishable [expectations](reference.md/#expectation). The latter can be achieved by setting them up in reverse order of matching, but this can make the test code very difficult to read. First example. Impose an order between logically parallel calls: ```Cpp class FileOps { public: using handle = int; MAKE_MOCK1(open, handle(const std::string&)); MAKE_MOCK3(write, size_t(handle, const char*, size_t)); MAKE_MOCK1(close, void(handle)); }; using trompeloeil::ne; void test() { FileOps ops; trompeloeil::sequence seq; int handle = 4711; REQUIRE_CALL(ops, open("name")) .RETURN(handle) .IN_SEQUENCE(seq); REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0))) .RETURN(_3) .IN_SEQUENCE(seq); REQUIRE_CALL(ops, close(handle)) .IN_SEQUENCE(seq); test_writes(&ops); } ``` Without the use of `trompeloeil::sequence` above, all three [expectations](reference.md/#expectation) would be logically parallel and all permutations of matches would be considered equally correct. By imposing an order between them, there is now only one legal sequence of calls. The other example is to provide an order between equally matching calls. Suppose we want the `write` function above to first return 0 once and then give the desired result: ```Cpp class FileOps { public: using handle = int; MAKE_MOCK1(open, handle(const std::string&)); MAKE_MOCK3(write, size_t(handle, const char*, size_t)); MAKE_MOCK1(close, void(handle)); }; using trompeloeil::ne; void test() { FileOps ops; trompeloeil::sequence seq; int handle = 4711; REQUIRE_CALL(ops, open("name")) .RETURN(handle) .IN_SEQUENCE(seq); REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0))) .RETURN(0) // indicate failure .IN_SEQUENCE(seq); REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0))) .RETURN(_3) // successful retry .IN_SEQUENCE(seq); REQUIRE_CALL(ops, close(handle)) .IN_SEQUENCE(seq); test_writes(&ops); } ``` Here the two calls to `write` are supposed to be made with exactly the same parameters, so they cannot be distinguished that way. We want the first call to indicate intermittent failure, and to be followed by a retry that will succeed. [**`.IN_SEQUENCE(...)`**](reference.md/#IN_SEQUENCE) can refer to several sequence objects, which is a way to allow some variation in order, without being too lax. For a more thorough walk through, see the blog post [Sequence control with the Trompeloeil C\+\+14 Mocking Framework](http://playfulprogramming.blogspot.se/2015/01/sequence-control-with-trompeloeil-c.html) [**`.IN_SEQUENCE(...)`**](reference.md/#IN_SEQUENCE) can also be used on [**`REQUIRE_DESTRUCTION(...)`**](reference.md/#REQUIRE_DESTRUCTION) and [**`NAMED_REQUIRE_DESTRUCTION(...)`**](reference.md/#NAMED_REQUIRE_DESTRUCTION). ### Expecting matching calls a certain number of times By default [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL) needs exactly one matching call, otherwise a violation is reported. Sometimes the need is for something else. A modifier [**`TIMES(...)`**](reference.md/#TIMES) is used to change that. You can either specify an exact number of times matching calls must be made, or a range of numbers. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); }; void some_test() { Mock m; REQUIRE_CALL(m, func(0)) .TIMES(2); REQUIRE_CALL(m, func(1)) .TIMES(3, 5); REQUIRE_CALL(m, func(2)) .TIMES(AT_LEAST(3)); REQUIRE_CALL(m, func(3)) .TIMES(AT_MOST(4)); func(&m); } ``` Above, `m.func(0)` must be called exactly twice. `m.func(1)` must be called three, four or five times. The call `m.func(2)` must be made three or more times. Finally `m.func(4)` must not be called more than four times. ## Controlling lifetime of mock objects If you test a case where you hand over ownership of a [mock object](reference.md/#mock_object), you may want to test that the mock object is destroyed when intended. For this there is a modifier class template `trompeloeil::deathwatched` and the macros [**`REQUIRE_DESTRUCTION(...)`**](reference.md/#REQUIRE_DESTRUCTION) and [**`NAMED_REQUIRE_DESTRUCTION(...)`**](reference.md/#NAMED_REQUIRE_DESTRUCTION). Example: ```Cpp class Mock { public: virtual ~Mock() {} // virtual destructor required for deathwatched<> MAKE_MOCK1(func, void(int)); } template class consumer { public: consumer(T&&); void poke(int n); private: ... }; void consume_test() { auto owner = std::make_unique>(); auto mock = owner.get(); // use raw unowned pointer consumer c(std::move(owner)); { REQUIRE_CALL(*mock, func(3)); c.poke(3); } { REQUIRE_CALL(*mock, func(-1)); REQUIRE_DESTRUCTION(*mock); c.poke(0); } } ``` Above, the constructor of object `c` takes ownership of the [mock object](reference.md/#mock_object). Since the mock object is on deathwatch, destruction is reported as a violation. Thus we can be sure that if the constructor destroys the mock object, the test will fail. Likewise if the call `c.poke(3)` would destroy the mock object. The local scope afterwards has a requirement that the mock object *is* destroyed. If the call `c.poke(0)` does not destroy the mock, a violation will be reported and fail the test. There is an implied order that the mock function `func(-1)` is called before the destruction of the mock object, since destroying any mock object that still has [expectations](reference.md/#expectation) is reported as a violation. It is also possible to be explicit with the sequencing by using [**`IN_SEQUENCE(...)`**](reference.md/#IN_SEQUENCE) on both [**`REQUIRE_CALL(...)`**](reference.md/#REQUIRE_CALL) and [**`REQUIRE_DESTRUCTION(...)`**](reference.md/#REQUIRE_DESTRUCTION), as below: ```Cpp { trompeloeil::sequence s; REQUIRE_CALL(*mock, func(-1)); .IN_SEQUENCE(s); REQUIRE_DESTRUCTION(*mock); .IN_SEQUENCE(s); c.poke(0); } ``` ## Customize output format of values When [tracing](#tracing) or printing parameter values in violation reports, the values are printed using their [stream insertion operators](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt), if available, or hexadecimal dumps otherwise. If this is not what you want, you can provide your own output formatting used solely for testing. The simple way to do this is to specialize a template [`printer`](reference.md/#printer), in namespace `trompeloeil`, and its static member function `print`, for your type `T`. Example: ```Cpp class char_buff : public std::vector { ... }; namespace trompeloeil { template <> struct printer { static void print(std::ostream& os, const char_buff& b) { os << b.size() << "#{ "; for (auto v : b) { os << int(v) << " "; } os << "}"; } }; } ``` Any reports involving the `char_buff` above will be printed using the `trompeloeil::print(...)` function, showing the size and integer values. Note that partial specializations also work. Example: ```Cpp template class buff : public std::vector { ... }; namespace trompeloeil { template struct printer> { static void print(std::ostream& os, const buff& b) { os << b.size() << "#{ "; for (auto v : b) { os << v << " "; } os << "}"; } }; } ``` The full type signature for the `printer` template is ```C++ template struct printer { static void print(std::ostream& os, const T&); }; ``` The second template parameter can be used for [SFINAE](https://en.cppreference.com/w/cpp/language/sfinae) constraints on the `T`. As an example, every type that has a formatter for the excellent [`fmt`](https://fmt.dev/latest/index.html) library, can be printed using a custom SFINAE printer like: ```C++ namespace trompeloeil { template struct printer::value>> { static void print(std::ostream& os, const T& t) { os << fmt::format("{}", t); } }; } ``` Note that the result of the type expression for the 2nd type in the partial specialization **must** be `void`. **NOTE!** Older documentation refers to specializing a function [`trompeloeil::print(sd::ostream&, T const&)`](reference.md/#print). This still works, but has the disadvantage that partial specializations are not possible. ## Tracing mocks *Trompeloeil* offers tracing as a way of manually following the calls of mocks. In pure [TDD](https://en.wikipedia.org/wiki/Test-driven_development) this is hardly ever needed, but if you are in the undesirable situation of exploring the behaviour of code written without tests, tracing can vastly simplify your job. Simply put, tracing is exposing which mocks are called with which values. *Trompeloeil* offers a [*`stream_tracer`*](#stream_tracer), which outputs all calls to a [`std::ostream`](http://en.cppreference.com/w/cpp/io/basic_ostream), but you can also write your own [custom tracer](#custom_tracer). ### Using `trompeloeil::stream_tracer` *`stream_tracer`* is a mechanism used to find out how [mock functions](reference.md/#mock_function) are called, by simply printing the calls with their parameter values on a [`std::ostream`](http://en.cppreference.com/w/cpp/io/basic_ostream) like [`std::cout`](http://en.cppreference.com/w/cpp/io/cout). There is no requirement from *Trompeloeil* on the [expectations](reference.md/#expectation) placed on the mocks, but open blanket [**`ALLOW_CALL(...)`**](reference.md/#ALLOW_CALL) can be a good start until more detailed tests can be written. Example: ```Cpp class Mock { public: MAKE_MOCK1(create, int(const std::string&)); MAKE_MOCK1(func, std::string(int)); }; using trompeloeil::_; void tracing_test() { trompeloeil::stream_tracer tracer{std::cout}; Mock m; ALLOW_CALL(m, create(_)) .RETURN(3); ALLOW_CALL(m, func(_)) .RETURN("value"); weird_func(&m); } ``` Running the above test will print on `std::cout` all calls made. A sample output may be: ```text /tmp/t.cpp:33 m.create(_) with. param _1 = hello /tmp/t.cpp:36 m.func(_) with. param _1 = 3 /tmp/t.cpp:36 m.func(_) with. param _1 = 2 /tmp/t.cpp:36 m.func(_) with. param _1 = 1 ``` ### Writing custom tracers If tracing is important, but the `trompeloeil::stream_tracer` for some reason does not satisfy your needs, you can easily write your own tracer. There is a base class: ```Cpp namespace trompeloeil { class tracer { public: tracer(); virtual ~tracer(); virtual void trace(const char* file, unsigned long line, const std::string& call) = 0; }; } ``` Write your own class inheriting from `trompeloeil::tracer`, and implement the member function `trace`, to do what you need, and you're done. ## Writing custom matchers If you need additional matchers over the ones provided by *Trompeloeil* ([**`eq(...)`**](reference.md/#eq), [**`ne(...)`**](reference.md/#ne), [**`lt(...)`**](reference.md/#lt), [**`le(...)`**](reference.md/#le), [**`gt(...)`**](reference.md/#gt) or [**`ge(...)`**](reference.md/#ge), and [**`re(...)`**](reference.md/#re)), you can easily do so. Matchers are created using the aptly named function template [**`trompeloeil::make_matcher(...)`**](reference.md/#make_matcher), which takes a predicate lambda to check the condition, a print lambda for error messages, and any number of stored values. All matchers, including your own custom designed matchers, can be used as [pointer matchers](#matching_pointers) by using the unary prefix `*` dereference operator. ### Typed matcher The simplest matcher is a typed matcher. As an example of a typed matcher, an `any_of` matcher is shown, checking if a value is included in a range of values. It is implemented using the standard library algorithm [`std::any_of`](http://en.cppreference.com/w/cpp/algorithm/all_any_none_of), allowing a parameter to match any of a set of values. To create a matcher, you provide a function that calls [**`trompeloeil::make_matcher(...)`**](reference.md/#make_matcher). Below is the code for the function `any_of(std::initializer_list)` which creates the matcher. ```Cpp inline auto any_of(std::initializer_list elements) { return trompeloeil::make_matcher( // matcher of int // predicate lambda that checks the condition [](int value, std::vector const & alternatives) { return std::any_of(std::begin(alternatives), std::end(alternatives), [&value](int element) { return value == element; }); }, // print lambda for error message [](std::ostream& os, std::vector const& alternatives) { os << " matching any_of({"; char const* prefix=" "; for (auto& element : alternatives) { os << prefix << element; prefix = ", "; } os << " }"; }, // stored value std::vector(elements) ); } ``` The *predicate* lambda is called with the value to check, and the stored values in order. The *print* lambda is called with an `ostream&`, and the stored values in order. You can capture values in the lambdas instead of storing in the matcher, but capturing them twice wastes memory, and what's in the lambda capture for the *predicate* lambda is not accessible in the *print* lambda. Example usage: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); }; void test() { Mock m; REQUIRE_CALL(m, func(any_of({1, 2, 4, 8}))); m.func(7); } ``` The *print* lambda is only called if a failure is reported. The report in the above example will look like: ```text No match for call of m.func with signature void(int) with. param _1 = 7 Tried m.func(any_of({1, 2, 4, 8}) at file.cpp:12 Expected _1 matching any_of({ 1, 2, 4, 8 }); ``` Where everything after `Expected _1` is the output from the *print* lambda. Extending the example above to work with any type, using a template, is straight forward: ```Cpp template inline auto any_of(std::initializer_list elements) { return trompeloeil::make_matcher( // matcher of T // predicate lambda that checks the condition [](T const& value, std::vector const & alternatives) { return std::any_of(std::begin(alternatives), std::end(alternatives), [&value](T const& element) { return value == element; }); }, // print lambda for error message [](std::ostream& os, std::vector const& alternatives) { os << " matching any_of({"; char const* prefix=" "; for (auto& element : alternatives) { os << prefix; ::trompeloeil::print(os, element); prefix = ", "; } os << " }"; }, // stored value std::vector(elements) ) } ``` The only difference compared to the `int` version, is that the *predicate* lambda accepts values by `const&` instead of by value, since `T` might be expensive to copy, and that the *print* lambda uses [**`trompeloeil::print(...)`**](reference.md/#print) to print the elements. ### Duck-typed matcher A duck-typed matcher accepts any type that matches a required set of operations. An example of a duck-typed matcher is a [`not_empty()`](#not_empty) matcher, requiring that a `.empty()` member function of the parameter returns false. Another example is an [`is_clamped(min, max)`](#is_clamped) matcher, that ensures `min <= value && value <= max`. A duck-typed matcher is created by specifying [**`trompeloeil::wildcard`**](reference.md/#wildcard) as the type to to [**`trompeloeil::make_matcher(...)`**](reference.md/#make_matcher). It is also important that the *predicate* lambda uses a [trailing return type](http://arne-mertz.de/2015/08/new-c-features-auto-for-functions) specifier, which uses the required operations, in order to filter out calls that would not compile. #### A `not_empty()` matcher Here's an implementation of a `not_empty()` matcher. ```Cpp inline auto not_empty() { return trompeloeil::make_matcher( // duck typed // predicate lambda that checks the condition [](auto const& value) -> decltype(!value.empty()) { return !value.empty(); }, // print lambda for error message [](std::ostream& os) { os << " is not empty"; } // no stored values ); } ``` It is unfortunate that the `!value.empty()` condition is expressed twice, but those are the rules of the language. Here's an example of the usage. ```Cpp struct C { MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(std::string&&)); MAKE_MOCK1(func2, void(std::vector const&); }; void test() { C obj; REQUIRE_CALL(obj, func(not_empty())); // std::string&& REQUIRE_CALL(obj, func2(not_empty())); // std::vector const& func_under_test(&obj); } ``` The expectation placed on `func()` is not ambiguous. While `func()` is overloaded on both `int` and `std::string&&`, the trailing return type specification on the *predicate* lambda causes [`SFINAE`](http://en.cppreference.com/w/cpp/language/sfinae) to kick in and chose only the `std::string&&` overload, since `.empty()` on an `int` would not compile. If you make a mistake and place an expectation with a duck-typed matcher that cannot be used, the [`SFINAE`](http://en.cppreference.com/w/cpp/language/sfinae) on the trailing return type specification of the *predicate* lambda, ensures a compilation error at the site of use ([**`REQUIRE_CALL()`**](reference.md/#REQUIRE_CALL), [**`ALLOW_CALL()`**](reference.md/#ALLOW_CALL) or [**`FORBID_CALL()`**](reference.md/#FORBID_CALL).) **TIP!** The expectation on `func()` in the example above is not ambiguous, as explained, but what if `func2` had been yet an overload of `func()` instead? You can easily make your matchers typed or duck-typed at the user's discretion. Alter the `not_empty()` to be a function template, with `trompeloeil::wildcard` as the default. ```Cpp template inline auto not_empty() { return trompeloeil::make_matcher( // typed or duck typed // predicate lambda that checks the condition [](auto const& value) -> decltype(!value.empty()) { return !value.empty(); }, // print lambda for error message [](std::ostream& os) { os << " is not empty"; } // no stored values ); } ``` Now, if the user writes `EXPECT_CALL(obj, func(not_empty()))`, it is duck-typed, but if the user writes `EXPECT_CALL(obj, func()` it will only match a call with a `std::string&&` parameter. #### An `is_clamped(min, max)` matcher Here's an implementation of an `is_clamped(min, max)` matcher. ```Cpp template inline auto is_clamped(T const& min, U const& max) { return trompeloeil::make_matcher( // typed or duck typed // predicate lambda that checks the condition [](auto const& value, auto const& lower, auto const& upper) -> decltype(lower <= value && value <= upper) { return !trompeloeil::is_null(value) && lower <= value && value <= upper; }, // print lambda for error message [](std::ostream& os, auto const& lower, auto const& upper) { os << " clamped by ["; trompeloeil::print(os, lower); os << ", "; trompeloeil::print(os, upper); os << "]"; } // stored values min, max ); } ``` The [`trompeloeil::is_null(value)`](reference.md/#is_null) in the *predicate* lambda is there to prevent against e.g. clamp checks for `const char*` between two [`std::string`s](http://en.cppreference.com/w/cpp/string/basic_string), where the `const char*` may be *null*. The `is_null()` check is omitted in the trailing return specification, because it does not add anything to it - it always returns a `bool` and it works for all types. By allowing `min` and `max` to be different types, it becomes possible to, e.g. check that a [`std::string_view`](http://en.cppreference.com/w/cpp/string/basic_string_view) is clamped by a [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) and a `const char*`. **NOTE!** There is a bug in [GCC](https://gcc.gnu.org) versions 5.3 and lower, that does not allow trailing return type specifications in lambdas expressed in template functions. The work around is annoying but simple: ```Cpp inline auto is_clamped_predicate() { return [](auto const& value, auto const& lower, auto const& upper) -> decltype(lower <= value && value <= upper) { return !trompeloeil::is_null(value) && lower <= value && value <= upper; }; } template inline auto is_clamped(T const& min, U const% max) { return trompeloeil::make_matcher( // duck typed // predicate lambda that checks the condition is_clamped_predicate(), ... ``` **NOTE!** There is also a bug in [VisualStudio 2015 Update 3](https://www.visualstudio.com/en-us/news/releasenotes/vs2015-update3-vs), which does not respect the trailing return type specifications of lambdas in the context of template deduction. The work around is annoying but simple - use a `struct` instead: ```Cpp struct is_clamped_predicate { template auto operator()(T const& value, L const& lower, U const& upper) -> decltype(lower <= value && value <= upper) { return !trompeloeil::is_null(value) && lower <= value && value <= upper; } }; template inline auto is_clamped(T const& min, U const% max) { return trompeloeil::make_matcher( // duck typed // predicate lambda that checks the condition is_clamped_predicate(), ... ``` ### Legacy Matchers Before [**`trompeloeil::make_matcher(...)`**](reference.md/#make_matcher) was introduced in *Trompeloeil* v18, writing matchers was more elaborate. This section is here for those who need to maintain old matcher code. All legacy matchers - inherit from `trompeloeil::matcher` or `trompeloeil::typed_matcher` - implement a `bool matches(parameter_value) const` member function - implement an output stream insertion operator All legacy matchers can be used as [pointer matchers](#matching_pointers) by using the unary prefix `*` dereference operator. ### Typed legacy matcher Typed legacy matchers are relatively easy to understand. As an example of a typed matcher, an `any_of` matcher is shown, mimicking the behaviour of the standard library algorithm [`std::any_of`](http://en.cppreference.com/w/cpp/algorithm/all_any_none_of), allowing a parameter to match any of a set of values. For templated matchers, it is often convenient to provide a function that creates the matcher object. Below is the code for `any_of_t`, which is the matcher created by the `any_of(std::vector)` function template. ```Cpp template class any_of_t : public trompeloeil::typed_matcher { public: any_of_t(std::initializer_list elements) : alternatives(elements) { } bool matches(T const& t) const { return std::any_of(std::begin(alternatives), std::end(alternatives), [&t](T const& val) { return t == val; }); } friend std::ostream& operator<<(std::ostream& os, any_of_t const& t) { os << " matching any_of({"; char const* prefix=" "; for (auto& n : t.alternatives) { os << prefix; trompeloeil::print(os, n); prefix = ", "; } return os << " })"; } private: std::vector alternatives; }; template auto any_of(std::initializer_list elements) { return any_of_t(elements); } ``` The `matches` member function at accepts the parameter and returns `true` if the value is in the specified set, in this case if it is any of the values stored in the `alternatives` vector, otherwise `false`. Example usage: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); }; void test() { Mock m; REQUIRE_CALL(m, func(any_of({1, 2, 4, 8})); m.func(7); } ``` The output stream insertion operator is only called if a failure is reported. The report in the above example will look like: ```text No match for call of m.func with signature void(int) with. param _1 = 7 Tried m.func(any_of({1, 2, 4, 8}) at file.cpp:12 Expected _1 matching any_of({ 1, 2, 4, 8 }); ``` Where everything after `Expected _1` is the output from the stream insertion operator. ### Duck-typed legacy matcher A duck-typed matcher accepts any type that matches a required set of operations. Duck-typed legacy matchers have a type conversion operator that selects which types it can operate on. The conversion operator is never implemented, but the signature must be available since it is used at compile time to select overload. As an example of a duck-typed matcher is a `not_empty` matcher, requiring that a `.empty()` member function of the parameter returns false. First the restricting [SFINAE](http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error) predicate used to match only types that has a `.empty()` member function. ```Cpp template class has_empty { template static constexpr std::false_type func(...) { return {}; } template static constexpr auto func(U const* u) -> decltype(u->empty(),std::true_type{}) { return {}; } public: static const bool value = func(nullptr); }; ``` Here `has_empty::value` is true only for types `T` that has a `.empty()` member function callable on const objects. ```Cpp class not_empty : public trompeloeil::matcher { public: template ::value>> operator T() const; //1 template bool matches(T const& t) const //2 { return !t.empty(); } friend std::ostream& operator<<(std::ostream& os, not_empty const&) { return os << " is not empty"; } }; ``` At **//1** the type conversion operator selects for types that has a `.empty()` member function. [`std::enable_if_t<>`](http://en.cppreference.com/w/cpp/types/enable_if) ensures that no calls to mismatching types will occur, and that if no matching call can be found, a compilation error is generated at the site of use ([**`REQUIRE_CALL()`**](reference.md/#REQUIRE_CALL), [**`ALLOW_CALL()`**](reference.md/#ALLOW_CALL) or [**`FORBID_CALL()`**](reference.md/#FORBID_CALL).) The `matches(T const&)` member function at **//2** becomes very simple. It does not need the [SFINAE]( http://en.wikipedia.org/wiki/Substitution_failure_is_not_an_error ) [`std::enable_if_t<>`]( http://en.cppreference.com/w/cpp/types/enable_if ) to select valid types, since a type mismatch gives a compilation error on the type conversion operator at **//1**. The output stream insertion operator is neither more or less tricky than with typed matchers. Making violation reports readable may require some thought, however. trompeloeil-47/docs/FAQ.md000066400000000000000000000671441454452461300155460ustar00rootroot00000000000000# FAQ - Q. [Why a name that can neither be pronounced nor spelled?](#why_name) - Q. [Which compilers supports *Trompeloeil*?](#compilers) - Q. [How do I use *Trompeloeil* with XXX unit test framework?](#unit_test_adaptation) - Q. [Is *Trompeloeil* thread-safe?](#thread_safety) - Q. [Can a mock function be marked `override`?](#override) - Q. [How can I assign to an out-parameter?](#assign_out) - Q. [Why can't I **`.RETURN()`** a reference?](#return_reference) - Q. [Why can't I change a local variable in **`.SIDE_EFFECT()`**?](#change_side_effect) - Q. [Why the "local reference" **`.LR_*()`** variants? Why not always capture by reference?](#why_lr) - Q. [Is it possible to allow all calls to all mocked functions for all mock objects?](#allow_all) - Q. [Why are parameters referenced by position and not by name?](#why_pos) - Q. [Why the need to provide the number of parameters in **`MAKE_MOCKn()`** when all information is in the signature?](#why_param_count) - Q. [Why *`C++14`* and not *`C++11`* or *`C++03`* that is more widely spread?](#why_cpp14) - Q. [Why are my parameter values printed as hexadecimal dumps in violation reports](#why_hex) - Q. [Can I mock a C function API?](#func_mock) - Q. [Can I match a value pointed to by a pointer parameter?](#match_deref) - Q. [Can I negate the effect of a matcher?](#negate_matcher) - Q. [Can I check if an expectation is fulfilled?](#query_expectation) - Q. [What does it mean to mix **`IN_SEQUENCE`** and **`TIMES`**?](#sequence_times) - Q. [How do I use *Trompeloeil* in a CMake project?](#cmake) - Q. [Why are mock objects not move constructible?](#move_constructible) - Q. [Why can't I mock a function that returns a template?](#return_template) - Q. [Can I mock a `noexcept` function?](#mock_noexcept) - Q. [What does it mean that an expectation is "saturated"?](#saturated_expectation) - Q. [Can I mock a coroutine functionp?](#coroutines) ## Q. Why a name that can neither be pronounced nor spelled? **A.** It's a parallel to arts. [Trompe-l'œil](https://en.wikipedia.org/wiki/Trompe-l%27%C5%93il), which literally means "trick the eye," refers to an art form where the artist creates something that tricks the viewer into thinking they see something other than what is there. Writing mocks for testing has resemblances to creating Trompe-l'œil art, in that you create mocks that "tricks" the test object as if it was interacting with the intended real world. When you use mocks in a test program, you are the Trompe-l'œil artist, tricking the code under test. Perhaps *Illusionist* or *Puppeteer* would have sufficed as names, but they were taken many times over for other projects, and besides, the author has a soft spot for Trompe-l'œil art. If you **really** cannot handle the name, you can use the following renaming mechanism. Assume that you'd like the name [`chimera`](http://www.merriam-webster.com/dictionary/chimera) instead. Create a file `chimera.hpp` with the following contents: ```Cpp #ifndef CHIMERA_HPP #define CHIMERA_HPP #include namespace chimera = trompeloeil; #endif /* include guard */ ``` Your tests can now `#include ` and use (for example) `chimera::expectation` and `chimera::deathwatched`. ## Q. Which compilers supports *Trompeloeil*? **A.** *Trompeloeil* is known to work well with: - [g\+\+](http://gcc.gnu.org) 4.9.3 and later. - [clang\+\+](http://clang.llvm.org) 3.5 and later. - [VisualStudio](http://visualstudio.com) 2015 and later. *Trompeloeil* is known to work somewhat with *g\+\+* 4.8.4 and 4.8.5, and somewhat less with *g\+\+* 4.8.3. *`g++ 4.8.x`* only compiles with a C\+\+11 dialect (e.g. *`-std=c++11`*). For details, see ["G\+\+ 4.8.x limitations"](Backward.md/#gxx48x_limitations). ## Q. How do I use *Trompeloeil* with XXX unit test framework? **A.** By default, *Trompeloeil* reports violations by throwing an exception, explaining the problem in the [`what()`](http://en.cppreference.com/w/cpp/error/exception/what) string. Depending on your test frame work and your runtime environment, this may, or may not, suffice. *Trompeloeil* offers support for adaptation to any test frame work. Adaptation examples for some popular unit test frame works are listed in the [Cook Book](CookBook.md/#unit_test_frameworks). ## Q. Is *Trompeloeil* thread-safe? **A.** Yes, with caveats. In a unit test you don't want to depend on the scheduler, which is typically out of your control. However, some times it is convenient to use a unit test like environment to exercise a larger aspect of your code. In this setting, using [mock objects](reference.md/#mock_object) with different [expectations](reference.md/#expectation) can make sense when statistically searching for synchronization problems. To enable this, *Trompeloeil* uses a global [`recursive_mutex`](http://en.cppreference.com/w/cpp/thread/recursive_mutex) which protects [expectations](reference.md/#expectation). [Expectations](reference.md/#expectation) can come and go in different threads, and [mock functions](reference.md/#mock_function) can be called in different threads, all protected by the global lock. However, it is essential that the [mock object](reference.md/#mock_object) is not deleted while establishing the [expectation](reference.md/#expectation) or calling the [mock function](reference.md/#mock_function), as per normal thread-safety diligence. Should you need to access the lock in your tests, you can do so with ```Cpp auto lock = trompeloeil::get_lock(); ``` `lock` holds the [`recursive_mutex`](http://en.cppreference.com/w/cpp/thread/recursive_mutex) until it goes out of scope. ## Q. Can a mock function be marked `override`? **A.** Yes, just add `override` a third parameter to [**`MAKE_MOCKn()`**](reference.md/#MAKE_MOCKn) or [**`MAKE_CONST_MOCKn()`**](reference.md/#MAKE_CONST_MOCKn) Example: ```Cpp class Interface { public: virtual ~Interface() = default; virtual int func1(int) = 0; }; class Mock : public Interface { public: MAKE_MOCK1(func1, int(int), override); // overridden MAKE_MOCK1(func2, int(int)); // not overridden }; ``` ## Q. How can I assign to an out-parameter? **A.** Use the positional name of the parameter and assign to it, for example in a [**`.SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT). Example: ```Cpp class C { public: MAKE_MOCK1(assign_out, void(int&)); }; using trompeloeil::_; TEST(some_test) { C mock_obj; REQUIRE_CALL(mock_obj, assign_out(_)) .SIDE_EFFECT(_1 = 3); int x = 0; mock_obj.assign_out(x); // x is 3 here } ``` ## Q. Why can't I [**`.RETURN()`**](reference.md/#RETURN) a reference? **A.** You can, but the language is a bit peculiar. For parameters or returned references from function calls, just use **`.RETURN(value)`**. For local variables you need [**`.LR_RETURN()`**](reference.md/#LR_RETURN), and for both global and local variables you either need to use [`std::ref(value)`](http://en.cppreference.com/w/cpp/utility/functional/ref) or [`std::cref(value)`](http://en.cppreference.com/w/cpp/utility/functional/cref) for it, or just enclose the value in an extra parenthesis, like this [**`.LR_RETURN((value))`**](reference.md/#LR_RETURN) Example: ```Cpp class C { public: MAKE_MOCK1(lookup, std::string&(int)); }; using trompeloeil::_; using trompeloeil::lt; TEST(some_test) { C mock_obj; std::map dictionary{ {...} }; std::string default_string; ALLOW_CALL(mock_obj, lookup(_)) .LR_RETURN(dictionary.at(_1)); // function call ALLOW_CALL(mock_obj, lookup(trompeloeil::lt(0))) .LR_RETURN((default_string)); // extra parenthesis ALLOW_CALL(mock_obj, lookup(0)) .LR_RETURN(std::ref(default_string)); test_func(&mock_obj); } ``` Above, the [expectations](reference.md/#expectation) on function `lookup()` is that any call is allowed and will return an [lvalue-reference](http://en.cppreference.com/w/cpp/language/reference) to either a match in `dictionary`, or to the local variable `default_string`. The reference is non-const, so `test_func()` is allowed to change the returned string. ## Q. Why can't I change a local variable in [**`.SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT)? **A.** It would almost certainly be very confusing. All local variables referenced in [**`.WITH()`**](reference.md/#WITH), [**`.SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT), [**`.RETURN()`**](reference.md/#RETURN) and [**`.THROW()`**](reference.md/#THROW) are captured by value, i.e. each such clause has its own copy of the local variable. If you could change it, it would change the value in that clause only and not in any of the others. Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; TEST(some_test) { C mock_obj; unsigned abs_sum = 0; ALLOW_CALL(mock_obj, func(trompeloeil::gt(0))) .SIDE_EFFECT(abs_sum+= _1); // illegal code! ALLOW_CALL(mock_obj, func(trompeloeil::lt(0)) .SIDE_EFFECT(abs_sum-= _1); // illegal code! ALLOW_CALL(mock_obj, func(0)); test_func(&mock_obj); ``` The two [**`SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT) clauses above each have their own copy of the local variable `abs_sum`. Allowing them to update their own copies would be very confusing, and it would also be difficult to get the value back to the test. If you need to change the value of a local variable it is better to use the alternative "local reference" forms [**`LR_SIDE_EFFECT()`**](reference.md/#LR_SIDE_EFFECT), [**`LR_WITH()`**](reference.md/#LR_WITH), [**`LR_RETURN()`**](reference.md/#LR_RETURN) or [**`LR_THROW()`**](reference.md/#LR_THROW). ## Q. Why the "local reference" **`.LR_*()`** variants? Why not always capture by reference? **A.** It's safer. Lifetime management can be tricky in *`C++`*, and even more so when complex functionality is hiding behind hideous macros in a frame work. Experiences from the alpha phase, where this distinction wasn't made, made the problem glaringly obvious. Making the default safe, and providing the option to very visibly use the potentially unsafe, is considerably better, although it makes the test code somewhat visually unpleasant. ## Q. Is it possible to allow all calls to all mocked functions for all mock objects? **A.** No, it is not. There are two reasons for this, technical and philosophical. **Technical** There is a problem with the return value. It is difficult, if at all possible, to come up with a generic return that works for all types. This could be overcome by allowing all calls to all functions with a certain return type, for all objects. **Philosophical** While there are no doubt situations where this would be convenient, it could be a very dangerous convenience that opens up for relaxing tests unnecessarily, simply because it's so easy to allow everything, and then when you introduce a bug, you never notice because everything is allowed. If a safe way of allowing all calls is thought of, then this may change, but having a perhaps unnecessarily strict rule that can be relaxed is safer than the alternative. ## Q. Why are parameters referenced by position and not by name? **A.** If you can figure out a way to refer to parameters by name, please [open an issue](https://github.com/rollbear/trompeloeil/issues) discussing the idea. If you can provide a pull request, so much the better. ## Q. Why the need to provide the number of parameters in [**`MAKE_MOCKn()`**](reference.md/#MAKE_MOCKn) when all information is in the signature? **A.** If you can figure out a way to infer the information necessary to generate a mocked implementation without an explicit parameter count, please [open an issue](https://github.com/rollbear/trompeloeil/issues) discussing the idea. If you can provide a pull request, so much the better. ## Q. Why *`C++14`* and not *`C++11`* or *`C++03`* that is more widely spread? **A.** *`C++03`* and older is completely out. The functionality needed for *Trompeloeil* isn't there. [Lambdas](http://en.cppreference.com/w/cpp/language/lambda) and [variadic templates](http://en.cppreference.com/w/cpp/language/parameter_pack) are absolutely necessary. The only thing "needed" that *`C++11`* doesn't provide is [generic lambdas](https://en.wikipedia.org/wiki/C%2B%2B14#Generic_lambdas). It is perhaps possible that "needed" is too strong a word, that it is in fact possible without them, in which case a back port to *`C++11`* could be made. And indeed, since this FAQ question was first answered, a back port of a useful subset of Trompeloeil has been completed for use with *`C++11`*. For details, see ["Backward compatibility with earlier versions of C\+\+"]( Backward.md ). ## Q. Why are my parameter values printed as hexadecimal dumps in violation reports? **A.** By default *Trompeloeil* prints parameter values using the [stream insertion operators](http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt) for the type, but if none exists, it presents a hexadecimal dump of the memory occupied by the value. You can change that either by providing a stream insertion operator for your type, or by providing a [custom formatter](CookBook.md/#custom_formatting) for it. ## Q. Can I mock a C function API? **A.** *Trompeloeil* can mock member functions only. However, there are tricks you can use to mock a function API, provided that it is OK to use a [link seam](http://www.informit.com/articles/article.aspx?p=359417&seqNum=3) and link your test program with a special test implementation of the API that calls mocks. Here's an example: ```Cpp /* c_api.h */ #ifdef __cplusplus extern "C" { #endif int func1(const char*); const char* func2(int); #ifdef __cplusplus } #endif ``` With the above C-API mocks can be made: ```Cpp /* mock_c_api.h */ #ifndef MOCK_C_API_H #define MOCK_C_API_H #include #include #include #include struct mock_api { static mock_api*& instance() { static mock_api* obj = nullptr; return obj; } mock_api() { assert(instance() == nullptr); instance() = this; } ~mock_api() { assert(instance() == this); instance() = nullptr; } mock_api(const mock_api&) = delete; mock_api& operator=(const mock_api&) = delete; MAKE_CONST_MOCK1(func1, int(std::string)); // strings are easier to deal with MAKE_CONST_MOCK1(func2, const char*(int)); }; endif /* include guard */ ``` Note that the mock constructor stores a globally available pointer to the instance, and the destructor clears it. With the mock available the test version the C-API can easily be implemented: ```Cpp #include "mock_c_api.h" int func1(const char* str) { auto obj = mock_api::instance(); assert(obj); return obj->func1(str); // creates a std::string } const char* func2(int value) { auto obj = mock_api::instance(); assert(obj); return obj->func2(value); } ``` Now your tests becomes simple: ```Cpp #include "mock_c_api.h" #include "my_obj.h" TEST("my obj calls func1 with empty string when poked") { mock_api api; my_obj tested; { REQUIRE_CALL(api, func1("")) .RETURN(0); tested.poke(0); } } ``` ## Q. Can I match a value pointed to by a pointer parameter? **A.** You can always match with [**`_`**](reference.md/#wildcard) and use [**`LR_WITH()`**](reference.md/#LR_WITH) or [**`WITH()`**](reference.md/#WITH) using whatever logic you like. But by using [matchers](CookBook.md/#matching_conditions) you can match the value pointed to using unary operator [**`*`**](reference.md/#deref_matcher) on the *matcher*. See [Matching pointers to values](CookBook.md/#matching_pointers) in the [Cook Book](CookBook.md). ## Q. Can I negate the effect of a matcher? **A.** You can always match with [**`_`**](reference.md/#wildcard) and use [**`LR_WITH()`**](reference.md/#LR_WITH) or [**`WITH()`**](reference.md/#WITH) using whatever logic you like. But by using [matchers](CookBook.md/#matching_conditions) you can negate the effect of the matcher, allowing what the matcher disallows and vice versa, using operator [**`!`**](reference.md/#negate_matcher) on the *matcher*. See [Matching the opposite of a matcher](CookBook.md/#negating_matchers) in the [Cook Book](CookBook.md). ## Q. Can I check if an expectation is fulfilled? Yes, if you use [**`NAMED_ALLOW_CALL(...)`**](reference.md/#NAMED_ALLOW_CALL), [**`NAMED_REQUIRE_CALL(...)`**](reference.md/#NAMED_REQUIRE_CALL) or [**`NAMED_FORBID_CALL(...)`**](reference.md/#NAMED_FORBID_CALL), then you can ask [`is_satisfied()`](reference.md/#is_satisfied) and [`is_saturated()`](reference.md/#is_saturated). Example: ```Cpp TEST("something") { mock_obj mock; auto ptr = NAMED_REQUIRE_CALL(mock, some_func()) .TIMES(2,4); ... if (ptr->is_satisfied()) // at least two call have been made ... if (ptr->is_saturated()) // four calls have been made } ``` Likewise you can ask [sequence objects](reference.md/#sequence_type) if the sequence they describe [`is_completed()`](reference.md/#is_completed). These are rarely useful in pure unit tests, but it can be useful for mini integration tests, especially when threading is involved. ## Q. What does it mean to mix **`IN_SEQUENCE`** and **`TIMES`**? **A.** Using [**`.TIMES()`**](reference.md/#TIMES) with [**`.IN_SEQUENCE()`**](reference.md/#IN_SEQUENCE) is confusing at best, and especially when you have a (possibly open) interval for **`.TIMES()`**. Trompeloeil always sees sequences as observed from a sequence object, and a sequence object can only move forward in what it allows. Example: ```Cpp trompeloeil::sequence seq; REQUIRE_CALL(mock, foo1) .TIMES(AT_LEAST(1)) .IN_SEQUENCE(seq); REQUIRE_CALL(mock, foo2) .IN_SEQUENCE(seq); REQUIRE_CALL(mock, foo3) .IN_SEQUENCE(seq); // later... mock.foo1(); mock.foo2(); mock.foo1(); // boom! mock.foo3(); ``` In the example above, a sequence violation is reported on the second call to `mock.foo1()`. It goes like this: `mock.foo1();` this is the first call for the sequence object, so it is allowed. It says **`AT_LEAST(1)`**, so it may move to the next step, or it may repeat the same call. `mock.foo2();` The current step in the sequence is `mock.foo1()`, but it is satisfied, so moving on to the next one is allowed. The next one is `mock.foo2()`, which matches this call, so everything is good. `mock.foo1();` The current step in the sequence is `mock.foo2()`. Is is satisfied and saturated, so the sequence object must move to the next step. The next step is `mock.foo3()`, which is a mismatch, so a sequence violation is reported. ## Q. How do I use *Trompeloeil* in a CMake project? **A.** To use *Trompeloeil* in a project that is built with CMake, there are several options to make it accessible to CMake. (The commands below of for Linux, but it works similarly on other platforms.) You can include *Trompeloeil* directly or use it from an installation, which can be per-project, per-user, or a system-wide installation. If you aren't using *Trompeloeil* from an system-wide installed package, you can clone *Trompeloeil* in a subdirectory or add it as a Git submodule to your project (here, in `./my_proj/toolkits`). For example: ```shell git clone https://github.com/rollbear/trompeloeil.git my_proj/toolkits/trompeloeil ``` To include *Trompeloeil* in a project, add the subdirectory that contains *Trompeloeil* to the project's CMakeLists.txt (or any other CMakeLists.txt that gets processed before the one that defines the test that use *Trompeloeil*). ```cmake add_subdirectory(toolkits/trompeloeil) ``` After that, tests can be linked with *Trompeloeil* without needing `find_package()` first. For example: ```cmake add_executable( my_unit_tests test1.cpp test2.cpp test_main.cpp ) target_link_libraries( my_unit_tests my_library_under_test # provided by an add_library() call elsewhere in your project # Nothing to link since both of these libs are header-only, # but this sets up the include path correctly too Catch2::Catch2 trompeloeil::trompeloeil ) # Optional: Use CTest to manage your tests add_test( run_my_unit_tests my_unit_tests ) # May need to call enable_testing() elsewhere also ``` Please note that *Trompeloeil* will not be installed along your project in this case (i.e. when *Trompeloeil* is added as a subdirectory). In most cases, this is the desired behavior. This behavior can be overridden by setting `TROMPELOEIL_INSTALL_TARGETS` CMake variable to `ON`. e.g: ```shell cmake -DTROMPELOEIL_INSTALL_TARGETS=ON -B build . cmake --build build --target install ``` Adding *Trompeloeil* subdirectory and including it in a project's CMakeLists.txt is not the only option. Building, and installing it locally somewhere in your project is another option: ```shshell mkdir build ; cd build cmake -G "Unix Makefiles" .. -DCMAKE_INSTALL_PREFIX=../../my_proj/toolkits cmake --build . --target install ``` This will create a directory structure inside `toolkits` that has `include/trompeloeil.hpp` and the CMake find modules in `lib/cmake/trompeloeil`. Whether you add the entire *Trompeloeil* repo to your source control is up to you, but the minimal set of files for proper CMake support in is in the `toolkits` directory. Alternatively, you could install it globally on your system by cloning the repo and installing with root privileges: ```shell git clone https://github.com/rollbear/trompeloeil.git cd trompeloeil mkdir build ; cd build cmake -G "Unix Makefiles" .. sudo cmake --build . --target install ``` In either case, add a `find_package()` call in your project's `CMakeLists.txt`: ```cmake find_package( Catch2 REQUIRED HINTS "${toolkitsDir}/Catch2" ) # Sample unit test framework find_package( trompeloeil REQUIRED HINTS "${toolkitsDir}/trompeloeil" ) add_executable( my_unit_tests test1.cpp test2.cpp test_main.cpp ) target_link_libraries( my_unit_tests my_library_under_test # provided by an add_library() call elsewhere in your project # Nothing to link since both of these libs are header-only, # but this sets up the include path correctly too Catch2::Catch2 trompeloeil::trompeloeil ) # Optional: Use CTest to manage your tests add_test( run_my_unit_tests my_unit_tests ) # May need to call enable_testing() elsewhere also ``` This assumes that you have defined a variable called `toolkitsDir` pointing to `my_proj/toolkits/lib/cmake`, that you have Catch2 installed similarly, and that you have defined a target called `my_library_under_test` in other parts of the CMake files. (If you installed the libraries globally on your system, you should be able to drop the hints in the `find_package()` calls.) Finally, you can add *Trompeloeil* to your project and then either (a) use CMake's `find_file()` to locate the header and add its path to `include_directories()`; or (b) use `add_subdirectory()` (one or two argument version) to add its path to your project. If you want to specify a version of *Trompeloeil*, drop the 'v' from the version name in `find_package`. E.g. `find_package( trompeloeil 39 EXACT )`. ### Q. Why are mock objects not move constructible? **A.** Because a move is potentially dangerous in non-obvious ways. If a mock object is moved, the actions associated with an expectation ([**`.WITH()`**](reference.md/#WITH), [**`.SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT), [**`.RETURN()`**](reference.md/#RETURN), [**`.THROW()`**](reference.md/#THROW)) and their `LR_` versions, are *not* moved. If they refer to data members stored in a moved mock object, they will refer to dead data. This is an accepted cost in normal C++ code, but since the effect is hidden under the macros, it is better to play safe. With that said, you can explicitly make mock objects movable, if you want to. See: [**`trompeloeil_movable_mock`**](reference.md/#movable_mock). ### Q. Why can't I mock a function that returns a template? Like this: ```Cpp struct M { MAKE_MOCK2(make, std::pair(int,int)); }; ``` **A.** You can, but there is a limitation in the preprocessor, that makes it work poorly with templates. It sees the parameters to the [**`MAKE_MOCK2()`**](reference.md/#MAKE_MOCKn) macro above as `make`, `std::pair(int,int)`, which of course is nonsense and causes compilation errors. One easy way around this is to put the signature into parentheses: ```Cpp struct M { MAKE_MOCK2(make, (std::pair(int,int))); }; ``` Or if you prefer the legacy way, create an alias: ```Cpp using pair_int_int = std::pair; struct M { MAKE_MOCK2(make, pair_int_int(int,int)); }; ``` These work around the preprocessor parameter problem. Another way, if you're mocking an interface, is to use [**`trompeloeil::mock_interface`**](reference.md/#mock_interface) and [**`IMPLEMENT_MOCKn`**](reference.md/#IMPLEMENT_MOCKn). See [CookBook](CookBook.md/#creating_mock_classes) for an intro. ### Q. Can I mock a `noexcept` function? **A.** Yes, but with a caveat. The way to mock a [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec) function is to add a `noexcept` specifier to [**`MAKE_MOCKn`**](reference.md/#MAKE_MOCKn), [**`MAKE_CONST_MOCKn`**](reference.md/#MAKE_CONST_MOCKn), [**`IMPLEMENT_MOCKn`**](reference.md/#IMPLEMENT_MOCKn) or [**`IMPLEMENT_CONST_MOCKn`**](reference.md/#IMPLEMENT_CONST_MOCKn). ```Cpp struct S { MAKE_MOCK1(func, void(int), noexcept); // ^^^^^^^^ noexcept function }; ``` The caveat is that the [violation handlers](CookBook.md/#unit_test_frameworks), and specifically the default one, reports violations by throwing an exception, which means that any call made in violation of the [expectation]( reference.md/#expectation) for a `noexcept` function leads to program termination. How much information you can gain from such an event depends on the runtime system of your tools. ### Q. What does it mean that an expectation is "saturated"? If you see a violation report like this: ```text [file/line unavailable]:0: FATAL ERROR: No match for call of func with signature void(int) with. param _1 == -3 Matches saturated call requirement object.func(trompeloeil::_) at example.cpp:240 ``` What this means is that there is an expectation for the call, but that expectation is no longer allowed to be called, its maximum call count has been met. An example: ```Cpp test_func() { test_mock obj; REQUIRE_CALL(obj, func(trompeloeil::_)) .TIMES(AT_MOST(2)); exercise(obj); // calls obj.func. OK. Expectation is alive, no prior calls, this one is accepted exercise(obj); // calls obj.func. OK. Expectation is alive, one prior call, this one is accepted exercise(obj); // calls obj.func. Fail. Expectation is alive, two prior calls, this one saturated } ``` ### Q. Can I mock a coroutine function? There is experimental support to handle [`co_return`](https://en.cppreference.com/w/cpp/language/coroutines) and [`co_yield`](https://en.cppreference.com/w/cpp/language/coroutines#co_yield) from member functions that return a co-routine type. Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. See the reference manual for [**`CO_RETURN(`** *expr* **`)`**](reference.md#CO_RETURN), [**`LR_CO_RETURN(`** *expr* **`)`**](reference.md#LR_CO_RETURN), [**`CO_THROW(`** *expr **`)`**](reference.md#CO_THROW), [**`LR_CO_THROW(`** *expr* **`)`**](reference.md#LR_CO_THROW), [**`CO_YIELD(`** *expr* **`)`**](reference.md#CO_YIELD), [**`LR_CO_YIELD(`** *expr* **`)`**](reference.md#LR_CO_YIELD). trompeloeil-47/docs/PlatformsAndLibraries.md000066400000000000000000000637631454452461300213710ustar00rootroot00000000000000# Platform and library support for Trompeloeil - [Using libc\+\+ with Trompeloeil](#using_libcxx) - [Using sanitizers with Trompeloeil](#using_sanitizers) - [Compiler versions in sample Linux distributions](#compilers_in_distributions) - [Ubuntu](#compilers_in_ubuntu) - [In summary](#ubuntu_summary) - [In detail](#ubuntu_detail) - [Fedora](#compilers_in_fedora) - [Tested configurations](#tested_configurations) - [Testing Trompeloeil on Artful Aardvark (Ubuntu 17.10)](#testing_on_artful) - [`std::to_string()` is not defined for some versions of `libstdc++-v3`](#defect_to_string) - [Glibc 2.26 no longer supplies `xlocale.h`](#defect_xlocale) - [Glibc 2.26 `std::signbit()` broken for GCC compilers < 6](#defect_signbit) - [Conclusion](#artful_conclusion) - [Supporting incomplete standard libraries](#incomplete_stdlib) - [Replacing `std::recursive_mutex`](#custom_recursive_mutex) - [Replacing `std::atomic`](#custom_std_atomic) - [Replacing `std::unique_lock`](#custom_std_unique_lock) ## Using libc\+\+ with Trompeloeil On some distributions `clang` is configured to use `libstdc++-v3` as the implementation of the C\+\+ Standard Library. In order to use `libc++`, pass the `-stdlib=libc++` command line flag to the compiler. For example, ```text clang++-5.0 -std=c++14 -stdlib=libc++ ``` To use `libc++` with `g++` a few more command line flags need to be passed. This is a command line known to work with `g++-6`, ```text g++-6 -std=c++14 -nostdinc++ -isystem/usr/include/c++/v1 \ \ -nodefaultlibs -lc++ -lc++abi -lm -lc -lgcc_s -lgcc ``` ## Using sanitizers with Trompeloeil Trompeloeil test cases have been compiled and run without error with AddressSanitizer (ASan), Undefined Behavior Sanitizer (UBSan) and Thread Sanitizer (TSan). Feel free to add `-fsanitize=address`, `-fsanitize=thread` or `-fsanitize=undefined` to your compiler command lines, especially when unit testing. Maybe your compiler supports `-fsanitize-address-use-after-scope`. Add that flag as well. ## Compiler versions in sample Linux distributions ### Ubuntu Canonical supports the `main` component of the repositories of a release. Canonical does not support the `universe` component. Support for `universe` is provided by the Ubuntu community. If a compiler or library is in `universe` for a particular release, then there is no guarantee that there will be a release of that compiler or library in the next or any future release of Ubuntu, let alone updates in the current release. Either migrate compilers and libraries with each Ubuntu release or take control of your toolchain and remove a dependency on the platform. In the latter case you then have the option of supporting the Ubuntu community with a contribution of your toolchain to `universe`. For more information, see ubuntu.com, "Repositories" \ Available: \ Accessed: 29 October 2017 #### In summary ```text Trusty Tahr Xenial Xerus Zesty Zapus Artful Aardvark Bionic Beaver (14.04LTS) (16.04LTS) (17.04) (17.10) (18.04LTS) Released 2014-04-17 2016-04-21 2017-04-17 2017-10-19 2018-04 Supported to 2019-04 2021-04 2018-01 2018-07 2023-04 Compiler(s) g++-4.8.4 g++-5 g++-6 g++-7 TODO clang++-3.5 clang++-4.0 clang++-4.0 universe TODO clang++-5.0 TODO libc++-dev universe universe universe universe TODO 1.0~svn199600-1 3.7.0 3.9.1 3.9.1 TODO ``` #### In detail ```text Trusty Tahr Xenial Xerus Zesty Zapus Artful Aardvark Bionic Beaver (14.04LTS) (16.04LTS) (17.04) (17.10) (18.04LTS) Released 2014-04-17 2016-04-21 2017-04-17 2017-10-19 2018-04 Supported to (2019-04) (2021-04) (2018-01) (2018-07) (2023-04) GCC g++-4.8 ports universe universe universe TODO 4.8.2-19ubuntu1 4.8.5-4ubuntu2 4.8.5-4ubuntu4 4.8.5-4ubuntu6 TODO security xenial-updates zesty-updates TODO 4.8.4-2ubuntu1~14.04.3 N/A N/A TODO trusty-updates xenial-backports zesty-backports TODO 4.8.4-2ubuntu1~14.04.3 N/A N/A TODO trusty-backports N/A g++-4.9 main universe universe universe TODO N/A 4.9.3-13ubuntu2 4.9.4-2ubuntu1 N/A TODO trusty-updates xenial-updates zesty-updates TODO N/A N/A N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO g++-5 main ports universe universe TODO N/A 5.3.1-14ubuntu2 5.4.1-8ubuntu1 5.5.0-1ubuntu1 TODO trusty-updates security zesty-updates TODO N/A 5.4.0-6ubuntu1~16.04.4 N/A TODO trusty-backports xenial-updates zesty-backports TODO N/A 5.4.0-6ubuntu1~16.04.5 N/A TODO xenial-backports N/A g++-6 main main ports universe TODO N/A N/A 6.3.0-8ubuntu1 6.4.0-8ubuntu1 TODO trusty-updates xenial-updates main TODO N/A N/A 6.3.0-12ubuntu2 TODO trusty-backports xenial-backports zesty-updates TODO N/A N/A N/A TODO zesty-backports N/A g++-7 main main main main TODO N/A N/A N/A 7.2.0-8ubuntu3 TODO trusty-updates xenial-updates xenial-updates TODO N/A N/A N/A TODO trusty-backports xenial-backports xenial-backports TODO N/A N/A N/A TODO Clang clang-3.5 ports universe N/A N/A TODO 1:3.5~svn201651-1ubuntu1 1:3.5.2-3ubuntu1 N/A N/A TODO security xenial-updates zesty-updates TODO 1:3.5-4ubuntu2~trusty2 N/A N/A TODO trusty-updates xenial-backports zesty-backports TODO 1:3.5-4ubuntu2~trusty2 N/A N/A TODO trusty-backports N/A clang-3.6 N/A universe N/A N/A TODO N/A 1:3.6.2-3ubuntu2 N/A N/A TODO trusty-updates/universe xenial-updates zesty-updates TODO 1:3.6-2ubuntu1~trusty1 N/A N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO clang-3.7 N/A universe universe N/A TODO N/A 1:3.7.1-2ubuntu2 1:3.7.1-3ubuntu4 N/A TODO trusty-updates xenial-updates zesty-updates TODO N/A N/A N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO clang-3.8 security universe universe universe TODO 1:3.8-2ubuntu3~trusty5 1:3.8-2ubuntu1 1:3.8.1-18ubuntu1 1:3.8.1-24ubuntu7 TODO trusty-updates/universe xenial-updates/universe zesty-updates TODO 1:3.8-2ubuntu3~trusty5 1:3.8-2ubuntu4 N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO clang-3.9 security security ports universe TODO 1:3.9.1-4ubuntu3~14.04.3 1:3.9.1-4ubuntu3~16.04.2 1:3.9.1-5ubuntu1 1:3.9.1-17ubuntu1 TODO trusty-updates/universe xenial-updates/universe security TODO 1:3.9.1-4ubuntu3~14.04.3 1:3.9.1-4ubuntu3~16.04.2 1:3.9.1-5ubuntu1.1 TODO trusty-backports xenial-backports zesty-updates TODO N/A N/A 1:3.9.1-5ubuntu1.1 TODO zesty-backports TODO N/A TODO clang-4.0 N/A security main universe TODO N/A 1:4.0-1ubuntu1~16.04.2 1:4.0-1ubuntu1 1:4.0.1-6 TODO trusty-updates xenial-updates zesty-updates TODO N/A 1:4.0-1ubuntu1~16.04.2 N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO clang-5.0 N/A N/A N/A universe TODO N/A N/A N/A 1:5.0-3 TODO trusty-updates xenial-updates zesty-updates TODO N/A N/A N/A TODO trusty-backports xenial-backports zesty-backports TODO N/A N/A N/A TODO libc++-dev 1.0 universe 1.0~svn199600-1 trusty-updates N/A trusty-backports N/A 3.7 universe 3.7.0-1 xenial-updates/universe 3.7.0-1ubuntu0.1 xenial-backports N/A 3.9 ports universe 3.7.0-1 3.9.1-3 universe 3.9.1-2 zesty-updates N/A zesty-backports N/A 4.0 TODO TODO 5.0 TODO TODO ``` Table first compiled: 28 October 2017. Last updated: 28 October 2017. ### Fedora A short list of Fedora releases tells a similar story to the Ubuntu distribution. ```text 25 26 27 28 Released 2016-11-22 2017-07-11 (2017-11-14) (2018-05-01) Supported to TODO TODO TBD TBD gcc-c++ 6.4.1-1.fc25 7.2.1-2.fc26 7.2.1-2.fc27 TODO g++ 6.4.1 20170727 7.2.1 20170915 7.2.1 20170915 TODO (Red Hat 6.4.1-1) (Red Hat 7.2.1-2) (Red Hat 7.2.1-2) clang 3.9.1-2.fc25 4.0.1-5.fc26 4.0.1-5.fc27 TODO clang++ 3.9.1 4.0.1 4.0.1 TODO (tags/RELEASE_391/final (tags/RELEASE_401/final) (tags/RELEASE_401/final) libcxx-devel 3.9.1-1.fc25 4.0.1-3.fc26 4.0.1-3.fc27 TODO ``` Table first compiled: 28 October 2017 Last updated: 9 November 2017 ## Tested configurations Before release, Trompeloeil is tested with the following configurations of compiler, language dialect, and standard library. ### GCC Last updated: 3 June 2019 Key: - `N/A`: The combination `g++-4.8/c++11/libc++` leads to compile errors and is not currently supported. Further investigation may change this outcome. - `--`: The version of `libstdc++-v3` lacks a definition of the `_GLIBCXX_RELEASE` macro. - `stdc++` means `libstdc++-v3` from GCC. - `c++` means `libc++` from Clang. `g++-latest` means the "live at head" build of `g++`. ```text Compiler Mode stdc++ c++ -std= __GLIBCXX__ _GLIBCXX_RELEASE _LIBCPP_VERSION ---------- ---- ------------------------------ --------------- g++-4.8 c++11 20150623 -- N/A g++-4.9 c++11 20160726 -- 8000 c++14 g++-5 c++11 20171010 -- 8000 c++14 c++17 g++-6 c++11 20181026 -- 8000 c++14 c++17 g++-7 c++11 20190326 7 8000 c++14 c++17 g++-8 c++11 20190406 8 8000 c++14 c++17 c++2a g++-9 c++11 20190402 9 8000 c++14 c++17 c++2a g++-latest c++11 20190421 9 8000 c++14 c++17 c++2a ``` ### Clang `clang++-latest` means the "live at head" version of `clang++`. ```text Compiler Mode stdc++ c++ -std= __GLIBCXX__ _GLIBCXX_RELEASE _LIBCPP_VERSION ---------- ---- ------------------------------ --------------- clang++-3.5 c++11 20190326 7 1101 c++14 clang++-3.6 c++11 20190326 7 1101 c++14 clang++-3.7 c++11 20190326 7 3700 c++14 clang++-3.8 c++11 20190326 7 3800 c++14 clang++-3.9 c++11 20190402 9 3900 c++14 clang++-4.0 c++11 20190402 9 4000 c++14 clang++-5.0 c++11 20190402 9 5000 c++14 c++17 c++2a clang++-6.0 c++11 20190402 9 6000 c++14 c++17 c++2a clang++-7 c++11 20190402 9 7000 c++14 c++17 c++2a clang++-8 c++11 20190402 9 8000 c++14 c++17 c++2a clang++-latest c++11 20190402 9 9000 c++14 c++17 c++2a ``` ### Microsoft Visual Studio Last update: 3 June 2019 Tested with Visual Studio Community 2019 16.1.1 . ```text Platform Toolset Configuration Platform ------------------------- ------------- -------- Visual Studio 2015 (v140) Debug x64 Visual Studio 2017 (v141) Release x86 Visual Studio 2019 (v142) ``` ## Testing Trompeloeil on Artful Aardvark (Ubuntu 17.10) The release of Artful Aardvark (Ubuntu 17.10) contains a number of issues requiring workarounds if you want to compile and test Trompeloeil with community supported compiler versions e.g. any version of `clang++`, any version `g++` less than 7, or community supported libraries e.g. any version of `libc++`. Canonical supported compilers and libraries - just `g++-7` with `libstdc++-v3` - do not have the issues described below, but this is rather a narrow list for testing Trompeloeil on its supported compilers and libraries. ### `std::to_string()` is not defined for some versions of `libstdc++-v3` Affects: `libstdc++-v3` from these packages - `libstdc++-4.8-dev:amd64 4.8.5-4ubuntu6` - See: - `libstdc++-5-dev:amd64 5.5.0-1ubuntu1` - See: Workaround: Add `-D_GLIBCXX_USE_C99=1` to your compiler command lines. ### Glibc 2.26 no longer supplies `xlocale.h` The version of `glibc` in package `libc6-dev (2.26-0ubuntu2)` drops support for `xlocale.h`. `libc++` tracked this change and supplied a fix for 5.0. See: "Fix libcxx build with glibc 2.26+ by removing xlocale.h include." \ Available: \ Accessed: 11 November 2017 But Artful Aardvark ships package `libc++-dev 3.9.1-3`. As a consequence, no software using `libc++` out-of-the-box version can compile on Artful. Workaround: Create a symlink from `locale.h` to `xlocale.h` ```text cd /usr/include sudo ln -s locale.h xlocale.h ``` ### Glibc 2.26 `std::signbit()` broken for GCC compilers < 6 A defect in GLIBC 2.26 prevents programs using `signbit()` from `math.h` from compiling with `g++-4.8`, `g++-4.9`, or `g++-5`. This happens to include any uses of `libc++`, which requires a functioning `signbit()` to compile function template `__libcpp_signbit()` in file `math.h`. The Clang compilers happen to work with this part of `glibc` 2.26 as they don't implement 128-bit floating point and a different code path is followed, even for the earliest supported compilers. See: Workaround: Patch your local copy of `math.h` in `glibc` with the fix from `glibc` upstream, found by following the links in this bug report: See: "Bug 22296 - glibc 2.26: signbit build issue with Gcc 5.5.0 on x86_64" \ Available: \ Accessed: 11 November 2017 ### Conclusion Hopefully updated packages for `glibc` (`libc6-dev`), `libc++`, and `libstdc++-dev` for `g++-4.8` and `g++-5` will be released allowing patch-free building and testing of Trompeloeil on Artful Aardvark. A better strategy may be to build GLIBC, GCC 4.8, GCC 5.x, and `libc++` from source and use these to build your software. Then consider contributing your build to the Ubuntu Community; you just might be the "support" in "community supported". ## Supporting incomplete standard libraries Some platforms, especially MCUs with RTOS, only have partial support for the standard library `` and `` headers used by trompeloeil. In many cases, it is possible to provide shims or custom implementations of the necessary parts. ### Replacing `std::recursive_mutex` To use your own recursive mutex, define `TROMPELOEIL_CUSTOM_RECURSIVE_MUTEX` either before including the Trompeloeil header (e.g. `#define TROMPELOEIL_CUSTOM_RECURSIVE_MUTEX`) or as preprocessor definition (e.g. GCC: `-DTROMPELOEIL_CUSTOM_RECURSIVE_MUTEX`). Now define in one translation unit your custom recursive mutex for trompeloeil. ```cpp namespace trompeloeil { std::unique_ptr create_custom_recursive_mutex() { class custom : public custom_recursive_mutex { void lock() override { mtx.lock(); } void unlock() override { mtx.unlock(); } private: mylib::recursive_mutex mtx; }; return std::make_unique(); } } ``` ### Replacing `std::atomic` To use your own implementation of `std::atomic`, define `TROMPELOEIL_CUSTOM_ATOMIC` and make sure there is a header `trompeloeil/custom_atomic.hpp` somewhere in the include search path. This header should contain a class template `trompeloeil::atomic` that implements (part of) the interface of `std::atomic`: ```cpp namespace trompeloeil { template class atomic { public: atomic() : m_atomic() { } explicit atomic(const T initial) : m_atomic(initial) { } T operator=(T desired) { m_atomic.store(desired); return m_atomic.load(); } operator T() const { return m_atomic.load(); } private: mylib::atomic m_atomic; }; } ``` ### Replacing `std::unique_lock` To use your own implementation of `std::unique_lock`, define `TROMPELOEIL_CUSTOM_UNIQUE_LOCK` and make sure there is a header `trompeloeil/custom_unique_lock.hpp` somewhere in the include search path. This header should contain a class template `trompeloeil::unique_lock` that implements (part of) the interface of `std::unique_lock`: ```cpp namespace trompeloeil { template class unique_lock { public: unique_lock() noexcept : m_mutex(nullptr) { } explicit unique_lock(Mutex& mutex) : m_mutex(&mutex) { m_mutex->lock(); } unique_lock(const unique_lock&) = delete; unique_lock(unique_lock&& other) noexcept : m_mutex(nullptr) { std::swap(other.m_mutex, m_mutex); } unique_lock& operator=(const unique_lock&) = delete; unique_lock& operator=(unique_lock&& other) noexcept { std::swap(other.m_mutex, m_mutex); } ~unique_lock() { if (m_mutex) { m_mutex->unlock(); } } private: Mutex* m_mutex; }; } ``` trompeloeil-47/docs/reference.md000066400000000000000000002344641454452461300170760ustar00rootroot00000000000000# Reference - [Notions](#notions) - [Mock function](#mock_function) - [Mock object](#mock_object) - [Expectation](#expectation) - [Matcher](#matcher) - [_](#wildcard) - [**`ANY(`** *type* **`)`**](#ANY) - [**`eq(`** *value* **`)`**](#eq) - [**`ne(`** *value* **`)`**](#ne) - [**`gt(`** *value* **`)`**](#gt) - [**`ge(`** *value* **`)`**](#ge) - [**`lt(`** *value* **`)`**](#lt) - [**`le(`** *value* **`)`**](#le) - [**`re(`** *string* **`)`**](#re) - [**`*`** *matcher*](#deref_matcher) - [**`!`** *matcher*](#not_matcher) - [Macros](#macros) (alphabetical order) - [**`ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#ALLOW_CALL) - [**`ANY(`** *type* **`)`**](#ANY_MACRO) - [**`AT_LEAST(`** *number* **`)`**](#AT_LEAST) - [**`AT_MOST(`** *number* **`)`**](#AT_MOST) - [**`CO_RETURN(`** *expr **`)**](#CO_RETURN) - [**`CO_THROW(`** *expr **`)**](#CO_THROW) - [**`CO_YIELD(`** *expr **`)**](#CO_YIELD) - [**`FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#FORBID_CALL) - [**`IMPLEMENT_CONST_MOCKn(`** *func_name* **`)`**`](#IMPLEMENT_CONST_MOCKn) - [**`IMPLEMENT_MOCKn(`** *func_name* **`)`**`](#IMPLEMENT_MOCKn) - [**`IN_SEQUENCE(`** *seq...* **`)`**](#IN_SEQUENCE) - [**`LR_CO_RETURN(`** *expr* **`)`**](#LR_CO_RETURN) - [**`LR_CO_THROW(`** *expr* **`)`**](#LR_CO_THROW) - [**`LR_CO_YIELD(`** *expr* **`)`**](#LR_CO_YIELD) - [**`LR_RETURN(`** *expr* **`)`**](#LR_RETURN) - [**`LR_SIDE_EFFECT(`** *expr* **`)`**](#LR_SIDE_EFFECT) - [**`LR_THROW(`** *expr* **`)`**](#LR_THROW) - [**`LR_WITH(`** *expr* **`)`**](#LR_WITH) - [**`MAKE_CONST_MOCKn(`** *func_name*, *signature* **`)`**](#MAKE_CONST_MOCKn) - [**`MAKE_MOCKn(`** *name*, *signature* **`)`**](#MAKE_MOCKn) - [**`NAMED_ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_ALLOW_CALL) - [**`NAMED_FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_FORBID_CALL) - [**`NAMED_REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_REQUIRE_CALL) - [**`NAMED_REQUIRE_DESTRUCTION(`** *mock_object* **`)`**](#NAMED_REQUIRE_DESTRUCTION) - [**`REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#REQUIRE_CALL) - [**`REQUIRE_DESTRUCTION(`** *mock_object* **`)`**](#REQUIRE_DESTRUCTION) - [**`RETURN(`** *expr* **`)`**](#RETURN) - [**`SIDE_EFFECT(`** *expr* **`)`**](#SIDE_EFFECT) - [**`THROW(`** *expr* **`)`**](#THROW) - [**`TIMES(`** *limit* **`)`**](#TIMES) - [**`WITH(`** *expr* **`)`**](#WITH) - [Types and Type Templates](#types_and_templates) (alphabetical order) - [`trompeloeil::deathwatched`](#deathwatched_type) - [`trompeloeil::expectation`](#expectation_type) - [`trompeloeil::expectation_violation`](#expectation_violation_type) - [`trompeloeil::lifetime_monitor`](#lifetime_monitor_type) - [`trompeloeil::matcher`](#matcher_type) - [`trompeloeil::mock_interface`](#mock_interface) - [`trompeloeil::ok_reporter_func`](#ok_reporter_func) - [`trompeloeil::printer`](#printer) - [`trompeloeil::reporter_func`](#reporter_func) - [`trompeloeil::sequence`](#sequence_type) - [`trompeloeil::severity`](#severity_type) - [`trompeloeil::stream_tracer`](#stream_tracer) - [`trompeloeil::tracer`](#tracer_type) - [`trompeloeil::typed_matcher`](#typed_matcher) - [Functions and Function Templates](#functions) - [`trompeloeil::expectation::is_satisfied()`](#is_satisfied) - [`trompeloeil::expectation::is_saturated()`](#is_saturated) - [`trompeloeil::get_lock()`](#get_lock) - [`trompeloeil::print(std::ostream&, T const&)`](#print) - [`trompeloeil::is_null(T const &)`](#is_null) - [`trompeloeil::make_matcher(...)`](#make_matcher) - [`trompeloeil::set_reporter(...)`](#set_reporter) - [`trompeloeil::sequence::is_completed()`](#is_completed) - [Constants](#constants) - [`trompeloeil_movable_mock`](#movable_mock) ## Notions ### Mock function A *mock function* is a member function that is mocked with [**`MAKE_MOCKn(name, signature)`**](#MAKE_MOCKn) or [**`MAKE_CONST_MOCKn(name, signature)`**](#MAKE_CONST_MOCKn). Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); MAKE_CONST_MOCK2(cfunc, int(std::string, int)); }; ``` Above `C` is a type that has two mock functions `void func(int)` and `int cfunc(std::string, int) const`. With a [mock object](#mock_object) of type `C` it is possible to place [expectations](#expectation) on the functions `func(...)` and `cfunc(...)`. ### Mock object A *mock object* is an object of a type that has [mock functions](#mock_function). Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; C obj; ``` Above, `obj` is a mock object. It is possible to place [expectations](#expectation) on [mock functions](#mock_function) for the object `obj`. ### Expectation By default it is illegal to call [mock functions](#mock_function). Expectations change that. Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(3)); tested_function(mock_obj); } ``` Above `mock_obj` is a [mock object](#mock_object) with one [mock function](#mock_function) `void func(int)`. The line [*`REQUIRE_CALL(mock_obj, func(3))`*](#REQUIRE_CALL) places an expectation that `mock_obj.func(3)` is called before the end of the scope. Unless `tested_function(mock_obj)` calls `mock_obj.func(3)` a violation is reported. The ways to set expectations are: - [**`REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#REQUIRE_CALL) - [**`ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#ALLOW_CALL) - [**`FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#FORBID_CALL) - [**`NAMED_REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_REQUIRE_CALL) - [**`NAMED_ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_ALLOW_CALL) - [**`NAMED_FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`**](#NAMED_FORBID_CALL) Each **NAMED** variant returns an expectation as [`std::unique_ptr`](#expectation_type) which can be saved in variables for storage in test fixtures or other programmatic lifetime control. If expectations are not met by the time they go out or scope (or in case of the **NAMED** variants, when the object held by the `std::unique_ptr<>` is destroyed) a violation is reported. By default there is no order imposed on expectations. One way to impose order is through their lifetimes. Another is by using [**`IN_SEQUENCE(...)`**](#IN_SEQUENCE). If there are several expectations that match the same call, they are tried in the reverse order of creation, and the first found match is accepted. In other words, the last created matching expectation is the one used. Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(_)); FORBID_CALL(mock_obj, func(3)); FORBID_CALL(mock_obj, func(4)); tested_function(mock_obj); } ``` Above, the first expectation [**`ALLOW_CALL(...)`**](#ALLOW_CALL) matches everything using the wildcard [`trompeloeil::_`](#wildcard), but the two [**`FORBID_CALL(...)`**](#FORBID_CALL) are created later and are thus matched first. This means that if `tested_function(...)` calls `mock_obj.func(int)` with `5`, the two [**`FORBID_CALL(...)`**](#FORBID_CALL) do not match, but the [**`ALLOW_CALL(...)`**](#ALLOW_CALL) does, so the call is allowed. A call with `3` or `4`, results in a violation is report since a [**`FORBID_CALL(...)`**](#FORBID_CALL) is matched. ### Matcher Each parameter in the parameter list of an [expectation](#expectation) can be an exact value to match for equality (using `operator==`,) or a matcher. Matchers check a condition on the parameter value. Trompeloeil provides the matchers - [_](#wildcard) - [**`ANY(`** *type* **`)`**](#ANY) - [**`eq(`** *value* **`)`**](#eq) - [**`ne(`** *value* **`)`**](#ne) - [**`gt(`** *value* **`)`**](#gt) - [**`ge(`** *value* **`)`**](#ge) - [**`lt(`** *value* **`)`**](#lt) - [**`le(`** *value* **`)`**](#le) You can also provide [your own matchers](CookBook.md/#custom_matchers). #### **`_`** Used in the parameter list of an [expectation](#expectation), `trompeloeil::_` matches any value of any type. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, int(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(_)) .RETURN(_1 + 1); test_function(&mock_obj); } ``` Above, `mock_obj.func()` is allowed to be called with any value, and it will return 1 + the value provided. If type information is needed, for example to disambiguate overloads, use [**`ANY(`** *type* **`)`**](#ANY). #### **`ANY(`** *type* **`)`** Used in the parameter list of an [expectation](#expectation) to match any value of a specified type. This can be used as an alternative to [`trompeloeil::_`](#wildcard) when it is important to disambiguate between overloads. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK2(func, void(std::string)); }; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(ANY(int))); test_function(&mock_obj); } ``` Above, any call to `mock_obj.func(int)` is accepted, but calls to `mock_obj.func(std::string)` renders a violation report since there is no matching [expectation](#expectation). #### **`eq(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value equal to the one provided. By default it matches any parameter type that supports `operator==()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int*)); MAKE_MOCK1(func, void(const char*)); MAKE_MOCK1(func, void(const std::string&)); }; using trompeloeil::eq; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(*eq(3))); std::string expected = "foo"; REQUIRE_CALL(mock_obj, func(eq(expected))); test_function(&mock_obj); } ``` Above, the first [expectation](#expectation) matches only calls to `mock_obj.func(int*)` with a non-null pointer pointing to the value `3`. Any call with a `nullptr` or a pointer pointing to a value other than `3` renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches only calls to `mock_obj.func(const char*)`, with a C-string `"foo"`. #### **`ne(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value not equal to the one provided. By default it matches any parameter type that supports `operator!=()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(const char*)); MAKE_MOCK1(func, void(const std::string&)); }; using trompeloeil::ne; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(ne(nullptr))); REQUIRE_CALL(mock_obj, func(ne(""))); test_function(&mock_obj); } ``` Above, the first [expectation](#expectation) matches only calls to `mock_obj.func(const char*)` with non-null pointer. Any call with a `nullptr` renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches only calls to `mock_obj.func(const std::string&)`, with a non-empty string. It is also possible to use `*ne(val)` to match a pointer to a non-equal value. #### **`gt(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value greater than the one provided. By default it matches any parameter type that supports `operator>()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(short)); MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(std::string)); }; using trompeloeil::gt; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(gt(0))); ALLOW_CALL(mock_obj, func(gt("foo"))); test_function(&mock_obj); } ``` Above, the first [expectation](#expectation) matches only calls to `mock_obj.func(short)` with positive values. Any call with 0 or negative, and any calls to `mock_obj.func(int)` renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches calls to `mock_obj.func(std::string)`, since [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) is greater-than comparable with a string literal. It is also possible to use `*gt(val)` to match a pointer to a greater-than value. #### **`ge(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value greater than on equal to the one provided. By default it matches any parameter type that supports `operator>=()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(short)); MAKE_MOCK1(func, void(std::string)); }; using trompeloeil::ge; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(ge(0))); REQUIRE_CALL(mock_obj, func(ge("foo"))); test_function(&mock_obj); } ``` Above, the first [expectation](#expectation) matches only calls to `mock_obj.func(short)` with zero or positive values. Any call with a negative value renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches only calls to `mock_obj.func(std::string)`, since [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) is greater-than-or-equal-to comparable with string literal. It is also possible to use `*ge(val)` to match a pointer to a greater-than or equal value. #### **`lt(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value less than the one provided. By default it matches any parameter type that supports `operator<()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(long)); MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(const std::string&)); }; using trompeloeil::lt; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(lt(0))); REQUIRE_CALL(mock_obj, func(lt("foo"))); test_function(&mock_obj); } ``` Above, the first [expectation](#expectation) matches only calls to `mock_obj.func(int)` with negative values. Any call with 0 or positive renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches calls to `mock_obj.func(cost std::string&)`, since [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) is less-than comparable with string a literal. It is also possible to use `*lt(val)` to match a pointer to a less-than value. #### **`le(`** *value* **`)`** Used in the parameter list of an [expectation](#expectation) to match a value less than or equal to the one provided. By default it matches any parameter type that supports `operator<=()` with the value, but an explicit type can be specified if needed for disambiguation. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(short)); MAKE_MOCK1(func, void(const char*)); }; using trompeloeil::le; using std::string_literals; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(le(0))); REQUIRE_CALL(mock_obj, func(le("foo"s))); test_function(&mock_obj); } ``` Above, first the [expectation](#expectation) matches only calls to `mock_obj.func(short)` with zero or negative values. Any call with a positive value renders a violation report since no [expectation](#expectation) matches. The second [expectation](#expectation) matches calls to `mock_obj.func(const char*)`, since a c-string is less-than comparable with a [`std::string`](http://en.cppreference.com/w/cpp/string/basic_string) It is also possible to use `*le(val)` to match a pointer to a less-than or equal value. #### **`re(`** *string* **`)`** Used in the parameter list of an [expectation](#expectation) to match a string with a regular expression. `#include ` **`re()`** exists in two flavours. - **`re(`** *string*, *flags...* **`)`** which can match both C-strings (`char*`, `const char*`) as well as `C++` `std::string`. - **`re(`** *string*, *flags...* **`)`** which can be used to disambiguate overloads. For both versions, the string can be either `std::string` or a C-string. *flags...* can be - empty - `std::regex_constants::syntax_option_type` - `std::regex_constants::match_flag_type` - `std::regex_constants::syntax_option_type, std::regex_constants::match_flag_type` Regular expression matching is made with [`std::regex_search()`](http://en.cppreference.com/w/cpp/regex/regex_search) Example: ```Cpp class C { public: MAKE_MOCK1(unique, void(std::string&)); MAKE_MOCK1(overloaded, void(const char*)); MAKE_MOCK1(overloaded, void(const std::string&)); }; using trompeloeil::re; TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, unique(re("end$", std::regex_constants::icase))); REQUIRE_CALL(mock_obj, overloaded(re("end", std::regex_constants::match_not_eol))); test_function(&mock_obj); } ``` Above, `test_function(&mock_obj)` must call `mock_obj.unique()` with a string case insensitively matching the regular expression `/end$/`, and also call `mock_obj.overloaded(const char*)` with a regular expression matching the regular expression `/end/`. It is also possible to use `*re(string)` to match a pointer to a string with a regular expression, or `!re(string)` to allow only strings that do not match a regular expression. #### **`*`** *matcher* Used in the parameter list of an [expectation](#expectation) together with a matcher, to match a value pointed to by a pointer. A [`nullptr`](http://en.cppreference.com/w/cpp/language/nullptr) value fails the matcher. `#include ` Example: ```Cpp struct C { MAKE_MOCK1(func, void(int*)); }; using trompeloeil::eq; // matching equal values TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(*eq(3))); test_function(&mock_obj); } ``` Above, `test_function(&mock_obj)` must call `mock_obj.func()` with a pointer to the value `3`. #### **`!`** *matcher* Used in the parameter list of an [expectation](#expectation) together with a matcher, to negate a matcher, i.e. to fail what the matcher allows, and to allow what the matcher fails. `#include ` Example: ```Cpp struct C { MAKE_MOCK1(func, void(const std::string&)); }; using trompeloeil::re; // matching regular expressions TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(!re("^foo"))); test_function(&mock_obj); } ``` Above, `test_function(&mock_obj)` must call `mock_obj.func()` with a string that does not begin with `"foo"`. ## Macros ### **`ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make an expectation that *mock_object*.*func_name*(*parameter_list*) may be called zero or more times until the end of the surrounding scope. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls. This is the same as [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL).[**`TIMES(`**](#TIMES) 0,infinity **`)`**. `#include ` Matches any number of times, but is not required to match. (_actually the limit is 0..~0ULL, but that is for all practical purposes "infinity"_) Example: ```Cpp class C { public: MAKE_MOCK1(func, int(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(_)) .RETURN(_1 + 1); test_function(&mock_obj); } ``` Above **`ALLOW_CALL(mock_obj, func(_))`** places an expectation that `mock_obj.func()` may be called any number of times with any parameter value and will always return the parameter value + 1. `test_function(...)` is allowed to call `mock_obj.func()` any number of times (including no call at all). The expectation is valid until the end of the scope, which in the example above is until after the return from `test_function(...)`. See also [**`NAMED_ALLOW_CALL(...)`**](#NAMED_ALLOW_CALL) which creates an expectation as a [`std::unique_ptr`](#expectation_type) which can be stored in test fixtures or otherwise have its lifetime programmatically controlled. ### **`ANY(`** *type* **`)`** A [matcher](#matcher) for use in the parameter list of an [expectation](#expectation) to disambiguate overloaded functions on type when the exact value is unimportant. See the matcher [**`ANY(`** *type* **`)`**](#ANY) above. `#include ` ### **`AT_LEAST(`** *number* **`)`** Used in [**`TIMES(...)`**](#TIMES) to set the range *number*..infinity. *number* must be [`constexpr`](http://en.cppreference.com/w/cpp/language/constexpr). `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(_)) .TIMES(AT_LEAST(3)); tested_function(&mock_obj); } ``` Above, the line [**`TIMES(`**](#TIMES)**`AT_LEAST(3))`** modifies the [expectation](#expectation) such that *mock_obj.func()* must be called 3 times or more, before the end of the scope, or a violation is reported. _In reality the upper limit is ~0ULL, but that is for all practical purposes "infinity"_. ### **`AT_MOST(`** *number* **`)`** Used in [**`TIMES(...)`**](#TIMES) to set the range 0..*number*. *number* must be [`constexpr`](http://en.cppreference.com/w/cpp/language/constexpr). `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(_)) .TIMES(AT_MOST(3)); tested_function(&mock_obj); } ``` Above, the line [**`TIMES(`**](#TIMES)**`AT_MOST(3))`** modifies the [expectation](#expectation) such that *mock_obj.func()* must be called 3 times or less (including no call at all) before the end of the scope, or a violation is reported. ### **`CO_RETURN(`** *expr* **`)`** Used in [expectations](#expectation) to set the return value from a coroutine. Note that when [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) are executed depends on the behaviour of the coroutine promise type. This code may alter out-parameters. `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`CO_THROW(`** *expr* **`)`** Used in [expectations](#expectation) to throw an exception from a coroutine. Note that when any [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) are executed depends on the behaviour of the coroutine promise type. This code may alter out-parameters. `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`CO_YIELD(`** *expr* **`)`** Used in [expectations](#expectation) with a coroutine type that can [`co_yield`](https://en.cppreference.com/w/cpp/language/coroutines#co_yield). You can add several **`CO_YIELD`** to the same expectation, and the values will be yielded one at the time, in the order they are listed. Note that [**`CO_RETURN(`** *expr* **`)`**](#CO_RETURN) or [**`LR_CO_RETURN(`** *expr* **`)`**](#LR_CO_RETURN) is still needed. See also [**`LR_CO_YIELD(`** *expr* **`]`**](#LR_CO_YIELD) `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make an expectation that *mock_object*.*func_name*(*parameter_list*) must not be called until the end of the scope. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls. This is the same as [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL).[**`TIMES(`**](#TIMES) 0 **`)`**, making any matching call an error. This is often done in a narrow scope where the wider scope would allow the call. [**`LR_RETURN(...)`**](#LR_RETURN), [**`RETURN(...)`**](#RETURN), [**`LR_THROW(...)`**](#LR_THROW) and [**`THROW(...)`**](#THROW) are illegal in a **`FORBID_CALL(...)`**. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(_)); tested_function(1, &mock_obj); { FORBID_CALL(mock_obj, func(2)); tested_function(2, &mock_obj); } tested_function(3, &mock_obj); } ``` Above, the [mock function](#mock_function) *C::func(int)* may be called with any value for *mock_obj*, except in the scope of the *tested_function(2, &mock_obj)*, where *mock_obj.func(2)* would lead to a violation being reported. At *tested_function(3, &mock_obj)* any value is allowed again. See also [**`NAMED_FORBID_CALL(...)`**](#NAMED_FORBID_CALL) which creates an expectation as a [`std::unique_ptr`](#expectation_type) which can be stored in test fixtures or otherwise have its lifetime programmatically controlled. ### **`IMPLEMENT_CONST_MOCKn(`** *func_name* {, *specifiers* } **`)`** Make a `const` [mock function](#mock_function) implementation of the `virtual` function named *func_name* from the inherited interface. This macro is only usable with `virtual` non-`final` functions, and only when used with [`mock_interface`](#mock_interface), where `T` is the interface. *specifiers* is an optional list which may include attributes or specifiers like [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec). `#include ` Example: ```Cpp class I { public: virtual ~I() = default; virtual int func(int, const std::vector&)) const = 0; }; class C : public trompeloeil::mock_interface { public: IMPLEMENT_CONST_MOCK2(func); }; ``` Above, class `C` will effectively become: ```Cpp class C : public trompeloeil::mock_interface { public: int func(int, const std::vector&) const override; }; ``` It is not possible to mock operators, constructors or the destructor, but you can call [mock functions](#mock_function) from those. **NOTE!** **`IMPLEMENT_CONST_MOCKn(...)`** cannot handle overloaded functions. See also [**`IMPLEMENT_MOCKn(...)`**](#IMPLEMENT_MOCKn) for non-`const` member functions. See also [**`MAKE_MOCKn(...)`**](#MAKE_MOCKn) and [**`MAKE_CONST_MOCKn(...)`**](#MAKE_CONST_MOCKn) for making mock implementations of any member functions. ### **`IMPLEMENT_MOCKn(`** *func_name* {, *specifiers* } **`)`** Make a non-`const` [mock function](#mock_function) implementation of the `virtual` function named *func_name* from the inherited interface. This macro is only usable with `virtual` non-`final` functions, and only when used with [`mock_interface`](#mock_interface), where `T` is the interface. *specifiers* is an optional list which may include attributes or specifiers like [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec). `#include ` Example: ```Cpp class I { public: virtual ~I() = default; virtual int func(int, const std::vector&)) = 0; }; class C : public trompeloeil::mock_interface { public: IMPLEMENT_MOCK2(func1); }; ``` Above, class `C` will effectively become: ```Cpp class C : public trompeloeil::mock_interface { public: int func(int, const std::vector&) override; }; ``` It is not possible to mock operators, constructors or the destructor, but you can call [mock functions](#mock_function) from those. **NOTE!** **`IMPLEMENT_MOCKn(...)`** cannot handle overloaded functions. See also [**`IMPLEMENT_CONST_MOCKn(...)`**](#IMPLEMENT_CONST_MOCKn) for `const` member functions. See also [**`MAKE_CONST_MOCKn(...)`**](#MAKE_CONST_MOCKn) for `const` member functions. ### **`IN_SEQUENCE(`** *seq...* **`)`** Where *seq...* is one or more instances of `trompeloeil::sequence`. Impose an order in which [expectations](#expectation) and destruction of [**`deathwatched_type`**](#deathwatched_type) objects must match. Several sequences can be parallel and interleaved. A sequence for an [expectation](#expectation) can move forward to the next once the lower limit from [**`TIMES(...)`**](#TIMES) is reached (defaults to 1). This means that if the lower limit is 0 (see [**`ALLOW_CALL(...)`**](#ALLOW_CALL)), the expectation may be skipped in the sequence. `#include ` Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); MAKE_MOCK1(func, void(const std::string&)); }; class ephemeral { public: virtual ~ephemeral() {}; }; TEST(atest) { Mock m[2]; auto e = new trompeloeil::deathwatched; trompeloeil::sequence seq1, seq2; REQUIRE_CALL(m[0], func(ANY(int)) .IN_SEQUENCE(seq1, seq2); REQUIRE_CALL(m[0], func(ANY(const std::string&)) .IN_SEQUENCE(seq1); REQUIRE_CALL(m[1], func(ANY(const std::string&)) .IN_SEQUENCE(seq2); REQUIRE_CALL(m[1], func(ANY(int)) .IN_SEQUENCE(seq1, seq2); REQUIRE_DESTRUCTION(*e) .IN_SEQUENCE(seq1, seq2); tested_func(&m[0], &m[1], e); } ``` All sequence objects are listed in the first [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL), thus it must be the first [expectation](#expectation) matched. Likewise all sequences are listed in the last [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL), so it must be last [expectation](#expectation) matched. The intermediate [expectations](#expectation) has one sequence object each, thus they have no matching order imposed between them. Last of all is the [**`REQUIRE_DESTRUCTION(...)`**](#REQUIRE_DESTRUCTION), which also lists all sequence objects and must happen after all other [expectations](#expectation) are fulfilled. The above allows the following two sequences only. - `m[0].func(int)` -> `m[0].func(string)` -> `m[1].func(string)` -> `m[1].func(int)` -> `delete e` - `m[0].func(int)` -> `m[1].func(string)` -> `m[0].func(string)` -> `m[1].func(int)` -> `delete e` Any other sequence of calls renders a violation report. Note that `.IN_SEQUENCE()` in combination with [**`.TIMES(...)`**](#TIMES) is greedy. It will stay on on the same expectation as long as it matches, and will leave for the next step in the sequence only when the upper bound from [**`.TIMES(...)`**](#TIMES) is reached, or a different expectation matches. Example: ```Cpp class Mock { public: MAKE_MOCK1(func, void(int)); }; TEST(a_test) { Mock m; trompeloeil::sequence seq; REQUIRE_CALL(m, func(0)) .IN_SEQUENCE(seq) .TIMES(1, 5); ALLOW_CALL(m, func(0)) .IN_SEQUENCE(seq) .SIDE_EFFECT(std::cout << "extra\n"); REQUIRE_CALL(m, func(1)) .IN_SEQUENCE(seq); test_func(m); } ``` The expectation `REQUIRE_CALL(m, func(0))` stays in effect until either matched 5 times, or a call to `m.func(1)` has been made. After a call to `m.func(1)`, no call to `m.func(0)` is allowed. The function `test_func()` must call `m.func(0)` at least once, and end with `m.func(1)`. If `m.func(0)` is called more than 5 times, each call prints `"extra"` on `std::cout`. ### **`LR_CO_RETURN(`** *expr* **`)`** Used in [expectations](#expectation) to set the return value from a coroutine. Note that when any [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) are executed depends on the behaviour of the coroutine promise type. This code may alter out-parameters. `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Any named local objects named in *expr* are captured by reference so lifetime management is important. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`LR_CO_THROW(`** *expr* **`)`** Used in [expectations](#expectation) to throw an exception from a coroutine. Note that when any [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) are executed depends on the behaviour of the coroutine promise type. This code may alter out-parameters. `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Any named local objects named in *expr* are captured by reference so lifetime management is important. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`LR_CO_YIELD(`** *expr* **`)`** Used in [expectations](#expectation) with a coroutine type that can [`co_yield`](https://en.cppreference.com/w/cpp/language/coroutines#co_yield). You can add several **`LR_CO_YIELD`** to the same expectation, and the values will be yielded one at the time, in the order they are listed. Note that [**`CO_RETURN(`** *expr* **`)`**](#CO_RETURN) or [**`LR_CO_RETURN(`** *expr* **`)`**](#LR_CO_RETURN) is still needed. See also [**`CO_YIELD(`** *expr* **`]`**](#LR_CO_YIELD) `#include ` Coroutines are supported if the compiler defines the [**`__cpp_impl_coroutines`**](https://eel.is/c++draft/cpp.predefined#:__cpp_impl_coroutine) feature test macro. **NOTE!** Any named local objects named in *expr* are captured by reference so lifetime management is important. **NOTE!** Be very extra careful with lifetime issues when dealing with coroutines. ### **`LR_RETURN(`** *expr* **`)`** Used in [expectations](#expectation) to set the return value after having evaluated every [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT). For `void` functions **`LR_RETURN(...)`** is illegal. For non-`void` functions exactly one of [**`RETURN(...)`**](#RETURN), **`LR_RETURN(...)`**, [**`LR_THROW(...)`**](#LR_THROW) or [**`THROW(...)`**](#THROW) is required. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. `#include ` If you need to return an [lvalue-reference](http://en.cppreference.com/w/cpp/language/reference), to a variable, use [`std::ref(value)`](http://en.cppreference.com/w/cpp/utility/functional/ref) or [`std::cref(value)`](http://en.cppreference.com/w/cpp/utility/functional/cref) for it, or just enclose the value in an extra parenthesis, like this [**`.LR_RETURN((value))`**](reference.md/#RETURN). **NOTE!** Any named local objects named in *expr* are captured by reference so lifetime management is important. Example: ```Cpp class C { public: MAKE_MOCK1(func, int&(unsigned)); }; TEST(atest) { C mock_obj; int rv = 3; ALLOW_CALL(mock_obj, func(0)) .LR_RETURN(std::ref(rv)); // reference to captured local variable rv = 4; test_func(&mock_obj); } ``` Above, the **`LR_RETURN(...)`** clause tells matching calls of `mock_obj.func(...)` to return a reference to the local variable `rv`. Since **`LR_RETURN(...)`** accesses local variables by reference, the value of the returned reference will be 4 if called from within `test_func(...)`. See also [**`RETURN(...)`**](#RETURN) which accesses copies of local variables. ### **`LR_SIDE_EFFECT(`** *expr* **`)`** Used in [expectations](#expectation) to cause side effects for matching calls. *expr* is only evaluated when all [**`WITH(...)`**](#WITH) and [**`LR_WITH(...)`**](#LR_WITH) clauses are matched. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. Several **`LR_SIDE_EFFECT(...)`** and [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) clauses can be added to a single [expectation](#expectation), and they are evaluated in order. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(unsigned)); }; TEST(atest) { C mock_obj; unsigned sum = 0; ALLOW_CALL(mock_obj, func(ANY(unsigned)) .LR_SIDE_EFFECT(sum += _1); tested_func(&mock_obj); std::cout << "parameter sum=" << sum << "\n"; } ``` Above, `tested_func(&mock_obj)` is allowed to call `C::func(int)` any number of times on `mock_obj`. Each time a side effect is that the local variable `sum` gets the parameter value added to it. Since **`LR_SIDE_EFFECT(...)`** refers to `sum` by reference, it is the actual local variable that is changed is every call. See also [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) which accesses copies of local objects. ### **`LR_THROW(`** *expr* **`)`** Used in [expectations](#expectation) to throw after having evaluated every [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) for a matching call. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. It is not legal to combine **`LR_THROW(...)`** with any of [**`THROW(...)`**](#THROW), [**`LR_RETURN(...)`**](#LR_RETURN) or [**`RETURN(...)`**](#RETURN). Named local objects are accessed by reference so lifetime management is important. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(unsigned)); }; TEST(atest) { C mock_obj; const char* what=""; ALLOW_CALL(mock_obj, func(3)) .LR_THROW(std::invalid_argument(what)); what = "nonsense"; tested_func(&mock_obj); } ``` Above, **`LR_THROW(std::invalid_argument(what))`** will refer to the C-string `what` with the value it has at the time of a call to `mock_obj.func(3)`, i.e. `"nonsense"` if `tested_func()` does the call. See also [**`THROW(...)`**](#THROW) which accesses copies of local objects. ### **`LR_WITH(`** *expr* **`)`** Used with [expectations](#expectation) to add further conditions for a matching call. Typically used when [matchers](#matcher) are used for the parameters, and often when the condition requires several parameter values together. *expr* can refer to parameters in the call with their positional names `_1`, `_2`, etc. Even if the function signature has parameters as non-`const` references, they are immutable in this context. Several **`LR_WITH(...)`** and [**`WITH(...)`**](#WITH) clauses can be added to a single expectation and they are tried in the order they are added until one has failed, or they all have passed. Named local objects are accessed by reference so lifetime management is important. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(const char*)); }; using trompeloeil::_; TEST(atest) { C mock_obj; const char buff[] = "string"; REQUIRE_CALL(mock_obj, func(_)) .LR_WITH(_1 == buff); tested_func(buff, &mock_obj); } ``` Above, **`LR_WITH(_1 == buff)`** checks the condition that the `const char*` parameter is the same pointer value as the address to the local array `buff`. **NOTE!** It is legal, but a *very* bad idea, to modify global/static objects in **`LR_WITH(...)`**. If several [expectations](#expectation) could match and are disambiguated by **`LR_WITH(...)`** and [**`WITH(...)`**](#WITH) the global/static objects will be modified also by those [expectations](#expectation) that do not match. See also [**`WITH(...)`**](#WITH) which accesses copies of local objects. ### **`MAKE_CONST_MOCKn(`** *func_name*, *signature* {, *specifiers* } **`)`** Make a `const` [mock function](#mock_function) named *func_name*. It is a good idea for this to implement a pure virtual function from an interface, but it is not a requirement. `n` is the number of parameters in *signature*. *specifiers* is an optional list which may include attributes or specifiers like [`override`](http://en.cppreference.com/w/cpp/language/override) or [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec). `#include ` Example: ```Cpp class I { public: virtual ~I() = default; virtual int func1(int, const std::vector&)) const = 0; }; class C { public: MAKE_CONST_MOCK2(func1, int(int, const std::vector&), override); MAKE_CONST_MOCK1(func2, int(std::string)); }; ``` Above, class `C` will effectively become: ```Cpp class C : public I { public: int func1(int, const std::vector&) const override; int func2(std::string) const; }; ``` It is not possible to mock operators, constructors or the destructor, but you can call [mock functions](#mock_function) from those. See also [**`MAKE_MOCKn(...)`**](#MAKE_MOCKn) for non-`const` member functions. ### **`MAKE_MOCKn(`** *func_name*, *signature* {, *specifiers* } **`)`** Make a non-const [mock function](#mock_function) named *func_name*. It is a good idea for this to implement a pure virtual function from an interface, but it is not a requirement. `n` is the number of parameters in *signature*. *specifiers* is an optional list which may include attributes or specifiers like [`override`](http://en.cppreference.com/w/cpp/language/override) or [`noexcept`](https://en.cppreference.com/w/cpp/language/noexcept_spec). `#include ` Example: ```Cpp class I { public: virtual ~I() = default; virtual int func1(int, const std::vector&)) = 0; }; class C : public I { public: MAKE_MOCK2(func1, int(int, const std::vector&), override); MAKE_MOCK1(func2, int(std::string)); }; ``` Above, class `C` will effectively become: ```Cpp class C : public I { public: int func1(int, const std::vector&) override; int func2(std::string); }; ``` It is not possible to mock operators, constructors or the destructor, but you can call [mock functions](#mock_function) from those. See also [**`MAKE_CONST_MOCKn(...)`**](#MAKE_CONST_MOCKn) for `const` member functions. ### **`NAMED_ALLOW_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make a [`std::unique_ptr`](#expectation_type) allowing *mock_object*.*func_name*(*parameter_list*) to be called zero or more times until the expectation object is destroyed. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls. This is the same as [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL).[**`TIMES(`**](#TIMES) 0,infinity **`)`**. Matches any number of times, but is not required to match. (_Actually the limit is 0..~0ULL, but that is for all practical purposes "infinity"_.) **NOTE!** Any named objects referenced in attached [**`LR_WITH(...)`**](#LR_WITH), [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT), [**`LR_RETURN(...)`**](#LR_RETURN) and [**`LR_THROW(...)`**](#LR_THROW) are captured by reference so lifetime management is important. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); }; using trompeloeil::gt; using trompeloeil::lt; using expectation = std::unique_ptr; TEST(atest) { C mock_obj; expectation x1 = NAMED_ALLOW_CALL(mock_obj, func(gt(0)); test_function(0, &mock_obj); expectation x2 = NAMED_ALLOW_CALL(mock_obj, func(lt(0)); test_function(1, &mock_obj); x1.reset(); // no longer allow calls with positive values test_function(2, &mock_obj); } ``` Above each **`NAMED_ALLOW_CALL(mock_obj, func(...))`** creates an expectation that *mock_obj.func()* may be called any number of times. Each expectation is valid for the lifetime of the expectation object. In the example above, this means that `x1` is valid for the first two calls to `test_function(...)`, while `x2` is valid for the last two calls to `test_function(...)`. See also [**`ALLOW_CALL(...)`**](#ALLOW_CALL) which creates an expectation that is valid until the end of the surrounding scope. ### **`NAMED_FORBID_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make a [`std::unique_ptr`](#expectation_type) disallowing calls to *mock_object*.*func_name*(*parameter_list*) until the expectation object is destroyed. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls. This is the same as [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL).[**`TIMES(`**](#TIMES) 0 **`)`**, making any matching call an error. This is typically done when a wider scope would allow the call. [**`RETURN(...)`**](#RETURN), [**`LR_RETURN(...)`**](#LR_RETURN), [**`LR_THROW(...)`**](#LR_THROW) and [**`THROW(...)`**](#THROW) are illegal in a **`NAMED_FORBID_CALL(...)`**. **NOTE!** Any named objects referenced in attached [**`LR_WITH(...)`**](#LR_WITH) are captured by reference so lifetime management is important. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); } using trompeloeil::_; using trompeloeil::gt; using trompeloeil::lt; using expectation = std::unique_ptr; TEST(atest) { C mock_obj; ALLOW_CALL(mock_obj, func(_)); expectation x1 = NAMED_FORBID_CALL(mock_obj, func(gt(0)); test_function(0, &mock_obj); expectation x2 = NAMED_FORBID_CALL(mock_obj, func(lt(0)); test_function(1, &mock_obj); x1.reset(); // allow calls with positive values again test_function(2, &mock_obj); } ``` Above, calls to `mock_obj.func()` are generally allowed throughout the test. However, `x1` imposes a restriction that calls with positive values are illegal, and that restriction is in place for the first two calls to `test_function(...)`. `x2` imposes a restrictions that calls with negative values are illegal, and that restriction is in place for the last two calls to `test_function(...)`. See also [**`FORBID_CALL(...)`**](#FORBID_CALL) which creates an [expectation](#expectation) that is valid until the end of the surrounding scope. ### **`NAMED_REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make a [`std::unique_ptr`](#expectation_type) requiring that *mock_obj*.*func_name*(*parameter_list*) is called exactly once before the expectation object is destroyed. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching calls. The number of matches required before the [expectation](#expectation) object is destroyed can be changed with an optional [**`TIMES(...)`**](#TIMES) clause. **NOTE!** Any named objects referenced in attached [**`LR_WITH(...)`**](#LR_WITH), [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT), [**`LR_RETURN(...)`**](#LR_RETURN) and [**`LR_THROW(...)`**](#LR_THROW) are captured by reference so lifetime management is important. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); } using trompeloeil::gt; using trompeloeil::lt; using expectation = std::unique_ptr; TEST(atest) { C mock_obj; expectation x1 = NAMED_REQUIRE_CALL(mock_obj, func(gt(0)); test_function(0, &mock_obj); expectation x2 = NAMED_REQUIRE_CALL(mock_obj, func(lt(0)); test_function(1, &mock_obj); x1.reset(); // The call with positive number must be done here. test_function(2, &mock_obj); } ``` Above, the first two calls to `test_function(...)` must together call `mock_obj.func(...)` exactly once with a positive value, and the last two calls to `test_function(...)` must together call `mock_obj.func(...)` exactly once with a negative number. See also [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL) which creates an [expectation](#expectation) that is valid until the end of the surrounding scope. ### **`NAMED_REQUIRE_DESTRUCTION(`** *mock_object* **`)`** Create a [`std::unique_ptr`](#expectation_type) object which reports a violation if the [**`deathwatched_type`**](#deathwatched_type) [mock object](#mock_object) is not destroyed by the time the `expectation` is destroyed. `#include ` Example: ```Cpp class C { public: virtual ~C() = default; // must be virtual for deathwatched MAKE_MOCK1(func, void(int)); } using monitor = std::unique_ptr; using trompeloeil::deathwatched; TEST(atest) { C* p = new deathwatched(); test_function(0, p); // must not destroy *p monitor m = NAMED_REQUIRE_DESTRUCTION(*p); test_function(1, p); m.reset(); // *p must have been destroyed here } ``` Above, `p` points to a [`deathwatched`](#deathwatched_type) [mock object](#mock_object), meaning that a violation is reported if `*p` is destroyed without having a destruction requirement. The monitor `m` is a requirement that `*p` is destroyed before the [`lifetime_monitor`](#lifetime_monitor_type) (subtype of [`expectation`](#expectation_type)) held by `m` is destroyed. It is thus a violation if the first call to `test_function(...)` destroys `*p`, and another violation if the second call to `test_function(...)` does not destroy `*p` See also [**`REQUIRE_DESTRUCTION(...)`**](#REQUIRE_DESTRUCTION) which places a requirement that the [`deathwatched`](#deathwatched_type) [mock object](#mock_object) is destroyed before the end of the scope. ### **`REQUIRE_CALL(`** *mock_object*, *func_name*(*parameter_list*)**`)`** Make an [expectation](#expectation) requiring that *mock_obj*.*func_name*(*parameter_list*) is called exactly once before the end of the scope. *parameter_list* may contain exact values or [matchers](#matcher) that describes matching parameter values for the [expectation](#expectation). The number of matches required before the [expectation](#expectation) object is destroyed can be changed with an optional [**`TIMES(...)`**](#TIMES) clause. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(int)); } using trompeloeil::gt; using trompeloeil::lt; TEST(atest) { C mock_obj; { REQUIRE_CALL(mock_obj, func(gt(0)); test_function(0, &mock_obj); // end of scope, requirement must be fulfilled here } { REQUIRE_CALL(mock_obj, func(lt(0)); test_function(1, &mock_obj); // end of scope, requirement must be fulfilled here } } ``` Above, the first call to `test_function(...)` must call `mock_obj.func(...)` exactly once with a positive value, and the second call to `test_function(...)` must call `mock_obj.func(...)` exactly once with a negative number. See also [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL) which creates an [expectation](#expectation) that is held by a [`std::unique_ptr`](#expectation_type) which can be stored in test fixtures. ### **`REQUIRE_DESTRUCTION(`** *mock_object* **`)`** Create an anonymous [`lifetime_monitor`](#lifetime_monitor_type) which reports a violation if the [**`deathwatched`**](#deathwatched_type) [mock object](#mock_object) is not destroyed by the end of the scope. `#include ` Example: ```Cpp class C { public: virtual ~C() = default; // must be virtual for deathwatched MAKE_MOCK1(func, void(int)); } using trompeloeil::deathwatched; TEST(atest) { C* p = new deathwatched(); test_function(0, p); // must not destroy *p { REQUIRE_DESTRUCTION(*p); test_function(1, p); // end of scope, *p must have been destroyed here } } ``` Above, `p` points to a [`deathwatched`](#deathwatched_type) [mock object](#mock_object), meaning that a violation is reported if `*p` is destroyed without having a destruction requirement. **`REQUIRE_DESTRUCTION(...)`** in the local scope puts a requirement on `*p` that it must be destroyed by the end of the scope. It is thus a violation if the first call to `test_function(...)` destroys `*p`, and another violation if the second call to `test_function(...)` does not destroy `*p`. See also [**`NAMED_REQUIRE_DESTRUCTION(...)`**](#NAMED_REQUIRE_DESTRUCTION) which creates the requirement that the [`deathwatched`](#deathwatched_type) [mock object](#mock_object) is destroyed as a [`std::unique_ptr`](#lifetime_monitor_type) which can be stored in test fixtures. ### **`RETURN(`** *expr* **`)`** Used in [expectations](#expectation) to set the return value after having evaluated every [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT). For `void` functions **`RETURN(...)`** is illegal. For non-`void` functions exactly one of [**`LR_RETURN(...)`**](#LR_RETURN), **`RETURN(...)`**, [**`LR_THROW(...)`**](#LR_THROW) or [**`THROW(...)`**](#THROW) is required. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. Named local objects accessed here refers to a immutable copies. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, int&(unsigned)); }; using trompeloeil::_; std::vector values{3,2,1,0}; TEST(atest) { C mock_obj; int offset = 1; ALLOW_CALL(mock_obj, func(_)) .WITH(_1 + offset < values.size()) .RETURN(values[_1 + offset]); offset = 2; test_func(&mock_obj); } ``` Above, the **`RETURN(...)`** clause tells matching calls of `mock_obj.func(...)` to return a reference to an element in the global `std::vector values`. Since **`RETURN(...)`** accesses copies of local variables, the value of `offset` is 1 in the index calculation if called from within `test_func(...)`. **NOTE!** It is illegal to return a reference to a captured local variable. See also [**`LR_RETURN(...)`**](#LR_RETURN) which accesses local variables by reference. ### **`SIDE_EFFECT(`** *expr* **`)`** Used in [expectations](#expectation) to cause side effects for matching calls. *expr* is only evaluated when all [**`WITH(...)`**](#WITH) and [**`LR_WITH(...)`**](#LR_WITH) clauses are matched. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. Several **`SIDE_EFFECT(...)`** and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) clauses can be added to a single [expectation](#expectation), and they are evaluated in order. Named local objects accessed here refers to immutable copies. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(unsigned)); }; unsigned sum = 0; TEST(atest) { C mock_obj; unsigned offset = 0; ALLOW_CALL(mock_obj, func(ANY(unsigned)) .SIDE_EFFECT(sum += offset + _1); offset = 2; tested_func(&mock_obj); std::cout << "offset corrected parameter sum=" << sum << "\n"; } ``` Above, `tested_func(...)` is allowed to call `mock_obj.func()` any number of times. Each time a side effect is that the global variable `sum` gets the parameter value added to it adjusted for `offset`. Since **`SIDE_EFFECT(...)`** refers to a copy of `offset`, the value of `offset` is `0` in any matching calls from within `tested_func(...)` See also [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) which accesses local objects by reference. ### **`THROW(`** *expr* **`)`** Used in [expectations](#expectation) to throw after having evaluated every [**`SIDE_EFFECT(...)`**](#SIDE_EFFECT) and [**`LR_SIDE_EFFECT(...)`**](#LR_SIDE_EFFECT) for a matching call. *expr* may refer to parameters in the call with their positional names `_1`, `_2`, etc. This code may alter out-parameters. It is not legal to combine **`THROW(...)`** with any of [**`LR_THROW(...)`**](#LR_THROW), [**`LR_RETURN(...)`**](#LR_RETURN) or [**`RETURN(...)`**](#RETURN). Named local objects here refers to immutable copies. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(unsigned)); }; TEST(atest) { C mock_obj; std::string what=""; ALLOW_CALL(mock_obj, func(3)) .THROW(std::invalid_argument(what)); what = ""; tested_func(&mock_obj); } ``` Above, **`THROW(...)`** will refer to a copy of the string `what` with the value `""` if a matching call is made from within `tested_func(...)` See also [**`LR_THROW(...)`**](#LR_THROW) which accesses copies of local objects. ### **`TIMES(`** *limits* **`)`** Used in [**`REQUIRE_CALL(...)`**](#REQUIRE_CALL) and [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL) to set the limits on the number of matching calls required. *limits* may be a single number, in which case it is the exact number of matching calls required. *limits* may also be two numbers, describing a range *min-inclusive*, *max-inclusive*. If the minimum number of matching calls in not met before the end of the lifetime of the [expectation](#expectation), a violation is reported. If the maximum number of matching calls is exceeded, a violation is reported. *limits* must be [`constexpr`](http://en.cppreference.com/w/cpp/language/constexpr). **`TIMES(...)`** may only be used once for each [**`REQUIRE_CALL(..)`**](#REQUIRE_CALL) or [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL). `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(unsigned)); }; using trompeloeil::_; TEST(atest) { C mock_obj; REQUIRE_CALL(mock_obj, func(_)) .TIMES(2, 5); tested_func(&mock_obj); ``` Above, `tested_func(...)` is expected to call `mock_obj.func()` at least two times, and no more than 5 times. See also the helpers [**`AT_LEAST(...)`**](#AT_LEAST) and [**`AT_MOST(...)`**](#AT_MOST). See also [**`IN_SEQUENCE(...)`**](#IN_SEQUENCE) for information about how `.TIMES(...)` works together with [**`sequence`**](#sequence_type) objects. ### **`WITH(`** *expr* **`)`** Used with [expectations](#expectation) to add further conditions for a matching call. Typically used when [matchers](#matcher) are used for the parameters, and often when the condition requires several parameter values together. *expr* can refer to parameters in the call with their positional names `_1`, `_2`, etc. Even if the function signature has parameters as non-`const` references, they are immutable in this context. Several **`WITH(...)`** and [**`LR_WITH(...)`**](#LR_WITH) clauses can be added to a single expectation and they are tried in the order until one has failed, or they all have passed. Named local objects here refers to immutable copies. `#include ` Example: ```Cpp class C { public: MAKE_MOCK1(func, void(const char*, size_t)); }; using trompeloeil::_; TEST(atest) { C mock_obj; std::string str = "string"; REQUIRE_CALL(mock_obj, func(_,_)) .WITH(std::string(_1, _2) == str); str = ""; // does not alter the copy in the expectation above. tested_func(buff, &mock_obj); } ``` Above, **`WITH(std::string(_1, _2) == str)`** checks the condition that the string constructed from the parameters is equal to a copy of the local variable `str`. To pass the test, `tested_func(...)` must in other words call `mock_obj.func()` with string `"string"`. **NOTE!** It is legal, but a *very* bad idea, to modify global/static objects in **`WITH(...)`**. If several [expectations](#expectation) could match and are disambiguated by [**`LR_WITH(...)`**](#LR_WITH) and **`WITH(...)`** the global/static objects will be modified also by those [expectations](#expectation) that do not match. See also [**`LR_WITH(...)`**](#LR_WITH) which accesses local objects by reference. ## Types and Templates (alphabetical order) ### `trompeloeil::deathwatched` Template used when it is necessary to control the life time of a [mock object](#mock_object). The macros [**`REQUIRE_DESTRUCTION(...)`**](#REQUIRE_DESTRUCTION) and [**`NAMED_REQUIRE_DESTRUCTION(...)`**](#NAMED_REQUIRE_DESTRUCTION) operates on instances of `trompeloeil::deathwatched`. `#include ` Example: ```Cpp class Mock { public: virtual ~Mock() = default; // virtual destructor needed for deathwatched<> MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; void test_func() { auto p = new trompeloeil::deathwatched(); ALLOW_CALL(*p, func(_)); func1(p); { FORBID_CALL(*p, func(_)); REQUIRE_DESTRUCTION(*p); func2(p); } } ``` Above, `func1(p)` must not destroy `p`, or a violation is reported, and `func2(p)` may not call the [mock function](#mock_function) on `p`, but is required to destroy the [mock object](#mock_object), or a violation will be reported. `trompeloeil::deathwatched` inherits from `T`, and the constructor accepts any parameters and [perfectly forwards](http://www.cppsamples.com/common-tasks/perfect-forwarding.html) them to the constructor of `T`. The mock type `T` must have a virtual destructor. ### `trompeloeil::expectation` Base class for all [expectations](#expectation). The macros [**`NAMED_ALLOW_CALL(...)`**](#NAMED_ALLOW_CALL), [**`NAMED_FORBID_CALL(...)`**](#NAMED_FORBID_CALL) and [**`NAMED_REQUIRE_CALL(...)`**](#NAMED_REQUIRE_CALL) results in a [`std::unique_ptr`](http://en.cppreference.com/w/cpp/memory/unique_ptr) which you can hold in a variable. `#include ` ### `trompeloeil::expectation_violation` The exception type used by default to report violations. ```Cpp class expectation_violation : public std::logic_error { public: using std::logic_error::logic_error; }; ``` The `what()` string contains the violation report message. `#include ` ### `trompeloeil::lifetime_monitor` The macro [**`NAMED_REQUIRE_DESTRUCTION(...)`**](#NAMED_REQUIRE_DESTRUCTION) results in a [`std::unique_ptr`](http://en.cppreference.com/w/cpp/memory/unique_ptr) which you can hold in a variable. `trompeloeil::lifetime_monitor` inherits from [`trompeloeil::expectation`](#expectation_type). `#include ` Example: ```Cpp class Mock { public: virtual ~Mock() = default; // virtual destructor needed for deathwatched<> MAKE_MOCK1(func, void(int)); }; using trompeloeil::_; using monitor = std::unique_ptr; void test_func() { auto p = new trompeloeil::deathwatched(); ALLOW_CALL(*p, func(_)); func1(p); { FORBID_CALL(*p, func(_)); monitor m = NAMED_REQUIRE_DESTRUCTION(*p); std::unique_ptr e = std::move(m); func2(p); e.reset(); } } ``` ### `trompeloeil::matcher` `trompeloeil::matcher` is the base class for all [matchers](#matcher). It does not do anything and is solely used in internal [`SFINAE`](http://en.cppreference.com/w/cpp/language/sfinae) constructions and [tag dispatch](http://www.generic-programming.org/languages/cpp/techniques.php#tag_dispatching) Use it, or [`trompeloeil::typed_matcher`](#typed_matcher), as the base class when writing custom [matchers](CookBook.md/#custom_matchers). `#include ` ### `trompeloeil::mock_interface` `trompeloeil::mock_interface` is a template useful when creating a mock from an existing interface (i.e. a `struct` or `class` with virtual functions that you want to mock). It enables use of the [**`IMPLEMENT_MOCKn(...)`**](#IMPLEMENT_MOCKn) and [**`IMPLEMENT_CONST_MOCKn(...)`**](#IMPLEMENT_CONST_MOCKn) macros. The [**`MAKE_MOCKn(...)`**](#MAKE_MOCKn) and [**`MAKE_CONST_MOCKn(...)`**](#MAKE_CONST_MOCKn) macros can also be used. The interface type `T` must not be final. `#include ` Example: ```Cpp class interface { public: virtual ~interface() = default; virtual void func(int) = 0; }; class mock : trompeloeil::mock_interface { public: IMPLEMENT_MOCK1(func); // implements pure virtual interface::func(int); }; void tested_func(interface& i); void test() { mock m; REQUIRE_CALL(m, func(3)); tested_func(m); } ``` **NOTE!** `mock_interface` cannot be used to inherit multiple interfaces. ### `trompeloeil::ok_reporter_func` A type used to pass information to the unit testing frame work that a call to a [mock function](#mock_function) has not been reported as a violation. ```Cpp using trompeloeil::ok_reporter_func = std::function; ``` `#include ` The string passed is the parameters to the expectation. E.g. ```Cpp struct Mock { MAKE_MOCK1(func, void(int)); }; TEST(...) { Mock m; REQUIRE_CALL(m, func(3)); // passes "m.func(3)" to OK reporter ... } ``` ### `trompeloeil::printer` `printer` is a type that formats values to strings in reports from *Trompeloeil*. ```Cpp template struct printer { static void print(ostream& os, const T& t); }; ``` By default the `print` function formats using `os << t`, provided the type `T` can be inserted into an `ostream`, otherwise it gives a hex-dump of the bytes occupied by the object. The type `trompeloeil::printer` is a customization point that you can use to define string formatting for types that do not support `os << t`, or for which you want a different representation in reports from *Trompeloeil*. The second template parameter, which must be `void` if present, is a chance to add SFINAE constraints on the T. See example in the [Cook Book](CookBook.md/#custom_formatting). `#include ` ### `trompeloeil::reporter_func` A type used to pass information to the unit testing frame work that a call has been made in violation of a [mock function](#mock_function). ```Cpp using trompeloeil::reporter_func = std::function; ``` See [`trompeloeil::severity`](#severity_type). The parameter `msg` contains detailed information about the violation and which (if any) [expectations](#expectation) there are on the [mock function](#mock_function). `#include ` ### `trompeloeil::sequence` Type of object used for fine-tuned control of sequencing of matched [expectations](#expectation). `#include ` Example: ```Cpp class FileOps { public: using handle = int; MAKE_MOCK1(open, handle(const std::string&)); MAKE_MOCK3(write, size_t(handle, const char*, size_t)); MAKE_MOCK1(close, void(handle)); }; using trompeloeil::ne; void test() { FileOps ops; auto seq = trompeloeil::sequence; // sequence object int handle = 4711; REQUIRE_CALL(ops, open("name")) .RETURN(handle) .IN_SEQUENCE(seq); REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0))) .RETURN(0) // indicate failure .IN_SEQUENCE(seq); REQUIRE_CALL(ops, write(handle, ne(nullptr), ne(0))) .RETURN(_3) // successful retry .IN_SEQUENCE(seq); REQUIRE_CALL(ops, close(handle)) .IN_SEQUENCE(seq); test_writes(&ops); } ``` Sequence objects are movable but not copyable. **NOTE!** The [**`.IN_SEQUENCE(...)`**](#IN_SEQUENCE) macro accepts many sequence objects. ### `trompeloeil::severity` Type used in violation reports to dictate what actions are allowed by the report handler. ```Cpp namespace trompeloeil { enum class severity { fatal, nonfatal }; } ``` A value of `trompeloeil::severity::fatal` dictates that the report handler must not return. It may throw or end the program execution. A value of `trompeloeil::severity::nonfatal` dictates that the report handler is called from stack rollback and must not throw, lest [`std::terminate`](http://en.cppreference.com/w/cpp/error/terminate) is called. `#include ` ### `trompeloeil::stream_tracer` An instance of `trompeloeil::stream_tracer` prints information about matched calls to the [output stream](http://en.cppreference.com/w/cpp/io/basic_ostream) it refers to. `stream_tracer` inherits from [`trompeloeil::tracer`](#tracer_type). `#include ` ```Cpp namespace trompeloeil { class stream_tracer : public ::trompeloeil::tracer { public: stream_tracer(std::ostream& stream); void trace(char const* file, unsigned long line, std::string const& call) override; }; } ``` See "[Using `trompeloeil::stream_tracer`](CookBook.md/#stream_tracer)" in the [Cook Book](CookBook.md). ### `trompeloeil::tracer` Base class for tracers. Inherit from it when writing custom tracers. `#include ` ```Cpp namespace trompeloeil { class tracer { public: virtual void trace(char const* file, unsigned long line, std::string const& call) = 0; protected: tracer(); tracer(tracer const&) = delete; virtual ~tracer(); ... }; } ``` See "[Writing custom tracers](CookBook.md/#custom_tracer)" in the [Cook Book](CookBook.md) for an example. ### `trompeloeil::typed_matcher` Convenience class available when writing custom matchers for a specific type. It inherits from [`trompeloeil::matcher`](#matcher_type). See "[Writing custom matchers](CookBook.md/#custom_matchers)" in the [Cook Book](CookBook.md) for examples. `#include ` ## Functions ### `trompeloeil::expectation::is_satisfied() const` Query an [expectation object](#expectation_type) if it is satisfied, i.e. if it will not report a missing call if it is destroyed. If [**`.TIMES()`**](#TIMES) is used, this is true if the minimum number of calls has been reached. `#include ` ```Cpp test(...) { ... auto e = NAMED_REQUIRE_CALL(mock_obj, func()) .TIMES(2,5); assert(!e->is_satisfied()); // no calls made yet. mock_obj.func(); assert(!e->is_satisfied()); // Only one call made, min is 2. mock_obj.func(); assert(e->is_satisfied()); // now 2 calls are made, so it's satisfied mock_obj.func(); assert(e->is_satisfied()); // 3 calls are made, it's still satisfied } ``` ### `trompeloeil::expectation::is_saturated() const` Query an [expectation object](#expectation_type) if it is saturated, i.e. if another call will report an unexpected call. If [**`.TIMES()`**](#TIMES) is used, this is true if the maximum number of calls has been reached. `#include ` ```Cpp ... auto e = NAMED_REQUIRE_CALL(mock_obj, func()) .TIMES(2,4); assert(!e->is_saturated()); // no calls made yet. mock_obj.func(); assert(!e->is_saturated()); // Only one call made, max is 4. mock_obj.func(); assert(!e->is_saturated()); // now 2 calls are made, still not saturated mock_obj.func(); assert(!e->is_saturated()); // 3 calls, one more to go. mock_obj.func(); assert(e->is_saturated()); // 4 calls, the expectation is now saturated /* mock_obj.func();*/ // would cause "unexpected call" error. ``` ### `trompeloeil::get_lock()` Get the global [`recursive_mutex`](http://en.cppreference.com/w/cpp/thread/recursive_mutex) used by *Trompeloeil*. The mutex is held until the end of the scope. `#include ` ### `trompeloeil::print(std::ostream& os, T const& t)` By default `print()` uses the type [`printer`](#printer) to format data to strings. You can write specializations of `trompeloeil::print(std::ostream& os, T const& t)` for your own types `T`, but it is preferable to write a specialization of the type [`printer`](#printer) instead, which also works for partial specializations. See example in the [Cook Book](CookBook.md/#custom_formatting). `#include ` ### `trompeloeil::is_null(T const&)` Null check that works for all types. If `T` is not comparable with `nullptr` the value is false. This is mostly used when writing [duck typed matchers](CookBook.md/#custom_matchers). `#include ` ### `trompeloeil::make_matcher(...)` ```Cpp template auto make_matcher(Predicate predicate /* bool (Type& value, T const& ...) */, Printer printer /* void (std::ostream&, T const& ...) */, T&& ... stored_values); ``` If `Type` is `trompeloeil::wildcard` a [duck typed matcher](CookBook.md/#duck_typed_matcher) is created, otherwise a matcher for the specified type `Type` is created. `T&&...` is any number of values you want stored in the matcher. `predicate` is a callable object, typically a lambda, that accepts the value to check for, and each of the stored values `T&&...` in order as `const&`. When `Type` is `trompeloeil::wildcard`, the first parameter must be of `auto` type. The return value must be convertible to `bool`. `printer` is a callable object, typically a lambda, that accepts an [`ostream&`](http://en.cppreference.com/w/cpp/io/basic_ostream) and the stored values `T&&...` in order as `const&`. Examples are found in the Cook Book under [Writing custom matchers](CookBook.md/#custom_matchers) `#include ` ### `trompeloeil::set_reporter(...)` These functions are used to adapt *Trompeloeil* to your unit test framework of choice. The default reporter throws [`trompeloeil::expectation_violation`](#expectation_violation_type) for all reports, with the violation message in the `what()` string. If this is not suitable, you can change the report mechanism by calling `trompeloeil::set_reporter(...)` `#include ` ```Cpp reporter_func trompeloeil::set_reporter(std::function) ``` The return value is the previous reporter function. ```Cpp std::pair trompeloeil::set_reporter(std::function reporter, std::function ok_reporter) ) ``` The return value is the previous `reporter` and `ok_reporter`. An `ok_reporter` is called for every call to a [mock function](#mock_function) that is not reported as a violation. By default OK reports are ignored. See [`trompeloeil::severity`](#severity_type) for the rules that it dictates. See [`trompeloeil::reporter_func`](#reporter_func) and [`trompeloeil::ok_reporter_func`](#ok_reporter_func) for details. The [Cook Book](CookBook.md) lists [adapter code](CookBook.md/#unit_test_frameworks) for a number of popular unit test frame works. ### `bool trompeloeil::sequence::is_completed() const` Member function of [`sequence`](#sequence_type) object, used to query if the sequence it describes is completed or not. `#include ` Example: ```Cpp void test() { auto seq = trompeloeil::sequence; mock_type mock; REQUIRE_CALL(mock, func1()) .IN_SEQUENCE(seq); REQUIRE_CALL(mock, func2()) .TIMES(100) .IN_SEQUENCE(seq); assert(!seq.is_completed()); // no calls yet mock.func1(); assert(!seq.is_completed()); // only first call, one remaining mock.func2(); assert(seq.is_completed()); // now sequence is completed } ``` ## Constants ### `trompeloeil_movable_mock` By adding a static constexpr bool member `trompeloeil_movable_mock` with the value `true` to your mock struct/class, you make it move constructible. Note that when a mock object is moved, any current expectations will be taken over by the newly constructed mock object, but note also that if the implicitly created lambdas associated with [**`.WITH()`**](reference.md/#WITH), [**`.SIDE_EFFECT()`**](reference.md/#SIDE_EFFECT), [**`.RETURN()`**](reference.md/#RETURN) and [**`.THROW()`**](reference.md/#THROW) and their **`LR_`** counter parts, refers to member variables in the mock objects, they will continue to refer the old moved from object. `#include ` ```Cpp class immobile { public: MAKE_MOCK1(func, void(int)); }; class movable { public: int i = 0; static constexpr bool trompeloeil_movable_mock = true; // allow move construction MAKE_MOCK1(func, void(int)); }; template T transfer(T t) { return t; } test(...) { auto m = transfer(immobile{}); // compilation error ... } test(...) { movable m; auto e = NAMED_REQUIRE_CALL(m, func(3)); auto mm = transfer(std::move(m)); // A call to mm.func() now satisfies e ... } test(...) { movable m{3}; auto e = NAMED_REQUIRE_CALL(m, func(_)) .LR_WITH(_1 == m.i); auto mm = transfer(std::move(m)); // Danger! e still refers to m.i. ... } ``` Also, keep in mind the lifetime of expectations. If the lifetime of an expectation is associated with the life of the moved-from object, your test will likely fail, since the expectation object would then be destroyed before it has been satisfied. Example: ```Cpp class movable { public: static constexpr bool trompeloeil_movable_mock = true; MAKE_MOCK0(func, void()); }; movable setup() { movable obj; REQUIRE_CALL(obj, func()); return obj; // Expectation dies here, unsatisfied, failing the test } test(...) { movable obj = setup(); // test fails when returning from setup() ... } ``` Using [**`NAMED_REQUIRE_CALL()`**](reference.md/#NAMED_REQUIRE_CALL), [**`NAMED_ALLOW_CALL()`**](reference.md/#NAMED_ALLOW_CALL) or [**`NAMED_FORBID_CALL()`**](reference.md/#NAMED_FORBID_CALL) can help, since they make the expectation life times more visible. trompeloeil-47/docs/trompeloeil_cheat_sheet.odp000066400000000000000000001520641454452461300222040ustar00rootroot00000000000000PKjEJ3&//mimetypeapplication/vnd.oasis.opendocument.presentationPKjEJ{G,,Thumbnails/thumbnail.pngPNG  IHDR3MTfPLTE """,,,444===CCCKKKSSS[[[ccckkkttt|||:6+IDATx]㨮JbOrzwIUllct$|[۷p | ޸m`o @r&F_dC ƽsIk8`4R`1~_ 3c|bb6e796 G1{gL )ifQ-,S42,|Yd4U SFp_ILl*20W+Ѭ +.˂7O ET@~*F7n=LbÇG?e z^MĂβUs'^(C|M!'٬V!6YoR,Q-𽦏dK1$>0z)KKv*˙8_)UR>ўO]-Hvp9A/m0U]Kos@hk^O{mwM"p A[@ Sޚilx@,4$S  ["- `*ǻy( ߂J5hKK+$1.--[]/SI!_/ H쵎⥭&Lmrhy}pn.BQWTEʶ|!nslS;/%@h9 Lbz?.k;V@1){ŃKDFBB*4M -MDnH `i|6ybOP;c5]&--~[&g;;LjDYɘ6F)К_#K"8U6^3`jƚNj^.*H]k\\afu)t!BA t U-G]2*m[@Z! cs*HAӦ)fKKvo7 Ƶ l` W5smm'mA"#6nՒhf"gv%B@7nmfe}hc:&A$դMqN*t Pͥ%U{s\5C bkKƩD j6l܏ =}ȱX4`!P8$4iqg Ѯg8$)%(Ys^0 M@;>(^P k%0se#gIR b/{.E*Niem6M$vMƢ05J$ͬa4j4z\b;hM4d<;$@3wd7.e6!.N\\x_/=CEFX7,ќ H"'ᐾ4g2)lfٔx%4~ѐhN!hE9Jg=iۗ{ѳGh/j-럸t9o6]Dj= ;FǛX.St hͪVr-˫̽Xj jI䆧^JvXJ`2ͱsbRV-זdihG1[=d&kyb8f@BI (7sT袑PAf#f$gb ,*ŕ[c<J%@c*eD,'ep#JL`{q:SP O` Ғ&N_"o њѫ^|uHkxo !Wb8&U yCk? œ0 \H d.& 2*\(eﶁ~Pl,YDI"&M ikEqC?0Oe@G' T[nbJ-(Ikh@k;2ລHS_ͦұ)=ښ->!ͻ=Qb?]`ţm{Ih{&{ G!{:nJZ 9S(ZG3\]reMh¹(X6 Qp-' foU}C,拲en%9ߛi7\h^'9kP5h#vUFTHPDԓPc_xP~C~~Dp@߿}'\p8lGO / 8ٷo)gRsqPUng$ٔb? ld@F\' !y`d%u1kXuQ ZfY#-Hp{s2~xp"s(Zps&~;M/. _TNmfs+f*'@(-gwYo>/J<#@G=@M@mM5(U(e$Jv+p,kW 35PP[\hm+ʅd.* vSxllLڛhDP0QɀZ0OAXRT7@T)<&JUlkh=j;QJ3"7DF.žrNX`طZ`FԸ@Te5h+G25]ʣfp,f] hU']M ]?l'\i308É@93 -Y96¤O8#{m#H!y2)52)HG,*Q[{X.@n w G=si 9⻛mQ^{.L1tTldţ0md1I6ЛBPPE @1΂ !UM> ÖK7Em`)P Z"@y3Ż{ q35x/[_l_P\IOɭtS~64gn CZ, t|Էխkpk t\V7M emUTѸV `ϴ>rԽm`}Ce P5'@8!Ӝ?V 8G_m` <}X]V:qfb%> eaNkE;E"ٱofB9,@hP:!O@6?w~27%,POM \ "9@&I>FY]:r>$^F)}ݙX٪эN@Ȱ$TT_]_V x Bt-H*џ@&2\w$jGP `^,?mgꏵwolwNa ZegW}}U?BFO@EzrE(L W]V{&W PйG~=ҵ|Jo`;j}Oo߅— {h{kwzRBal<6zBS/;xp@EPP)(@5(KwP * ЏZ :!b}}#$߷THËBqB8XR8k z? !X 8r,<&'9p ovTLJҜs(>yl"P1KشzknHpB BjBwiB7~v6F``0cۼm= #s|F!!ȷ.bB!Zq1#HT'i7"' bGȀP|Xę#NB?APk'I /Vj/ wA@Tb3!F##KQBΟ W rzd!~~E_C/$BeЕkeӎ;o~orSZ.Bz깞v>SN'7'|^qih: M0P9 t'ԵCED?oRV   9 ks{`&B )4 .E<*p+ t|5v&&Ϧ{|$@8 ڤ8K!aA#t86ʒpm4} f՜PuC>Q@n8 +BHYBXBqEcwg!yO ܫ-;D}"v>yK]cA1B6 'VK{cn^u} O8!(@l=BWd{mR-(8S<B2B d]/|(O>7=aP3@]¦@H"*id]BA:g6QW7{d#=D`3 ' 8oxB$$Z9DIR ʀ9+kC@ LhX\q:fǿU;N1B!Xڶp|ki%#Xem˜e9E#nw|3FH&9_xX=ByCcv1 "z oQһo>^: qmI/goWg#)qI)ͺ$C}띹-./Y ]&:&Po;+S#9h2 ssvά(*MfZ-Txakͺ`6-w#2fhS mޛb Qa^] x. J[4U4Uv֦)L$0LIZA8 CM*H-m@<;VIEajẍ́C]$-yE6V$Pi) $1ɞD6he#!R)aS@VM8kMZ`'0,|_tK00# /I% ?z8X*L8M J1 ;hkgBr-CS NibVu5F ihZbü)TXik%,[ApބKirq^- .<i.r,kk1g!R\,VaL|1VHX\3uy^ Aٌ¹d%\uetEϥ^sOxRl]ЉL}.ytY](v%ъb4RcŶ!iv#S=N؜jEEZV/)JS;gRbQi+ Ã%s%Sޝ}KZ@d[&811+-&Ee #dX"K574G*-Ǧi8jlfʓ/]4AuT(u4Ŧ*K-e m XBiͼ@4o3>AuytAQZ ^1@۲_ 4H>aEЌ@3eQ L24`I{q[,ZFnA@T J!q;,xj2gN5-Oa}uؐUicIf:!Ķվ.M\Sw@Q-ȬxHY'K;KO NHz( [DJs/"'c~ȕ9ezx+"Wcn⍀Fu}!@o}Bys-5#,ElG ŔSξx*^5ʼd|c:Qa>ĴHTan=$uy{0i#j6BqƴZm|F ذzޘa# $=~}@e5r$ja 9͌$2ilS@D&2ː_e~;co?~7c[7~a5mmlH;O.S&&_u3b": $ mB8u@?ʨOts\%UX` ,>^/oʤ.ɛ0{e]jpr xdA;YN&1.AիaMA鈹WEe.ZiU𧬦_yF?B1&TTgzu(>q,!\yu^Q*V9hMr3y((Z^G^mnrv<ʈ%KmBNNZ' S[D\cgilY -J6n$ h01';Ms{4:T~/ӺKͫ kزk- s`Aw °`v6XhyXy,nphC!H%RBG,뒂)1!lՎ$E;"-P" ~wݬ˩Ai(2A-Q,Q%MࡘE3sļڛQ)Bl> ;yUg y5CH#U*6O^1@p 6CӴ=h`jG*/H1 ͹TU'y!?2$-nOan/d%\ H :9Q:`h @kbu-ٻ/}[ y'TFQut.P/}EhhOֿ揇~s)u:n"y|޹ϓū;'QOC`cG?mяdKFT#ֱnb5֜xTJO5KS(Qbl%@9Q :`CJ-*Y:-@M,#G.hMx.+adI:}wX3b 8"xw cM[H؉na~n,#H4 9sh6Ԭ#b,&/i[Zqhd*hhH4 YKqyWZų,ah*T@ ‘G^4~HD4@:tNVhCKxL'9# .̉r22!О#{j%@2cż`$$u'u l522C}Z3.|HIbKQ3p-RB#5m=@AM-f4mĆqMZV> </z1MowbߒWTy<(0G#&nu;:?@"-Q4JI~V1_>ϥ|n]|=BE*Ƚ6[yh:+_U7!Hj1F}5|hB:kSaSgul2aYL ł[G%w!JEImCr:B۾`;CwҸIj6H0æl~ F3SNͺ5hczDS$?jHQv3%at<]U{,MZ]P ?`F{q7{/-gP? H(cgbJ?SFRT~P!q~H{6M,CVlV HO+lmNZƙcu{;|B H tįcdrܛD6Oy*WQ vCE/?\?p7 I @{&݉͟~}j:#=F:o0o#_J?5IENDB`PKjEJmeta.xmlT0+ݫ16jRo1[mRU\yo̘6 SK QT\ w|z┑ZҾe€*TɘچDVk"ib(3, SmØ@8 C4$TG<>;Ckzuj<5)h"gsx)]Z6[ߔj,9ZRʳiG8N=u˛[PvV\þq}Tu\@T}x?m~>a9oGYPż7`Yc1(ۡ$s} x1Va57vA++8 HцW)>L0˖|>,{?oVU,NgFO=dU;>U^: 7+,eemJR^ >'59cĕ zMMDDt>(E!W1/\f/b7!"/vN^Ag {ΑX e&LB"CNoQ! 33J}|  bIE0?&F8Bh:[ȒGCZzM@ H0|Uw LQwGo5\D=0]T^]fJbV ym.*H3G\ғ)RŚ6ܔP]j$6K]cȒh>R}я]Y=3 (KNۡfQ}p<xJf-FES#J$Q)RDqqw{UGPߚY^YxH<q?5+HȅU,¯ҀW.dusΩ*R1*uUPu,Ԩ+His:XHځVNtT>X2 9$+֖ӏ䫍D7|ſu4>![QU!FOp^}z}`AL;M<{Izi ӟM l$>ӕf #q-eryU(cL}y=MbHLe@"*)Hhj# VOd,PHJѥ"7+!/n>!Nk Ca4DدIyZjs]Z >NR3)]ٶw2&u ;Fb=q!,d-)c6@invZ:AZj(#5KX  |#S,&Ås lwn16 c6Pk٨g[T2;ylWlؚzE̙Kofm9b*Sz4qa2]\us3u<5gߝFNj 19vӤa++mx!(1O'S~;.~ AWf*ðl}3@b\/_-wdu2w=莮þaTZF?[jcjoz;̚R+s<{f' &xגISDjxe!V^spBD~Vf߷PK7@(PKjEJConfigurations2/menubar/PKjEJConfigurations2/floater/PKjEJConfigurations2/statusbar/PKjEJConfigurations2/popupmenu/PKjEJConfigurations2/images/Bitmaps/PKjEJ'Configurations2/accelerator/current.xmlPKPKjEJConfigurations2/toolpanel/PKjEJConfigurations2/progressbar/PKjEJConfigurations2/toolbar/PKjEJ styles.xml]KWos..Wq\u.$z)ERўr!/$x((Qpjw4h@{Yg'> 50 ]QOD_ޡwჇ &=\8LX棶?y &"B"mTSbt _R„P[bi/„c*#/IϑUR??j4fclŋ5N47guP*ƒeX}N)PЊ, Ѐz5aID/*y] zFxxbHp&Nj[Z,Y%`ڦ9|)r#VUa:)tLT>{RcZWЖT5&K%c8]܊e &rEy7_i٠^{@M"H,OhUc7Qċ|*u~`—>-PAQe6 5&R"UVJt?EBJ'OINfDlv\{ Γ{3aQ =txlo@o":#?uś/}LC>a:'4 qbBã9= gt58 L2Zӄuhޑ]4,$]rvZ-F+kDMNѧ2P8E$#s]ߟ K$xz? 2Ex)PuN~A)b{RdZë/[dYVMY=w610zQ3{f6{inĥm~9Xk!A]f/`0'i>C7 } FC0s?=WC;"X)EV:X(Dpukjhݸ7UD,?Cb>wWs:ZЅ~A!(Z a H`7`PQ>JҮoph3$x L9F'o \'&xƸXW< Ӱ2Fxޗ%Z?Rnltr՜Àu2I:k#҉Q+PspN#,@_f~jM4`5eu6>:k38G1 BNkYLAMak.sN5wj-"tv2[h Wcw; "0Ed[, lRL7(Y2u,!+o4"S#=)u+jIc-f! BSh󝝐EYO1Z/ betH<t'.節5| ,KVĕoKq#b«d}LY*7ҍ[ >ޝk9)yGˇ*fA@!(:JD\X*rN!:'Ph FR +=WdAfvFAp~pzٟM7~q}q+x=8=fXC̤?Q^;ذfɛL9lٳT:Br<yD?IG2a!"]"o\Olu)Eb3,f Ɓؔ ykrZ$#<48>A\N:ْd)E84aPQ"k$=2TviS}jwͻ>\i\sםNoT9ke=`XAQѿX;&%޵JghlQ1HE7 kP5LffTxrTDW$㵼ne]_RYN"-7ؠC?}d7Y\>fB}]z`⟹B I;re8#R isuܾW$P ^o8QڣUzw nF<ϯqlzږᑛ|nN4MpD~1\/ɰK1\C~ ߌvQRV2~:O{HDsRJ1UX*16(9"ZbH* o݆JZ<D^ɋJ}o˴=ZtY'QI/#rYKqwҕkC_1FGi@r WTSQnՌt]Ӈ=6 ΐ. :. :ꂎPt/n-vؾ=vb[l6Bb[e+Y*=w$wّ[#Pu= 4pZJbbPdLƒ)U_x3=<&;~OiS4-.׫Y 1pbL ‘1`CE4 LҴmr-_k^<:_1h[ RTQN05\' vbsWMmƹN<[<+zOVal?m]sOhۘPnƏ5]@ţe:_.& XfA@qҔ`#xVXkn̰IgC,k@oK%wk Ԭ=C.av/ʶ5w/+`6VךyVYEgz_u n|m"usPn=̨v)ACrygߙ<3^Q[-#Eܵ@z jL=at ,*N+WO \yj:~;[d|۴Zԭ`Z1[K-0C%k ZW b lZҤқK9 齉4iz &a.m3R''[-Sݺp7<@ƞIt+lv{Cv,+c}yCNIJ$W:׸aLv#ԝ/o,,n?Hٔ|PjqOS\&vM$Y`tx:dž_~1M辘p-̼s0Az..&׮]R`d޹6d|ɬtk8 ]*[a@Q;0 mw=7eh{fA1|ztIwVSO*gEI͝zNIeQ1%{'ny4&Ci8%pCh{mS?:mHzlsyF;RM] 40-SO ޻ ?1xt;kVeMIgnl5v!xLOه5u L39ם#F+XhovU57l~m-ip݀'j%AnU wWB =/=Y^Fx{$1x{Is9'Q*gؓlZ. Ol߄!ۺ{УƢʖ/LJmq 3Q_G+1ӕt3-s o?0OŊdƶm#ZdNa-<UN,$; 5!eBr ,)+" %J(_s " [Pkb7lNqd2.W9C,Ɯڶ 8$JJ< y\oX"Shat ,R8h hhj5J\="jIlHH>5w-s.Ա2 KFQ#8r;*cmĹR9;"iZG%ɓ>q{LAči?#ң{ڏNA̖e$t=搎ݿ$V3/O};McLw~ST+)WaT$xd-usg=w&~#La닉𜱆-u´¶fmm2n]M@/e[{pNx2N+B—l2yp$>7`Ԏ;6 ]tغ'GvVa1TJ*x+q$ 4mznzo ΖЉ!&̉0 vZjY_L T,$Ep-ӏurnh7$[؊UƲpD9$3*+ݻOD%<6XAIzS1>&[/@?Ɇ˞M{0r>GmӍ%FYH;_ACHBO!q'3x$$BNewVwxrZ!B)IxGI/KPghkhkChG[{G[{7Bgba8niDq;JA><֗8:\$Jy|Nں`oJ*OsE-ݤ[7-;06>?W}/=. w]ލۨI} ͭ >M5)~D1Ly"W S\tbgEXϧK8&~%oaXd6QNjYWuB;4^l2CF`)\xK|%|#$C%V;14 щWf[nr;1cfiY"%]cͭW?]~'<56܋fɠfζ4C*(M3Dr9Շn7Kb, m֑ HYb&uīBn8Q;I"_l 壾5 m). mɬ"vr%R[քH,+R 8bGz*b('DLbbbb5yLDQiP9JqN3<1|E ۹*1R1 M 0 F$ $03>^㗷xussPy+M fG<BջןT_RT$ vZSR41@|">:0JՎW+.+ie{ӛ|pU;=Qh E(bCTh.C9ß-LFAΥ+Y^f|{ ϙ Yb?`q9 1{ ֦Ϙ`=1(7ϔv]SZb;'/~w.D/&?,X懅K,e>ͅ=h'RV&/aN8&ɱjb&OH)!~E@/W4Hͧ N*A2YNHW' orijK0 f؆ ]K8nC>72051_N@RE͹xdПXp4e$+T!HC`| ө1qK-L 8 nD.JK|}^:15iUT(0$1!qڛLt6|]1]߹ H]125gJHb׷;PŰ{`mC}$޾|R)Գ{@fHHA&>VDFSA@^{0C"> Ψpnïe{J J$$̍j5k1Q, )He5w(2wTmxx= A]FPF!kjwEЕE"t6CjIՌciG !BU-@#[444)jdWAT9/mBq^ Idp\>C6+ũ jG.C2'.b~{ږl:#`GjUJ4NLl9jkB}L s<V\{?ۯ+l޴(6Nws!L~.x;y's V+֓SR뉃կS!U4*"4G"UC<69>4mmr!ZT=@ɧDObP?P%6YdUv}@ͱG6VdRAh9,r@,a,_OlR_:0BI KNucXRނ[39sE3 ?/j}X7J[qZI0@wnZ֕T(!Gd,yć-%Άܫ bXGe)_%/ռEk;_}4xv0cΎMJިa=Hq'ZR1e>,fFER?$^OxP# O&7|7K$B\L=!PAָMgIJIō 7._ 4Tw1S[Vn+ĭBL \9Io]wZL\P4dxGҫc$dV[4+ |wH%Hp(}4B״[uqQF Jbޗږp1;Q>#3d#;E23ֶVtrcȐfOwnI=L|tE07\i 5ĩ 'nT-9o Zi߁צwpМ!0>8fD A%Wr%8#XSP`LC1߉D 匈ѓE[GbuHzCDEC 0 ҐC0X}(cWh-# ̷̐=6U3ZaS -DW>aӤʡƖЪqZQ*#m5rtZjb=IӪfӚT9\+򫸽oWr]RMYڪT\^h:r¶1$1|xzF1$Agr`HB{C2J[#anyh@>1e䊥>dHZvq~hA )?||8(2d֤jb8(4ī 0_  /6xX9,w^MIcG J(- J(=J P)R@QJ (J'(Ghh˕1 y( =V|)(-6PܲmV9<ؚJ /Q_IL.P'zzߴoݐse֮FKԍoJ=V@us0 2;!l9Ԯ W`u:~;u_uLz; g ::kaѬ9n&JlEDI,N&sXKBԍ4`5&|@7VI},3Rt?+]aV2 ]r=1 o&:S0'a4{9b:fGkI5Z'%8$SyErBPzJ1{yI8)*l}1[=iǡqC "=Pyi$Y9$V1Mq*u>s-\cn?tn)~-{UK?)ɛoYB֙X>sOۿ$ PKgK/PKjEJPictures/TablePreview1.svmZMlTU>Ж ~v4AebF RRh#JAPDq;&Ƥ ]n ;c&wޝ3=wx:yΜww2?0j@ϓ9D#>I:1,޴Swy7} L8KlffӅČti ѕ6K)8XG#Ù}C{3d_nd=?ѩ㓹 3#fѫJCq(}V>BDŽ!qSQ>pvޣjf+t_`wHtrx5䙃颯U[UV;UY*V%ܪenU[TWc0z b|dv$l27wv WE8Ŗ)s]DS8)D8ga,n-prU B/$@H!z2MO`d[ ) |{u|*u* & (z_wX C|mqwg<GznnLֶ'MEZ'jY{dDÜI  f?7\0k'+*GVDΒEׄa^ |nlK$r<_%^K eL!U%J\܎l7?GQHKe /@^ynB;O|+㋴kyWÜI  o6tt2#ٚ%&0^>Ycvj Ϙl-㋴djY[ZÜI  V˧LTe^`ɷ,yѫ5r4Vw-_-ۡ6oEx|ZU0g)DBZN-X-2#ٚ%&0^>YcvjYvl-52Y RJ{tކSo!3 n8zXFďN|a|en$4Ќ[Atd%]|pCg/Y)[t[ܭZVtV٭*Fp@X]#ZqPp/u|]7t?7zu#=cD_Π AWnqZݪn7*WRQ0}N {LoWz!h#Z jnV1jw e6P1jz*av%}мTmOSUznTST^ygyf6 K#yw&1bgYDx#"BDfu׽/^c ч~8^__~f;'H;AP~"">?}gp|o'2,S|H="4#GX1}Ѡ>TNꫯ^c~GC.Fq!"M3D1Ho'K4)/2c~W1>\q׿&k's/ow72$1Hx1HoAj[o5Y!>jӞ|k=ӷ^_诼4zl뭷ޟ""ŅH?~ ٭޺ gYJ+tݔSNz_&i:9݁xYgVtDhvmwbBSLƵ^[nyzzx2zW&-(ˆ{7͍SO=U^,o|޿¬q+VO\DK?{אߏ!Q O`76~;hGv Rr߿{zhZp-/ҷq!˾Gqsƕ8`"s/M'to'|7waDZ%[6:Z{7Qp6xs}O"Ux0>O?)+s&L0K/MW1A.P`zyGq ȹ_єf^GnJWZ:jq/]\QG;i1=iUW^ _"wFD Hq xj/5q7Ȁ:"&G}Usl(lEQ\H?Zwu/VR aom-=<<1_}tоx㍿!u豱2zm=ܳ(3u|v)y2Q]wJMd0`tziHEC7t&oةo矿a9 @ԺʎsJ$"݃7HsE_XN^uF,bwcoe&Uݓ' -_xx^r 7</}Rc'ads55v9"mQ 'L#Ek:"yeߋsk^^"VdDYYr%@&T/N$ֱ7]wxD皍ZBq!i$(Zjn&iR=/IwP!_'=b*3Py‚{dW1ETC,rR3Dw\ [{_9$iPٹ%Gq!9&^l'uYm=Sa@l^.3xD1^X;L$f}'I !qE8F#9jqK9~] M7_}ʲc837|bvs;;rs=bo^FNx qECq" B;,RS70@:X!/N!v||~/;t콹o`0!,fHgzG;%<_ -"BG+ֈS?(?'ŭy/ڛo!kځUvL$D-x)E*(OXpOP{;"R""݃BG%e|lm9þL<÷~R(Q 3xV1'}Dҋ ??YMc.qT)&j8 rL]Iw:ZDzŅHB-Dl,CtW6.Zz{ 6.)x^I 2RIHxu,b37r6Jlh H#Ble{^9 BF ~j37qVkeٱK.d(Ex*˽'ݐBp>+B'CfyqOR[AYv$Aq!҃*㥤D1ye_^!v-0D.8^6bA R[@;^[u*/7_I'uyމn/%@ВvcE1S GI KIV}O‘fȹoj!/ DH"ŅH1 j% c+:Uc(|DwygRE1O5T١xy?Xlz-+ϱRc?LN=$o1=1xo hH#GU}^21up#يBq!҃*>ׇ E[ٶx)$9kMZt{qUDCT[nY6>Nda?Eͻ({\3އ{")ffQ ;XZ(Q\ yaUW-f2'%j]CvY()0)`E a߉[ouTKvVwSe!&$;".0bqH!%*#Cq~/E*KTN{25:G-[IA#ZxH3w|U{C] )\4D~x~(: _3Eq!҃Btt!-VzD"q"DBOjTlţ堛F-Elb[JvY0lè9xsfljŅeo r/3]-<}@4"r 6;BÝ{mDXS^׫gޛ젆O,087!:Ut? }%bO) [n鈂L<ݲc.˾9O?}zǐC\0 1/{̆f1ᴟŻ|ꩧns'R؏N>m݉V]yE DqԂO?=$@;GaxM7-_5=~Wq\x>{^s9g:_9!j:j6Ζ\r;Sk[!^%l)!@6ԀRBax}Pd zjF- "0tx_HI76Q\(Hogy }Oc=DZ4dxqpr!w:DH(J#㜏c=wDiH:!q!,Z)hY=C{\J\9Ep,wq;΍O>"= it@ 0vtM  UG jkpVJ$3H00F<Ԍ 1a[ O؁c'dq޾(Ljl8x9VuؠڇC^=lذ8C?DC "ދ_")]&>R=i_th"E^9q {Dnټ_;e6HgaXӛgc$3^VD"38Z^ 8=3H*z[B4I7o$Oe`qRBqǐ!C&ڑ`ۗ'7*{oM;T콹CD\p7{HEUI"'GŅHoq( %d喻oe#Fxt"T} BHjꩧ~NSxySmnAG5cǐ1u3[QDSq RHS$E`(۪a=G>PBnVu""eQ\&|7~yI8#vǰШi%]x衇5)$="K!) EP,JN^:= ȳ65 s1;y1rcT_[A< j?iOn{G G}tn"u=UWXaܑſDS⺑UuJ8(ާݳHQ\HA:6W^yC#0DA6Æ^#4^o ZOZ[ \)&=# * 4vY(H|jx+ޯ/A f3/%^o!ĹHPZD#tq nö~ʾ#y>g}lE4q!~{sQ"Dڕw2)BY)|ߤvq!ʴV;(/P>e? sY"](.DGdCF< = O"VUB D&000 Vvbkq 3SZ} t2Z.#q*і T-oU!2B`sw~ev.}YDC(4 ܇~.Fwy_(.D1@ڭnE{z=vPCa/u!xn٠,+\ųK O*|>b c6IzN]c>""}BDz9<38c c x8ݹPXH_n[:x&s)t9H@q!"= /0CPDξҥhۊ"{S@z9{!"RgI% bȑ{G=*|GzuBDDDDD$(.DzoxGn8DD1H"=s5cO"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!_<@!"")曓{ "E(.9kDDDD IBʀmDDDz Vi' i+~נHB\[x񉈈H"""""Ņ!C<=|~3tӽԇCh^zYgڗ Q\H[8pZy晟uY񈈈t:>׵^omi% IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IBDDDDD$(.DDDDD$ IB:!C<1H9"""""Ņ$Aq!me1jРAe9r~u)""R|;pשּׂo4⤭|Wc|Gߩ!mHW13?o"""""Ņ$Aq!meꩧ~uz,})|}Fc&ⵓB~=iŅ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\H"""""Ņ$Aq!"""""IP\nX3|i} Q$""1b?^z}ꩧ~ukcP\W^f5ָ⫯_~i=.no_jذa|~;xܾ{hM;'矿a&, V{aGyEvA{}-|7f1/(͡ç hkPDDD~C^zUWVwy[o{ƭCq!RW_}uhXDDDeEy睷[lq",ro%iQ\!\(.DDDc?~_<_zo裏\wu+QB]G*rMU\Ԁ7xcؔSNz#""ҍ>[lU(wҎ/첵gGx9Qw駟G>12~xnz_rV\O>5Wcu.u3a؜f_[q!R/rXcE;"""ҍ\x5"-Dc)-.;W$tc1 _jnc)'ną-I?=/h .lH8>Hk~r嗯ndM)zdMV|,NQyw'{J;+.(.ҡlomȑ_{_PsGn38)(NkDg}6ε^2s~/?O~h8ED5[`-<2>6䓿يG 82uYb /9C'ơ?oPO6Ӿ\xzq 3 A>jd"Uz r6p_.+b2(߇#By.UXEP;2U?3?qu*E‚ Bm. V""裏u|u}? ablzjR:jrmygqE{M5 Q 4 [?| Q:(c9fy6BbC85*~ary⦛nZ",ro*qqmk?>gtH"#&.oÅYf[}wޙ4j,EK/4]th~6#eV ~]}ի8 %Dawz3?=CkL"EPBĂ>q oԫOY}կ 筻j""wL8‘Dwv G^ˎ]|Q6YeH5XL*,%׿.tE[1y%QZ 睶_|X1iDs=t.n7C+_cCX+.DDzjBqA'F8J4LJk}ITHWH..> 5ȕ&':Iy0PГHQB: D)q:Bq͖y O..ho ֞"Ralh!l)M;)R-첷JڒCgއƏ%U}veǏM*.{曗 J&";{S6k5)h~m916 M|₍⃋.=ޠ,d#F %y38 /}O_ۢSI'=5PEq;6z/vgƀk댎l)r5w}w #I&y{p0{;gy ko,s=F_O^)9Ç4`Ce˱pM1aC-RvޅtŘ3vX`4@Vܛx1짚j)<^#M̓6Cه\p!D؃c:LڀPP4<,K;|t/nNg+z, J+t¾,L,5F[lb|C=KNlT_]O;7Nq+&o>wFޛ34?Bqؾ1)kuG5vw,o1` [xHq [ g`\PC[篼4\3V {:ggas饗'to_|4y{VNϰ|<뭷ޟ=ctdmiii3}ѹ%^B{t?Nf~嗧k5\AOT>&ӟw kV4hG)E{^t`wq;2qQ0NY dѡ 16$88hAUēO>9;b/B̭޺ m[Bg >ЏUEwf{"$|k)9 +ܐr.WOr2|p~ZMr vΧ4'qusA/V/ºc/`pA`׿_Rg=3bl~D6 k*itXRxkNz#$%ʮsPL ce\ưaڂ>vÆ ۭ3y—şMy¿Ĩ+C/*rMaL xROZp߆62>FZ>̣\3D ><%ZkR?IQ=bU> MP 8ꨣvAu%l)DfS9@9wOi#E{,`cIé i0 psz΃HMpHz'{ I06uC6m r|~V^yù8՞] z0+*co*-71ZBNfSܥ"D=w-K. !N-,-{Kכ߿ ΖP{׳.]"9\>/^siъ6$%nidM%TFr=a!}Bl.[wpnhzAIŧQOͮ:fߟZ^(l EH!7EzfOZ | k&fcL$C"kc1j+Ibq&ޓ'4NcK o&ɸf|1nŋF^݌d5ָ"{p{v8VD%!xclPDMS1\sxXd'vVry?օpP5KFb߹Y8wtMc@A󹮸5:գZFZhhM΃5v6cb5C\G\oB.U\zu*iy-DֻXX` q2dn~KqO ̌yaRbHd-uS[ITy^)=(&}[0ؙg;v>?i^T+;d:p]U}vڴ!|^'>DUgϸ.YK^Dĩ,%///(Tq q!dQ, U|c?cg%I{7 -~螵D"+F#K t%1C/N=!wذ7KaL2b$,P,Z-ƍD'=͈ yfg+|m  b ;M*b/(\"0n'i{ bs)Q#7Q90EDY'@ zq$쭄qHpW}F%,X<90"FZOxgօnjߎ y_YI&g|p5׼SP= U@Ļ[Gp9眏98Niq?c~,etI(Nyfc@! )|N$O ̼X& A<X3oG"N6'&G=%5s1,2&.AL KRa2`ģc\@v" crءQ e!\LX8Uze+tMvmOˁUh zx74Cmpu3)LxM,&T 6;3F U6q>^-0VR@Y0~YcS, 0 S/]8ˤԲ*DX45FE#6m,FJg=/.M-b_`hݣRڌ,ju4 )yCGS ='".š6@P5ZH{QqA]X| C87S c5>Z -$~ vRx-⻮epւ|D4sS|_xIA* V@sh4jӆ9eV3prz"'.N]76ֳqB0u7[Bs0Zc(*#&XA[y ZfC1~Ny{DuAC\r|#Zoo"A ג?{T/11Xd*U+  dND7'.XhT7DhjYDDQqsuW8Vn=2ea=#%6d>{UM VHɎa0~JDIn㍈ "Xq7>i1yϋ0KƞsR *1qyN'Ml;k 2ge&-ƺLq~: ԃ#r)aioشA y;c׃HZ^C^3Iʈ* <=ԛ0qOU /I^אK2 )]ܽ$y骲/@kW03Ry!"Kx#ZccP 2!RWB&D+cNd`b3ěE,.p[2Xkz3(5_Hj@9#R1a)Nf;"V4*JqoZ`^`BμeyOP\AD\4I!`<׼TuSD,)d xQ( ".nk E9U@ssX0ZE?1{RjǏϻ[jܣ J/4c8kuw^4L>hSoUE^KTa׫pr}Xz7~"e^'bTQh~hx2<uȇɇ}*5$fWy~*?:?E (jD-*豸kF-zJqpY1FT/Hy#"/+ |V#‚=nUͺ0 kQѽ(5aSqp#?6xn,s,R,Uߟ|zvZd]#"NwfQqpYL'g4l-ړ-/LZ9:-" CBH !(@{+omQ͓',H+àJ\h6d_X2WTiO'uEybTz'C'v@́{\-…a5ʈ7ECF^Ob P\vWӮLq*K*QC5/7&.BU 4{8/ÆbZ #sЀ*5t=+ن][F\9qs=4Zsb3S *uUEk[F~!0c'/ ~7ldo6#˅mtK1Z<{-9qZzfU浼:VIǮ R0[*m Sk}b$C‘UӅHra'<1D&esvEZ:D䢇Lw'lHUaPl&y`$yTn:.2~n3^RI'\#{t* e)k͊%.&ᒷk琶v')O<邍IRiy3M Ru s[H !Wu/2!敉."bG2n"~F=}hjh%+WN&OX6z\OdprѬ#<_tURBAA&a8|p%g p:"j[E bۜ.7y`Q$a̕h- %<-I) `h4/EH5\"c)p4e&,<e(zdCx C}1!z ES1d3ixB@dJ\y\::v] W*~|<;*Px%E-,v}¢\)(,ؤ n!S#6)ɾj(.J5)*y5e 4GblЌ-p^dg) "ӡI=# i4A Ljo6 `j}ٕ>ܦs#N:\*]AW^${ ]q⬦^#tg0g#qF䵪N%)KrqdV\)N*ad .ZTr39`녞 ;]6xh{# zFwϛˊ )Vu.&{Ȉ*ܑ !\EK~x}gCz窙S qcIc,,Rymy%QBZ" &jH !(l2I xC!+QqȰP/ZS%](.ZK66 ԏ J )͵&}"gꝁc#6/md3QbtE #oQ$Ixm:jg=!:GQcTmïz^%x#yM% o+K(08ߵ qZQ0沼2(wl -"^bۂ5Z6G lJQ_=CksQV`pmw6GifqvYkqloCއ?\]`S zFٱrpO]2p7[|M0G8p>Ԥte9yySփ=,aq^1AxBf<-1r!(8E'DrsqMz,NLF\\@V+W /_4a`xzrH@gQ{Ee9\`3"pmx)ldj &Ū"9l@W+v֥3I\Z)CN:E?Hg)҆00l!xv#y3џvԗ1GF'kZk76DV̹9X3wgɈa-]Ka-[)%p;c(L?#88U92c [c }/|R<8Ҳ)l@q A8Ce(r~1芘 D4R{إ=aO};ՙB"v5;o,a`ah EN,,t`RhCYfq baÃZ9<(Y*a=^/ m,DE \|.誟7u. ,@kĂMcx1p!j.t#EF.~4 9Gu@t эjA%#W``Ds#,o0;7R(.?A7%:Oj柸-zUC,T \ELXf.@Lrs=ia18 {Q'V}g  &R&P"u,Z`gohۨzh$BJ PX]XpV M}(s'i.+uUKj?%c]벐1qu*i U$҅Xd\ܟHイ) RPuwܳy\yAŹc@ 2HhsDqU|Oa{gzŅH0ꨣ~wܔ(PGqo?C&*}ȑT꣸GXDDDp6pfHKj(.DD:"q1餓cF}Iݷ'h9昝Dz^|l 'W /P\t Wy睏?K7جL+P\t eQjN{wܱd;Q&V?E).DDc>><?7ޘ⮻Z<71rLL䌯o_[iԊӹɅlq3βEscxTxQJm{# kaYY[vy&T[Y4rET㥩86F䧡Z[̣Se|rPZU>YՓ sRҺ"^߳\mfxȋT#Pި"o?EFB ^턑AvA{44%Pa zT֊EQR{'SP/O;KP:81f9]Gi؍jؼO5nnYA !Ut9*lCdئdvgw. N^Ջ'Cu!rC'gJ8*:i-g :MJ9Rpۨ7b:|+R ֜TֺKRM%˥U59A.O0 Ou7WT몒XSA>\3n)QKM] nf)ҜpzrT(2RDMb*gY)}7GRlijZ`k…E*E:`}T wKNZHK-ux[N>rX]M-u8bXhtUj*{'OTalXrEq4Haoj:{g7*m D~w_:a$WqL>`[ ͯ x"2y3|BAW"n 5^u.SHi.^BLk׌z!B3*7=4SSȮ^bEq)1q(L> pa?9.:&i2$Iքn_1v7Q@gTr)DN8 γ!vQ۩#j+}1׋x\PK2z,PKjEJMETA-INF/manifest.xmlTn0 ; hD@́~1d;NT^J/ͮgc;QNjV]>MƭbZ`]r:m/iIf lxR KѸվBB'7kwSD@lS )be)g.Z0ՉK6ĺg^m4wRv@S, TGGS 'n_:;oj;mL !!S9?_u%{-“ w%ᦓ5HX8KO0QH{`New{7I,4׊<qwMtȖEc m!PKwKPKjEJ3&//mimetypePKjEJ{G,,UThumbnails/thumbnail.pngPKjEJ'77c%-meta.xmlPKjEJ7@( > stream xɊd^_΂ɈܡiE AV§%!zlf|;\UUw#A5Eƞ-,m>-nq[\r۴i}k ㆑]FOqC7~`,D:,?:{usx| n#ְ&oY><~ ~Koqߑnsd6ϋ%Kܖ5'4?)R~rx/CRw7W{~X݃n'%KT!*_|p"f6VeD @tk5PWv 2_LG咔e8q YcV=y2Oe@Iy@R 8[J{[E'WOWӕNĂR ֳ`Ҍ$8c9Ywimy[O'!w yB{>lJ~A5A/+0fEbF,3M[rVPLr%l-Tt +&ʉ{tHC:t< rrl;JWL"q@ϼ B!]O02.!|UI*beit%<3+yr5 SӬUS6Jڴ8jt@H*A5AsV-swMOCmv~d?WBEEjAt;&=\8Yd[KP[| r~˂ec c'-BB)ȜVI-qau&.R["=|?61"w*%Nٙ*@yiAKފb9vf)ٽ )s* RX!/E۠(ܩZt/icH)J G~ ZL&M$C%Ўl^]nILJ"pvld/4XqŲTo2bfZ*O ŎBi{gM&ܟF8-8L EKtDn%xXC8\ B¡;5CQT@d'w&o .: RZ5_ VEJ)A$ ةw&!C aep v+eLPO%{1I|UyaEH.jh\wWk:rƝ1*+&*\3Qp6dgLcꗰTHь&RfN"+5"v6ΈcwR=VKL@l@%)'<'9Iv^iTkPhB䌎dh`䟤i00Ȧ^{TN5:^JR{Csɮ $('r1 {UG:^jUW[0blg.Óc|[q=ή5Kir0oǍbK|%0}fBe;{jW<,*0hՑHfZ+ȤL_~8 )rU7(WeTxU L?c8͡6)$SW4hm"Gwi}x1z thBzbjx"^Iu+2#Xh(k]}3I(Ki[ˡ;5D|Z&B;gO'7.[C U@ӏɩ\7z7rTDLۭ8)l7߹ݛs;9\Z>YA-nu۔ |#;&1Ԟ=DrfncJh/0y,M4)cg7tRʓO$ V!ًhEz۬P %hDPLm)yز4ޖʪbf‡,)Q-%tDi(%} H l@F OߵŔ7'N2aҐל;PJÝT'nϕ`)=m?n*VyQ %9 h!ܼ|T\#kQu_<-ʊ-|[V-Ch2G2 d-4 ^BUI1x5ܴ.l7*ڮdlTŁB;Rr%CIvpZ+-D?p㝖ٟv(k\jdP-IԥF)lRlZdDe IdD.U]\+DWQGMоhwL m0 P:b7ț5P7N<𜕄 5'> /Length 58 /Filter/FlateDecode >> stream x3103T0163Q243rr  c=s TQedFBBT endstream endobj 5 0 obj <> endobj 6 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3гP0643V23rr `lj†+BҟÕ endstream endobj 7 0 obj <> endobj 8 0 obj <> /Length 60 /Filter/FlateDecode >> stream x357ҳT0643V267^gb`g䙛虢*LLQRH  endstream endobj 9 0 obj <> endobj 10 0 obj <> /Length 52 /Filter/FlateDecode >> stream x3413S063R2slC c=c S0 +K!M t endstream endobj 11 0 obj <> endobj 12 0 obj <> /Length 52 /Filter/FlateDecode >> stream x3343R063V21sr C #= Qef+K!M  endstream endobj 13 0 obj <> endobj 14 0 obj <> /Length 57 /Filter/FlateDecode >> stream x341ճT043V23rr#s#=S D QRHuP endstream endobj 15 0 obj <> endobj 17 0 obj <> stream xˎ$_QgӖ70e@^ IlØM`_RInorX [$URLwS*P/L<؉ǃӧ!%O2 OaRxxp=}+} ? ?-"_o_;~_m5 foχǂZ&| 's HѺgօ{-Rt1x3Y8Bױ!&=:bcdqߠZ$XE00 /;zo^ed>`荷$:SVl0DŬ7O) G9h"r{2/  Yog/2YژLC<Q9!8Xh"lp-Y<" ?S_T|uMQ G2.ܣP'I!D$!% $v{m#Ԥ8  `spKa)@r:T|1`-̼< %E{$p@Ë7p!'|"IXtQ֩^,A1, ϤL6+La פ&Laxpgt00ÝW g+i,̊fAh(Ct}{Lƥ[nM^6R}Ň]1f MdQHx e,S2Γ"K Is.ccKQfv1b:t1`}Rec*.+cQ zeN<tSeP3JԏkC:@yPMk"|F®RΣL-;EA/hfi.xig\T GaA{x~ι3Ecg[lPQ3bzS ^R)LQ92 {a> /Tُ~a2Җ!vZ?ªzfax3^?V}DQ{g[WΣL۞I|3,ҘHٍ b^ˆ>g c#byiq&G؏~H ^҆!n^=̪yfJvqIgT-+QA P}=c~GO0Tٍ b^ˆ>gꣅ=m]0V]A*CRlre_=)>Z~@pftK[u&Te,y^ va|2XLyƎMօk=dOEwq9|wCG硿^r yN|6svr_lVslMVߧ/tf.{Y]izqn5Y]X^~|6sH rJӋs{͗5waw+yь|6sѪ x9wŹbRߩ y\h ^e9[]Xzr^/tf.P`sW^k +w6n3yO}no8N8]<Έ`Ȍl"'|3Qgo4O>Axր=4 1lnyϲB_Oo~"x*T+OYglyrL:wGsZ>6$N4gryMs岫ϣye{k?S.+SMNl?U=~z)ܭ%xU  |꧐rajݖ2e33uhH{ J lrfVmѐq+LJ=d{V mАx =fVJ`櫎C[:4$S;"iX:h z4Sxe%eV3޶VhC "ayJ`K+=J Q̤$՚k Qjخd1 urQs>vmCzh]2ũY`:bm#׭9c^$8Z_nȏ<ݕ,S5y鿃u9N2[SNک,W Dە p|&aZPHkK\L˄2[W%ѡ%:meBXmT!ѣ%J+KJ˄ZW%ѡ%:2DIthI뇎xkVto pnT h/~Ա~𶵪eBڨ&"m~a]MDZ&Dj"hI im1ɄbJ-s@dMj!jfM6bOoX}bDw2ڰ;K)-A+=ÞM^EG_@tfL~Ę%A=9V'N=žG4)͎=,qM]Ia9_}[G/|QIx˃&\IfJ֩g#DMX!ݯپVtN|j pspus 2Zc]BlLv;ߢ٬ d m"aD1pB-xo)B Y?q'tm[,qVU`Bީ#GgTfZn,CzL.!9,ũviCU.bR |C"B7a g(!',Ǹc -8Zp#}XJYs1#]0+t:INhTSxoW^tc/gjF]TA:Ox |  T? =*#$s]G_XH3D HىȂ2=VUˠW Z2 K{]m'ƫon+޶kV늎c?V we{3}1 ;M;/vBri1d~dt:][ tcwncۮ(7Qv+> &4p\''".c%Ajn=#泐uU Wh?pk:ug}7tj#u Hg N޺91n$W,⑖"*=@ M)6| :d*oh!ؑ~ TxFc}.v'ʩH*} ]M |eby(VJH)6>w3crp+`%HA j4, x3)+Ñ3jycj]vi*fĹ7 X{lϞu3Lm՟=Ti 0%'qw4ͮ n%_Z_b] &Q67kEoCnF ܨ/+s |M aB7Lww;%$&_tL\X D endstream endobj 18 0 obj 4287 endobj 19 0 obj <> /Length 55 /Filter/FlateDecode >> stream x303Q07ҳT22s@LCCs\=+K!M J endstream endobj 20 0 obj <> endobj 21 0 obj <> /Length 56 /Filter/FlateDecode >> stream x3гP07ҳT243slCCs= H`pep)iq endstream endobj 22 0 obj <> endobj 23 0 obj <> /Length 54 /Filter/FlateDecode >> stream x33ԳP022\&zP^gba d!`*̐tpep)iqn endstream endobj 24 0 obj <> endobj 25 0 obj <> /Length 56 /Filter/FlateDecode >> stream x3443S022׳P223rr S R Sd?+K!M  endstream endobj 26 0 obj <> endobj 27 0 obj <> /Length 55 /Filter/FlateDecode >> stream x3413Q023T243sl3K `dfgʁBhRHG endstream endobj 28 0 obj <> endobj 30 0 obj <> stream xy{X[׵<q1 0/lcK $1Mmcgԍ̤ir' ۙL[7M7<4ni;_s'ikku{c>kkZk( M! yv‚rºɸеK] 5HN D $cFvBo#": _1 4­+,롞?3pɥ}Gd(~X =]%'.v~^cE#x6BhyGq~;bzOɊuB ++t_#eT=uv\xzC@G 4C_C{aoгhX@W z=/w^>Xˠq@-YaU670h7螃,1qaڋ +9v@ ҇#:M֣q,CG`AA{QS[x# 6v FeVi]w0-OїY ڈi qټ,uEGSQ::ko>C~2ѷ-9J[yΠzD֌g*ԋ~"0fFz{:֮h_575zV֯,+u9Km< eruJXF>?($lmuk,2 !( JzAr$IImI XYVaox_Hܐ5MۤJ:T,!F rtl}*e),)FJ*vktDn y8l*>_b/)nKRjT&ئLR)ḻ9 iЦ3off:u$ ͉=eÉbk/wΐ8pVa3ӱ޸~/'gH$̌*g3ũAYgff>@GM u΍} RFCj1YK2?׌0XĉA$:u . џ Ae~%WlZj=hlImV`|4&.KgXgtZ/ `U`l xe*%_7L0MjFh(J%@xC5͖G(K4,-_e& )% M JJ|Ȃo&؜4Ae컌܋f+E7@͢ ޚaBɒ[B`84b4w[;7դ I6XLI5r y\#&9`~ P&drx8\⊮X/aZ3/ܜ(eDwjj]ƊUj[bBj`!Am]j %b%g [B&#C9Ň7]Hv)?m}\)V"jꂊ\7]&Ca$K[irK0ρjPkX l֎8$@8#{dR.u3h8pl p: x JQ?-0=k.b論"DFY TˍVF?NK4s{.@J5zi-_\q[w4{\=ς@ho44[o1>`:B k`,V!6 &@(&a ^mg9Qqaa+[mó-#O}9*=O|ĉT'm.<@W XAAݢ}H;&݇dS"j3!duΆR`r,)6Wz|U=xVpT< 2FޔҸTſdb7Jx*N?J9U,cN/%S7Rpu՝xN:αA0j9O)5/gVFk6n_I ݼ>C^ W>ײ2+76 ]^[Cp6ιu7ySM{kCEC/$(i9[qL*& yyT#QnUIKV`Fe\)+ZPE(PR"C|z6\)%L0J+s՝cA%$^Ճ .zF[a)U\jYXAMY=^Jgh~tHP)k76jKl*vv֐5 3/3}"UPQ]Qz`ZX׎Ћ#-١v} ȓ-[i ,bXe ܥhWii<ە{DIur,J( e֊9r}{H#z+v9\ѶܝE$DpCcuڡK! |{ޮv\ռ멾q5 9 ~R&!N?@C,2$tfpcCchJdl "F gnFyep>"BrJۍa:ng}gvpX*J,Ǵ8}%P8?=Gm +酯3 T%o(dUm("2pQJn(9L!3 R0MS*Rq AA)[B}Г)a\ARIG<ؤ3 \'D˧/<B>/OpUzV`j #%B:/4b^؈I\9 >UvO!2#i&6 /LY( (s[Krs3-HũJhq1svbGf4GSyfYޔj6gFuPĄ[S#8crӦ-߾gUwRԳW ~edVuWxqӁsÑKH3yfmcOoYWśmgZӾ͵#'wU ԁ\F吱Z4Lud{6(Uh[s`޵ݒWp֮nYgFM_*r \:U/>Q^f,t\zmY)d'GLOܵ6P"Ťr) `b,p_2Rjg{ 3_Vd|zlTXg [ouO5(uW'4L[ryGƢY!YXZ+z[5˛Z_,^p:,EWXS#К.HhR~Cpͣ!$h$8!JxޏF"obޮr_V]+ ~8ǿ>5 lupK)-/ x@~k~aۨ4{4kl( [w!FQbx3&:G#GVf~G٨ N1(٪GkR6Ʌ6 ")>+0BR5%&);whљ 5z1E0WS p[V 5H*a_0$"F $FǴjd0EcKh(oP#ՑiTLH ʡ^M,*~eSh9ӟharR 05): mb): V:I>\S${bld4.؇ j+<,BSXc Ąp,<1v mU=m c1!$'BᝡBd;Xd\XC;ƆVņ D\?w}x"&ʜΊ;2H:lFb0ƅ^gSznw\uPXb'!Gm&bcCh195E& dXXñh<sz!g(%<ΡN_jñqs4sG4wI#5w菌bH pX@0l ŝCc\I}c#;jD-quQDdFh Q!8_5P]( 9F@(@qr ?. 1wޓR_Qz5"h[z^wLȆNxOq?(#C8wƌA$/ɦ_GÿDv$-UX:Q},i)gC,6#;)9&nI* KKR=qU7|䐤[KRs OH KNNF[nRsďK>'J(]ʅ s桔^D~qcXZMSҹֳ#и"Bc?~靌WV|}*D- epKh;%41X1O\,r|_M9Sm g;~;[%'/|'ޛO$oėnb7ޤכ\_?p]0|/}L9ld#V\^6~^ [~z^sWױ5`zoJÕlR`#?z,c4_ p~؀3.CzO-L}?~}Z>~7_.G)<1 Xx7So7^_})E(4^#7Hs`+S$^ի|\\y-PNOVus|Kdw_"=/_=G./^ù} R-<"M*K\ ARKAX A#K}JNjRkҳs_sy8}\>n~h^CuyrJ")\z \HSN 'Ey'r D j-#ǩcXs?:Fyqz?w`, Q HSGE;ˏGVCSr*}i"?9Z&oSfOq&Չ&ȃV>?O6]ꕹ^; AеEҷ좿u> `gzy@qV~ ֗zI\KWm5>\?t+[ Z&fb'vVv;_ JcuTuPwv8$.na60x~2^-r^!yGE_Ck4.:MDsRfQ#閭H?2b;5p>(Ko{8z7lDQ=Qݗ@xEb > endobj 33 0 obj <> stream x]Mo0 CERGatFBz/M8~_DZӪ97FMmy9 6Șߣcg4xe06f"IBnnazxHise q{ F0,!ys7B]F:XXP+rR0Nu]&`Կ8gT) oȻț yK-4=@|?Eȏq|* k} NÚ/pG?e\k\d'NR`˶E[r endstream endobj 34 0 obj <> endobj 35 0 obj <> stream xz Xՙywo3p I \" @XbMĤnLfUZڮ1vm֚TSMŤv5 {buwyg8{&ƶ"fk"A$oo`g G7lcBZBT†;3 !HCᾁB|O!!lxpI簞>e⦷ 䩱~>dzˏc}շ4{Xm X?Oz`td|ɌRGToF6/Yr No0̖p&&%%O7=#3+;'חO?oTrPGd/"6r#!s`/&j IIHJj\?}>(nH.!vHs/G9,גI8qr5e;ȃ$|u;JOW[_>l転7"aS1W&]=RƑ׌c##,U<+ENziZ݁ZoQ g*V<!%J"CSuNԻ4#ǵ:uE%4nqJl˨4uy4W \D:āflBxk*QeJ+S՚ }h$##ՅkX*SDVE(!1:iggTo'q@D]rhᚈ[ګX{U]d* p@~S:柳JH t@hlZEǁ*VnEXVKOkZ< SKh:?N-J*׾.F-_+6AMTPcZ"PCZ5|رAFLa5ޒcZ4U"R, }"tw[N(݉8TXGeT9Tuх /BSTgj7ÊZYˣ ui3Q.bz%뀲/Y Pc# 9Ak^sh {Ԫ3?Ay@yJ)Yԣ=TT!g}͠#Loh9Efyǎ[nٱfXð:}4())Dz!=d2 !3{8[e:\'k-L VbY_Y;ޯju kwi)>M΄4^'ҀF#.3gBy9 |( ~f޴T-%~J`)fv[*u ک>Og6o{Y`oL}1W.-[ܺGϸ~KB҂ҺeS_HY.WZPb4x+F @G:< Il#v*1拇k&\h]:2ϱMyB=mh0ƚ׍{o~52Owo| Ѧē('jrr-ZNKQt# lf+q:] Ԏ`' S}`*ڢ UP'w@w] k *^8(2 -Y} ;*AuR/,hؓۈ/PV"~_fD݄ }Sx f3q.jy=zc=u~N#O*HU8$K!zݶߜtOϿ?1}7>?mzg>+*&k5 xza+2Y䱿 YtH}݉8nF:zp-9^HCf-j &ɶi`UJ=i=[KqrZt+ʚvOɽ>Cf?E_:ιX\e4=`BmIN%F6w3܂NJN6m&l g2i$s \ϨL@*y#q:W4}-3 DPT!ev# ԦLe>ҥ)rjPKS\Z޼hru@nC߼Dn3[RuL:h9CQD0 YFoxR)n˱Րe󅊊%BVk'leWr[=U_Ye_z_ޱMaLwDVQGgռZTT0"Lb 5p@C5GzB1٘7Anln >.mOP{/}9V&Hcl:iŁ j0$b<+t LeC5 K0b"νw/_o{{goM{mыu9{'~IzuWIq,O}1 ETx>RKH]Euz(҃3\FXN@>s&@Yԃfv^Z+86ZnDz;Ԝ`*=3Y~`*Oݥ99X wEAfAEy6;nKko-G09.G|W޺XL$JHrH$pz 3h]^7 `0AGw)0ۏ ZuA *IUURP*(IR]f%ʃ -3@݊ /ʜ**KUU~=g~ɟ_t閷+nhWPoWF9dt egmm lL Lm$mn2dv7 +S/8t?Jy7,wmU?ǷDI*iعed˒rM潭-Oߺԡ{O{WWnW*>/ҽsLyS X,X% xy͒Qܬ49Ks˚7Dh%#@)BKK]^*G;?|{K RCvUw8џ|IV-MҢ,mICЛ}K9j|}]iaӋsb:(HȚh59phVZ`֔XؚDEp)BQ6a$[VId7)2hC F0yYa,JDZJk;9LJIG8lfřY0X5Rxtײ.ρ‚V/MяD )YKKR{U"Un11`o;tj-oj7hJtK{v럞N_sooh'$t Y0zHJN6d@ۧM$#×nY& jL);0)Rla0w IOLp*c^Zy]/MsW\>fM²})gUEGVnk/q+玧T xbyܤ>٬u=MHZ&b<3 ;nǘlbSɗ6,ilE "D^U 7rj]:NlhItU.YPNjURKn tWTɔJ!vv-W[˜Ίef1J4lfk}΁*挪|&%K|/  `Uʮ\ 3@ Y^#gUJUˣwg3[=_RjRvv~ưV\Pzӯ*T..m[j޼k3/[Td7zm[M9v>Q+Cᢦ.-_o\dr|dϼNhC9$JUef#jCQ~ܓnqsnSsC͔yjĄHqdY}CL- Zcv*%Pس-:)xU˻2V ^@| Nܥ6gR nY/l3>M I~=3HM[R6b‹:x#X7vv.[nuoB q>>t&/h\f4g0oGbP_Cz3}r?>4y{ד%w&ݟD;nJI$&ar]u!=g*J4ό<#>5ٚn2 zW`0X(Wn ~|a֎{7Kڻ/ <^.3+3KT;`]4cť'"VрiW:獪/MQ3ܸbGr[ŚP1=}(jԍtRJ*e& X C n2X`F7mNCɍԸ*χ+MLE'X p|CƐ4٘:sMc&voL }.a&F6kv~>}~+p_n%V6b$;BWMg"qbbnbfXq ݎo0.m=o̬- VxOAnQy %j|_x#I.>nEc p2].ӂiىY0f.Wb,7D5`7&+h7SC:z۫2{;nuf$kx|ϩ߾{¾W[_8 bɭNx] "DB Dcl*EN`(#T#~xZEtdG`By%;{}fP?Tމ{A`>+\5v}oxxm<r2`q:'B2Pj5A]f )dA#ձn6Zfj,b"juji*%eѬ$֕WSBjO8dge:&ck@ *n P~+g[9/^G%%౦ %BC?h^ss^_ֵ͑ Qr^-v EkL 箮 @.M7s]埘.Ƅ銟/'bb]61rM㛫w~o|ãM2}!b;#ݴP@NƻoU; m]0Usf&SnHe[W%cB VdMf_vOB{\R#JJU @r:% $>$0v8 ԑib7+fv]Ǝ`q[Z\1&,eP,Q૩ʋ_[U9Ab_vK\4\{\( OnJ1U|Jܱ|{7c79rgec7'>1{y ]-+>'dB) y܉zruK֑dMF0qz<F1G㰈ⰊL~qXCuHCPd68d ]Irq50sd 'ads_Y=EɽU|Vl8! 0:PⰞ:Ⰱ'|/N#;Ɔ7 MH9RQAA&򤆭~zfI0.c~iECM]Ku[C*ix\&[6I#W_1><71G{Ė+H6eEJF6IЏ#6:61?qxp oxh:d)Z(A0@r]D [P z|ף@#< $RM6WøR ;\6rΪAтsn", Va}86L{l¶2_Wa=8~+T#60 (c%_͕.F3~yD!'_cCC1YlPL(c#8UլdR kߵ\y-9,Awݣ'kG0ȝ-ȿC)[.?l]ɵ{~1 zcoӟ^_&~dkbhyIۑ,a, KNǥG{>`[z!^|+6B:.NpH>}74+ 1xtXu|kضmVن}!#8,]>ka C4)|e-2F'/l endstream endobj 36 0 obj 10130 endobj 37 0 obj <> endobj 38 0 obj <> stream x]͎0<|!fF2Dʢ?j@IJ]>s?Y|{0lC裿ys!dVL?twwm,OmC8uO{9>ӦOSCcZ_}M59N_ګϵЧa~<R{6\|.Ƭ&oZt~1EmEeĢ%yفWd)_kW~oXW-xGVwf̣-?,w0eYN3 0ε5O7KZ\;ܕ{__/#/ <5u ^q,g=Kܳ,7 OY5OB,S1œOcL?$qaqB>4 endstream endobj 39 0 obj <> endobj 40 0 obj <> stream x{ T[׹YHBH @1 Ida1 ƀ 383:b<&q7v4Xqrv$m5&mķmzo#޿[ݷ[ tοÿhr|j4bзwH"u}['/3}!R98~sן"&"$o6- !%:?4ۿb!xpI Pmm2H 4k,2C:Dӛ{o;̼ Tbuw@7HCy06:1قad@=[bM-|BS׮wEnϡГ8z GwCt=fOC;=(= ̠4 {}%܈>ϢW݂^oh.8 Dwj4B>aiWQ܉ւ r0K^t PS?v7R.8އfaug X :X`4?@ϋyJ`"}_?BQ a: 2휏,CO~4:GG^N+Z[V66-_ذ>ʊҒvgTc ԴWf='>cPdHRMZ)hdsʶ{}!'mj? ׺!.[g>G0OnH% ޙ[^g*̘$mPkn!3ˣ77+:B$omf}L#djс:HWEV,\O/>1'ӋOVl6l ivxohz:v>>Z\bY+pU?l q Ժh 2ËDnЁC١ڎo2A֜PBΑd j { cX{lWUBu!rgoae_v.,OQ!jquWL[`cKm!&6N $y=H]K[J{Ê(#96fmH3r!YFL;!^[ א4M_.RUa3Z, l2oM(Gթ.ؚ&n|r $-?wAnJ$J TRhjuVtSqN[.RSWr/i˴nәrڴ%%i 2v&IwAk׺g,.%zy[̣>/)W)M3 ~Gx)GM+TRW3re|3my</s +)`qVO73jf-Ųb$HJ%RX*βbwq%P<*wWR nWlsUyh/g&lcb)cc3o{?uQ˲1^}o|_б_Ra1ƠDGI.+V)LtRKDx#AR)SXVuVwʉ|nᢐdr^.GJDTK0P"U=R"Ųk,+21e*u;eeNsBjR:Z:Rp#Α2#?vrnWtaEIhjkҞ$R'xqT6>=U<د^&v)g:uX'uSgPy[Ú98:.Ky%1؞IQ { :w:wӂw[^辣G{τ8پ &O /$ 5G`N3ѣBNY:'JLbq1< 鱌Yq XBRjjU(!u>*P8= <`d OX@ҺWXyŘSL+V\T E="qK],dIuTpl2qTc sLQ 91gܱ3Tn8<7ޘotY?9[>X\=, ac,V[gqANƳQc))&mllxD/ ZxF +g#%zF&|c.tiO%-+$g%G6zX}EْQ%+ [*O߻qr f+֖5unqœ gŚ~ k@Aei)&`[x[h)eչs\ .5"q1Mn׬]VWq*Uk5yK}AMxnE`|JC[P\# ص<]ӥ2͊gH!AK*j+tĊ腨Sܶzs\U-ieMj;VwQ3Jcӗ[z] }{TwAVVDT N>=s8OmO%SIM{1wƐ5O%-łQ(rt"2t88[0g 2MOuDGѵP7u^kpTHIS2ѸeiICᾡiω;wrVU0$ +\gԜzW;rgiˑ_N$-ݱnV0 c'Ĺ2!]AL<`:9M)|?9 07ȇ fȠTPY)a.ɐDMUۍ3F/H 1cHLLeAW$Q $!CSL5A "$OB$Η-xoW|YD& Ek0DC8a~DWnYSYc'#kF|?a?E}/myMEudOom`0?X2aEJͫ^h,yc?=t7$;+ӯ1omy/;;[Mw<zAx5sV m1. L8?m.Jas\jRY Q?7ϩ"^FU]\Ql+:݈ȊD[T"n,@jH&frkyݷEɩg֮tv^n$=ܥD*oC~ЭS0Z62P%_ltzgHq=І+dxLYNnZGtTޤњK /yO G]CSEo}вoxrf %<)1K+LZaeBac1xn?4*y8 w,qw8mIZ A۩%S2\P$.̳cf-1c9]6f̛{ciyLv99`6 gQP*"y"]ڲ꺶\!!}w]\Gg:ZnRukI iaڋZ֣"Y-`{!n H׌0㲐x;kCx HC^GW*qqA᫛:ؑn-/e'Cxf78sW|_M_fzC;=($l+›spCRgUM&P"{*l-SB&w.%'ۥx?DHzKclVFd[PϹzRR٘nND.ow$^D-]uJ7 蚑1FfLءCӪZj6 ]QGxc(KMIE|%ckxuv|i%5ԮU'5 [ټ-hsmes*KVYo#ȴTȗ`İCC}GRAu~O z4JX|J-j܇A0DZ^,y٪ܣ$uS`nVGĝ&q6IJ,O-q;'n4Xgql\2t_ݲzkyKKCgs?'rڰzj~)Đ&K>={*[vv~;|VnYgG;7/2:"{D-V 늲wg3ES3rvnj)Oٞ2 kiilKUO\HXuںm&np-֖|;ILIU\yu\~OG4/rq,+e:\+IdMt 㒸Fpks8xբMR|RD0OYByMn"u^f=8MuJ"Ht>ڟ4d! @sxyOL=ݵ32k<=? j]BIF nO*K0w??9럸sOQ Sz".M&!aiRӍ2CEҌAD'j,ӊZc1uQ4~-+GWe67֘*M0ixG*RH͈gR?E4R,\aC׸uA# GشP%ZTA`(,EFWn1<P=Wì!f0#s/$xR0Ġ 4 yJ ,F"cH8&xmPNnYr>!{Gl ŶF[)K1~2Qt*I;qԵ^ ܋9 V7Z=&T7owlIg%W.)-/8o)!lBlacbb;- 3ѩ:[]G\xxݵ3x+ot[UU+*b䥫KYpWptmd|įŽA+rE@q叱3^%Z-T*;dD1ݼFŝsEnځt4$%RSnc"KءM<Ϧ3rQ#|o3 bsB7%?i(,X )0'5HM`3,gYY $tT M"L(nwHc16mown{$`,)>Y̿TSXz< w8l"ūqY9rȗ@SΦ'McLJy;=Yй8p+6xiiĘ21nܟp!  2&8 bExaNg4ӽtSG9͏OO :'oơp7g,~a8!ѡɦFB1}c"vfJtZ[Fz(>lxY(\$J &rqSE 49nA5 X@PC@))2JW)R8F`1+`#`⁶Wi$o_yY ^mхlU ţs^q (>lߛN6v5.RP"!cg,{=r <=x AL~8KS473@d"prd>|sOs}ۘy>3#D^7aex\SCCT`{Le|y3s7`WO" yO۴?O:eJk0du`{fYereUCSVo.9.E’Μ97%?)OE R SSY5:ceu4.LJai/w-0oә襧ka׵:{?qCW봵MU&B} Cg@g_!5ު_vi\_oguu_ˋp<67iMpwdñ }O|=sUdJg]rz܎1SO}=}qn?bW 629atLyByNDޙŷ0iI 8x~tR,pB"/--錼JW9+u_G7GwW]=p=Ӻ(+Dvysxd2~TYe_?L&;bC51|wk*?Gq~1oF9p@C8CK2uV7aMo{xK-^QڍoT n}N8`0<@ B34!a@CY&/B'TN(SdUL5Men_-DIgv<]Zv_JQyUɋ/.iv\ί=/}@dlqCGq #-:y@s#QI%xsUFiPO&5G4c5JPpP :%@?h;z1JP,.r룴xX}ox"J(nAՄ1+yao2wt|îH{#]ךDFu`}chGh=bE2^f4@P"z4rAz] bjp*֥%V-Ak5&D`wJBh#䍂7{7Bub? <]&Gzn۫ gDc\UⓉX.*5~=IDd^leRl;RrXlJKŚT bo#bc8̮۞tQ9-mz "w[>.gCbj CqĿ\(sc}vsEj3?7 1&q@P62bAJh1FdMZtC;tf]~"ODjcps׋c9z茭}E^n˾##v̰џa岿Ȳ?}Sfg?#/~ ?lg ؿ`:,}Xe݇ɖ~(,_[^~ EհkzAUŴ^z7UﶾX#qZ_pǝRs8YXrL>g߭a,X ߛ~/nwCﲚwvt2ʎWs/z6DsrxΌ9q3u.o.8767=ljQ3 BB/χ'SS' ·13gg~x&5 VzB@O:j'&'&ă%&99 w1!>/zi;'&''9PR)ꜘ+b6 Pa9xޠjbpgPNtO=}}-Aɉ#/4 endstream endobj 41 0 obj 12103 endobj 42 0 obj <> endobj 43 0 obj <> stream x]M0 ư+EHYr臚 H w^zH Ovi\oa~Uq{uqʴQدi%[<_yl{ܻᡞ|k|zx__UYӨc\CsLX2Tߖ.>E6}ioϕL9]:Ek"[$;v{p5ق_wyo\꿑-Y߂x/\. U_YӿF%^M#u?5ߕ`;C/Ԥ^4+IcL'4%%| z7_r_J|:e_[tR0kYkoїE}KmNK ҿj墦+3 @O?n8yw8yA~@ endstream endobj 44 0 obj <> endobj 45 0 obj <> stream xZ puIiR?eQ@ I!H# Dъl%cɲ,'iGMlE$6:gI[דL&ɤ4娙: WqIgJyj2%#:0 FD!!6xH%'}h21qHaNEf&K]E+'6#Tf!hI`ʯE&Ãv#BM`]CϕоB mڸSUd?9ڃmoÛ6hR{4߄ s 4siى&Yބ߁~p42@0AAz=FϵsS\'hHvrosFM7ОCϠp>qTx$Ao“-A6%%6,\-~A{m赒IsV\611AѯJ,`AtZѻnj&e-m]E (N~tH7KϕTqa|D1a#9C[ݾpuK̥dUΐGwK9an/޹;kmC~]k?wA`]l?9 G͏*?^հcРy`e3|oެ|7 {۫6jhԷ2]9V{&/JS\{;5( pEZn)WݝYCV xwww m]Tn¡PO7=TҰāj;k EzgiИ$j̵@m "bE'7?NnEg/[5r'=-l,Guh]oS9LPC5I#Ѐ6Y4DQ%ǕnfaF& iY?o\WG ?{/0z~Ãyi^9 \?2^j̭@@Wջ/k}zrqQ=gC%]q~Ao8vZ'֮,,ޮBGA3ǗC576HE\oPYimj]V.CVSޮ@=!]YޮB3TH%ın21CUEMbFܱ8#R Ɋ<$Kvc|@ܑSAM 2 H"5 XF/2ŷ#R91o<^f2\* jSC)O%d<9%c:(JiCJe2!Gv|ŀP$,Ƶ3?> 1b&'ǐ1=.Y(;~8}n?0\OXA}>i<:^#:vcv];rB?q,dpPN4ͭGVJicYHl\m5!agGpEd^~iH+!BK 8-&at8qSUY)b)Y*s &aX2 PLd>(NGUJ1 A5|HA6I3$VTwT{25T%SLåNuN;PD^(Q\h%QM\>5m.*HHDQdQ7ZNA.dxʰJ iD:vHAV-SL@'% a#>vE6WϴP # VF`ɑ!86 kobgk|:?AtC o8<&wv!Úu YՃ0Ⱦ(er٨9YkY I6+giֲp[3^0 ͗tFPRA! ]{Fְk$e5/K,rtĞ 5A(Ӣ ?Њy*1g}_9ㄎ$7VR g̫"-w36Qק'db[#)Wbmz#l]U=W ͌(SD\i[9YWP̩k6m 3l! /˜3cNG;DVYkocBTt2˨b5ΦT!ËJˏݳ~%']QAB wJv.jFźWQsq26bv=j Isfv@FY\l[n mыƘ.M~q {@]B h3I=trtEAj<*]GhH0Z,f@Nf(~c=Y:R'j:01xd>kh=̇|q1Z$4D}Tbp j)Kژԟ~Zb2ei\j8(;aF,6NПћɝAa$Gc?',lesEpVҗ>E,9#E=h+bّ0s1xt;;壛ڧs^ˉ___M_^_L8_n\x11gW ύzgWg+|4^>⧝/9/9O3WZv<ۈ?ƟIOi|Z6 OY) ~̌ON6 'Q>qp"?W8~??vᑽ^SᇪCY4{N8&?G@sF|Kx:T J%Nki|'`6qq,zAq4W^c|$.DH/ >pz;1%I4ٌe38i, Eؓ> endobj 48 0 obj <> stream x]PN0[N…&NJC>7-)qDakfwf_?F0KgmHU2\Y";k7:Bbn ~ý#zmf8|ȇ͹/\`sP8:O=iv{:hμ*HpuBfF1ơ\8A')|TVQ]#3nO 7%^%|[p1&VLI~6ywA.7y/ endstream endobj 49 0 obj <> endobj 50 0 obj <> stream xgPS)T!KJ@:HL@^BT)"E(s<;sowgg<x, ꢭ( 3I` h`qm Ea_>(ПuvCk%[@@3~UU@QiIPT  .⁐۸9(A #u?H88k B(DJ bq6hO (.ûL:m@q+$ " D$ "%8)8@(wEt[4XV$Wi dF`/&%1 o?a~wK_L/&W__ ~M! 1e~&`66k7syǶ؟B=ր`kMj 5L?o aK:g4DWQE11΍g"{A/=|dINb!n׭`+"]gf"H[Fo/Q+dj$\/)i#;h|ו`ҿRAfM9ueu6 !ڭTGvw͹"ewI曳pԩJYm>q&5/ uB|Exly\NٽuIy[;H[&rO-cmm>s˸Zquwb:"uSVR HfcQSzDt$-ol>U+H|?)KuմC =ŴjvG~_xm?h61m"r k~9 M);wą:"fSЈ2yCTs܁U lU.pb΁B= 㫓[ChntgUDz |UYhE0"ʩkHljXFR|,}0F(VflLվ*Vw_"xz`/Y H*&U.8/$:lZ&*'A1 ehR7m],6~fvɗҷWb2򎡪ōƒz hnk=Ud!j U=翉 BL|X uDE[P'U!eWͶ7=0ǮoM{Y=!l0 iy m r()my-Ro'k҄FƩI-[U8@*Mܼ^41xT;U) _O"LnYℾٛ?͑%B9A]1oW'?օNi WKz3P\{}]yk\%VmO*\\JlVܮq05U:f7œψ!Ulu*c RKsGƔC㎟1ښʪ Q3tYwz_)}^Rnx G%3CvL8ƒRHQk9]'q kT_$n偾t^y_:9Z,+L2n/,׫3esz!2nNi[,*bH۵\)WQq =\p@N|L]<=nGoѓS-Lt#Kl*/ьE8׉Ud=WGK7v咲0ɍܗwCxy}X?C<.4_ea^mYx6=F[퀢cƒ\u Ji>Abխ$1>J3 .7k_xhG]@νLz`TV hp,;< BD,?ّ4FֻL,!Bq׾՛MqXA~{$P9ƾkRcl[c:˰TyNqZ䵮P[ݨI&kiHrÓ߭c~Avers^-nxIٲD&S=;,Sm z H]+4<_oc_(T Q<┗/g5Wn<y܁H]iuS LRݖk8G|Vn#Ar鴋`mv_ij֚cZI~zBKQLHhFU0~5eqW8ZQ(hܕ'aO]8ִcb_+1!ߛ)Je#mh+tw<"O|)[|=Z|oLC=B>O7$[ G4=-nJ7퐗2[cC.j5i/Ud'ti8g%x e\gEL5f,8^OI r!2f0𕶛rZYoc 45Z2Ps(*R6(/{R5cO̮ ;5Vn䩄Dz.z6<\x~GSh[als5b9Pi͕c!#[峑5o3%gp^s6p"8!R |.nɼ8ԡswq>풨HgF+pk֡GX2B41\["TyiLt[2NNV U} ʾqsN3$2R3!/1_;`OՂj+LP2QvwW{6 Oxw=,X z(+>_<6J endstream endobj 51 0 obj 5126 endobj 52 0 obj <> endobj 53 0 obj <> stream x]n0E /EM !$H,Pi?Te_6QF2s=jV.yh^iia.V=à4)J O1v$.T$yمr:I^@WUu{1FЎ2RTByK7B\Fr[n 㧈Il:u]_rWg}+m74~+G :eȻX;! 9?μ?ۢΣCO>*rf"u3g6s<#=0X~b:\nU`&~L`j endstream endobj 54 0 obj <> endobj 55 0 obj <> stream xWmlS~Ͻ ء4Jew Mf$@wv7Mlؖ} 5DLYYvETi[U)LZiҪvki3JcB됤JM|>y9jnaD*B ε(f$;:^cG~6T2HRŖ6A$7Q>.P~eX&.+ 1.k 3dY3p6"Pוc69i ɦU}dwJt7m)VՕHQ͸ۂ^ p0 UvLz%"a' bDF*M`Dd}&/z1O敲*m~>YY@nڪv bqK,3 bR ,9s3ō~6Bόkq] "'pЈݩ8Q)DB5`:'Ϩ 탑o(Y/` u%afЈ`hhCHm-xuذeKFX@_cF;LL8vgY=,eX SlӈHQ)I5_(û7\E҂fa]:lDApk9l?rn=/D}P TG#g"ڢŵ[Ydeԏ& .ǧpRħg+srpjcoEXq?ш #m+\[&)mZ^M7 5}` HjO70lO`P4m9# (23fSŧ-g㛫uj_7֒gn$7'~╽֖k(x/E @?F>o +τC\d4mQ1v5y`>Nl>&A˘}V"ဎ h󤎍P/؄gIMf8tlUd+q%ְ{t!+ C~*&PҴЯcT\c :>ѧcLœ:6O-[+`ᒎ+aѢg<*P{&{0M>@745mJvʪv:6FA攼PoESy<99˹hfdOjXj*J.5үsN(9HZ,Pry&4ml]j`Li3!YU* :8;2++9UF㌚RϥTe{GОe3zI2Н*L:٭^;AF 7.H{Ky.)T9}ezA ^؅lQZF[ߓd!7߃<Ӥ>ΤЗy؊ȤyZ6>?(?Yuy|t+/:R(%Fn➬*ϖV؋GПueVQ.E N]݇ ܯ<*|GѶ4sWޡ4_Cԛۭ vآ8lfٓ}tGNNO\G&r;긫6ln&q> endobj 58 0 obj <> stream x]AO 96О&f&=?´؁L)VM<@x7kQ13.qe0HU5fߖsGcl_[2opzqwȁ&8_{'Hj[8=O6=u.;"_mKuw=.:dKƘۭUHw>,K1)t~ڀ[IT?)+ +m endstream endobj 59 0 obj <> endobj 60 0 obj <> stream x| tSוޫeYW%[Idb?0?@ I0 !`H % tJ|i$$ ɣ}NNPN4`}dI[oZo'{9g}g} ]$+v7!`Zq~q>Ot3!_ Q =kT#DU Wvutn-r(ZÓ1=k|P(3kVtiB4r>"$WV?_'$ wCkɳ t< d_&ߏ@{~"!O;ǰ{(iVWGJϒ~5)-1#?# xGGN{`}r]tF &uzB=!}%F:XX_NGq.$aFĉdjgu{ƕ H oh U1>&yFG;Qo2|!?}u<[ս*j9!Ҿ"R+䭮b-۫G۫,0Zo{ҋ>R@eUfhSgw֞ԉmoJrffgSW3S4PylΡsj9k[# 9>&2Φ0T&CcoI\3"a ]ϐ:C?2U]no$2lr]Uq.eĝ9 r1I~f@1ZbϣdJfΚQ碦r=IY[&R s=fsc2\!Άұe;J.e,%,(-ĄFOzY&dD) %4%O3di(w5mof:N,(!pVtǀCQή!s6˯d|Wfr=Gjg l B#Fjw \?~]~cXqJ{8|apU>Ml6 ȒOI 0+2`ͦ ҂VCb!Yhoy=Qk5#3hDM F#Xl9J*/+!^on̼0CjĥR_~ΙG *x_~*W3-Bl;}ᤶgo}鳚zJ>#_#'ѴW\=e%}ε߻dcUL*_JPDXi:ڗfjBNW낺\ is8'g Nq4"c +h筗ƚH:31 "3W e/[ׯHݺ> lt (}ƸjbR^2JM& a m= Wμ;k+5ycvqZ ?>/dr^sJ\jEV4Wx ddH(eMdXbSA/R!,"9MS 8l+Fn7j,)759k6rW7'wa.?MiVNB9fd3"&i,׻*ght/]i_Q}I$ʍCyhyy̭@F\5SKMJ5N' -KtT UNw٣LGJ;Yy 7f^+U5mr[3X[)r%b,iFktUw{qZOIV:²MA+~Ft\Tl/jN:=u^^&D"BDm)&)c)SԆJr.b !.Rŝ9H))QSThl]4::fRYcj]v@=B]¼|bЛ *NocYʺՉ\S/Ewr we]nj'Xrʳ:C_}M Fa.;JޞL7ZvXi~:qTMR$` G̕ `H!]q:[ΥuM(15b<^ϴZ? *zP(:З VP>o^|,=6Uo~g^oEu|MpOU{R`ϻ{9<+g-<<;klLwH-%35ѶۏDΓKDkv%h6ja#P{ٌ>f>6eR9Oqo"7JqǺKJ,:Zdf"W6wvi||YEI\Ҳ5 U-w!~Y|3(9u^%~'mr*/<=#/  x9xC*E_H^O^~?COn~ᇏ~W!K4Z?c~ڋ~,w #L5E6tZRj?oϚO_S,꿡XoO129ӭ~e~HWPH1?C*Y0m~FSꇛZ1)m }ʗE֏3^ӿua>esXi J?_C~bU}ͱ0Cf[<:Oyl]D&.[lbg_ 6t^j7mß̽+mջj̕0ov\dƾT9}f/mcS.C2%u 7ݞ~|`լƻ<-J#OI,_͞;d!-s7ܳʃh'G2I)+Ŵ5;\ˬ-V5hYMwp_}eAVȌdC(D^#ʡ˩a|9Mԥ!IST'c<6`50re;c:Igf9Q\7Kuv &+rU^Uٿ5Մ巕ZY&P,m9ڥfA,sit_ibA\:_S~ݥ24 osg%ky@ &zP~aD&K`eL'3yQ 1|U)6 'VܟGfU [[eڊA25BU,~" Y05B8 ۓ2:_zufz̕4V*kkʛXpUކoRհދ'p1ΜArptzvU@ctW4m)]UJ3"f xkpx^bI٘#zr~[cИ#" 5$BT}<3\񹡹|ݹ01̅R\\zf%&ǐ6EdUgh Uke؛(-\\?Ϋq%{+8UMN[ǻ嘗L[:LWVqoHE2̨)^1fW,̟\9wyybm}Z흋_ȩ-uVgai5Y~Ͻ;ݒ : ͨ<#_ wQجjXBI/&PQ\U@TΥNщ !^'t>}SI::6Jatj.H.azm)=oЇzD//Zl׏'g94p9R4]5`D[%8n8lnfi7R6`,1'":@(O+G8gߛ_Nn޺A+*2Mhr>.GdnLG_nJF p.b:%b^ .eѩ,ر1%M Fy@#S6Bpmϴ/pro.$sQ7lVi]i%U>-EQ(0Uj4]dtDM#64Bj+B(<_Hfy4"U*J?GYR#F̐>ô"V?Χ94!z%WW][yvZԲS| :eắ\Jhz5g-Aj$ dbu 2-L%%^oq1q%mthe~Bo&M>&@O'*1K+^y7<{Yd;qBeRGBE89E֋A p?=K` ɀ鿏ҜrќopbH7'rE)Z)L-zc$&$C"XV)Yd"bjWĈZc0FoIIVqf; өpbCYָ.o>r.angu.8Ɋhk(U\r%SZC0l ox>|{`=yj{{`y=T偟}0B|ocP{=;<pJU>*<ɰSiӸ?=z <8 ,L=;_<}# fgN&$2ҫ 2o4xht3t!vVp ⡟.|{==Ыtyn>.xHǦÞ={>#Xk= ER"-atz$\Rs&ힽ҃=Tfcp Ԑurg08\)m8xf/``˒vYk$b-w_ n|آXv+9(]?`pІz˃,:Ԝ|o/Y3coLyQFib5LSZjDZDXQԯ2=\OBە0rqϱgded3k4'$si Q<~\6[nJk( Eoh؜:JkRS{S mtm= KsWn嶉)QƠ^٬B>TI"{b`s ,YÜIt01Sic1_`9UdEWJ-M崩/pe˰8 >}nTu"8- y"NE#9@deZYYQ%rKs9N \{6ɃWhȃ<ؒ}y4]7w4˓A{G yDHOo9N wv36  ?'JUI0OT) ` ޑ ]`I+Az g%x[W$x^ - ZiDKv ;_(Fa' w+*%`l6itPzM:'MI*BR7:53pYŲϮ Z Ƅ!j1GƖm׶n݃/]u@m_~F?vS;)^%_+qi8[)&q0?|%>p+FN3A٩TCZ4bMnkJ̒ҙRwm¶*QZP='|fBǑrk1`b"3k' C1AM#CBHɣ,) ᒠ ؾʋΕI ܀#&vM9D:k¶mU{sȺY;cxvyuTpG>tIIo؇A;v1&tkLB,[u)Do؉d[ :>$=JR*onو]. 9x%O I^YczuAYFYPҴ+?k^X,Zwy00ٜ:lldwz;\qu=)L..cke["USFS*P< ;ba vGLXlE"Iטj` m8hl&hT9@t9nFӎ79>wDɞbߩ|nk, 8c+gcǻzpr@f;:h~AÎ`v:TALw87-f4AA0У1 >|544b#!w*G8=䠯;woƛA "(!tK9%F9F uqƑ&T!NHbsL918[5o5^ ӭ_ߛR.(~mFefѢJ5*>ޑ`JqNqrćQ6[SR'xq/V7na*]E/&D:'?Nl.s4?he36V ;g 1+:+5Xm6ku*[) UZZ_c/Z!dr٭0qׇgXcVڇX Y4,XzVtU8Nё[LQ+е_xF½2P|Nh?_j|b<|}s'7 QdloV{a "U"j%` ts"xNrq⊎q󶲻zE_(f3c4,ϗe~D,򼼀]!閌tU&ܕ'JUШ\)RxpůƬai]b{"=Z"'!D_b=8$m6D 0b01`fkȞ׍х[aVpĖI LE|ݹ|nz+>vG_r7]ٺWϚ`ggOA+]\('5!8Ot+_/<0r:|[3<ħ _beSƇK*l/۴=]?}?Ø[-Y桺Y6~!cfˬՋ3-z~usW:(Y^ﭬ/J7a@2 -QbL8Lv 8uP" hrpaDzb.|=|ڇh3Z(0ȲtIq\rc&ΤDLrDҙI|L4- 6OƄ}'|X8m%#6*ŭx n8HЙ'x{Q泥ܶcn~윍bo#^RsjD12Ժ`T^ж785AӶUAmiۈiplNƐ+1t["a+8ѕ9k9,{0~ c0&w_wsOHyJ*7-i6/Xava+XZS5\ o]*|cz;£fbc8"9uE "*|ޜ&yӏ{%1KO"x'Y>ь.C4E(W~G~uN#mQ麐]vGOǩn;oɳk0hՙgfvY 5 {ή}7ֿwy@Po:u z65k]g׀=~M] '+Vx 伧wpk3{: ;uV\ݻK\50ԁ}C+Uz;{W?o/P.u+KM6uDW nފo*Y[9vкAd|"rs}p`քq<.;#?:U]+zzWzzxaT"j#d ^CV!e |"w&B Iwt E~A%Յ.|oT2۱lRf۫wo;Yy}ۿ/Wa%Kajezћ9+0g*\}o.] ^͟1呂Tk˼G2c*cUdRRZ[`5|E ndv sB{a}sz@S7ݷAlV3@IFJ!EXJ%OJqM7qn"B7O"i!~E]( nxkQnHhLBcX6_e57a#ެ4vRgʽKvۣǰc#ɻi^n˶H|E?5kNyx!GQ Y]/l\K֋pqŶc^t0o wwΟ;<'lk~pl_~I;?W'mPiᏲmS/C#9)?`;UyjS[O#;P5-4h.H,F#|C#l6CͰ ^Cap0ePWbE8 ݵS kC꺥!XĞr}KH3D[6x$SjCB)͵Nd %h7@ Cn ؙ9q܃XhC@݃C08< A=X0y!| I" LXz?埞: endstream endobj 61 0 obj 12892 endobj 62 0 obj <> endobj 63 0 obj <> stream x]n0E|"Bʢ5H CzVؾ!GNM\MLڨy$uW AkOqh/}_'wWMӟ!_\CW؝t/N* B5t> endobj 65 0 obj <> stream x{ tSו#wlY-ۺϖ-kr l&mȇ4@B 1R iZ6$)t&L^iLWNӾ!d o+ !7o֓ug}gs\kzr1݄%ЖM!6cZ>_ Nl⍼pFBw77 Z|w5!UgGFDxZ,7nY{7 >c( 1Ѭ,o2RwIH5twOOM,! TFybrdTi,c{NF|exV' FY,i ݑu#sAT}Jn'd}Zv]W ]q%9N 0O &M_#H#/#I9F'q &r|{_Gi2 ĝ^@f`| :ȃH~= ez%o \M7(mx G(a'[=ǃ8>DX{g##d!Q~um7burZ{m Z|iօc';*n|6nb0W>d^J0@HIb6{IocJsOwW窎m+/k%4mlPjk,^TUYQV*)z =ynjDɠtZ ϱ `'6 ' \'/e " 2b$LRA($r$fx#+~#'.r Ղ n7 ͉؎3MADGArBo@ЀP8:PۼCt&m-hNnnr=ӤV2&*KyN'gf:%gx;mg晙 K 4%|w$DrmO.!Hy#\|z` )>"zgfb96303xjnz,yfN3ͨaލNͽr=ԓ6`cLAL8{܋nK缋FZ8ƬXyBV~Y0`='eE2K ԁJ|Y!dZ˩F]dPLk9p2diie:Œ,ʪ`73`F/_^fz{],+M}7rmy \&c ͹=xjcC'6}yˢWnmi2FUV9%{_XCÕ|gǢE -,g.{hj1w;?f18L(L$4& P/4ʭs.8w(ҡp+HV@lgaLxP` vf,3iO͝Q*p+Nd a]?9Y.+IT{RA{ָ %|gy2QxINJ!*@JZ-*Z^YUSڵ%Uো*ӟ^9Ț _ i[sؖ} 6;rKY5u~];ƟX+fs[*rkn*G=͵%9[l]<-E0Q `p;7ȹ ce{+3qWJT03\.~5뙐^ߦgh3||%i%o0HHQZ5gK(H/\[fj* `Q [Q^ǤTTut=sY@^}h$y1_ܶ`(GՁp_阊k3bRbNO+]:&7w}f7$9˂ɱLz%di[[N[4댋1H6QAV/mZUנߥtJLfIjgmIDeUKi24DKZm> ՠkR|?/$j΀nKĒV*+ QStե{"UmDa WVҮA=v۬fp8)d2weu_gM+ڤe"n)ss l4!2(k GHDKð/ c;L8=(tF02BVGE};QEGWQx2F(TF͏2(h͢YUX%EҒvTmV Rj=OeaQjI7(DQx6 / zU([<|v^(<ǣWW憩S%K@ M Q|@BZ(|Hg{KJ:UDI^ZUN8Ԯ^Sګ9_e¦O\9&VɆU2}JM:ZUŗ8ɾyK-]PG 4ͨ?EH(RF\FwB#ޅ% b^цZYH:j;^\*zYnZ5? 3wYKKbk[W14}[ޓ P҆oݻʗJ3+Ew 0^٣8@3p P 0{ԛ;RX" hJڝݒ a]TPٓPf2y} Zj::N$*s}% [tkkuLfoޱ++Xyao]Ti]}#9e =-_0Z 3Vq>7]듺Aݔ?">ROTFS¬ְ߰f,/=S V{|-Kj!PI\t%V{՞#eWrvj9nː9Rnۉ4K07ʺniMFԝ@/IE3KjҳSmi_3&7IڏNM[딩ʺu6{"|}+÷?{k7e-)/@M8ۓSnK 5g(۔h^'y7E%\on2ܲOk8~q+@ܭtNUo  /=՝^g۞-I^H% } la3$$f;wP2 z\ņ,C>n|ʏ:OqVSWm[$x֌c^rȽ/ϔ[K$03gd,UEc!DW"Zx/?XtbY0žt}龻. h42 6m}[=w[LPݚ9]˄zM%>*<,0Xℇ|ib }F60,5Yd<`0Y ~M8ozCἁ3(bam/h.|W~(Wr=|%X5Җa6c8Kuurz'X-7jګk\$ 7'O@5in=)q{bX\Q:_y5e.&)(0,7NGi?9 mp\8- &kry vs8 >8#@B$]n2UU'Ivw[`G ey+~|'oP[;wJN(;Z<ơj55wh4l:8&V*-^@4ALO0]#2M>Ә3Zhh_ղZ<*rJ2)F1qq~kzIó,eIZt!R1|/ 5I wHٮAunJ"apsW|pmgwD{~1;܃O{V48.{hv TPH텚u.wE$HsZ$+FKupYN}[-,l,Kjw zb].VLttY۳Υ X6:W3qr0)7");SiNo D7-EhvM.ZC=Q;顪rџWIe1&|T5:q_9e XƜ41Etx:v+ĕ\yN\4VlVҵu?fA0nϴCq4?kТu`] MYх'NzM+{>y A>9{q`P>N!A+嗱;Ҝi4;X,5Abq1 ihZZ}Fڸ\!^yHJvVpX=F/4JEYRL|U3׎Ɋ.Q TZ35\9Qu-+{C+[k-WH/7n>g̠EyիZ3 5Z!he\ѹ^zΊ\#%ukĢh$n- 5El%ւ|`rՊ*6Sӽ!@msv | b فZ:Q@E=i,g̬͗Y)*xQ-q3Khh)㗌#4А"l^Q2m5.~+5gMa˿h,jU鼕'Jݦ<9~]]m^%#3{xK1n.fq 苙lHɖ_mEW#gTO81IšuL;M?4q @ƿܫi=ki6nv#舃0Z^0j+ּ< :We=|S[6ϞyyNj5}~I~郷|>c| ,6;tPd5j5x[ ˳,S+KAMdt/d&?$&6+mw <#A8ag Ax-'~<x~AQi* Xy^ $J~J 8e$Ӊy8I|N~ }V,llsTm: (j۞Si~<XUuǃ0Ϧd 3 *GBEiZ`01 ,?冮Bި7 l^&, aKH-P v IsOmz13]/k3s`y/YUl FJ#ؓՋB!1v?JO@;!(F]#, u mw\l5 2d6ӣMiSIrȚʁl5;ۙ-9N 3'd 7e9Ycw#jyURRݤz?oX4½\cP]u-΂HEtѬg= ^\=*V9d1 qKMl6`[U4Rt}vV?+*Cï/d 3fvwE,-ͅ\bSlmϗ44>_h 8ա@*{O&UݤU^zUx2BbGzScWVe"H*%e,8#1<;_eep|k[yɮo;d0/]%&FyFou_θ㳗F+LJl:]~Cwnf0ή)h]_`j\.Şe[Y4 s۱ulJ4CrA-٬sƵ^1rX~4xв:A fB:z0Ofu:@hb$Z+$H+s  '.1x϶ 4b`"&tttěLtRkq¶UL8+$P)xa1̐M $ Ι &8jk.bF"xQ]}EkW(XW/6jMwFS3 hh}ޟ>l2/f c]_9՛_0W?T =Fy0Ss?{$ŽԠl2V9_fxUX6Zl_W`C`$݈_2N)@([fg=G( vr=IPF̨OoݿK}Y/OϹ79b?KɉtMNjN=䪹v.>3 bK.8lg\ y=_-w my%V2M%E:dAf~By\ZMk\yy|]x^^<5P+7a'y!%&ɻ@ iFئkTszI* T25VcE7n:N~35Mo\xX;nSUY|wHQ_)૟k|b ou]m9L4̃JK_}w>06{ ncVFk!ØxV:/hDIt.М/q<+V^xȔT?}9&zpfss//l͟f|-1v<S2cccw>`-R4,w¿ a]0T[=a֧>>Մ1@[[JCnANC98D`4dI~wF^ñ0χNR0dU~a jDUvm[[!'Q߆00 QSW^088ӯSGJoWҿ/zU$laB$m2W8LsЂ>.]OJP~zJ .Kj#L6y#^w7#,fj(Q}QSl&vJ= 1DnP@5`%|5K|ԢQfSwK2̌PlGנ1:2 K G)r7]U5J}m{0S39S[Seg\mђڜhyd@}hIWz`ptp;LvXW3>-?tuڝtMlDof~5  Ԩ+fD}?;ySׇ>>~W~,Kd>۲;1;~OS?O@w|{QB4׼죊Hώ?OzPӚY@M9Ś%;av漖V{9\o; 9t-7 Ml5F+ <یEK2ƽͦӑiՂUl0iMml͖V]K^/1CdZEUk_׾enoEinkzJ>a/-~mO?~H j?E9nF[Բp,e"p03gNaFC>~8vwU~~^vV~ШIŴY Al*#o~0*)!2z^啬F^~~W;'ձ)Ra%*+r8⧍!~xu,Q9'ޤRy^oͳ;4I~_Znl}6iF3)F`PFkŎqYu2LE\zs: O`&QG`I{f$i`&y̳/Ќ(~eEɜc  o(R,p]Bڔm3r%r8|=3^/|D\Z?Ncd#:R?d"D[7Dh_"yxEGH/&xsj]3^9X8 ׉_=w#sQq%S8675&mXGhGU9(cn2sOh5 mwsV~Bi|?WMҽ-1]?mUIgj f!3aJٰ:ABRZwKj!)EnS0Glhp0)X|%k]l +` fo 6 ]b O&2IfRc X:ìO@rټ#`4R0G#)'+)XC)XK>H /a H6 d(ɭD 6_(l&wkO99a*cdXN喭C%rͲJ0%OLL.46w4tǦAyzrpxdm헍*:2=ylajhdȤ\,P/' n]=29EQe%U%h(I p4ƦG&9U*YU"Nl˝W ȡA$ވo>965<6D{*:xJ#鑩'B~{`xiKƷX##ScK6Noټ :oW{Di16'ks&(OȔF&&7 MOn>vX(ol56KZk]I&@6i"/">|I)U!AFж$N"P يT%5'/0F9j[J [5fրSFA![9InC8Z?2l^֌!V]ȷq(6`y)=L"U*k/_vJ7u e,!73ϥ?Mcɹ٠rVy')T]HJjW[R}MmU:oc8;rHMǒ<Ɣ7T%V͏ M扮I\7hJCsVۨ&bR!rW4sJ-Q-HnwЄu7 mrKT[p>4UTC1Z1YCg>iyR$6qAB 3!QyY˾Y>ī|NvТ)_sW'|{]y]]Ą._ux~~_#{e%_lsp r!Rs{_Բ]9; O~~ ~鿂7cS&N4NcK/1 텓)]/^z D"cb~+-fpsL1F<~ƿF "%&ϔ0lsF]~~0=UB%;f&cmx)> endobj 68 0 obj <> stream x]Mn0FtR$Qi@"cVگ뻵_0Es R׶~o /dv0٦טY"+<\q>*}4KY1;buFC sr>B>pz{B~^ 딿p\ҳ8uȫ?e?9!>2')2TgE+1zJO_L>쿧W> endobj 70 0 obj <> stream xzkX[ו'B @soGe^H1$;$vj۵h޴I31n21sILfN؝ftj&b>G~wskk^GN84h$Ǻ[B!v/V| !ꖭywSݽxW"<7 #dx b$|,hg >)@F? Юݟ&ghwoz]o"dCH1 I?d'8 XFͰ2BRi:}Bb!9%՘НȀvKϛ.fJB!D}3|])q6}pC[(.Hsq>=CW+ D?BgBOkv~ C>)DU)zKw=35<4YSY@5@<b f)АiCt;jkv6枢աxKԅ%!YcH.G?[8?}tNxqA텱Ӵsz`Ho [B{KB&gJ_8f,cYf7e>Ftz]5-Mm:l\ܴ Fm0jnGL!ў3WEZJl]0Wg1WMWu#Ptj6hڻ#mm1Fc"=S fkGt^=hqxCS[B2- z# >Z`ԍRȐiԈSh r |>N5 P5! #lFx=E#M(ҰD,HG4$:,B訐DfӞr,]]ɛw'7]88i-&s9rRG' ԖX pPDncCb[7YQ2$G 5!3tD!trCR{ձn~Zai&-Q$_BĄ I~>+C [:OSj4fA_9r I' i=4霈ДH=0Sp Q.Dp#R0ⷓ$gxCl%FcŔ,.BjK|]/#x9XNE{uNǩE$kR l$o9bd>-g2Y4 %rjiLYm֛(> ]~y.adf8S_JZ-]*3~nSqIjddhSp*lhML4PP'QC8"nB@- ~Tx hnY*2%2|Fx ^)MG qԸ;cS0~82м@&#DI{D |&("3=İ  A%3`Q3~̊a&[IT ;@D>Jh3A'-(,Kb̂auS"N. W p 4x)+6T,%'%ZQ }\k2rm*vM|7qBtŒ z Y\&崅ѹ9)iN))etyYϚh NiX'(ibGRqY\\)>Lop ze? +ŌfmWb![PRPXGmCfJD%&%5lO?JkV:&źEl_$))I%FBŮ̱d IЪo>]ޘ5,boY!7:?xݯ?y^(C"O9ãr1CjM.w:NLnf*NMdJu#"Wtw 70NxZDׁ1WVLJ5=1Q NS5~&|5k;~0 jZԁlǡn U}]JG8 [UC*UaZAeȅBu깥yQkQ5v Ӯ3|>+tdG0Dc %Wa,+,bb*`=zۭV>np8୯,)͌ĀجtC7u]}χ{ž:a$2̺22,S6%uJRRأĜ_V)@+ e }:uPĄ(' D9Dڅ ̪^FPҕH0Hn !M ªΪU?zVTNYaWQU-T]OVaOT8b͂ '5YќC%j4bA)ENIE}IkskΠ ZS4h!8}n]H(}8M玵YӑNQu#E絗-RQLh-Ot_kPYcfof볲*]r;H"`ALC$޵~1:fImRhmeK\N ]%lC-2~;kky&W%9}џ_sAEή슺Ac,{q`!9`urBYOdʦ+}%MgA5Q['lEcDcҢ#$JfՎB<^dQm-*mv=7.@)StPy$^'$U )˺~zi1i 떩d $HLwY'0)[J`'%]1cޯ~;uii+ Swr wB^996Z1)e2*r-Q&I.?IrA ^$b!4$_eQlhI#`edᇼ;Ά<Ӻ=Hp'lȎפeo{t&񿣝`S+sH \f0pa;pt  E "c[\N1I~#hn Tz݀ mU+(-, 7Ow?r{?Y֡&z[α좊 T]P¥h-]kww֥:2ԎںKsG .<." 4(BE}El% X,Z6Ѻs(V;ZM4eb8Nb!<斤$ybC$%/0jQD_iR殿7/_.peC]wgmpyf`SgK?bI2N:^AZtR֔ jW|B>:nNnN!6oHmIInfE-_Rq}Ǔd}{.-إ,G2Vp kRHu4vˎ$F $ |xlouWc)3wĉ[%OƼm>bOd5Wud&Y;oLy[0[wn 'ûr G 1>RRPֺv/UPEE*q/\42/:9PejJ%@V(R;RViH"cY&۲M_`椆r0 VKGJ=AW>RHFNqϓR+ 'jRMR b}LJ·SvJ~ o7vms=JG~I6^szJS!.d308p*N{yߟ2/e&I`H(A+%+ycB k" X@/;>~\a;&Bɵ?wWx޿թ {uΥ߲A=n;ryZEib- SLIϣ 8_O+Ty.VaSQ*cѲ@o"%c,Y9 eYIN`cǻh`e._φ?9w+y+lU:MУ+Ko[b q'U/秜Ω޳Z?)S3'8]

rRI0Jc8ofXgm)#fOe##h?tHKFcIy#{ \2Z#8ZתS]Û?'$LL $I/D KPӤw ̫˩1>sՏFbvgx ҁ䄛uю$ۛXbt8h+Yf];1ŠlG2l iO} D$Ch$eGe˩>z`q D햂չN 6jڄ*3T잡ol C}%GM'ĎUk .oIokO_6Ο4d(wɳ]3U[,>y洹c:e#5 aTK+'̧̔_zWe3NKv-3%Väӵ:ݨQʕi?h~RHD BoJF.k?F\wf20x:cR$ͣ8ymxj3~GN>DMa淨 HqL@RBFWH}4G 'g*Q'Ut h:NUPw߻s]e/bZ)SFU7IR+. }<`y׉bxQAI(B.|" hqV$\(wEa50Xlx_֠qlGT:̎%(Q)+0ji1 3(+ (~" PQX>ߏ * +Q:Da5`(6QXe_hqɑ 7 z l|(/I_77h׬np\^Ǐx/vx'[ofdo;col7I6&Qb+.NA>7V14&92w:l|7 ޱAsy{֑M@< 4Oǣb}|Zo0 UvmfF60A_`dh Vo]@Ҍ ͍t&Fh 7'Ƿ!m#G~#cCl<ƑFh aDxKK(ȊaL'nD~p >ޓh;ֿ8Ev@k 6@{F<TcI(Kct$2E GgC+GC1OC%wPtHTmH4ۘD%3aƭ0h:;qކvJJ2.Ž!69 V99mvIsAH߰U6 hn<k@:.{h#{ox\ИDC;oXcD7_e.ћ%o26&} *Vi$m$쐴nPyibܼssV.9> endobj 73 0 obj <> stream x]n0 _Kʏ{(:ű' =9 ?Asd`N1zD^3/vAb|?ca(~^8^}Lf4XoK endstream endobj 74 0 obj <> endobj 75 0 obj <> stream x9kP[]$yl@<6@"l˖@d$Mj]%$n;u8mfw$iN݉پmn6qm:;MA{+Iәvg^ys^A|v. Y0,F&ӅٙZ @rGǥ^މU=:=6Y?6qrt$Uڂp0tz+( m5?% ~'Zd?o2A7M?4e>Tp2m?7ſGu"g_^3vi?BPCqx @T\.0 ez4z_72?$#D7* r#^"\F^7-B޳H. &56<oG,Uۛp .{,~>=/܈yre uw6_N(<ì} vq4| <+h!_'\!@>oᄑ=wwuv{Z-.gݻv޵n*/+-.oA cU= )+;;).P$$*HULU҅IRMIbJȒ6YZ!|/CrM0W"وX!y $$~|< ̌V5Q]Kf"KSٵĀ6UO0x|6:T]ե6IEӪI)BC+FTfPOa`=%R۔SJQ*~o$ _b;ˑ}+%hJ1D,'Jr~Xrb)++1 ׇZ+()8ٕ^lneKA”KA)[,֜ b&Ӂ9ZZq0"|/K0lYrHa Φz@jv W=㇂0QZ ٨kʉ>JUW(")|)nVN* YAiN(j#{4 UW)W`F;jXHZ>.O+&ٽYO'SUjUHZK{ڨgɓB> H^],PCmT܊}UIBpJ>Uq ad_x6f*u/w5I19sgIS%ZX!4"AjG@v7]J8pJ[$ސ0 nKQ+T*CH"~DTPi &E3nq)K T09#h}Oh3_#7/Fda))I]Cv1S G~>#Z&۲%e+VԴ2K<%/ oZ&ȱXsm|z}3mܷ>=d!51,kd.0Db!NLuDґJp^s?W6u~ZXwZ?xc{{_Wq"D\-&`0dЭ՛zQ՞>Mj9W ȉV k<{7`%v+9bE~әۘӈjHƯѯHyFКٝV=+8YGV&ɯ/99'LKXAcm]uYŅZvx:,wM͍惻-q&.xDEykKvrNW2f gFoQk0f\;ډ_M3\=.ofh|AOL[l&ܓcG_:ټow:ךz}^w~f}>{ ~l8!EySS{5Ӽktp:6h;M ƆƆRM5 ZQVrɔm7fY2{ͬ4d6ZhbwNoM9-u7 +nu^7Ā_Mjp+y771ըߏ_ vw89t``WwϬG>g҄$4j#7VjW{)o{H)gu_=f5<m>ٙ!FNDZb#M-'ob5e+=|XRj:Y}e)[wkW56{vpʟHl?Pcbzz$_]{t^t94YbuGyyؼ]NVW[[WwQor88\;%Gq$W]zsgRm;lw4BoqvFRL %2Bo 6_g-~S'G%~Kzʨ46Lv oLUUR {}G}iIj+|Yy[i'7~}4iu;v_'"O:i<{v0X`1Tzn;Ѿݱ]|/3d[r!:\urǎ- 02!'l,2b,#P- -/R)+f֎̚nܹbݓ9plfF{괨y]MYS>M̍L͝dctח3cS_wOO?5Q6CFz:sȏUGgn~+rwyCO_84s;lClؼ;ܻq3J0:ɣ< Lߛ9oɦ$ȣ'Wyr'ySUajǀss[}ޱԍ;S[s V"_]=э88( x8 /ts9uixB?!u䂎]G9#:􁉗? r:\3g#J!%%[,V]R*+ܮwMG M{ǫk?MweueZ\gB=y}n-6q? 9*'ӈU*+lc~b.KI-i_ iiVDҫwb$ 4B)JX3R0zr@!sPgiX]u( @Op&Ϳgp6DiXg;t2siVvGfazH.4CV@'a~5a-iXE{3IYpbΆh44?oNǥ f?:*kj&LLH@L ³!o'EbRPC1):z~Od8<GSRp*Nxp"2 O³Rtt (VVCUSX#"xx)ioxx*.Bbhd$G³ G㸔sX(2Bl+lNG`<E]v'lFONCXdl s`ON`@S1 |Nܜo"%S%apC m1ȱ=e/25faZI4YqF:NC :!UuJj H7YX0U]*كZn@!5qQ:ay!- U?A)#6v݈O] "A䌠ΔkjtdI4{Tئ|-fkq^?ßTT+qvJ2D~Uʫj\UoSxEj$GTt-)QU9 sjWPm-[Cɳ2G;ܫjgR޸M.|̭Gvm*4^ٴǰZ1MM9IghJ=4Cs71?ԫء3݈>T4ޣmJSF9>Z4h6bu=HG|e%_\uyiH]z̿CqEx]gWğ^#ǃ?x/7LFxppU &ŗkFґ+_$ŕKfѸB,. DIϹc/_b G%I\!&W:Qy:)/:/^dH\K+ O\ ijQ왧wO{Kϝ+?W"~ c]?<ѝ 1c>X*~0, ̑ZؒnxQdRǵGs88b8''{O3QQ0ю`Q0(8A $$Q!pNdLxB++WnETY]}Y-Ѓ .V}Jx[ !<%3bX|.L]x% *71؜WyETciX% w.U 8Uʈ6*ԅBs|J endstream endobj 76 0 obj 5051 endobj 77 0 obj <> endobj 78 0 obj <> stream x]j >,OMzn(9腦}ThTY崅.o6ݵWgDFŬN 8)M[x;="-6=J3/NSzGӇ_F$'n4 i}oLqGFb@bmkZ]b'wu2|F>dF>ߏϙȗS$!չ.3يFݹ56} endstream endobj 79 0 obj <> endobj 80 0 obj <> stream xZ x\U?wsvѦNV&IIjVLI:6I(Лw2i*V]b$ˮ"tWEW]eѮVf/(> GGww-dwAx{}=男*OQڇZ(ξ}p+g+vyu*= \}}?7{cihav{y]W12Js't_Eiە1fyCgcPaIvz s1gؚs ۽|O=X kxyv`'žkcaʌw'}I<ޝ}y9 ZÞVsAYlŸ;new#Lx j7>Oz̢|BC蹈I(ס/#& Mcvrfc}NGa~r]?cmf[!6~h {Cꙇc!o9Ͼ泝-+6sq(gAړZ/'-מ{mۉ1OYoRW=;* SPW{+O?kaI6̋k++J2{tǀ;jwbϼaEV9w`pK߄5,JVqvw;Voчp؋Oclxױ3qNjX{+6厗,;q;nbɳ0s3Tyφ  Oٖ7.HyDRYjf~]V;j䭔=]79{r2afKv[=.,FO]Y"2it_g4.:h%|~{y-Z)>߸Ϥ,BF@]Sy-k'<&ײ3<#9iéjђN.Z6|K(<`4"<4:> Z(<021 ~ Hh4C1buEQ)l4،@h$CXXB>B#E(cņCj  406##S < G-~iD҅V *##?" F%F@,4At%?tlCWFQ? ѲISC2 H`ϣ Hp F="1BK&p*0 RNl,+- y J"ch'rH'Ok\;9;Jr#(0*8+7nlnq;Z?Nb:k4|ʢpGm}`vi_}]ВÔd:eQ11sҨ JT/4Y%3 x )dΧll&\+j>(λGURKyIcg6/3$Vu۽j)x)S׺SS)Q{r\(slYM$gXwۀ8D ۺXq5IJH߅KㇳHIE3>6](a++ Ei52ER>G)Y|f妐#z5ګ%)R(ReMtJ[$zЋȵ:.z!e]=H߅t&AyB e3T!V1j'GII44ʘDBԷf9 G6u>;|G&/v甋"}b!Tw㚉=-ҳq!itd'ip"-Y0$h(is"d2,MR ;M66u[Kq@RL)TL*=*Wecm0WDG3bk!5즾IS씋juOu9\)횬+{4Mxd^b5$gf] :=?%"N[GNNT;@>^ZnNj/ p"pv;PeɨlZ Ub-0D;Z>Qa8N9Vb^OpduWGpiĵ0ZBrs-NwR߮>+o[i_k+oN&L ]yΙUSy[*~KvonQW{sJ0K7i-η QT~߳HY娕/5-Hmhꄪ2Mc۽H .\Oͷ|ͷŠSsw!,]<+~?+c"pz9^V{LUXwR&u~u޻lEU(^.]<}s@Y~͗3l> 8^Fϥl)>[iBfv;>he ۏFցփO[LTX>i\G4*o!p{~~/a/P_^>}s՗vK}υЭ %g~?ihq^}UGfyCs?\>'}7gY>{Yߟ=}z]O/·\oР~k9~^8c'SM*|}?<"kNWo_~E0{ >4Бԇ#HwY;P(|=p +/R } ?_ ̧SZ'T?O[ U]:US!ccn_ڥ&.(,2 syt7_7yo'n8`  p=.\uupm+|H|@iU/VcW x_k(WpՕի\$`_G= vZhœ~k-ϛn9f6ͬSQȬ=K@'`j Yj\$kQ'MNW&Lw=;l0z:1Qqcm0tFa:xGhMXVJua 0yA\R-V0@3攇qwq}s]ܸX.St M]^oCߦ[?C}$6Bol8C` lF=H#|> pt{%t-^vCsҪ_;=yތo^uu$fXѯvpf]Zީgp&b{ի !XS]ZːnY,EZ~hA -`Ԩ67C]MvK%>X6.F[ |Oԡ:j:' ^PX (s~ yw~ۀg d-? endstream endobj 81 0 obj 5308 endobj 82 0 obj <> endobj 83 0 obj <> stream x]Ak 9Bo!P,ni`t (sȿM[Aާoԗ+Ga!g1˻*lRZn3N- ~oμJ#qDwKJ_8!e0i > endobj 85 0 obj <> endobj 86 0 obj <> /ExtGState<> /ProcSet[/PDF/Text/ImageC/ImageI/ImageB] >> endobj 1 0 obj <>/Contents 2 0 R>> endobj 16 0 obj <>/Contents 17 0 R>> endobj 87 0 obj <> endobj 88 0 obj < /Dest[1 0 R/XYZ 0 595 0]/Parent 87 0 R/Next 89 0 R>> endobj 89 0 obj < /Dest[16 0 R/XYZ 0 595 0]/Parent 87 0 R/Prev 88 0 R>> endobj 29 0 obj <> endobj 90 0 obj <> endobj 91 0 obj < /Creator /Producer /CreationDate(D:20170422104332+02'00')>> endobj xref 0 92 0000000000 65535 f 0000108370 00000 n 0000000019 00000 n 0000003554 00000 n 0000003575 00000 n 0000003809 00000 n 0000003851 00000 n 0000004080 00000 n 0000004122 00000 n 0000004359 00000 n 0000004401 00000 n 0000004629 00000 n 0000004672 00000 n 0000004901 00000 n 0000004944 00000 n 0000005178 00000 n 0000108514 00000 n 0000005221 00000 n 0000009581 00000 n 0000009603 00000 n 0000009833 00000 n 0000009876 00000 n 0000010108 00000 n 0000010151 00000 n 0000010383 00000 n 0000010426 00000 n 0000010659 00000 n 0000010702 00000 n 0000010932 00000 n 0000108959 00000 n 0000010975 00000 n 0000018591 00000 n 0000018613 00000 n 0000018817 00000 n 0000019194 00000 n 0000019435 00000 n 0000029652 00000 n 0000029675 00000 n 0000029874 00000 n 0000030368 00000 n 0000030715 00000 n 0000042905 00000 n 0000042928 00000 n 0000043122 00000 n 0000043652 00000 n 0000044030 00000 n 0000049855 00000 n 0000049877 00000 n 0000050079 00000 n 0000050398 00000 n 0000050588 00000 n 0000055824 00000 n 0000055846 00000 n 0000056032 00000 n 0000056414 00000 n 0000056640 00000 n 0000059812 00000 n 0000059834 00000 n 0000060031 00000 n 0000060322 00000 n 0000060488 00000 n 0000073467 00000 n 0000073490 00000 n 0000073686 00000 n 0000074159 00000 n 0000074485 00000 n 0000086039 00000 n 0000086062 00000 n 0000086270 00000 n 0000086704 00000 n 0000087001 00000 n 0000094982 00000 n 0000095004 00000 n 0000095207 00000 n 0000095618 00000 n 0000095889 00000 n 0000101026 00000 n 0000101048 00000 n 0000101260 00000 n 0000101590 00000 n 0000101794 00000 n 0000107189 00000 n 0000107211 00000 n 0000107408 00000 n 0000107700 00000 n 0000107865 00000 n 0000108001 00000 n 0000108660 00000 n 0000108716 00000 n 0000108837 00000 n 0000109066 00000 n 0000109168 00000 n trailer < ] /DocChecksum /EB615454BC35DF42CBFCE0F7FCC8BC84 >> startxref 109385 %%EOF trompeloeil-47/include/000077500000000000000000000000001454452461300152745ustar00rootroot00000000000000trompeloeil-47/include/boost/000077500000000000000000000000001454452461300164225ustar00rootroot00000000000000trompeloeil-47/include/boost/trompeloeil.hpp000066400000000000000000000016721454452461300214740ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_BOOST_HPP_ #define TROMPELOEIL_BOOST_HPP_ #ifndef BOOST_TEST #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, char const *file, unsigned long line, const char* msg) { std::ostringstream os; if (line != 0U) os << file << ':' << line << '\n'; auto text = os.str() + msg; if (s == severity::fatal) BOOST_FAIL(text); else BOOST_ERROR(text); } } #endif //TROMPELOEIL_BOOST_HPP_ trompeloeil-47/include/cantata/000077500000000000000000000000001454452461300167075ustar00rootroot00000000000000trompeloeil-47/include/cantata/trompeloeil.hpp000066400000000000000000000024641454452461300217610ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2023 * Copyright Andreas Schätti 2023 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CANTATA_HPP_ #define TROMPELOEIL_CANTATA_HPP_ #ifndef INCLUDED_CANTPP_H #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, char const *file, unsigned long line, const char* msg) { std::ostringstream os; if (line != 0U) os << file << ':' << line << '\n'; auto text = os.str() + msg; if (s == severity::fatal) { text += "\nseverity: fatal\n"; CHECK_NAMED(text.c_str(), true, false); throw expectation_violation("severity: fatal"); } else { CHECK_NAMED(text.c_str(), true, false); } } template <> inline void reporter::sendOk( const char* trompeloeil_mock_calls_done_correctly) { CHECK_NAMED(trompeloeil_mock_calls_done_correctly, true, true); } } #endif //TROMPELOEIL_CANTATA_HPP_ trompeloeil-47/include/catch2/000077500000000000000000000000001454452461300164405ustar00rootroot00000000000000trompeloeil-47/include/catch2/trompeloeil.hpp000066400000000000000000000031511454452461300215040ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * Copyright Tore Martin Hagen 2019 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CATCH2_HPP_ #define TROMPELOEIL_CATCH2_HPP_ #if !((defined(CATCH_CONFIG_PREFIX_ALL) && defined(CATCH_CHECK)) \ || (!defined(CATCH_CONFIG_PREFIX_ALL) && defined(CHECK))) #error "Catch2 macros must be defined before including " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, const char* file, unsigned long line, const char* msg) { std::ostringstream os; if (line) os << file << ':' << line << '\n'; os << msg; auto failure = os.str(); if (s == severity::fatal) { #ifdef CATCH_CONFIG_PREFIX_ALL CATCH_FAIL(failure); #else FAIL(failure); #endif } else { #ifdef CATCH_CONFIG_PREFIX_ALL CATCH_CAPTURE(failure); CATCH_CHECK(failure.empty()); #else CAPTURE(failure); CHECK(failure.empty()); #endif } } template <> inline void reporter::sendOk( const char* trompeloeil_mock_calls_done_correctly) { #ifdef CATCH_CONFIG_PREFIX_ALL CATCH_REQUIRE(trompeloeil_mock_calls_done_correctly != 0); #else REQUIRE(trompeloeil_mock_calls_done_correctly != 0); #endif } } #endif //TROMPELOEIL_CATCH2_HPP_ trompeloeil-47/include/criterion/000077500000000000000000000000001454452461300172725ustar00rootroot00000000000000trompeloeil-47/include/criterion/trompeloeil.hpp000066400000000000000000000024441454452461300223420ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * Copyright Etienne Barbier 2020 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CRITERION_HPP_ #define TROMPELOEIL_CRITERION_HPP_ #ifndef CRITERION_H_ #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, char const *file, unsigned long line, const char* msg) { struct criterion_assert_stats cr_stat__; cr_stat__.passed = false; cr_stat__.file = file; cr_stat__.line = line; cr_stat__.message = msg; if (s == severity::fatal) { criterion_send_assert(&cr_stat__); CR_FAIL_ABORT_(); } else { criterion_send_assert(&cr_stat__); CR_FAIL_CONTINUES_(); } } template <> inline void reporter::sendOk( const char* trompeloeil_mock_calls_done_correctly) { cri_asserts_passed_incr(); } } #endif //TROMPELOEIL_CRITERION_HPP_ trompeloeil-47/include/crpcut/000077500000000000000000000000001454452461300165745ustar00rootroot00000000000000trompeloeil-47/include/crpcut/trompeloeil.hpp000066400000000000000000000022321454452461300216370ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CRPCUT_HPP_ #define TROMPELOEIL_CRPCUT_HPP_ #ifndef CRPCUT_HERE #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity, char const *file, unsigned long line, const char* msg) { std::ostringstream os; os << file << ':' << line; auto loc = os.str(); auto location = line == 0U ? ::crpcut::crpcut_test_monitor::current_test()->get_location() : ::crpcut::datatypes::fixed_string::make(loc.c_str(), loc.length()); ::crpcut::comm::report(::crpcut::comm::exit_fail, std::ostringstream(msg), location); } } #endif //TROMPELOEIL_CRPCUT_HPP_ trompeloeil-47/include/cxxtest/000077500000000000000000000000001454452461300167765ustar00rootroot00000000000000trompeloeil-47/include/cxxtest/trompeloeil.hpp000066400000000000000000000023611454452461300220440ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * Copyright (C) 2019 Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CXXTEST_HPP_ #define TROMPELOEIL_CXXTEST_HPP_ #ifndef CXXTEST_FLAGS #error " must be included before " #endif #include "../trompeloeil.hpp" #include #include namespace trompeloeil { template <> inline void reporter::send( severity s, const char* file, unsigned long line, const char* msg) { std::ostringstream os; if (line) os << file << ':' << line << '\n'; os << msg; auto failure = os.str(); if (s == severity::fatal) { // Must not return normally i.e. must throw, abort or terminate. TS_FAIL(failure); } else { // nonfatal: violation occurred during stack rollback. // Must not throw an exception. TS_WARN(failure); } } } /* namespace trompeloeil */ #endif //TROMPELOEIL_CXXTEST_HPP_ trompeloeil-47/include/doctest/000077500000000000000000000000001454452461300167415ustar00rootroot00000000000000trompeloeil-47/include/doctest/trompeloeil.hpp000066400000000000000000000024731454452461300220130ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2022 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_DOCTEST_HPP_ #define TROMPELOEIL_DOCTEST_HPP_ #ifndef DOCTEST_VERSION_MAJOR #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, const char* file, unsigned long line, const char* msg) { doctest::String msgstr(msg); auto f = line ? file : "[file/line unavailable]"; if (s == severity::fatal) { DOCTEST_ADD_FAIL_AT(f, line, msgstr); } else { DOCTEST_ADD_FAIL_CHECK_AT(f, line, msgstr); } } template <> inline void reporter::sendOk( const char* trompeloeil_mock_calls_done_correctly) { #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING DOCTEST_REQUIRE_UNARY(trompeloeil_mock_calls_done_correctly); #else DOCTEST_REQUIRE_NE(doctest::String(trompeloeil_mock_calls_done_correctly), ""); #endif } } #endif //TROMPELOEIL_DOCTEST_HPP_ trompeloeil-47/include/gtest/000077500000000000000000000000001454452461300164225ustar00rootroot00000000000000trompeloeil-47/include/gtest/trompeloeil.hpp000066400000000000000000000017271454452461300214750ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright Björn Fahller 2014-2019 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_GTEST_HPP_ #define TROMPELOEIL_GTEST_HPP_ #ifndef GTEST_TEST #error " must be included before " #endif #include "../trompeloeil.hpp" namespace trompeloeil { template <> inline void reporter::send( severity s, char const *file, unsigned long line, const char* msg) { if (s == severity::fatal) { std::ostringstream os; if (line != 0U) { os << file << ':' << line << '\n'; } throw expectation_violation(os.str() + msg); } ADD_FAILURE_AT(file, line) << msg; } } #endif //TROMPELOEIL_GTEST_HPP_ trompeloeil-47/include/trompeloeil.hpp000066400000000000000000000023701454452461300203420ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller 2014-2021 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_HPP_ #define TROMPELOEIL_HPP_ // trompe l'oeil noun (Concise Encyclopedia) // Style of representation in which a painted object is intended // to deceive the viewer into believing it is the object itself... // project home: https://github.com/rollbear/trompeloeil // Deficiencies and missing features // * Mocking function templates is not supported // * If a macro kills a kitten, this threatens extinction of all felines! #include "trompeloeil/mock.hpp" #include "trompeloeil/lifetime.hpp" #include "trompeloeil/matcher.hpp" #include "trompeloeil/matcher/any.hpp" #include "trompeloeil/matcher/compare.hpp" #include "trompeloeil/matcher/deref.hpp" #include "trompeloeil/matcher/not.hpp" #include "trompeloeil/matcher/re.hpp" #include "trompeloeil/sequence.hpp" #include "trompeloeil/stream_tracer.hpp" #ifdef __cpp_impl_coroutine #include "trompeloeil/coro.hpp" #endif #endif // include guard trompeloeil-47/include/trompeloeil/000077500000000000000000000000001454452461300176275ustar00rootroot00000000000000trompeloeil-47/include/trompeloeil/coro.hpp000066400000000000000000000362031454452461300213060ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CORO_HPP #define TROMPELOEIL_CORO_HPP #if defined(__cpp_impl_coroutine) # define TROMPELOEIL_COROUTINES_SUPPORTED 1 #else # error "Coroutines are not supported by this compiler" #endif #ifdef TROMPELOEIL_COROUTINES_SUPPORTED #ifndef TROMPELOEIL_MOCK_HPP_ #include "mock.hpp" #endif namespace trompeloeil { template struct type_wrapper{ template static V remove_rvalue_ref(V&&); using type = decltype(remove_rvalue_ref(std::declval())); }; template <> struct type_wrapper { using type = void; }; template struct coro_value_type { static auto func() { if constexpr (requires {std::declval().operator co_await();}) { return type_wrapper().operator co_await().await_resume())>{}; } else { return type_wrapper().await_resume())>{}; } } using type = typename decltype(func())::type; }; template using coro_value_type_t = typename coro_value_type::type; template struct yield_expr_base : public list_elem> { ~yield_expr_base() override = default; using ret_type = coro_value_type_t>; virtual ret_type expr( call_params_type_t&) const = 0; }; template struct yield_expr_base : public list_elem> { using ret_type = return_of_t; virtual ret_type expr( call_params_type_t&) const = 0; }; template struct yield_expr : yield_expr_base { using ret_type = typename yield_expr_base::ret_type; template explicit yield_expr( E&& e_) : e(std::forward(e_)) {} ret_type expr( call_params_type_t& t) const override { return e(t); } private: Expr e; }; template class co_return_handler_t : public return_handler { public: template explicit co_return_handler_t( U&& u, std::shared_ptr> yields_) : func(std::forward(u)) , yields(std::move(yields_)) {} return_of_t call( trace_agent& /*agent*/, call_params_type_t& params) override { using coro_type = return_of_t; using promise_type = typename std::coroutine_traits::promise_type; using value_type = coro_value_type_t; if constexpr (requires {std::declval().yield_value(std::declval());}) { for (auto & e : *yields) { co_yield e.expr(params); } } co_return func(params); } private: T func; std::shared_ptr> yields; }; template struct co_throw_handler_t { using R = decltype(default_return>()); using promise_value_type = trompeloeil::coro_value_type_t; explicit co_throw_handler_t(H&& h_) : h(std::move(h_)) {} template promise_value_type operator()(T& p) { return ((void)h(p), trompeloeil::default_return()); } private: H h; }; struct handle_co_yield { template static call_modifier action( call_modifier&& m, E&& e) { using signature = typename Parent::signature; using params_type = call_params_type_t&; using sigret = return_of_t; using ret = std::invoke_result_t; constexpr bool is_void = std::is_same_v; constexpr bool is_coroutine = trompeloeil::is_coroutine::value; constexpr bool is_matching_type = std::invoke([]{ if constexpr (is_coroutine && !is_void) { using promise = typename std::coroutine_traits::promise_type; return requires(promise p, ret r){ p.yield_value(r); }; } else { return false; } }); static_assert(is_coroutine, "CO_YIELD when return type is not a coroutine"); static_assert(!is_coroutine || !is_void, "You cannot CO_YIELD void"); static_assert(!is_coroutine || is_void || is_matching_type, "CO_YIELD is incompatible with the promise type"); constexpr auto valid = is_coroutine && !is_void && is_matching_type; if constexpr (valid) { if (!m.matcher->yield_expressions) { m.matcher->yield_expressions = std::make_shared>(); } auto expr = new yield_expr(std::forward(e)); m.matcher->yield_expressions->push_back(expr); } return {m.matcher}; } }; struct handle_co_return { template static call_modifier, Parent>> action( call_modifier&& m, H&& h) { using signature = typename Parent::signature; using return_type = typename Parent::return_type; using co_return_type = typename Parent::co_return_type; using params_type = call_params_type_t&; using sigret = return_of_t; using ret = std::invoke_result_t; constexpr bool has_return = !std::is_same_v; constexpr bool has_co_return = !std::is_same_v; constexpr bool is_coroutine = trompeloeil::is_coroutine::value; constexpr bool is_matching_type = std::invoke([]{if constexpr (is_coroutine) { using promise = typename std::coroutine_traits::promise_type; if constexpr (std::is_same_v) { return requires (promise p){p.return_void();}; } else { return requires(promise p) { p.return_value(std::declval()); }; }} return true;}); static_assert(!has_return, "CO_RETURN and RETURN cannot be combined"); static_assert(has_return || !has_co_return, "Multiple CO_RETURN does not make sense"); static_assert(has_return || is_coroutine, "CO_RETURN when return type is not a coroutine"); static_assert(has_return || has_co_return || !is_coroutine || is_matching_type, "Expression type does not match the coroutine promise type"); static_assert(!Parent::throws || Parent::upper_call_limit == 0, "CO_THROW and CO_RETURN does not make sense"); static_assert(Parent::upper_call_limit > 0, "CO_RETURN for forbidden call does not make sense"); constexpr bool valid = !has_return && !has_co_return && is_coroutine && is_matching_type && !Parent::throws && Parent::upper_call_limit > 0; if constexpr (valid) { using basic_t = typename std::remove_reference::type; using handler = co_return_handler_t; if (!m.matcher->yield_expressions) { m.matcher->yield_expressions = std::make_shared>(); } m.matcher->return_handler_obj.reset( new handler(std::forward(h), m.matcher->yield_expressions) ); } return {m.matcher}; } }; struct handle_co_throw { template static call_modifier> action( call_modifier&& m, H&& h) { using signature = typename Parent::signature; using co_return_type = typename Parent::co_return_type; using sigret = return_of_t; constexpr bool is_coroutine = trompeloeil::is_coroutine::value; static_assert(is_coroutine, "Do not use CO_THROW from a normal function, use THROW"); static_assert(!is_coroutine || !Parent::throws, "Multiple CO_THROW does not make sense"); constexpr bool has_return = !std::is_same::value; static_assert(!is_coroutine || !has_return, "CO_THROW and CO_RETURN does not make sense"); constexpr bool forbidden = Parent::upper_call_limit == 0U; static_assert(!is_coroutine || !forbidden, "CO_THROW for forbidden call does not make sense"); constexpr bool valid = is_coroutine && !Parent::throws && !has_return; if constexpr (valid) { if (!m.matcher->yield_expressions) { m.matcher->yield_expressions = std::make_shared>(); } using throw_handler_t = co_throw_handler_t; auto handler = throw_handler_t(std::forward(h)); using ret_handler = co_return_handler_t; m.matcher->return_handler_obj.reset(new ret_handler(std::move(handler), m.matcher->yield_expressions)); } return {m.matcher}; } }; } #define TROMPELOEIL_CO_RETURN(...) TROMPELOEIL_CO_RETURN_(=, __VA_ARGS__) #define TROMPELOEIL_LR_CO_RETURN(...) TROMPELOEIL_CO_RETURN_(&, __VA_ARGS__) #define TROMPELOEIL_CO_RETURN_(capture, ...) \ template action([capture](auto& trompeloeil_x)\ -> decltype(auto) { \ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ return ::trompeloeil::decay_return_type(__VA_ARGS__); \ }) #define TROMPELOEIL_CO_THROW(...) TROMPELOEIL_CO_THROW_(=, __VA_ARGS__) #define TROMPELOEIL_LR_CO_THROW(...) TROMPELOEIL_CO_THROW_(&, __VA_ARGS__) #define TROMPELOEIL_CO_THROW_(capture, ...) \ template action([capture](auto& trompeloeil_x){\ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ throw __VA_ARGS__; \ }) #define TROMPELOEIL_CO_YIELD(...) TROMPELOEIL_CO_YIELD_(=, __VA_ARGS__) #define TROMPELOEIL_LR_CO_YIELD(...) TROMPELOEIL_CO_YIELD_(&, __VA_ARGS__) #define TROMPELOEIL_CO_YIELD_(capture, ...) \ template action([capture](auto& trompeloeil_x){\ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ return __VA_ARGS__; \ }) #ifndef TROMPELOEIL_LONG_MACROS #define CO_RETURN TROMPELOEIL_CO_RETURN #define LR_CO_RETURN TROMPELOEIL_LR_CO_RETURN #define CO_THROW TROMPELOEIL_CO_THROW #define LR_CO_THROW TROMPELOEIL_LR_CO_THROW #define CO_YIELD TROMPELOEIL_CO_YIELD #define LR_CO_YIELD TROMPELOEIL_LR_CO_YIELD #endif #endif #endif //TROMPELOEIL_CORO_HPP trompeloeil-47/include/trompeloeil/cpp11_shenanigans.hpp000066400000000000000000000333531454452461300236510ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_CPP11_SHENANIGANS_HPP #define TROMPELOEIL_CPP11_SHENANIGANS_HPP namespace trompeloeil { namespace detail { template struct unwrap_type { using type = T; }; template struct unwrap_type> { using type = T&; }; /* Implement C++14 features using only C++11 entities. */ /* */ /* Implementation of make_unique is from * * Stephan T. Lavavej, "make_unique (Revision 1)," * ISO/IEC JTC1 SC22 WG21 N3656, 18 April 2013. * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3656.htm * Accessed: 14 June 2017 * * Renamed types to avoid the use of reserved identifiers. */ template struct unique_if { typedef std::unique_ptr single_object; }; template struct unique_if { typedef std::unique_ptr unknown_bound; }; template struct unique_if { typedef void known_bound; }; template typename unique_if::single_object make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } template typename unique_if::unknown_bound make_unique(size_t n) { typedef typename std::remove_extent::type U; return std::unique_ptr(new U[n]()); } template typename unique_if::known_bound make_unique(Args&&...) = delete; /* */ /* The implementation of these is from * * Walter E. Brown, "TransformationTraits Redux, v2," * ISO/IEC JTC1 SC22 WG21 N3655, 18 April 2013. * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3655.pdf * Accessed: 2 November 2017 * * Minor changes to capitalize template parameter `bool B` has been made. * * See also: * http://en.cppreference.com/w/cpp/types/conditional * http://en.cppreference.com/w/cpp/types/decay * http://en.cppreference.com/w/cpp/types/enable_if * http://en.cppreference.com/w/cpp/types/remove_pointer * http://en.cppreference.com/w/cpp/types/remove_reference * Accessed: 17 May 2017 */ template using conditional_t = typename std::conditional::type; template using decay_t = typename std::decay::type; template using enable_if_t = typename std::enable_if::type; template using remove_pointer_t = typename std::remove_pointer::type; template using remove_reference_t = typename std::remove_reference::type; /* */ /* This implementation of exchange is from * * Jeffrey Yasskin, "exchange() utility function, revision 3," * ISO/IEC JTC1 SC22 WG21 N3688, 19 April 2013. * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3668.html * Accessed: 2 November 2017 * * See also: * http://en.cppreference.com/w/cpp/utility/exchange * Accessed: 17 May 2017 */ template inline T exchange( T& obj, U&& new_value) { T old_value = std::move(obj); obj = std::forward(new_value); return old_value; } /* integer_sequence and index_sequence implementations are from * * Jonathan Wakely, "Compile-time integer sequences," * ISO/IEC JTC1 SC22 WG21 N3658, 18 April 2013. * Available: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3658.html * Accessed: 2 November 2017 * * See also: * http://en.cppreference.com/w/cpp/utility/integer_sequence * Accessed: 17 May 2017 */ template struct integer_sequence { // Replaces a typedef used in the definition found in N3658. using value_type = T; static constexpr size_t size() noexcept { return sizeof...(I); } }; template using index_sequence = integer_sequence; /* This implementation of make_integer_sequence is from boost/mp11, * * Copyright 2015, 2017 Peter Dimov * * Distributed under the Boost Software License, Version 1.0. * * Implemented here: * * https://github.com/pdimov/mp11/blob/master/include/boost/ * integer_sequence.hpp * Accessed: 17 May 2017 * * (now missing) and here: * * https://github.com/boostorg/mp11/blob/develop/include/boost/ * mp11/integer_sequence.hpp * Accessed: 13 August 2017 */ namespace impl { // iseq_if_c template struct iseq_if_c_impl; template struct iseq_if_c_impl { using type = T; }; template struct iseq_if_c_impl { using type = E; }; template using iseq_if_c = typename iseq_if_c_impl::type; // iseq_identity template struct iseq_identity { using type = T; }; template struct append_integer_sequence; template struct append_integer_sequence, integer_sequence> { using type = integer_sequence; }; template struct make_integer_sequence_impl; template struct make_integer_sequence_impl_ { private: static_assert( N >= 0, "make_integer_sequence: N must not be negative" ); static T const M = N / 2; static T const R = N % 2; using S1 = typename make_integer_sequence_impl::type; using S2 = typename append_integer_sequence::type; using S3 = typename make_integer_sequence_impl::type; using S4 = typename append_integer_sequence::type; public: using type = S4; }; template struct make_integer_sequence_impl: iseq_if_c>, iseq_if_c>, make_integer_sequence_impl_>> { }; } template using make_integer_sequence = typename impl::make_integer_sequence_impl::type; template using make_index_sequence = make_integer_sequence; template using index_sequence_for = make_index_sequence; } /* namespace detail */ } #define TROMPELOEIL_WITH_(capture, arg_s, ...) \ template action( \ arg_s, \ [capture] \ (typename trompeloeil_e_t::trompeloeil_call_params_type_t const& trompeloeil_x)\ { \ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore( \ _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ return __VA_ARGS__; \ }) #define TROMPELOEIL_SIDE_EFFECT_(capture, ...) \ template action( \ [capture] \ (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ { \ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore( \ _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ __VA_ARGS__; \ }) #define TROMPELOEIL_RETURN_(capture, ...) \ template action( \ [capture] \ (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ -> typename trompeloeil_e_t::trompeloeil_return_of_t \ { \ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore( \ _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ return ::trompeloeil::decay_return_type(__VA_ARGS__); \ }) #define TROMPELOEIL_THROW_(capture, ...) \ template action( \ [capture] \ (typename trompeloeil_e_t::trompeloeil_call_params_type_t& trompeloeil_x) \ { \ auto&& _1 = ::trompeloeil::mkarg<1>(trompeloeil_x); \ auto&& _2 = ::trompeloeil::mkarg<2>(trompeloeil_x); \ auto&& _3 = ::trompeloeil::mkarg<3>(trompeloeil_x); \ auto&& _4 = ::trompeloeil::mkarg<4>(trompeloeil_x); \ auto&& _5 = ::trompeloeil::mkarg<5>(trompeloeil_x); \ auto&& _6 = ::trompeloeil::mkarg<6>(trompeloeil_x); \ auto&& _7 = ::trompeloeil::mkarg<7>(trompeloeil_x); \ auto&& _8 = ::trompeloeil::mkarg<8>(trompeloeil_x); \ auto&& _9 = ::trompeloeil::mkarg<9>(trompeloeil_x); \ auto&&_10 = ::trompeloeil::mkarg<10>(trompeloeil_x); \ auto&&_11 = ::trompeloeil::mkarg<11>(trompeloeil_x); \ auto&&_12 = ::trompeloeil::mkarg<12>(trompeloeil_x); \ auto&&_13 = ::trompeloeil::mkarg<13>(trompeloeil_x); \ auto&&_14 = ::trompeloeil::mkarg<14>(trompeloeil_x); \ auto&&_15 = ::trompeloeil::mkarg<15>(trompeloeil_x); \ ::trompeloeil::ignore( \ _1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15); \ throw __VA_ARGS__; \ }) #endif //TROMPELOEIL_CPP11_SHENANIGANS_HPP trompeloeil-47/include/trompeloeil/lifetime.hpp000066400000000000000000000142701454452461300221420ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_LIFETIME_HPP #define TROMPELOEIL_LIFETIME_HPP #ifndef TROMPELOEIL_MOCK_HPP_ #include "mock.hpp" #endif #if defined(__cxx_rtti) || defined(__GXX_RTTI) || defined(_CPPRTTI) # define TROMPELOEIL_TYPE_ID_NAME(x) typeid(x).name() #else # define TROMPELOEIL_TYPE_ID_NAME(x) "object" #endif namespace trompeloeil { struct lifetime_monitor; template class deathwatched : public T { static_assert(std::has_virtual_destructor::value, "virtual destructor is a necessity for deathwatched to work"); public: template ::value>> deathwatched( U&& ...u) noexcept(noexcept(T(std::declval()...))) : T(std::forward(u)...) {} ~deathwatched() override; trompeloeil::lifetime_monitor*& trompeloeil_expect_death( trompeloeil::lifetime_monitor* monitor) const noexcept { auto lock = get_lock(); trompeloeil_lifetime_monitor = monitor; return trompeloeil_lifetime_monitor.leak(); } private: mutable null_on_move trompeloeil_lifetime_monitor; }; struct lifetime_monitor : public expectation { template lifetime_monitor( ::trompeloeil::deathwatched const &obj, char const* obj_name_, char const* invocation_name_, char const* call_name_, location loc_) noexcept : object_monitor(obj.trompeloeil_expect_death(this)) , loc(loc_) , object_name(obj_name_) , invocation_name(invocation_name_) , call_name(call_name_) { } bool is_satisfied() const noexcept override { return died; } bool is_saturated() const noexcept override { return died; } lifetime_monitor(lifetime_monitor const&) = delete; ~lifetime_monitor() override { auto lock = get_lock(); if (!died) { std::ostringstream os; os << "Object " << object_name << " is still alive"; send_report(severity::nonfatal, loc, os.str()); object_monitor = nullptr; // prevent its death poking this cadaver } } void notify() noexcept { died = true; sequences->validate(severity::nonfatal, call_name, loc); sequences->increment_call(); if (sequences->is_satisfied()) { sequences->retire_predecessors(); } } template void set_sequence( T&& ... t) { using handler = sequence_handler; auto seq = detail::make_unique(*sequences, invocation_name, loc, std::forward(t)...); sequences = std::move(seq); } private: atomic died{false}; lifetime_monitor *&object_monitor; location loc; char const *object_name; char const *invocation_name; char const *call_name; std::unique_ptr sequences = detail::make_unique>(); }; template deathwatched::~deathwatched() { auto lock = get_lock(); if (trompeloeil_lifetime_monitor) { trompeloeil_lifetime_monitor->notify(); return; } std::ostringstream os; os << "Unexpected destruction of " << TROMPELOEIL_TYPE_ID_NAME(T) << "@" << this << '\n'; send_report(severity::nonfatal, location{}, os.str()); } template struct lifetime_monitor_modifier : std::unique_ptr { explicit lifetime_monitor_modifier( std::unique_ptr&& p) noexcept : unique_ptr(std::move(p)) {} template auto in_sequence(T&& ... t) -> lifetime_monitor_modifier { static_assert(!b, "Multiple IN_SEQUENCE does not make sense." " You can list several sequence objects at once"); std::unique_ptr& m = *this; m->set_sequence(std::forward(t)...); return lifetime_monitor_modifier{std::move(m)}; } }; struct lifetime_monitor_releaser { template std::unique_ptr operator+( lifetime_monitor_modifier&& m) const { return std::move(m); } }; } #define TROMPELOEIL_REQUIRE_DESTRUCTION(obj) \ TROMPELOEIL_REQUIRE_DESTRUCTION_(obj, #obj) #define TROMPELOEIL_REQUIRE_DESTRUCTION_(obj, obj_s) \ std::unique_ptr \ TROMPELOEIL_CONCAT(trompeloeil_death_monitor_, __LINE__) \ = TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_(,obj, obj_s) #define TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION(obj) \ TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_("NAMED_", obj, #obj) #define TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION_(prefix, obj, obj_s) \ trompeloeil::lifetime_monitor_releaser{} + \ trompeloeil::lifetime_monitor_modifier{ \ ::trompeloeil::detail::make_unique( \ obj, \ obj_s, \ prefix "REQUIRE_DESTRUCTION(" obj_s ")", \ "destructor for " obj_s, \ ::trompeloeil::location{__FILE__, \ static_cast(__LINE__)}) \ } #ifndef TROMPELOEIL_LONG_MACROS #define REQUIRE_DESTRUCTION TROMPELOEIL_REQUIRE_DESTRUCTION #define NAMED_REQUIRE_DESTRUCTION TROMPELOEIL_NAMED_REQUIRE_DESTRUCTION #endif #endif //TROMPELOEIL_LIFETIME_HPP trompeloeil-47/include/trompeloeil/matcher.hpp000066400000000000000000000150661454452461300217730ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_MATCHER_HPP #define TROMPELOEIL_MATCHER_HPP #ifndef TROMPELOEIL_MOCK_HPP_ #include "mock.hpp" #endif namespace trompeloeil { template struct typed_matcher : matcher { template operator T() const { static_assert(b, "Getting a value from a typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "and https://github.com/rollbear/trompeloeil/issues/290"); return {}; } }; template <> struct typed_matcher : matcher { template < typename T, typename = decltype(std::declval() == nullptr) > operator T&&() const { static_assert(std::is_same{}, "Getting a value from a typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "https://github.com/rollbear/trompeloeil/issues/290"); return *this; } template < typename T, typename = decltype(std::declval() == nullptr) > operator T&()const volatile { static_assert(std::is_same{}, "Getting a value from a typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "and https://github.com/rollbear/trompeloeil/issues/290"); return *this; } template operator T C::*() const { static_assert(std::is_same{}, "Getting a value from a typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "and https://github.com/rollbear/trompeloeil/issues/290"); return *this; } }; template class duck_typed_matcher : public matcher { public: #if (!TROMPELOEIL_GCC) || \ (TROMPELOEIL_GCC && TROMPELOEIL_GCC_VERSION >= 40900) // g++ 4.8 gives a "conversion from to is ambiguous" error // if this operator is defined. template < typename V, typename = detail::enable_if_t{}>, typename = invoke_result_type > operator V&&() const { #if !TROMPELOEIL_CLANG || TROMPELOEIL_CLANG_VERSION >= 40000 // clang 3.x instantiates the function even when it's only used // for compile time signature checks and never actually called. static_assert(std::is_same{}, "Getting a value from a duck typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "and https://github.com/rollbear/trompeloeil/issues/290"); #endif return *this; } #endif template < typename V, typename = detail::enable_if_t{}>, typename = invoke_result_type > operator V&() const volatile { static_assert(std::is_same{}, "Getting a value from a duck typed matcher is not allowed.\n" "See https://github.com/rollbear/trompeloeil/issues/270\n" "and https://github.com/rollbear/trompeloeil/issues/290"); return *this; } }; template struct matcher_kind { using type = typed_matcher; }; template struct matcher_kind { using type = duck_typed_matcher; }; template using matcher_kind_t = typename matcher_kind::type; template class predicate_matcher : private Predicate , private Printer , public MatcherType { public: template constexpr predicate_matcher( Predicate&& pred, Printer&& printer, U&& ... v) noexcept(noexcept(std::tuple(std::declval()...)) && noexcept(Predicate(std::declval())) && noexcept(Printer(std::declval()))) : Predicate(std::move(pred)) , Printer(std::move(printer)) , value(std::forward(v)...) {} template constexpr bool matches( V&& v) const noexcept(noexcept(std::declval()(std::declval(), std::declval()...))) { return matches_(std::forward(v), detail::make_index_sequence{}); } friend std::ostream& operator<<( std::ostream& os, predicate_matcher const& v) { return v.print_(os, detail::make_index_sequence{}); } private: // The below function call operator must be declared to // work around gcc bug 78446 // // For some reason microsoft compiler from VS2015 update 3 // requires the function call operator to be private to avoid // ambiguities. template void operator()(U&&...) const = delete; template bool matches_(V&& v, detail::index_sequence) const { return Predicate::operator()(std::forward(v), std::get(value)...); } template std::ostream& print_(std::ostream& os_, detail::index_sequence) const { Printer::operator()(os_, std::get(value)...); return os_; } std::tuple value; }; template using make_matcher_return = predicate_matcher...>, detail::decay_t...>; template inline make_matcher_return make_matcher(Predicate pred, Printer print, T&& ... t) { return {std::move(pred), std::move(print), std::forward(t)...}; } } #endif //TROMPELOEIL_MATCHER_HPP trompeloeil-47/include/trompeloeil/matcher/000077500000000000000000000000001454452461300212525ustar00rootroot00000000000000trompeloeil-47/include/trompeloeil/matcher/any.hpp000066400000000000000000000041021454452461300225470ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_ANY_HPP #define TROMPELOEIL_ANY_HPP #ifndef TROMPELOEIL_MATCHER_HPP #include "../matcher.hpp" #endif namespace trompeloeil { namespace lambdas { struct any_predicate { template bool operator()( T&&) const { return true; } }; // Define `struct` with `operator()` to replace generic lambdas. struct any_printer { explicit any_printer( char const* type_name_) : type_name(type_name_) {} void operator()( std::ostream& os) const { os << " matching ANY(" << type_name << ")"; } private: char const* type_name; }; } template < typename T, typename R = make_matcher_return> inline auto any_matcher_impl(char const* type_name, std::false_type) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::any_predicate(), lambdas::any_printer(type_name)); } template wildcard any_matcher_impl(char const*, std::true_type); template inline auto any_matcher(char const* name) TROMPELOEIL_TRAILING_RETURN_TYPE(decltype(any_matcher_impl(name, std::is_array{}))) { static_assert(!std::is_array::value, "array parameter type decays to pointer type for ANY()" " matcher. Please rephrase as pointer instead"); return any_matcher_impl(name, std::is_array{}); } } #define TROMPELOEIL_ANY(type) ::trompeloeil::any_matcher(#type) #ifndef TROMPELOEIL_LONG_MACROS #define ANY TROMPELOEIL_ANY #endif #endif //TROMPELOEIL_ANY_HPP trompeloeil-47/include/trompeloeil/matcher/compare.hpp000066400000000000000000000117231454452461300234150ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_COMPARE_HPP #define TROMPELOEIL_COMPARE_HPP #ifndef TROMPELOEIL_MATCHER_HPP #include "../matcher.hpp" #endif namespace trompeloeil { namespace lambdas { // The below must be classes/structs to work with VS 2015 update 3 // since it doesn't respect the trailing return type declaration on // the lambdas of template deduction context #define TROMPELOEIL_MK_PRED_BINOP(name, op) \ struct name { \ template \ auto operator()(X const& x, Y const& y) const -> decltype(x op y) \ { \ ::trompeloeil::ignore(x,y); \ return x op y; \ } \ } TROMPELOEIL_MK_PRED_BINOP(equal, ==); TROMPELOEIL_MK_PRED_BINOP(not_equal, !=); TROMPELOEIL_MK_PRED_BINOP(less, <); TROMPELOEIL_MK_PRED_BINOP(less_equal, <=); TROMPELOEIL_MK_PRED_BINOP(greater, >); TROMPELOEIL_MK_PRED_BINOP(greater_equal, >=); #undef TROMPELOEIL_MK_PRED_BINOP #define TROMPELOEIL_MK_OP_PRINTER(name, op_string) \ struct name ## _printer \ { \ template \ void \ operator()( \ std::ostream& os, \ T const& value) \ const \ { \ os << op_string; \ ::trompeloeil::print(os, value); \ } \ } TROMPELOEIL_MK_OP_PRINTER(equal, " == "); TROMPELOEIL_MK_OP_PRINTER(not_equal, " != "); TROMPELOEIL_MK_OP_PRINTER(less, " < "); TROMPELOEIL_MK_OP_PRINTER(less_equal, " <= "); TROMPELOEIL_MK_OP_PRINTER(greater, " > "); TROMPELOEIL_MK_OP_PRINTER(greater_equal, " >= "); #undef TROMPELOEIL_MK_OP_PRINTER } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto eq( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::equal(), lambdas::equal_printer(), std::forward(v)); } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto ne( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::not_equal(), lambdas::not_equal_printer(), std::forward(v)); } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto ge( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::greater_equal(), lambdas::greater_equal_printer(), std::forward(v)); } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto gt( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::greater(), lambdas::greater_printer(), std::forward(v)); } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto lt( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::less(), lambdas::less_printer(), std::forward(v)); } template < typename T = wildcard, typename V, typename R = make_matcher_return> inline auto le( V&& v) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::less_equal(), lambdas::less_equal_printer(), std::forward(v)); } } #endif //TROMPELOEIL_COMPARE_HPP trompeloeil-47/include/trompeloeil/matcher/deref.hpp000066400000000000000000000030531454452461300230510ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_DEREF_HPP #define TROMPELOEIL_DEREF_HPP #ifndef TROMPELOEIL_MATCHER_HPP #include "../matcher.hpp" #endif namespace trompeloeil { template class ptr_deref : public matcher { public: template ())>>(std::declval()))> operator U() const; template explicit ptr_deref( U&& m_) : m( std::forward(m_) ) {} template bool matches( const U& u) const noexcept(noexcept(std::declval().matches(*u))) { return (u != nullptr) && m.matches(*u); } friend std::ostream& operator<<( std::ostream& os, ptr_deref const& p) { return os << p.m; } friend std::string param_name_prefix( const ptr_deref*) { return "*" + param_name_prefix(static_cast(nullptr)); } private: M m; }; template ::value>> inline ::trompeloeil::ptr_deref> operator*( M&& m) { return ::trompeloeil::ptr_deref>{std::forward(m)}; } } #endif //TROMPELOEIL_DEREF_HPP trompeloeil-47/include/trompeloeil/matcher/not.hpp000066400000000000000000000030551454452461300225660ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_NOT_HPP #define TROMPELOEIL_NOT_HPP #ifndef TROMPELOEIL_MATCHER_HPP #include "../matcher.hpp" #endif namespace trompeloeil { template class not_matcher : public matcher { public: template ())>>(std::declval()))> operator U() const { return {}; } template explicit not_matcher( U&& m_) : m( std::forward(m_) ) {} template bool matches( const U& u) const noexcept(noexcept(!std::declval().matches(u))) { return !m.matches(u); } friend std::ostream& operator<<( std::ostream& os, not_matcher const& p) { return os << p.m; } friend std::string param_name_prefix( const not_matcher*) { return "not " + param_name_prefix(static_cast(nullptr)); } private: M m; }; template ::value>> inline ::trompeloeil::not_matcher> operator!( M&& m) { return ::trompeloeil::not_matcher>{std::forward(m)}; } } #endif //TROMPELOEIL_NOT_HPP trompeloeil-47/include/trompeloeil/matcher/re.hpp000066400000000000000000000060471454452461300224000ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) Andrew Paxie * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_RE_HPP #define TROMPELOEIL_RE_HPP #ifndef TROMPELOEIL_MATCHER_HPP #include "../matcher.hpp" #endif #include #include namespace trompeloeil { namespace lambdas { struct regex_check { class string_helper // a vastly simplified string_view type of class { public: template < typename S, typename = decltype(std::declval() = std::declval().data()), typename = decltype(std::declval().length()) > string_helper( const S& s) noexcept : begin_(s.data()) , end_(begin_ + s.length()) {} constexpr string_helper( char const* s) noexcept : begin_(s) , end_(s ? begin_ + strlen(s) : nullptr) { } constexpr explicit operator bool() const { return begin_; } constexpr char const * begin() const { return begin_; } constexpr char const * end() const { return end_; } private: char const* begin_; char const* end_; }; regex_check( std::regex&& re_, std::regex_constants::match_flag_type match_type_) : re(std::move(re_)), match_type(match_type_) {} template bool operator()( string_helper str, T const&) const { return str && std::regex_search(str.begin(), str.end(), re, match_type); } private: std::regex re; std::regex_constants::match_flag_type match_type; }; struct regex_printer { template void operator()( std::ostream& os, T const& str) const { os << " matching regular expression /" << str << "/"; } }; } template < typename Kind = wildcard, typename R = make_matcher_return> auto re( std::string s, std::regex_constants::syntax_option_type opt = std::regex_constants::ECMAScript, std::regex_constants::match_flag_type match_type = std::regex_constants::match_default) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::regex_check(std::regex(s, opt), match_type), lambdas::regex_printer(), std::move(s)); } template < typename Kind = wildcard, typename R = make_matcher_return> auto re( std::string s, std::regex_constants::match_flag_type match_type) TROMPELOEIL_TRAILING_RETURN_TYPE(R) { return make_matcher(lambdas::regex_check(std::regex(s), match_type), lambdas::regex_printer(), std::move(s)); } } #endif //TROMPELOEIL_RE_HPP trompeloeil-47/include/trompeloeil/mock.hpp000066400000000000000000003613661454452461300213100ustar00rootroot00000000000000/* * Trompeloeil C++ mocking framework * * Copyright (C) Björn Fahller * Copyright (C) 2017, 2018 Andrew Paxie * Copyright Tore Martin Hagen 2019 * * Use, modification and distribution is subject to the * Boost Software License, Version 1.0. (See accompanying * file LICENSE_1_0.txt or copy atl * http://www.boost.org/LICENSE_1_0.txt) * * Project home: https://github.com/rollbear/trompeloeil */ #ifndef TROMPELOEIL_MOCK_HPP_ #define TROMPELOEIL_MOCK_HPP_ // trompe l'oeil noun (Concise Encyclopedia) // Style of representation in which a painted object is intended // to deceive the viewer into believing it is the object itself... // project home: https://github.com/rollbear/trompeloeil // Deficiencies and missing features // * Mocking function templates is not supported // * If a macro kills a kitten, this threatens extinction of all felines! #if defined(_MSC_VER) # define TROMPELOEIL_NORETURN __declspec(noreturn) # if (!defined(__cplusplus) || _MSC_VER < 1900) # error requires C++ in Visual Studio 2015 RC or later # endif #else # define TROMPELOEIL_NORETURN [[noreturn]] # if (!defined(__cplusplus) || __cplusplus < 201103L) # error requires C++11 or higher # endif #endif #if defined(__clang__) # define TROMPELOEIL_CLANG 1 # define TROMPELOEIL_GCC 0 # define TROMPELOEIL_MSVC 0 # define TROMPELOEIL_CLANG_VERSION \ (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__) # define TROMPELOEIL_GCC_VERSION 0 # define TROMPELOEIL_CPLUSPLUS __cplusplus # define TROMPELOEIL_NOT_IMPLEMENTED(...) \ _Pragma("clang diagnostic push") \ _Pragma("clang diagnostic ignored \"-Wunneeded-member-function\"") \ __VA_ARGS__ \ _Pragma("clang diagnostic pop") #elif defined(__GNUC__) # define TROMPELOEIL_CLANG 0 # define TROMPELOEIL_GCC 1 # define TROMPELOEIL_MSVC 0 # define TROMPELOEIL_CLANG_VERSION 0 # define TROMPELOEIL_GCC_VERSION \ (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) # define TROMPELOEIL_CPLUSPLUS __cplusplus #elif defined(_MSC_VER) # define TROMPELOEIL_CLANG 0 # define TROMPELOEIL_GCC 0 # define TROMPELOEIL_MSVC 1 # define TROMPELOEIL_CLANG_VERSION 0 # define TROMPELOEIL_GCC_VERSION 0 # if defined(_MSVC_LANG) // Compiler is at least Microsoft Visual Studio 2015 Update 3. # define TROMPELOEIL_CPLUSPLUS _MSVC_LANG # else /* defined(_MSVC_LANG) */ /* * This version of Microsoft Visual C++ is released * in a version of Microsoft Visual Studio between * 2015 RC and less than 2015 Update 3. * * It is an amalgam of C++ versions, with no provision * to specify C++11 mode. * * It also has a __cplusplus macro stuck at 199711L with * no way to change it, such as /Zc:__cplusplus. * * Assume the C++14 code path, but don't promise that it is a * fully conforming implementation of C++14 either. * Hence a value of 201401L, which less than 201402L, * the standards conforming value of __cplusplus. */ # define TROMPELOEIL_CPLUSPLUS 201401L # endif /* !defined(_MSVC_LANG) */ #endif #ifndef TROMPELOEIL_NOT_IMPLEMENTED #define TROMPELOEIL_NOT_IMPLEMENTED(...) __VA_ARGS__ #endif #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cpp_impl_coroutine #include #endif #ifndef TROMPELOEIL_CUSTOM_ATOMIC #include namespace trompeloeil { using std::atomic; } #else #include #endif #ifndef TROMPELOEIL_CUSTOM_UNIQUE_LOCK namespace trompeloeil { using std::unique_lock; } #else #include #endif #ifdef TROMPELOEIL_SANITY_CHECKS #include #define TROMPELOEIL_ASSERT(x) assert(x) #else #define TROMPELOEIL_ASSERT(x) do {} while (false) #endif #define TROMPELOEIL_IDENTITY(...) __VA_ARGS__ // work around stupid MS VS2015 RC bug #define TROMPELOEIL_ARG16(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15, ...) _15 #define TROMPELOEIL_COUNT(...) \ TROMPELOEIL_IDENTITY(TROMPELOEIL_ARG16(__VA_ARGS__, \ 15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0)) #if TROMPELOEIL_MSVC #define TROMPELOEIL_CONCAT_(x, y, ...) x ## y __VA_ARGS__ #define TROMPELOEIL_CONCAT(x, ...) TROMPELOEIL_CONCAT_(x, __VA_ARGS__) #else /* TROMPELOEIL_MSVC */ #define TROMPELOEIL_CONCAT_(x, ...) x ## __VA_ARGS__ #define TROMPELOEIL_CONCAT(x, ...) TROMPELOEIL_CONCAT_(x, __VA_ARGS__) #endif /* !TROMPELOEIL_MSVC */ #define TROMPELOEIL_SEPARATE1(p1) p1 #define TROMPELOEIL_SEPARATE2(p1,p2) p1 p2 #define TROMPELOEIL_SEPARATE3(p1,...) p1 TROMPELOEIL_SEPARATE2(__VA_ARGS__) #define TROMPELOEIL_SEPARATE4(p1,...) p1 TROMPELOEIL_SEPARATE3(__VA_ARGS__) #define TROMPELOEIL_SEPARATE5(p1,...) p1 TROMPELOEIL_SEPARATE4(__VA_ARGS__) #define TROMPELOEIL_SEPARATE6(p1,...) p1 TROMPELOEIL_SEPARATE5(__VA_ARGS__) #define TROMPELOEIL_SEPARATE7(p1,...) p1 TROMPELOEIL_SEPARATE6(__VA_ARGS__) #define TROMPELOEIL_SEPARATE8(p1,...) p1 TROMPELOEIL_SEPARATE7(__VA_ARGS__) #define TROMPELOEIL_SEPARATE9(p1,...) p1 TROMPELOEIL_SEPARATE8(__VA_ARGS__) #define TROMPELOEIL_SEPARATE(...) \ TROMPELOEIL_CONCAT(TROMPELOEIL_SEPARATE,\ TROMPELOEIL_COUNT(__VA_ARGS__))(__VA_ARGS__) #define TROMPELOEIL_REMOVE_PAREN(...) TROMPELOEIL_CONCAT(TROMPELOEIL_CLEAR_, \ TROMPELOEIL_REMOVE_PAREN_INTERNAL __VA_ARGS__) #define TROMPELOEIL_REMOVE_PAREN_INTERNAL(...) \ TROMPELOEIL_REMOVE_PAREN_INTERNAL __VA_ARGS__ #define TROMPELOEIL_CLEAR_TROMPELOEIL_REMOVE_PAREN_INTERNAL #define TROMPELOEIL_EXPAND(x) x #define TROMPELOEIL_INIT_WITH_STR15(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR14(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR14(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR13(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR13(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR12(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR12(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR11(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR11(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR10(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR10(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR9(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR9(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR8(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR8(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR7(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR7(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR6(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR6(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR5(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR5(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR4(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR4(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR3(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR3(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR2(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR2(base, x, ...) \ base{#x, x}, TROMPELOEIL_EXPAND(TROMPELOEIL_INIT_WITH_STR1(base, __VA_ARGS__)) #define TROMPELOEIL_INIT_WITH_STR1(base, x) \ base{#x, x} #define TROMPELOEIL_INIT_WITH_STR0(base) #define TROMPELOEIL_INIT_WITH_STR(base, ...) \ TROMPELOEIL_CONCAT(TROMPELOEIL_INIT_WITH_STR, \ TROMPELOEIL_COUNT(__VA_ARGS__))(base, __VA_ARGS__) #define TROMPELOEIL_PARAM_LIST15(...) \ TROMPELOEIL_PARAM_LIST14(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 14> p15 #define TROMPELOEIL_PARAM_LIST14(...) \ TROMPELOEIL_PARAM_LIST13(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 13> p14 #define TROMPELOEIL_PARAM_LIST13(...) \ TROMPELOEIL_PARAM_LIST12(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 12> p13 #define TROMPELOEIL_PARAM_LIST12(...) \ TROMPELOEIL_PARAM_LIST11(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 11> p12 #define TROMPELOEIL_PARAM_LIST11(...) \ TROMPELOEIL_PARAM_LIST10(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 10> p11 #define TROMPELOEIL_PARAM_LIST10(...) \ TROMPELOEIL_PARAM_LIST9(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 9> p10 #define TROMPELOEIL_PARAM_LIST9(...) \ TROMPELOEIL_PARAM_LIST8(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 8> p9 #define TROMPELOEIL_PARAM_LIST8(...) \ TROMPELOEIL_PARAM_LIST7(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 7> p8 #define TROMPELOEIL_PARAM_LIST7(...) \ TROMPELOEIL_PARAM_LIST6(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 6> p7 #define TROMPELOEIL_PARAM_LIST6(...) \ TROMPELOEIL_PARAM_LIST5(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 5> p6 #define TROMPELOEIL_PARAM_LIST5(...) \ TROMPELOEIL_PARAM_LIST4(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 4> p5 #define TROMPELOEIL_PARAM_LIST4(...) \ TROMPELOEIL_PARAM_LIST3(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 3> p4 #define TROMPELOEIL_PARAM_LIST3(...) \ TROMPELOEIL_PARAM_LIST2(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 2> p3 #define TROMPELOEIL_PARAM_LIST2(...) \ TROMPELOEIL_PARAM_LIST1(__VA_ARGS__), \ ::trompeloeil::param_list_t<__VA_ARGS__, 1> p2 #define TROMPELOEIL_PARAM_LIST1(...) \ ::trompeloeil::param_list_t<__VA_ARGS__, 0> p1 #define TROMPELOEIL_PARAM_LIST0(func_type) #define TROMPELOEIL_PARAM_LIST(num, func_type) \ TROMPELOEIL_CONCAT(TROMPELOEIL_PARAM_LIST, num) \ (TROMPELOEIL_REMOVE_PAREN(func_type)) #define TROMPELOEIL_PARAMS15 TROMPELOEIL_PARAMS14, p15 #define TROMPELOEIL_PARAMS14 TROMPELOEIL_PARAMS13, p14 #define TROMPELOEIL_PARAMS13 TROMPELOEIL_PARAMS12, p13 #define TROMPELOEIL_PARAMS12 TROMPELOEIL_PARAMS11, p12 #define TROMPELOEIL_PARAMS11 TROMPELOEIL_PARAMS10, p11 #define TROMPELOEIL_PARAMS10 TROMPELOEIL_PARAMS9, p10 #define TROMPELOEIL_PARAMS9 TROMPELOEIL_PARAMS8, p9 #define TROMPELOEIL_PARAMS8 TROMPELOEIL_PARAMS7, p8 #define TROMPELOEIL_PARAMS7 TROMPELOEIL_PARAMS6, p7 #define TROMPELOEIL_PARAMS6 TROMPELOEIL_PARAMS5, p6 #define TROMPELOEIL_PARAMS5 TROMPELOEIL_PARAMS4, p5 #define TROMPELOEIL_PARAMS4 TROMPELOEIL_PARAMS3, p4 #define TROMPELOEIL_PARAMS3 TROMPELOEIL_PARAMS2, p3 #define TROMPELOEIL_PARAMS2 TROMPELOEIL_PARAMS1, p2 #define TROMPELOEIL_PARAMS1 , p1 #define TROMPELOEIL_PARAMS0 #define TROMPELOEIL_PARAMS(num) TROMPELOEIL_CONCAT(TROMPELOEIL_PARAMS, num) #if (TROMPELOEIL_CPLUSPLUS == 201103L) #define TROMPELOEIL_DECLTYPE_AUTO \ auto #define TROMPELOEIL_TRAILING_RETURN_TYPE(return_type) \ -> return_type #else /* (TROMPELOEIL_CPLUSPLUS == 201103L) */ #define TROMPELOEIL_DECLTYPE_AUTO \ decltype(auto) #define TROMPELOEIL_TRAILING_RETURN_TYPE(return_type) \ /**/ #endif /* !(TROMPELOEIL_CPLUSPLUS == 201103L) */ #if TROMPELOEIL_CPLUSPLUS > 201403L && (!TROMPELOEIL_GCC || TROMPELOEIL_GCC_VERSION >= 70000) # define TROMPELOEIL_INLINE_VAR [[maybe_unused]] static inline #else # define TROMPELOEIL_INLINE_VAR static #endif static constexpr bool trompeloeil_movable_mock = false; namespace trompeloeil { template struct identity_type { using type = T; }; template identity_type nonconst_member_signature(R (C::*)(Args...)); template identity_type const_member_signature(R (C::*)(Args...) const); template struct void_t_ { using type = void; }; template using void_t = typename void_t_::type; template