├── src ├── generator │ ├── bench │ │ ├── consume.cpp │ │ ├── CMakeLists.txt │ │ ├── bench.h │ │ ├── main.cpp │ │ ├── gor_generator.h │ │ └── bench.cpp │ ├── src │ │ └── generator.cpp │ ├── test │ │ ├── CMakeLists.txt │ │ ├── generator.cpp │ │ ├── main.cpp │ │ └── doctest.h │ ├── CMakeLists.txt │ └── include │ │ ├── coroutine.h │ │ └── generator.h └── CMakeLists.txt ├── CMakeLists.txt ├── .gitmodules ├── .gitignore ├── LICENSE.txt └── README.md /src/generator/bench/consume.cpp: -------------------------------------------------------------------------------- 1 | void consume(int) {} 2 | -------------------------------------------------------------------------------- /src/generator/src/generator.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/generator/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(generator_test generator.cpp) 2 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | 3 | project(ranges-coroutines) 4 | 5 | add_subdirectory(src) 6 | -------------------------------------------------------------------------------- /src/generator/bench/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(generator_bench 2 | main.cpp 3 | bench.h 4 | bench.cpp 5 | consume.cpp 6 | ) 7 | target_link_libraries(generator_bench generator range-v3 hayai) 8 | if(MSVC) 9 | target_compile_definitions(generator_bench PRIVATE HAS_EXPERIMENTAL_GENERATOR) 10 | else() # clang 11 | endif() 12 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "deps/range-v3"] 2 | path = src/deps/range-v3 3 | url = https://github.com/ericniebler/range-v3.git 4 | [submodule "src/deps/Range-V3-VS2015"] 5 | path = src/deps/Range-V3-VS2015 6 | url = https://github.com/Microsoft/Range-V3-VS2015 7 | [submodule "src/deps/hayai"] 8 | path = src/deps/hayai 9 | url = https://github.com/nickbruun/hayai.git 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | # This .gitignore file was automatically created by Microsoft(R) Visual Studio. 3 | ################################################################################ 4 | 5 | /RangesCoroutines/.vs/ 6 | Debug/ 7 | Release/ 8 | *.VC.db 9 | /build/ 10 | /.vs 11 | /.idea/ 12 | /.vscode/ 13 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.4) 2 | 3 | project(ranges-coroutines) 4 | 5 | add_library(range-v3 INTERFACE) 6 | if(MSVC) 7 | target_include_directories(range-v3 INTERFACE deps/Range-V3-VS2015/include) 8 | else() 9 | target_include_directories(range-v3 INTERFACE deps/range-v3/include) 10 | endif() 11 | 12 | add_library(hayai INTERFACE) 13 | target_include_directories(hayai INTERFACE deps/hayai/src) 14 | 15 | enable_testing() 16 | add_subdirectory(generator) 17 | -------------------------------------------------------------------------------- /src/generator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_library(generator 2 | src/generator.cpp) 3 | target_include_directories(generator 4 | PUBLIC include 5 | PRIVATE src) 6 | target_compile_features(generator 7 | PUBLIC cxx_generic_lambdas) 8 | target_link_libraries(generator PUBLIC range-v3) 9 | if(MSVC) 10 | target_compile_options(generator 11 | PUBLIC /await) 12 | else() # clang 13 | target_compile_options(generator 14 | PUBLIC -fcoroutines-ts -stdlib=libc++) 15 | target_link_libraries(generator PUBLIC -stdlib=libc++) 16 | endif() 17 | 18 | add_executable(generator_test test/generator.cpp test/main.cpp) 19 | target_link_libraries(generator_test generator range-v3) 20 | 21 | add_test(generator_test generator_test) 22 | 23 | add_subdirectory(bench) 24 | -------------------------------------------------------------------------------- /src/generator/bench/bench.h: -------------------------------------------------------------------------------- 1 | #ifndef BENCH_H 2 | #define BENCH_H 3 | 4 | void bench_ints_generator_toby(int n); 5 | void bench_ints_generator_gor(int n); 6 | #ifdef HAS_EXPERIMENTAL_GENERATOR 7 | void bench_ints_generator_exp(int n); 8 | #endif 9 | void bench_ints_generator_toby_atomic(int n); 10 | void bench_ints_handrolled(int n); 11 | void bench_ints_ranges(int n); 12 | 13 | void bench_filter_generator_toby(int n); 14 | void bench_filter_generator_toby_ref(int n); 15 | void bench_filter_generator_gor(int n); 16 | void bench_filter_generator_gor_ref(int n); 17 | #ifdef HAS_EXPERIMENTAL_GENERATOR 18 | void bench_filter_generator_exp(int n); 19 | #endif 20 | // void bench_filter_generator_toby_atomic(int n); 21 | void bench_filter_handrolled(int n); 22 | void bench_filter_ranges(int n); 23 | 24 | #endif // BENCH_H 25 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Toby Allsopp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/generator/bench/main.cpp: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | 3 | #include 4 | 5 | static const int NUM = 100; 6 | 7 | BENCHMARK(ints, generator_toby, 1000, 100000 / NUM) { bench_ints_generator_toby(NUM); } 8 | BENCHMARK(ints, generator_gor, 1000, 100000 / NUM) { bench_ints_generator_gor(NUM); } 9 | #ifdef HAS_EXPERIMENTAL_GENERATOR 10 | BENCHMARK(ints, generator_exp, 1000, 100000 / NUM) { bench_ints_generator_exp(NUM); } 11 | #endif 12 | BENCHMARK(ints, generator_toby_atomic, 1000, 100000 / NUM) { 13 | bench_ints_generator_toby_atomic(NUM); 14 | } 15 | BENCHMARK(ints, handrolled, 1000, 100000 / NUM) { bench_ints_handrolled(NUM); } 16 | 17 | /* 18 | BENCHMARK(ints, callback, 1000, 100000/NUM) { 19 | cb_ints(0, NUM, [](int i) { consume(i); }); 20 | } 21 | */ 22 | 23 | BENCHMARK(ints, ranges, 1000, 100000 / NUM) { bench_ints_ranges(NUM); } 24 | 25 | BENCHMARK(filter, generator_toby, 1000, 100000 / NUM) { 26 | bench_filter_generator_toby(NUM); 27 | } 28 | BENCHMARK(filter, generator_toby_ref, 1000, 100000 / NUM) { 29 | bench_filter_generator_toby_ref(NUM); 30 | } 31 | BENCHMARK(filter, generator_gor, 1000, 100000 / NUM) { bench_filter_generator_gor(NUM); } 32 | BENCHMARK(filter, generator_gor_ref, 1000, 100000 / NUM) { 33 | bench_filter_generator_gor_ref(NUM); 34 | } 35 | #ifdef HAS_EXPERIMENTAL_GENERATOR 36 | BENCHMARK(filter, generator_exp, 1000, 100000 / NUM) { bench_filter_generator_exp(NUM); } 37 | #endif 38 | BENCHMARK(filter, handrolled, 1000, 100000 / NUM) { bench_filter_handrolled(NUM); } 39 | BENCHMARK(filter, ranges, 1000, 100000 / NUM) { bench_filter_ranges(NUM); } 40 | 41 | int main() { 42 | hayai::ConsoleOutputter consoleOutputter; 43 | 44 | hayai::Benchmarker::AddOutputter(consoleOutputter); 45 | hayai::Benchmarker::RunAllTests(); 46 | return 0; 47 | } 48 | -------------------------------------------------------------------------------- /src/generator/bench/gor_generator.h: -------------------------------------------------------------------------------- 1 | #ifndef GOR_GENERATOR_H 2 | #define GOR_GENERATOR_H 3 | 4 | namespace gor { 5 | namespace coro = std::experimental; 6 | template 7 | struct generator { 8 | struct promise_type { 9 | _Ty current_value; 10 | coro::suspend_always yield_value(_Ty value) { 11 | this->current_value = value; 12 | return {}; 13 | } 14 | coro::suspend_always initial_suspend() { return {}; } 15 | coro::suspend_always final_suspend() { return {}; } 16 | generator get_return_object() { return generator{this}; } 17 | void return_void() {} 18 | }; 19 | 20 | struct iterator { 21 | coro::coroutine_handle _Coro; 22 | bool _Done; 23 | 24 | iterator(coro::coroutine_handle Coro, bool Done) 25 | : _Coro(Coro), _Done(Done) {} 26 | 27 | iterator& operator++() { 28 | _Coro.resume(); 29 | _Done = _Coro.done(); 30 | return *this; 31 | } 32 | 33 | bool operator==(iterator const& _Right) const { return _Done == _Right._Done; } 34 | 35 | bool operator!=(iterator const& _Right) const { return !(*this == _Right); } 36 | 37 | _Ty const& operator*() const { return _Coro.promise().current_value; } 38 | 39 | _Ty const* operator->() const { return &(operator*()); } 40 | }; 41 | 42 | iterator begin() { 43 | p.resume(); 44 | return {p, p.done()}; 45 | } 46 | 47 | iterator end() { return {p, true}; } 48 | 49 | generator(generator&& rhs) : p(rhs.p) { rhs.p = nullptr; } 50 | 51 | ~generator() { 52 | if (p) p.destroy(); 53 | } 54 | 55 | private: 56 | explicit generator(promise_type* p) 57 | : p(coro::coroutine_handle::from_promise(*p)) {} 58 | 59 | coro::coroutine_handle p; 60 | }; 61 | } 62 | 63 | #endif // GOR_GENERATOR_H 64 | -------------------------------------------------------------------------------- /src/generator/include/coroutine.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace std { namespace experimental { inline namespace coroutines_v1 { 4 | 5 | template struct coroutine_traits { 6 | using promise_type = typename R::promise_type; 7 | }; 8 | 9 | template struct coroutine_handle; 10 | 11 | template <> struct coroutine_handle { 12 | static coroutine_handle from_address(void *addr) noexcept { 13 | coroutine_handle me; 14 | me.ptr = addr; 15 | return me; 16 | } 17 | void operator()() { resume(); } 18 | void *address() const { return ptr; } 19 | void resume() const { __builtin_coro_resume(ptr); } 20 | void destroy() const { __builtin_coro_destroy(ptr); } 21 | bool done() const { return __builtin_coro_done(ptr); } 22 | coroutine_handle &operator=(decltype(nullptr)) { 23 | ptr = nullptr; 24 | return *this; 25 | } 26 | coroutine_handle(decltype(nullptr)) : ptr(nullptr) {} 27 | coroutine_handle() : ptr(nullptr) {} 28 | // void reset() { ptr = nullptr; } // add to P0057? 29 | explicit operator bool() const { return ptr; } 30 | 31 | protected: 32 | void *ptr; 33 | }; 34 | 35 | template struct coroutine_handle : coroutine_handle<> { 36 | using coroutine_handle<>::coroutine_handle; 37 | using coroutine_handle<>::operator=; 38 | 39 | static coroutine_handle from_address(void *addr) noexcept { 40 | coroutine_handle me; 41 | me.ptr = addr; 42 | return me; 43 | } 44 | 45 | Promise &promise() const { 46 | return *reinterpret_cast( 47 | __builtin_coro_promise(ptr, alignof(Promise), false)); 48 | } 49 | static coroutine_handle from_promise(Promise &promise) { 50 | coroutine_handle p; 51 | p.ptr = __builtin_coro_promise(&promise, alignof(Promise), true); 52 | return p; 53 | } 54 | }; 55 | 56 | template 57 | bool operator==(coroutine_handle<_PromiseT> const& _Left, 58 | coroutine_handle<_PromiseT> const& _Right) noexcept 59 | { 60 | return _Left.address() == _Right.address(); 61 | } 62 | 63 | template 64 | bool operator!=(coroutine_handle<_PromiseT> const& _Left, 65 | coroutine_handle<_PromiseT> const& _Right) noexcept 66 | { 67 | return !(_Left == _Right); 68 | } 69 | 70 | struct suspend_always { 71 | bool await_ready() { return false; } 72 | void await_suspend(coroutine_handle<>) {} 73 | void await_resume() {} 74 | }; 75 | struct suspend_never { 76 | bool await_ready() { return true; } 77 | void await_suspend(coroutine_handle<>) {} 78 | void await_resume() {} 79 | }; 80 | 81 | }}} 82 | 83 | namespace coro = std::experimental::coroutines_v1; 84 | 85 | -------------------------------------------------------------------------------- /src/generator/test/generator.cpp: -------------------------------------------------------------------------------- 1 | #define SPDLOG_FMT_EXTERNAL 2 | #include "generator.h" 3 | 4 | //#include 5 | #include 6 | #include "doctest.h" 7 | 8 | #include 9 | 10 | using toby::generator; 11 | 12 | generator upto(int n) { 13 | for (int i = 0; i < n; ++i) co_yield i; 14 | } 15 | 16 | generator> move_only() { 17 | co_yield std::make_unique(7); 18 | co_yield std::make_unique(42); 19 | } 20 | 21 | TEST_CASE("empty sequence") { 22 | auto g = upto(0); 23 | CHECK(g.begin() == g.end()); 24 | } 25 | 26 | TEST_CASE("one element") { 27 | auto g = upto(1); 28 | auto b = g.begin(); 29 | CHECK(b != g.end()); 30 | CHECK(*b == 0); 31 | CHECK(*b == 0); 32 | auto&& v = *b; 33 | CHECK(v == 0); 34 | ++b; 35 | CHECK(b == g.end()); 36 | CHECK(v == 0); 37 | } 38 | 39 | TEST_CASE("three elements") { 40 | auto g = upto(3); 41 | auto i = g.begin(); 42 | REQUIRE(i != g.end()); 43 | auto v = *i; 44 | SUBCASE("first element is zero") { CHECK(v == 0); } 45 | ++i; 46 | REQUIRE(i != g.end()); 47 | SUBCASE("incrementing the iterator doesn't change the previous value") { 48 | CHECK(v == 0); 49 | } 50 | auto&& v2 = *i; 51 | SUBCASE("second element is one") { CHECK(v2 == 1); } 52 | i++; 53 | i++; 54 | SUBCASE("post-increment to end") { CHECK(i == g.end()); } 55 | } 56 | 57 | TEST_CASE("move-only type") { 58 | auto g = move_only(); 59 | auto i = g.begin(); 60 | CHECK(**i == 7); 61 | auto v = std::move(*i); 62 | CHECK(*v == 7); 63 | i++; 64 | REQUIRE(*i); 65 | CHECK(**i == 42); 66 | auto v2 = std::move(*i); 67 | CHECK(*v2 == 42); 68 | i++; 69 | CHECK(i == g.end()); 70 | } 71 | 72 | TEST_CASE("move iterator") { 73 | // these tests fail because std::move_iterator::operator++(int) is WRONG for input 74 | // iterators (see http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0541r0.html) 75 | #if move_iterator_is_fixed 76 | auto g = move_only(); 77 | auto i = std::make_move_iterator(g.begin()); 78 | CHECK(**i == 7); 79 | auto v = *i++; 80 | CHECK(*v == 7); 81 | REQUIRE(*i); 82 | CHECK(**i == 42); 83 | auto v2 = *i; 84 | CHECK(*v2 == 42); 85 | i++; 86 | CHECK(i == std::make_move_iterator(g.end())); 87 | #endif 88 | } 89 | 90 | generator infinite() { 91 | for (int i = 0;; ++i) { 92 | co_yield i; 93 | } 94 | } 95 | 96 | TEST_CASE("infinite generator") { 97 | auto g = infinite(); 98 | SUBCASE("first coouple of elements") { 99 | auto i = g.begin(); 100 | CHECK(*i == 0); 101 | ++i; 102 | CHECK(*i == 1); 103 | i++; 104 | } 105 | SUBCASE("take 5") { 106 | CONCEPT_ASSERT(ranges::v3::Destructible::value); 107 | CONCEPT_ASSERT(ranges::v3::Iterator::value); 108 | CONCEPT_ASSERT(ranges::v3::Readable::value); 109 | CONCEPT_ASSERT(ranges::v3::InputIterator::value); 110 | CONCEPT_ASSERT(ranges::v3::Regular::value); 111 | #if !defined(RANGE_V3_VERSION) || RANGE_V3_VERSION < 200 112 | CONCEPT_ASSERT( 113 | ranges::v3::CommonReference::value); 114 | CONCEPT_ASSERT( 115 | ranges::v3::EqualityComparable::value); 116 | #endif 117 | CONCEPT_ASSERT(ranges::v3::Range::value); 118 | CONCEPT_ASSERT(ranges::v3::InputRange::value); 119 | auto a = ranges::view::take(5) | ranges::to_vector; 120 | auto b = g | ranges::view::take(5); 121 | std::vector v = b; 122 | CHECK(v == std::vector({0, 1, 2, 3, 4})); 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Helpers for Ranges + Coroutines # 2 | 3 | ## UPDATE 4 | 5 | The code in this repository is now obsolete. The range-v3 library now contains a generator that works as a View. Please use that instead as it is more feature-complete and correct that the implementation in this repository. 6 | 7 | ## Introduction 8 | 9 | This repository contains some helpers for and demonstrations of using Ranges and Coroutines together. 10 | 11 | Currently this code has only been tested using Visual Studio 2017 and a build of specific branches of clang and libc++. 12 | 13 | ## `generator` - a Range-friendly generator 14 | 15 | Included in Microsoft's Coroutines support library is the class template `std::experimental::generator`. This allows a coroutine to return a lazy sequence of values using `co_yield`. 16 | 17 | This allows code like: 18 | 19 | ```c++ 20 | generator infinite_sequence() { 21 | for (int i = 0; ; ++i) { 22 | co_yield i; 23 | } 24 | } 25 | 26 | for (int i : infinite_sequence()) { 27 | cout << i; 28 | if (i > 10) break; 29 | } 30 | ``` 31 | 32 | This is wonderful, however these `generator` objects can't be using alongside the also wonderful range-v3 library. This is due to `generator` not satisfying all of the requirements of the `Range` concept (see https://github.com/Microsoft/Range-V3-VS2015/issues/12). 33 | 34 | The `generator` class template included in this repository is intended to be a drop-in replacement for Microsoft's one. It has the advantage that it supports Ranges. It has the disadvantage that it is ever-so-slightly less efficient because it has to maintain a reference count in order to support copying. 35 | 36 | It allows you to write code like: 37 | 38 | ```c++ 39 | generator infinite_sequence() { 40 | for (int i = 0; ; ++i) { 41 | co_yield i; 42 | } 43 | } 44 | 45 | infinite_sequence() 46 | | take(10) 47 | | for_each([](int x) { cout << x; }); 48 | ``` 49 | 50 | Also, it's easy to write an adaptor using a coroutine: 51 | 52 | ```c++ 53 | template 54 | auto filter_co(InputRange range, UnaryPredicate pred) 55 | -> generator> { 56 | for (auto&& x : range) { 57 | if (pred(x)) { 58 | co_yield x; 59 | } 60 | } 61 | } 62 | 63 | template 64 | auto filter_co(UnaryPredicate pred) { 65 | return ranges::make_pipeable([pred = std::move(pred)](auto&& rng) { 66 | return filter_co(std::forward(rng), std::move(pred)); 67 | }); 68 | } 69 | 70 | infinite_sequence() 71 | | filter_co([](int x) { return x % 2 == 0; }) 72 | | take(10) 73 | | for_each([](int x) { cout << x; }); 74 | ``` 75 | 76 | # Dependencies # 77 | 78 | To build the tests, you will need either: 79 | 80 | - Visual Studio 2017 (2015 might also work - not tested) 81 | - Clang and libc++ built from particular branches (see below) 82 | 83 | The following are included: 84 | - range-v3 85 | - spdlog (currently not) 86 | - doctest 87 | 88 | The library itself is header-only and only depends on having an `` header available. 89 | 90 | # Building # 91 | 92 | ## Visual Studio ## 93 | 94 | ## Clang ## 95 | 96 | Currently, you will need to build your own clang and libc++. Hopefully this stuff will get merged into those projects' trunks soon. 97 | 98 | ### Checkout llvm, clang, libcxx and libcxxabi 99 | 100 | cd $SRC_ROOT # you choose this directory 101 | git clone -b merge0307 https://github.com/GorNishanov/llvm.git 102 | cd llvm/tools 103 | git clone -b merge0307 https://github.com/GorNishanov/clang.git 104 | cd ../projects 105 | git clone -b coroutines https://github.com/efcs/libcxx.git 106 | git clone https://github.com/llvm-mirror/libcxxabi.git 107 | 108 | ### Configure 109 | 110 | cd $SRC_ROOT 111 | mkdir build 112 | cd build 113 | cmake .. 114 | 115 | ### Build 116 | 117 | cd $SRC_ROOT/build 118 | make # use -jN if you have lots of RAM 119 | 120 | ### Configure generator 121 | 122 | cd $LOCATION_OF_THIS_FILE 123 | mkdir build 124 | cd build 125 | cmake CXX=$SRC_ROOT/build/bin/clang++ .. 126 | 127 | ### Build generator 128 | 129 | make 130 | 131 | ### Run tests 132 | 133 | LD_LIBRARY_PATH=$SRC_ROOT/build/lib ./generator/generator_test 134 | -------------------------------------------------------------------------------- /src/generator/bench/bench.cpp: -------------------------------------------------------------------------------- 1 | #include "bench.h" 2 | #include "generator.h" 3 | #include "gor_generator.h" 4 | 5 | #include 6 | 7 | template 8 | Generator co_ints(int start, int end) { 9 | for (int i = start; i < end; ++i) { 10 | co_yield i; 11 | } 12 | } 13 | 14 | template 15 | void cb_ints(int start, int end, F&& f) { 16 | for (int i = start; i < end; ++i) { 17 | f(i); 18 | } 19 | } 20 | 21 | extern void consume(int); 22 | 23 | void bench_ints_generator_toby(int n) { 24 | RANGES_FOR(int i, co_ints>(0, n)) { consume(i); } 25 | } 26 | 27 | void bench_ints_generator_gor(int n) { 28 | for (int i : co_ints>(0, n)) { 29 | consume(i); 30 | } 31 | } 32 | 33 | #ifdef HAS_EXPERIMENTAL_GENERATOR 34 | 35 | #include 36 | 37 | void bench_ints_generator_exp(int n) { 38 | for (int i : co_ints>(0, n)) { 39 | consume(i); 40 | } 41 | } 42 | 43 | #endif 44 | 45 | void bench_ints_generator_toby_atomic(int n) { 46 | RANGES_FOR(int i, co_ints>>(0, n)) { consume(i); } 47 | } 48 | 49 | void bench_ints_handrolled(int n) { 50 | for (int i = 0; i < n; ++i) { 51 | consume(i); 52 | } 53 | } 54 | 55 | void bench_ints_ranges(int n) { 56 | for (auto i : ranges::view::ints(0, n)) { 57 | consume(i); 58 | } 59 | } 60 | 61 | template 62 | auto co_remove_if_impl(InputRange range, UnaryPredicate pred) -> Generator { 63 | RANGES_FOR(auto&& x, range) { 64 | if (pred(x)) { 65 | co_yield x; 66 | } 67 | } 68 | } 69 | 70 | template 71 | auto co_remove_if(InputRange&& range, UnaryPredicate&& pred) -> Generator { 72 | return co_remove_if_impl(std::forward(range), 73 | std::forward(pred)); 74 | } 75 | 76 | template 77 | auto co_remove_if_nonrange_impl(InputRange range, UnaryPredicate pred) -> Generator { 78 | for (auto&& x : range) { 79 | if (pred(x)) { 80 | co_yield x; 81 | } 82 | } 83 | } 84 | 85 | template 86 | auto co_remove_if_nonrange(InputRange&& range, UnaryPredicate&& pred) -> Generator { 87 | return co_remove_if_nonrange_impl( 88 | std::forward(range), std::forward(pred)); 89 | } 90 | 91 | template 92 | auto co_remove_if(UnaryPredicate pred) { 93 | return ranges::make_pipeable([pred = std::move(pred)](auto&& rng) { 94 | return co_remove_if(std::forward(rng), std::move(pred)); 95 | }); 96 | } 97 | 98 | auto pred = [](int x) { return x % 2 == 0; }; 99 | 100 | void bench_filter_generator_toby(int n) { 101 | RANGES_FOR( 102 | int i, 103 | co_ints>(0, n) | co_remove_if>(pred)) { 104 | consume(i); 105 | } 106 | } 107 | 108 | void bench_filter_generator_toby_ref(int n) { 109 | auto g = co_ints>(0, n); 110 | RANGES_FOR(int i, g | co_remove_if>(pred)) { consume(i); } 111 | } 112 | 113 | void bench_filter_generator_gor(int n) { 114 | for (int i : co_remove_if_nonrange>( 115 | co_ints>(0, n), pred)) { 116 | consume(i); 117 | } 118 | } 119 | 120 | void bench_filter_generator_gor_ref(int n) { 121 | auto g = co_ints>(0, n); 122 | for (int i : co_remove_if_nonrange>(g, pred)) { 123 | consume(i); 124 | } 125 | } 126 | 127 | #ifdef HAS_EXPERIMENTAL_GENERATOR 128 | void bench_filter_generator_exp(int n) { 129 | RANGES_FOR(int i, 130 | co_ints>(0, n) | 131 | co_remove_if>(pred)) { 132 | consume(i); 133 | } 134 | } 135 | #endif 136 | 137 | void bench_filter_handrolled(int n) { 138 | for (auto i : ranges::view::ints(0, n)) { 139 | if (pred(i)) consume(i); 140 | } 141 | } 142 | 143 | void bench_filter_ranges(int n) { 144 | for (auto i : ranges::view::ints(0, n) | ranges::view::remove_if(pred)) { 145 | consume(i); 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/generator/test/main.cpp: -------------------------------------------------------------------------------- 1 | #define SPDLOG_FMT_EXTERNAL 2 | #include "generator.h" 3 | 4 | #include 5 | 6 | //#include 7 | 8 | #define DOCTEST_CONFIG_IMPLEMENT 9 | //#include 10 | #include "doctest.h" 11 | 12 | #include 13 | 14 | // auto logger = spdlog::stdout_logger_mt("STDOUT"); 15 | 16 | using toby::generator; 17 | 18 | generator co_ints() { 19 | // logger->info("before loop"); 20 | for (int i = 0; i < 5; ++i) { 21 | // logger->info("about to yield: {}", i); 22 | co_yield i; 23 | } 24 | // logger->info("after loop"); 25 | } 26 | 27 | template 28 | auto filter_co(InputRange range, UnaryPredicate pred) 29 | -> generator> { 30 | RANGES_FOR(auto&& x, range) { 31 | if (pred(x)) { 32 | co_yield x; 33 | } 34 | } 35 | } 36 | 37 | template 38 | auto filter_co(UnaryPredicate pred) { 39 | return ranges::make_pipeable([pred = std::move(pred)](auto&& rng) { 40 | return filter_co(std::forward(rng), std::move(pred)); 41 | }); 42 | } 43 | 44 | // A class that adapts an existing range with a function 45 | template 46 | class filter_view : public ranges::view_adaptor, Rng> { 47 | friend ranges::range_access; 48 | ranges::semiregular_t fun_; // Make Fun model SemiRegular if it doesn't 49 | class adaptor : public ranges::adaptor_base { 50 | ranges::semiregular_t fun_; 51 | ranges::range_sentinel_t end_; 52 | 53 | public: 54 | adaptor() = default; 55 | adaptor(ranges::semiregular_t const& fun, ranges::range_sentinel_t end) 56 | : fun_(fun), end_(end) {} 57 | auto begin(filter_view& rng) const { 58 | return ranges::find_if(ranges::begin(rng.mutable_base()), end_, fun_); 59 | } 60 | void next(ranges::range_iterator_t& it) const { 61 | ++it; 62 | it = ranges::find_if(it, end_, fun_); 63 | } 64 | }; 65 | 66 | adaptor begin_adaptor() const { return {fun_, ranges::end(this->mutable_base())}; } 67 | 68 | public: 69 | filter_view() = default; 70 | filter_view(Rng&& rng, Fun fun) 71 | : filter_view::view_adaptor{std::forward(rng)}, fun_(std::move(fun)) {} 72 | }; 73 | 74 | template 75 | filter_view filter_rv(Rng&& rng, Fun fun) { 76 | return {std::forward(rng), std::move(fun)}; 77 | } 78 | 79 | template 80 | auto filter_rv(Fun fun) { 81 | return ranges::make_pipeable([fun = std::move(fun)](auto&& rng) { 82 | return filter_rv(std::forward(rng), std::move(fun)); 83 | }); 84 | } 85 | 86 | #include 87 | 88 | int main() { 89 | doctest::Context context; // initialize 90 | int res = context.run(); // run 91 | 92 | if (context.shouldExit()) // important - query flags (and --exit) rely on the 93 | // user 94 | // doing this 95 | return res; // propagate the result of the tests 96 | 97 | RANGES_FOR(auto&& x, co_ints()) { std::cout << x << "\n"; } 98 | 99 | auto pred = [](int x) { return x % 2 == 0; }; 100 | 101 | // filter a vector 102 | RANGES_FOR(auto&& x, filter_co(std::vector{1, 2, 3, 4, 5}, pred)) { 103 | std::cout << x << "\n"; 104 | } 105 | 106 | // filter a generator using a generator 107 | RANGES_FOR(auto&& x, filter_co(co_ints(), pred)) { std::cout << x << "\n"; } 108 | RANGES_FOR(auto&& x, co_ints() | filter_co(pred)) { std::cout << x << "\n"; } 109 | 110 | // filter a generator using a range view 111 | RANGES_FOR(auto&& x, filter_rv(co_ints(), pred)) { std::cout << x << "\n"; } 112 | 113 | // filter a generator using a range view 114 | RANGES_FOR(auto&& x, co_ints() | filter_rv(pred)) { std::cout << x << "\n"; } 115 | 116 | // filter a generator using a range view 117 | CONCEPT_ASSERT(ranges::v3::InputRange::value); 118 | CONCEPT_ASSERT(ranges::v3::Range()); 119 | CONCEPT_ASSERT(ranges::v3::MoveConstructible()); 120 | CONCEPT_ASSERT(ranges::v3::Movable()); 121 | CONCEPT_ASSERT(ranges::v3::CopyConstructible()); 122 | CONCEPT_ASSERT(ranges::v3::Copyable()); 123 | CONCEPT_ASSERT(ranges::v3::SemiRegular()); 124 | CONCEPT_ASSERT(ranges::v3::View()); 125 | 126 | RANGES_FOR(auto&& x, co_ints() | ranges::view::remove_if(pred)) { 127 | std::cout << x << "\n"; 128 | } 129 | 130 | RANGES_FOR(auto&& x, ranges::view::remove_if(co_ints(), pred)) { 131 | std::cout << x << "\n"; 132 | } 133 | 134 | // filter a lambda generator 135 | RANGES_FOR(auto&& x, []() -> generator { 136 | for (int i = 0; i < 5; ++i) co_yield i; 137 | }() | ranges::view::remove_if(pred)) { 138 | std::cout << x << "\n"; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/generator/include/generator.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #if !USE_MY_COROUTINE_HEADER 7 | #include 8 | #else 9 | #include "coroutine.h" 10 | #endif 11 | 12 | namespace toby { 13 | /// An RAII-style shared-ownership wrapper for 14 | /// std::experimental::coroutine_handle. 15 | /// 16 | /// Cooperation with the promise object is required in order to maintain the reference 17 | /// count, ala boost::intrusive_ptr. 18 | /// 19 | /// The reference count in increased by calling `intrusive_coroutine_handle_add_ref` and 20 | /// decreased by calling `intrusive_coroutine_handle_release`. These functions are found 21 | /// via ADL based on the promise type. 22 | template 23 | class intrusive_coroutine_handle { 24 | public: 25 | using handle = std::experimental::coroutine_handle; 26 | 27 | intrusive_coroutine_handle() : m_coro(nullptr) {} 28 | intrusive_coroutine_handle(handle coro) : m_coro(coro) { 29 | if (m_coro) intrusive_coroutine_handle_add_ref(m_coro.promise()); 30 | } 31 | 32 | intrusive_coroutine_handle(const intrusive_coroutine_handle& other) 33 | : intrusive_coroutine_handle(other.m_coro) {} 34 | intrusive_coroutine_handle(intrusive_coroutine_handle&& other) 35 | : intrusive_coroutine_handle() { 36 | std::swap(m_coro, other.m_coro); 37 | } 38 | 39 | intrusive_coroutine_handle& operator=(const intrusive_coroutine_handle& other) { 40 | this->~intrusive_coroutine_handle(); 41 | new (this) intrusive_coroutine_handle(other); 42 | return *this; 43 | } 44 | intrusive_coroutine_handle& operator=(intrusive_coroutine_handle&& other) { 45 | this->~intrusive_coroutine_handle(); 46 | new (this) intrusive_coroutine_handle(std::move(other)); 47 | return *this; 48 | } 49 | 50 | ~intrusive_coroutine_handle() { 51 | if (m_coro && intrusive_coroutine_handle_release(m_coro.promise()) == 0) 52 | m_coro.destroy(); 53 | } 54 | 55 | handle& operator*() { return m_coro; } 56 | handle* operator->() { return &m_coro; } 57 | 58 | private: 59 | handle m_coro; 60 | }; 61 | 62 | struct generator_sentinel { 63 | #if !defined(RANGE_V3_VERSION) || RANGE_V3_VERSION < 200 64 | // Range-V3-VS2015 still requires these: 65 | bool operator==(const generator_sentinel&) const { return true; } 66 | bool operator!=(const generator_sentinel&) const { return false; } 67 | #endif 68 | }; 69 | 70 | template 71 | struct generator_iterator; 72 | 73 | template 74 | class generator { 75 | public: 76 | struct promise_type; 77 | 78 | generator() = default; 79 | generator(std::experimental::coroutine_handle coro) : m_coro(coro) {} 80 | 81 | auto begin() { 82 | m_coro->resume(); 83 | return generator_iterator{*m_coro}; 84 | } 85 | auto end() { return generator_sentinel{}; } 86 | 87 | private: 88 | intrusive_coroutine_handle m_coro; 89 | }; 90 | 91 | template 92 | struct generator::promise_type { 93 | ElementType currentElement; 94 | RefCountType ref_count{0}; 95 | 96 | void add_ref() { ++ref_count; } 97 | auto del_ref() { return --ref_count; } 98 | 99 | generator get_return_object() { 100 | return generator{ 101 | std::experimental::coroutine_handle::from_promise(*this)}; 102 | } 103 | auto initial_suspend() { return std::experimental::suspend_always{}; } 104 | auto yield_value(ElementType element) { 105 | currentElement = std::move(element); 106 | return std::experimental::suspend_always{}; 107 | } 108 | void return_void() {} 109 | auto final_suspend() { return std::experimental::suspend_always{}; } 110 | }; 111 | 112 | template 113 | void intrusive_coroutine_handle_add_ref(PromiseType& promise) { 114 | promise.add_ref(); 115 | } 116 | 117 | template 118 | int intrusive_coroutine_handle_release(PromiseType& promise) { 119 | return promise.del_ref(); 120 | } 121 | 122 | template 123 | struct generator_iterator { 124 | using ElementType = decltype(std::declval().currentElement); 125 | using value_type = ElementType; 126 | using difference_type = std::ptrdiff_t; 127 | using reference = ElementType&; 128 | using pointer = ElementType*; 129 | using iterator_category = std::input_iterator_tag; 130 | 131 | generator_iterator() = default; 132 | generator_iterator(std::experimental::coroutine_handle coro) 133 | : m_coro(coro) {} 134 | 135 | bool operator==(const generator_sentinel&) const { return m_coro.done(); } 136 | bool operator!=(const generator_sentinel& other) const { return !(*this == other); } 137 | 138 | #if !defined(RANGE_V3_VERSION) || RANGE_V3_VERSION < 200 139 | // Range-V3-VS2015 still requires these: 140 | bool operator==(const generator_iterator&) const { return true; } 141 | bool operator!=(const generator_iterator&) const { return false; } 142 | #endif 143 | 144 | generator_iterator& operator++() { 145 | m_coro.resume(); 146 | return *this; 147 | } 148 | 149 | void operator++(int) { ++(*this); } 150 | 151 | reference operator*() const { 152 | // This const_cast shouldn't be necessary according to N4663 but VS2017.1 has 153 | // promise() const returning a const reference. 154 | return const_cast(m_coro.promise()).currentElement; 155 | } 156 | 157 | std::experimental::coroutine_handle m_coro; 158 | }; 159 | 160 | template 161 | bool operator==(const generator_sentinel& s, 162 | const generator_iterator& it) { 163 | return it == s; 164 | } 165 | template 166 | bool operator!=(const generator_sentinel& s, 167 | const generator_iterator& it) { 168 | return it != s; 169 | } 170 | 171 | } // namespace toby 172 | 173 | #include 174 | 175 | #if !defined(RANGE_V3_VERSION) || RANGE_V3_VERSION < 200 176 | namespace ranges { 177 | namespace v3 { 178 | template 179 | struct common_type, toby::generator_sentinel> { 180 | using type = common_iterator, 181 | toby::generator_sentinel>; 182 | }; 183 | template 184 | struct common_type> { 185 | using type = common_iterator, 186 | toby::generator_sentinel>; 187 | }; 188 | } 189 | } 190 | #endif 191 | -------------------------------------------------------------------------------- /src/generator/test/doctest.h: -------------------------------------------------------------------------------- 1 | // ====================================================================== 2 | // == DO NOT MODIFY THIS FILE BY HAND - IT IS AUTO GENERATED BY CMAKE! == 3 | // ====================================================================== 4 | // 5 | // doctest.h - the lightest feature-rich C++ single-header testing framework for unit tests and TDD 6 | // 7 | // Copyright (c) 2016 Viktor Kirilov 8 | // 9 | // Distributed under the MIT Software License 10 | // See accompanying file LICENSE.txt or copy at 11 | // https://opensource.org/licenses/MIT 12 | // 13 | // The documentation can be found at the library's page: 14 | // https://github.com/onqtam/doctest/blob/master/doc/markdown/readme.md 15 | // 16 | // ================================================================================================= 17 | // ================================================================================================= 18 | // ================================================================================================= 19 | // 20 | // The library is heavily influenced by Catch - https://github.com/philsquared/Catch 21 | // which uses the Boost Software License - Version 1.0 22 | // see here - https://github.com/philsquared/Catch/blob/master/LICENSE_1_0.txt 23 | // 24 | // The concept of subcases (sections in Catch) and expression decomposition are from there. 25 | // Some parts of the code are taken directly: 26 | // - stringification - the detection of "ostream& operator<<(ostream&, const T&)" and StringMaker<> 27 | // - the Approx() helper class for floating point comparison 28 | // - colors in the console 29 | // - breaking into a debugger 30 | // 31 | // The expression decomposing templates are taken from lest - https://github.com/martinmoene/lest 32 | // which uses the Boost Software License - Version 1.0 33 | // see here - https://github.com/martinmoene/lest/blob/master/LICENSE_1_0.txt 34 | // 35 | // ================================================================================================= 36 | // ================================================================================================= 37 | // ================================================================================================= 38 | 39 | // Suppress this globally (without push/pop) - there is no way to silence it in the 40 | // expression decomposition macros _Pragma() in macros doesn't work for the c++ front-end of g++ 41 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55578 42 | // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=69543 43 | // Also the warning is completely worthless nowadays - http://stackoverflow.com/questions/14016993 44 | #if defined(__GNUC__) && !defined(__clang__) 45 | #pragma GCC diagnostic ignored "-Waggregate-return" 46 | #endif 47 | 48 | #if defined(__clang__) 49 | #pragma clang diagnostic push 50 | #pragma clang diagnostic ignored "-Wunknown-pragmas" 51 | #pragma clang diagnostic ignored "-Wpadded" 52 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 53 | #pragma clang diagnostic ignored "-Wshorten-64-to-32" 54 | #pragma clang diagnostic ignored "-Wunused-local-typedef" 55 | #endif // __clang__ 56 | 57 | #if defined(__GNUC__) && !defined(__clang__) 58 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 59 | #pragma GCC diagnostic push 60 | #endif // > gcc 4.6 61 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 62 | #pragma GCC diagnostic ignored "-Weffc++" 63 | #pragma GCC diagnostic ignored "-Wstrict-overflow" 64 | #pragma GCC diagnostic ignored "-Wmissing-declarations" 65 | #pragma GCC diagnostic ignored "-Winline" 66 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 67 | #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 68 | #endif // > gcc 4.6 69 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7) 70 | #pragma GCC diagnostic ignored "-Wunused-local-typedefs" 71 | #endif // > gcc 4.7 72 | #if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3) 73 | #pragma GCC diagnostic ignored "-Wuseless-cast" 74 | #endif // > gcc 5.3 75 | #endif // __GNUC__ 76 | 77 | #ifdef _MSC_VER 78 | #pragma warning(push) 79 | #pragma warning(disable : 4996) // The compiler encountered a deprecated declaration 80 | #pragma warning(disable : 4706) // assignment within conditional expression 81 | #pragma warning(disable : 4512) // 'class' : assignment operator could not be generated 82 | #pragma warning(disable : 4127) // conditional expression is constant 83 | #endif // _MSC_VER 84 | 85 | #ifndef DOCTEST_LIBRARY_INCLUDED 86 | #define DOCTEST_LIBRARY_INCLUDED 87 | 88 | #define DOCTEST_VERSION_MAJOR 1 89 | #define DOCTEST_VERSION_MINOR 1 90 | #define DOCTEST_VERSION_PATCH 4 91 | #define DOCTEST_VERSION_STR "1.1.4" 92 | 93 | #define DOCTEST_VERSION \ 94 | (DOCTEST_VERSION_MAJOR * 10000 + DOCTEST_VERSION_MINOR * 100 + DOCTEST_VERSION_PATCH) 95 | 96 | // ================================================================================================= 97 | // == MODERN C++ FEATURE DETECTION ================================================================= 98 | // ================================================================================================= 99 | 100 | #if __cplusplus >= 201103L 101 | #ifndef DOCTEST_CONFIG_WITH_NULLPTR 102 | #define DOCTEST_CONFIG_WITH_NULLPTR 103 | #endif // DOCTEST_CONFIG_WITH_NULLPTR 104 | #ifndef DOCTEST_CONFIG_WITH_LONG_LONG 105 | #define DOCTEST_CONFIG_WITH_LONG_LONG 106 | #endif // DOCTEST_CONFIG_WITH_LONG_LONG 107 | #ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT 108 | #define DOCTEST_CONFIG_WITH_STATIC_ASSERT 109 | #endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT 110 | #endif // __cplusplus >= 201103L 111 | 112 | // nullptr 113 | 114 | #ifndef DOCTEST_CONFIG_WITH_NULLPTR 115 | #ifdef __clang__ 116 | #if __has_feature(cxx_nullptr) 117 | #define DOCTEST_CONFIG_WITH_NULLPTR 118 | #endif // __has_feature(cxx_nullptr) 119 | #endif // __clang__ 120 | 121 | #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) 122 | #define DOCTEST_CONFIG_WITH_NULLPTR 123 | #endif // __GNUC__ 124 | 125 | #if defined(_MSC_VER) && (_MSC_VER >= 1600) // MSVC 2010 126 | #define DOCTEST_CONFIG_WITH_NULLPTR 127 | #endif // _MSC_VER 128 | #endif // DOCTEST_CONFIG_WITH_NULLPTR 129 | 130 | #if defined(DOCTEST_CONFIG_NO_NULLPTR) && defined(DOCTEST_CONFIG_WITH_NULLPTR) 131 | #undef DOCTEST_CONFIG_WITH_NULLPTR 132 | #endif // DOCTEST_CONFIG_NO_NULLPTR 133 | 134 | // long long 135 | 136 | #ifndef DOCTEST_CONFIG_WITH_LONG_LONG 137 | #if !defined(DOCTEST_CONFIG_WITH_LONG_LONG) && defined(_MSC_VER) && (_MSC_VER >= 1400) 138 | #define DOCTEST_CONFIG_WITH_LONG_LONG 139 | #endif // _MSC_VER 140 | #endif // DOCTEST_CONFIG_WITH_LONG_LONG 141 | 142 | #if defined(DOCTEST_CONFIG_NO_LONG_LONG) && defined(DOCTEST_CONFIG_WITH_LONG_LONG) 143 | #undef DOCTEST_CONFIG_WITH_LONG_LONG 144 | #endif // DOCTEST_CONFIG_NO_LONG_LONG 145 | 146 | // static_assert 147 | 148 | #ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT 149 | #ifdef __clang__ 150 | #if __has_feature(cxx_static_assert) 151 | #define DOCTEST_CONFIG_WITH_STATIC_ASSERT 152 | #endif // __has_feature(cxx_static_assert) 153 | #endif // __clang__ 154 | 155 | #if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 3 && defined(__GXX_EXPERIMENTAL_CXX0X__) 156 | #define DOCTEST_CONFIG_WITH_STATIC_ASSERT 157 | #endif // __GNUC__ 158 | 159 | #if defined(_MSC_VER) && (_MSC_VER >= 1600) // MSVC 2010 160 | #define DOCTEST_CONFIG_WITH_STATIC_ASSERT 161 | #endif // _MSC_VER 162 | #endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT 163 | 164 | #if defined(DOCTEST_CONFIG_NO_STATIC_ASSERT) && defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) 165 | #undef DOCTEST_CONFIG_WITH_STATIC_ASSERT 166 | #endif // DOCTEST_CONFIG_NO_STATIC_ASSERT 167 | 168 | #if defined(DOCTEST_CONFIG_WITH_NULLPTR) || defined(DOCTEST_CONFIG_WITH_LONG_LONG) || \ 169 | defined(DOCTEST_CONFIG_WITH_STATIC_ASSERT) 170 | #define DOCTEST_NO_CPP11_COMPAT 171 | #endif // c++11 stuff 172 | 173 | #if defined(__clang__) && defined(DOCTEST_NO_CPP11_COMPAT) 174 | #pragma clang diagnostic ignored "-Wc++98-compat" 175 | #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" 176 | #endif // __clang__ && DOCTEST_NO_CPP11_COMPAT 177 | 178 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS 179 | #if defined(__GNUC__) && !defined(__EXCEPTIONS) 180 | #define DOCTEST_CONFIG_NO_EXCEPTIONS 181 | #endif // clang and gcc 182 | // in MSVC _HAS_EXCEPTIONS is defined in a header instead of as a project define 183 | // so we can't do the automatic detection for MSVC without including some header 184 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 185 | 186 | #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS 187 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS 188 | #define DOCTEST_CONFIG_NO_EXCEPTIONS 189 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 190 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS 191 | 192 | #if defined(DOCTEST_CONFIG_NO_EXCEPTIONS) && !defined(DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS) 193 | #define DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS 194 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS && !DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS 195 | 196 | // ================================================================================================= 197 | // == MODERN C++ FEATURE DETECTION END ============================================================= 198 | // ================================================================================================= 199 | 200 | // internal macros for string concatenation and anonymous variable name generation 201 | #define DOCTEST_CAT_IMPL(s1, s2) s1##s2 202 | #define DOCTEST_CAT(s1, s2) DOCTEST_CAT_IMPL(s1, s2) 203 | #ifdef __COUNTER__ // not standard and may be missing for some compilers 204 | #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __COUNTER__) 205 | #else // __COUNTER__ 206 | #define DOCTEST_ANONYMOUS(x) DOCTEST_CAT(x, __LINE__) 207 | #endif // __COUNTER__ 208 | 209 | // macro for making a string out of an identifier 210 | #define DOCTEST_TOSTR_IMPL(x) #x 211 | #define DOCTEST_TOSTR(x) DOCTEST_TOSTR_IMPL(x) 212 | 213 | // for concatenating literals and making the result a string 214 | #define DOCTEST_STR_CONCAT_TOSTR(s1, s2) DOCTEST_TOSTR(s1) DOCTEST_TOSTR(s2) 215 | 216 | // counts the number of elements in a C string 217 | #define DOCTEST_COUNTOF(x) (sizeof(x) / sizeof(x[0])) 218 | 219 | #ifndef DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE 220 | #define DOCTEST_REF_WRAP(x) x& 221 | #else // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE 222 | #define DOCTEST_REF_WRAP(x) x 223 | #endif // DOCTEST_CONFIG_ASSERTION_PARAMETERS_BY_VALUE 224 | 225 | // not using __APPLE__ because... this is how Catch does it 226 | #if defined(__MAC_OS_X_VERSION_MIN_REQUIRED) 227 | #define DOCTEST_PLATFORM_MAC 228 | #elif defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 229 | #define DOCTEST_PLATFORM_IPHONE 230 | #elif defined(_WIN32) || defined(_MSC_VER) 231 | #define DOCTEST_PLATFORM_WINDOWS 232 | #else 233 | #define DOCTEST_PLATFORM_LINUX 234 | #endif 235 | 236 | #define DOCTEST_GCS() (*doctest::detail::getTestsContextState()) 237 | 238 | // should probably take a look at https://github.com/scottt/debugbreak 239 | #ifdef DOCTEST_PLATFORM_MAC 240 | // The following code snippet based on: 241 | // http://cocoawithlove.com/2008/03/break-into-debugger.html 242 | #if defined(__ppc64__) || defined(__ppc__) 243 | #define DOCTEST_BREAK_INTO_DEBUGGER() \ 244 | __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" : : : "memory", "r0", "r3", "r4") 245 | #else // __ppc64__ || __ppc__ 246 | #define DOCTEST_BREAK_INTO_DEBUGGER() __asm__("int $3\n" : :) 247 | #endif // __ppc64__ || __ppc__ 248 | #elif defined(_MSC_VER) 249 | #define DOCTEST_BREAK_INTO_DEBUGGER() __debugbreak() 250 | #elif defined(__MINGW32__) 251 | extern "C" __declspec(dllimport) void __stdcall DebugBreak(); 252 | #define DOCTEST_BREAK_INTO_DEBUGGER() ::DebugBreak() 253 | #else // linux 254 | #define DOCTEST_BREAK_INTO_DEBUGGER() ((void)0) 255 | #endif // linux 256 | 257 | #define DOCTEST_BREAK_INTO_DEBUGGER_CHECKED() \ 258 | if(doctest::detail::isDebuggerActive() && !DOCTEST_GCS().no_breaks) \ 259 | DOCTEST_BREAK_INTO_DEBUGGER(); 260 | 261 | #ifdef __clang__ 262 | // to detect if libc++ is being used with clang (the _LIBCPP_VERSION identifier) 263 | #include 264 | #endif // __clang__ 265 | 266 | #ifdef _LIBCPP_VERSION 267 | // not forward declaring ostream for libc++ because I had some problems (inline namespaces vs c++98) 268 | // so the header is used - also it is very light and doesn't drag a ton of stuff 269 | #include 270 | #else // _LIBCPP_VERSION 271 | #ifndef DOCTEST_CONFIG_USE_IOSFWD 272 | namespace std 273 | { 274 | template 275 | struct char_traits; 276 | template <> 277 | struct char_traits; 278 | template 279 | class basic_ostream; 280 | typedef basic_ostream > ostream; 281 | } 282 | #else // DOCTEST_CONFIG_USE_IOSFWD 283 | #include 284 | #endif // DOCTEST_CONFIG_USE_IOSFWD 285 | #endif // _LIBCPP_VERSION 286 | 287 | // static assert macro - because of the c++98 support requires that the message is an 288 | // identifier (no spaces and not a C string) - example without quotes: I_am_a_message 289 | // taken from here: http://stackoverflow.com/a/1980156/3162383 290 | #ifdef DOCTEST_CONFIG_WITH_STATIC_ASSERT 291 | #define DOCTEST_STATIC_ASSERT(expression, message) static_assert(expression, #message) 292 | #else // DOCTEST_CONFIG_WITH_STATIC_ASSERT 293 | #define DOCTEST_STATIC_ASSERT(expression, message) \ 294 | struct DOCTEST_CAT(__static_assertion_at_line_, __LINE__) \ 295 | { \ 296 | doctest::detail::static_assert_impl::StaticAssertion((expression))> \ 297 | DOCTEST_CAT(DOCTEST_CAT(DOCTEST_CAT(STATIC_ASSERTION_FAILED_AT_LINE_, __LINE__), \ 298 | _), \ 299 | message); \ 300 | }; \ 301 | typedef doctest::detail::static_assert_impl::StaticAssertionTest \ 303 | DOCTEST_CAT(__static_assertion_test_at_line_, __LINE__) 304 | #endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT 305 | 306 | #ifdef DOCTEST_CONFIG_WITH_NULLPTR 307 | #ifdef _LIBCPP_VERSION 308 | #include 309 | #else // _LIBCPP_VERSION 310 | namespace std 311 | { typedef decltype(nullptr) nullptr_t; } 312 | #endif // _LIBCPP_VERSION 313 | #endif // DOCTEST_CONFIG_WITH_NULLPTR 314 | 315 | namespace doctest 316 | { 317 | class String 318 | { 319 | char* m_str; 320 | 321 | void copy(const String& other); 322 | 323 | public: 324 | String(const char* in = ""); 325 | String(const String& other); 326 | ~String(); 327 | 328 | String& operator=(const String& other); 329 | 330 | String operator+(const String& other) const; 331 | String& operator+=(const String& other); 332 | 333 | char& operator[](unsigned pos) { return m_str[pos]; } 334 | const char& operator[](unsigned pos) const { return m_str[pos]; } 335 | 336 | char* c_str() { return m_str; } 337 | const char* c_str() const { return m_str; } 338 | 339 | unsigned size() const; 340 | unsigned length() const; 341 | 342 | int compare(const char* other, bool no_case = false) const; 343 | int compare(const String& other, bool no_case = false) const; 344 | }; 345 | 346 | // clang-format off 347 | inline bool operator==(const String& lhs, const String& rhs) { return lhs.compare(rhs) == 0; } 348 | inline bool operator!=(const String& lhs, const String& rhs) { return lhs.compare(rhs) != 0; } 349 | inline bool operator< (const String& lhs, const String& rhs) { return lhs.compare(rhs) < 0; } 350 | inline bool operator> (const String& lhs, const String& rhs) { return lhs.compare(rhs) > 0; } 351 | inline bool operator<=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) < 0 : true; } 352 | inline bool operator>=(const String& lhs, const String& rhs) { return (lhs != rhs) ? lhs.compare(rhs) > 0 : true; } 353 | // clang-format on 354 | 355 | std::ostream& operator<<(std::ostream& stream, const String& in); 356 | 357 | namespace detail 358 | { 359 | #ifndef DOCTEST_CONFIG_WITH_STATIC_ASSERT 360 | namespace static_assert_impl 361 | { 362 | template 363 | struct StaticAssertion; 364 | 365 | template <> 366 | struct StaticAssertion 367 | {}; 368 | 369 | template 370 | struct StaticAssertionTest 371 | {}; 372 | } // namespace static_assert_impl 373 | #endif // DOCTEST_CONFIG_WITH_STATIC_ASSERT 374 | 375 | template 376 | struct deferred_false 377 | { static const bool value = false; }; 378 | 379 | namespace has_insertion_operator_impl 380 | { 381 | typedef char no; 382 | typedef char yes[2]; 383 | 384 | struct any_t 385 | { 386 | template 387 | any_t(const DOCTEST_REF_WRAP(T)); 388 | }; 389 | 390 | yes& testStreamable(std::ostream&); 391 | no testStreamable(no); 392 | 393 | no operator<<(const std::ostream&, const any_t&); 394 | 395 | template 396 | struct has_insertion_operator 397 | { 398 | static std::ostream& s; 399 | static const DOCTEST_REF_WRAP(T) t; 400 | static const bool value = sizeof(testStreamable(s << t)) == sizeof(yes); 401 | }; 402 | } // namespace has_insertion_operator_impl 403 | 404 | template 405 | struct has_insertion_operator : has_insertion_operator_impl::has_insertion_operator 406 | {}; 407 | 408 | std::ostream* createStream(); 409 | String getStreamResult(std::ostream*); 410 | void freeStream(std::ostream*); 411 | 412 | template 413 | struct StringMakerBase 414 | { 415 | template 416 | static String convert(const DOCTEST_REF_WRAP(T)) { 417 | return "{?}"; 418 | } 419 | }; 420 | 421 | template <> 422 | struct StringMakerBase 423 | { 424 | template 425 | static String convert(const DOCTEST_REF_WRAP(T) in) { 426 | std::ostream* stream = createStream(); 427 | *stream << in; 428 | String result = getStreamResult(stream); 429 | freeStream(stream); 430 | return result; 431 | } 432 | }; 433 | 434 | String rawMemoryToString(const void* object, unsigned size); 435 | 436 | template 437 | String rawMemoryToString(const DOCTEST_REF_WRAP(T) object) { 438 | return rawMemoryToString(&object, sizeof(object)); 439 | } 440 | } // namespace detail 441 | 442 | template 443 | struct StringMaker : detail::StringMakerBase::value> 444 | {}; 445 | 446 | template 447 | struct StringMaker 448 | { 449 | template 450 | static String convert(U* p) { 451 | if(!p) 452 | return "NULL"; 453 | else 454 | return detail::rawMemoryToString(p); 455 | } 456 | }; 457 | 458 | template 459 | struct StringMaker 460 | { 461 | static String convert(R C::*p) { 462 | if(!p) 463 | return "NULL"; 464 | else 465 | return detail::rawMemoryToString(p); 466 | } 467 | }; 468 | 469 | template 470 | String toString(const DOCTEST_REF_WRAP(T) value) { 471 | return StringMaker::convert(value); 472 | } 473 | 474 | #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 475 | String toString(char* in); 476 | String toString(const char* in); 477 | #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 478 | String toString(bool in); 479 | String toString(float in); 480 | String toString(double in); 481 | String toString(double long in); 482 | 483 | String toString(char in); 484 | String toString(char unsigned in); 485 | String toString(int short in); 486 | String toString(int short unsigned in); 487 | String toString(int in); 488 | String toString(int unsigned in); 489 | String toString(int long in); 490 | String toString(int long unsigned in); 491 | 492 | #ifdef DOCTEST_CONFIG_WITH_LONG_LONG 493 | String toString(int long long in); 494 | String toString(int long long unsigned in); 495 | #endif // DOCTEST_CONFIG_WITH_LONG_LONG 496 | 497 | #ifdef DOCTEST_CONFIG_WITH_NULLPTR 498 | String toString(std::nullptr_t in); 499 | #endif // DOCTEST_CONFIG_WITH_NULLPTR 500 | 501 | class Approx 502 | { 503 | public: 504 | explicit Approx(double value); 505 | 506 | Approx(Approx const& other) 507 | : m_epsilon(other.m_epsilon) 508 | , m_scale(other.m_scale) 509 | , m_value(other.m_value) {} 510 | 511 | Approx operator()(double value) { 512 | Approx approx(value); 513 | approx.epsilon(m_epsilon); 514 | approx.scale(m_scale); 515 | return approx; 516 | } 517 | 518 | friend bool operator==(double lhs, Approx const& rhs); 519 | friend bool operator==(Approx const& lhs, double rhs) { return operator==(rhs, lhs); } 520 | friend bool operator!=(double lhs, Approx const& rhs) { return !operator==(lhs, rhs); } 521 | friend bool operator!=(Approx const& lhs, double rhs) { return !operator==(rhs, lhs); } 522 | 523 | Approx& epsilon(double newEpsilon) { 524 | m_epsilon = newEpsilon; 525 | return *this; 526 | } 527 | 528 | Approx& scale(double newScale) { 529 | m_scale = newScale; 530 | return *this; 531 | } 532 | 533 | String toString() const; 534 | 535 | private: 536 | double m_epsilon; 537 | double m_scale; 538 | double m_value; 539 | }; 540 | 541 | template <> 542 | inline String toString(const DOCTEST_REF_WRAP(Approx) value) { 543 | return value.toString(); 544 | } 545 | 546 | #if !defined(DOCTEST_CONFIG_DISABLE) 547 | 548 | namespace detail 549 | { 550 | // the function type this library works with 551 | typedef void (*funcType)(void); 552 | 553 | namespace assertType 554 | { 555 | enum Enum 556 | { 557 | // macro traits 558 | 559 | is_warn = 1, 560 | is_check = 2, 561 | is_require = 4, 562 | 563 | is_throws = 8, 564 | is_throws_as = 16, 565 | is_nothrow = 32, 566 | 567 | is_fast = 64, // not checked anywhere - used just to distinguish the types 568 | is_false = 128, 569 | is_unary = 256, 570 | 571 | is_eq = 512, 572 | is_ne = 1024, 573 | 574 | is_lt = 2048, 575 | is_gt = 4096, 576 | 577 | is_ge = 8192, 578 | is_le = 16384, 579 | 580 | // macro types 581 | 582 | DT_WARN = is_warn, 583 | DT_CHECK = is_check, 584 | DT_REQUIRE = is_require, 585 | 586 | DT_WARN_FALSE = is_false | is_warn, 587 | DT_CHECK_FALSE = is_false | is_check, 588 | DT_REQUIRE_FALSE = is_false | is_require, 589 | 590 | DT_WARN_THROWS = is_throws | is_warn, 591 | DT_CHECK_THROWS = is_throws | is_check, 592 | DT_REQUIRE_THROWS = is_throws | is_require, 593 | 594 | DT_WARN_THROWS_AS = is_throws_as | is_warn, 595 | DT_CHECK_THROWS_AS = is_throws_as | is_check, 596 | DT_REQUIRE_THROWS_AS = is_throws_as | is_require, 597 | 598 | DT_WARN_NOTHROW = is_nothrow | is_warn, 599 | DT_CHECK_NOTHROW = is_nothrow | is_check, 600 | DT_REQUIRE_NOTHROW = is_nothrow | is_require, 601 | 602 | DT_WARN_EQ = is_eq | is_warn, 603 | DT_CHECK_EQ = is_eq | is_check, 604 | DT_REQUIRE_EQ = is_eq | is_require, 605 | 606 | DT_WARN_NE = is_ne | is_warn, 607 | DT_CHECK_NE = is_ne | is_check, 608 | DT_REQUIRE_NE = is_ne | is_require, 609 | 610 | DT_WARN_GT = is_gt | is_warn, 611 | DT_CHECK_GT = is_gt | is_check, 612 | DT_REQUIRE_GT = is_gt | is_require, 613 | 614 | DT_WARN_LT = is_lt | is_warn, 615 | DT_CHECK_LT = is_lt | is_check, 616 | DT_REQUIRE_LT = is_lt | is_require, 617 | 618 | DT_WARN_GE = is_ge | is_warn, 619 | DT_CHECK_GE = is_ge | is_check, 620 | DT_REQUIRE_GE = is_ge | is_require, 621 | 622 | DT_WARN_LE = is_le | is_warn, 623 | DT_CHECK_LE = is_le | is_check, 624 | DT_REQUIRE_LE = is_le | is_require, 625 | 626 | DT_WARN_UNARY = is_unary | is_warn, 627 | DT_CHECK_UNARY = is_unary | is_check, 628 | DT_REQUIRE_UNARY = is_unary | is_require, 629 | 630 | DT_WARN_UNARY_FALSE = is_false | is_unary | is_warn, 631 | DT_CHECK_UNARY_FALSE = is_false | is_unary | is_check, 632 | DT_REQUIRE_UNARY_FALSE = is_false | is_unary | is_require, 633 | 634 | DT_FAST_WARN_EQ = is_fast | is_eq | is_warn, 635 | DT_FAST_CHECK_EQ = is_fast | is_eq | is_check, 636 | DT_FAST_REQUIRE_EQ = is_fast | is_eq | is_require, 637 | 638 | DT_FAST_WARN_NE = is_fast | is_ne | is_warn, 639 | DT_FAST_CHECK_NE = is_fast | is_ne | is_check, 640 | DT_FAST_REQUIRE_NE = is_fast | is_ne | is_require, 641 | 642 | DT_FAST_WARN_GT = is_fast | is_gt | is_warn, 643 | DT_FAST_CHECK_GT = is_fast | is_gt | is_check, 644 | DT_FAST_REQUIRE_GT = is_fast | is_gt | is_require, 645 | 646 | DT_FAST_WARN_LT = is_fast | is_lt | is_warn, 647 | DT_FAST_CHECK_LT = is_fast | is_lt | is_check, 648 | DT_FAST_REQUIRE_LT = is_fast | is_lt | is_require, 649 | 650 | DT_FAST_WARN_GE = is_fast | is_ge | is_warn, 651 | DT_FAST_CHECK_GE = is_fast | is_ge | is_check, 652 | DT_FAST_REQUIRE_GE = is_fast | is_ge | is_require, 653 | 654 | DT_FAST_WARN_LE = is_fast | is_le | is_warn, 655 | DT_FAST_CHECK_LE = is_fast | is_le | is_check, 656 | DT_FAST_REQUIRE_LE = is_fast | is_le | is_require, 657 | 658 | DT_FAST_WARN_UNARY = is_fast | is_unary | is_warn, 659 | DT_FAST_CHECK_UNARY = is_fast | is_unary | is_check, 660 | DT_FAST_REQUIRE_UNARY = is_fast | is_unary | is_require, 661 | 662 | DT_FAST_WARN_UNARY_FALSE = is_fast | is_false | is_unary | is_warn, 663 | DT_FAST_CHECK_UNARY_FALSE = is_fast | is_false | is_unary | is_check, 664 | DT_FAST_REQUIRE_UNARY_FALSE = is_fast | is_false | is_unary | is_require 665 | }; 666 | } // namespace assertType 667 | 668 | const char* getAssertString(assertType::Enum val); 669 | 670 | // clang-format off 671 | template struct decay_array { typedef T type; }; 672 | template struct decay_array { typedef T* type; }; 673 | template struct decay_array { typedef T* type; }; 674 | 675 | template struct not_char_pointer { enum { value = true }; }; 676 | template<> struct not_char_pointer { enum { value = false }; }; 677 | template<> struct not_char_pointer { enum { value = false }; }; 678 | 679 | template struct can_use_op : not_char_pointer::type> {}; 680 | 681 | template struct enable_if {}; 682 | template struct enable_if { typedef T type; }; 683 | // clang-format on 684 | 685 | struct TestFailureException 686 | {}; 687 | 688 | bool checkIfShouldThrow(assertType::Enum assert_type); 689 | void fastAssertThrowIfFlagSet(int flags); 690 | void throwException(); 691 | bool always_false(); 692 | 693 | // a struct defining a registered test callback 694 | struct TestData 695 | { 696 | // not used for determining uniqueness 697 | const char* m_suite; // the test suite in which the test was added 698 | const char* m_name; // name of the test function 699 | funcType m_f; // a function pointer to the test function 700 | 701 | // fields by which uniqueness of test cases shall be determined 702 | const char* m_file; // the file in which the test was registered 703 | unsigned m_line; // the line where the test was registered 704 | 705 | TestData(const char* suite, const char* name, funcType f, const char* file, unsigned line) 706 | : m_suite(suite) 707 | , m_name(name) 708 | , m_f(f) 709 | , m_file(file) 710 | , m_line(line) {} 711 | 712 | bool operator<(const TestData& other) const; 713 | }; 714 | 715 | struct SubcaseSignature 716 | { 717 | const char* m_name; 718 | const char* m_file; 719 | int m_line; 720 | 721 | SubcaseSignature(const char* name, const char* file, int line) 722 | : m_name(name) 723 | , m_file(file) 724 | , m_line(line) {} 725 | 726 | bool operator<(const SubcaseSignature& other) const; 727 | }; 728 | 729 | struct Subcase 730 | { 731 | SubcaseSignature m_signature; 732 | bool m_entered; 733 | 734 | Subcase(const char* name, const char* file, int line); 735 | Subcase(const Subcase& other); 736 | ~Subcase(); 737 | 738 | operator bool() const { return m_entered; } 739 | }; 740 | 741 | template 742 | String stringifyBinaryExpr(const DOCTEST_REF_WRAP(L) lhs, const char* op, 743 | const DOCTEST_REF_WRAP(R) rhs) { 744 | return toString(lhs) + op + toString(rhs); 745 | } 746 | 747 | struct Result 748 | { 749 | bool m_passed; 750 | String m_decomposition; 751 | 752 | // to fix gcc 4.7 "-Winline" warnings 753 | #if defined(__GNUC__) && !defined(__clang__) 754 | __attribute__((noinline)) 755 | #endif 756 | ~Result() { 757 | } 758 | 759 | Result(bool passed = false, const String& decomposition = String()) 760 | : m_passed(passed) 761 | , m_decomposition(decomposition) {} 762 | 763 | Result(const Result& other) 764 | : m_passed(other.m_passed) 765 | , m_decomposition(other.m_decomposition) {} 766 | 767 | // to fix gcc 4.7 "-Winline" warnings 768 | #if defined(__GNUC__) && !defined(__clang__) 769 | __attribute__((noinline)) 770 | #endif 771 | Result& 772 | operator=(const Result& other) { 773 | m_passed = other.m_passed; 774 | m_decomposition = other.m_decomposition; 775 | 776 | return *this; 777 | } 778 | 779 | operator bool() { return !m_passed; } 780 | 781 | void invert() { m_passed = !m_passed; } 782 | 783 | // clang-format off 784 | // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence 785 | template Result operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 786 | template Result operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 787 | template Result operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 788 | template Result operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 789 | template Result operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 790 | template Result operator== (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 791 | template Result operator!= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 792 | template Result operator< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 793 | template Result operator> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 794 | template Result operator<= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 795 | template Result operator>= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 796 | template Result operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 797 | template Result operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 798 | template Result operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 799 | template Result operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 800 | template Result operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 801 | template Result operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 802 | template Result operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 803 | template Result operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 804 | template Result operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 805 | template Result operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 806 | template Result operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return Result(); } 807 | // clang-format on 808 | }; 809 | 810 | #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION 811 | 812 | #if defined(__clang__) 813 | #pragma clang diagnostic push 814 | #pragma clang diagnostic ignored "-Wsign-conversion" 815 | #pragma clang diagnostic ignored "-Wsign-compare" 816 | #pragma clang diagnostic ignored "-Wdouble-promotion" 817 | //#pragma clang diagnostic ignored "-Wconversion" 818 | //#pragma clang diagnostic ignored "-Wfloat-equal" 819 | #endif // __clang__ 820 | 821 | #if defined(__GNUC__) && !defined(__clang__) 822 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 823 | #pragma GCC diagnostic push 824 | #endif // > gcc 4.6 825 | #pragma GCC diagnostic ignored "-Wsign-conversion" 826 | #pragma GCC diagnostic ignored "-Wsign-compare" 827 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) 828 | #pragma GCC diagnostic ignored "-Wdouble-promotion" 829 | #endif // > gcc 4.5 830 | //#pragma GCC diagnostic ignored "-Wconversion" 831 | //#pragma GCC diagnostic ignored "-Wfloat-equal" 832 | #endif // __GNUC__ 833 | 834 | #ifdef _MSC_VER 835 | #pragma warning(push) 836 | // http://stackoverflow.com/questions/39479163 what's the difference between C4018 and C4389 837 | #pragma warning(disable : 4389) // 'operator' : signed/unsigned mismatch 838 | #pragma warning(disable : 4018) // 'expression' : signed/unsigned mismatch 839 | //#pragma warning(disable : 4805) // 'operation' : unsafe mix of type 'type' and type 'type' in operation 840 | #endif // _MSC_VER 841 | 842 | #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION 843 | 844 | // clang-format off 845 | #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 846 | #define DOCTEST_COMPARISON_RETURN_TYPE bool 847 | #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 848 | #define DOCTEST_COMPARISON_RETURN_TYPE typename enable_if::value || can_use_op::value, bool>::type 849 | inline bool eq(const char* lhs, const char* rhs) { return String(lhs) == String(rhs); } 850 | inline bool ne(const char* lhs, const char* rhs) { return String(lhs) != String(rhs); } 851 | inline bool lt(const char* lhs, const char* rhs) { return String(lhs) < String(rhs); } 852 | inline bool gt(const char* lhs, const char* rhs) { return String(lhs) > String(rhs); } 853 | inline bool le(const char* lhs, const char* rhs) { return String(lhs) <= String(rhs); } 854 | inline bool ge(const char* lhs, const char* rhs) { return String(lhs) >= String(rhs); } 855 | #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 856 | 857 | template DOCTEST_COMPARISON_RETURN_TYPE eq(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs == rhs; } 858 | template DOCTEST_COMPARISON_RETURN_TYPE ne(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs != rhs; } 859 | template DOCTEST_COMPARISON_RETURN_TYPE lt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs < rhs; } 860 | template DOCTEST_COMPARISON_RETURN_TYPE gt(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs > rhs; } 861 | template DOCTEST_COMPARISON_RETURN_TYPE le(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs <= rhs; } 862 | template DOCTEST_COMPARISON_RETURN_TYPE ge(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { return lhs >= rhs; } 863 | // clang-format on 864 | 865 | template 866 | struct Expression_lhs 867 | { 868 | L lhs; 869 | 870 | Expression_lhs(L in) 871 | : lhs(in) {} 872 | 873 | Expression_lhs(const Expression_lhs& other) 874 | : lhs(other.lhs) {} 875 | 876 | operator Result() { return Result(!!lhs, toString(lhs)); } 877 | 878 | // clang-format off 879 | #ifndef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 880 | template Result operator==(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs == rhs, stringifyBinaryExpr(lhs, " == ", rhs)); } 881 | template Result operator!=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs != rhs, stringifyBinaryExpr(lhs, " != ", rhs)); } 882 | template Result operator< (const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs < rhs, stringifyBinaryExpr(lhs, " < " , rhs)); } 883 | template Result operator<=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs <= rhs, stringifyBinaryExpr(lhs, " <= ", rhs)); } 884 | template Result operator> (const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs > rhs, stringifyBinaryExpr(lhs, " > " , rhs)); } 885 | template Result operator>=(const DOCTEST_REF_WRAP(R) rhs) { return Result(lhs >= rhs, stringifyBinaryExpr(lhs, " >= ", rhs)); } 886 | #else // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 887 | template Result operator==(const DOCTEST_REF_WRAP(R) rhs) { return Result(eq(lhs, rhs), stringifyBinaryExpr(lhs, " == ", rhs)); } 888 | template Result operator!=(const DOCTEST_REF_WRAP(R) rhs) { return Result(ne(lhs, rhs), stringifyBinaryExpr(lhs, " != ", rhs)); } 889 | template Result operator< (const DOCTEST_REF_WRAP(R) rhs) { return Result(lt(lhs, rhs), stringifyBinaryExpr(lhs, " < " , rhs)); } 890 | template Result operator<=(const DOCTEST_REF_WRAP(R) rhs) { return Result(le(lhs, rhs), stringifyBinaryExpr(lhs, " <= ", rhs)); } 891 | template Result operator> (const DOCTEST_REF_WRAP(R) rhs) { return Result(gt(lhs, rhs), stringifyBinaryExpr(lhs, " > " , rhs)); } 892 | template Result operator>=(const DOCTEST_REF_WRAP(R) rhs) { return Result(ge(lhs, rhs), stringifyBinaryExpr(lhs, " >= ", rhs)); } 893 | #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 894 | // clang-format on 895 | 896 | // clang-format off 897 | // forbidding some expressions based on this table: http://en.cppreference.com/w/cpp/language/operator_precedence 898 | template int operator& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 899 | template int operator^ (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 900 | template int operator| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 901 | template int operator&& (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 902 | template int operator|| (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 903 | template int operator= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 904 | template int operator+= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 905 | template int operator-= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 906 | template int operator*= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 907 | template int operator/= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 908 | template int operator%= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 909 | template int operator<<=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 910 | template int operator>>=(const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 911 | template int operator&= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 912 | template int operator^= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 913 | template int operator|= (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison); return int(); } 914 | // these 2 are unfortunate because they should be allowed - they have higher precedence over the comparisons, but the 915 | // ExpressionDecomposer class uses the left shift operator to capture the left operand of the binary expression... 916 | template int operator<< (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Please_Surround_The_Left_Shift_Operation_With_Parenthesis); return int(); } 917 | template int operator>> (const R&) { DOCTEST_STATIC_ASSERT(deferred_false::value, Please_Surround_The_Right_Shift_Operation_With_Parenthesis); return int(); } 918 | // clang-format on 919 | }; 920 | 921 | #ifndef DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION 922 | 923 | #if defined(__clang__) 924 | #pragma clang diagnostic pop 925 | #endif // __clang__ 926 | 927 | #if defined(__GNUC__) && !defined(__clang__) 928 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 929 | #pragma GCC diagnostic pop 930 | #endif // > gcc 4.6 931 | #endif // __GNUC__ 932 | 933 | #ifdef _MSC_VER 934 | #pragma warning(pop) 935 | #endif // _MSC_VER 936 | 937 | #endif // DOCTEST_CONFIG_NO_COMPARISON_WARNING_SUPPRESSION 938 | 939 | struct ExpressionDecomposer 940 | { 941 | template 942 | Expression_lhs operator<<(const DOCTEST_REF_WRAP(L) operand) { 943 | return Expression_lhs(operand); 944 | } 945 | }; 946 | 947 | // forward declarations of functions used by the macros 948 | int regTest(void (*f)(void), unsigned line, const char* file, const char* name); 949 | int setTestSuiteName(const char* name); 950 | 951 | void addFailedAssert(assertType::Enum assert_type); 952 | 953 | void logTestStart(const char* name, const char* file, unsigned line); 954 | void logTestEnd(); 955 | 956 | void logTestCrashed(); 957 | void logTestException(const char* what); 958 | 959 | void logAssert(bool passed, const char* decomposition, bool threw, const char* expr, 960 | assertType::Enum assert_type, const char* file, int line); 961 | 962 | void logAssertThrows(bool threw, const char* expr, assertType::Enum assert_type, 963 | const char* file, int line); 964 | 965 | void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const char* expr, 966 | assertType::Enum assert_type, const char* file, int line); 967 | 968 | void logAssertNothrow(bool threw, const char* expr, assertType::Enum assert_type, 969 | const char* file, int line); 970 | 971 | bool isDebuggerActive(); 972 | void writeToDebugConsole(const String&); 973 | 974 | struct TestAccessibleContextState 975 | { 976 | bool success; // include successful assertions in output 977 | bool no_throw; // to skip exceptions-related assertion macros 978 | bool no_breaks; // to not break into the debugger 979 | const TestData* currentTest; 980 | bool hasLoggedCurrentTestStart; 981 | int numAssertionsForCurrentTestcase; 982 | }; 983 | 984 | struct ContextState; 985 | 986 | TestAccessibleContextState* getTestsContextState(); 987 | 988 | namespace binaryAssertComparison 989 | { 990 | enum Enum 991 | { 992 | eq = 0, 993 | ne, 994 | gt, 995 | lt, 996 | ge, 997 | le 998 | }; 999 | } // namespace binaryAssertComparison 1000 | 1001 | // clang-format off 1002 | template struct RelationalComparator { bool operator()(const DOCTEST_REF_WRAP(L), const DOCTEST_REF_WRAP(R) ) const { return false; } }; 1003 | template struct RelationalComparator<0, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return eq(lhs, rhs); } }; 1004 | template struct RelationalComparator<1, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ne(lhs, rhs); } }; 1005 | template struct RelationalComparator<2, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return gt(lhs, rhs); } }; 1006 | template struct RelationalComparator<3, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return lt(lhs, rhs); } }; 1007 | template struct RelationalComparator<4, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return ge(lhs, rhs); } }; 1008 | template struct RelationalComparator<5, L, R> { bool operator()(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) const { return le(lhs, rhs); } }; 1009 | // clang-format on 1010 | 1011 | struct ResultBuilder 1012 | { 1013 | assertType::Enum m_assert_type; 1014 | const char* m_file; 1015 | int m_line; 1016 | const char* m_expr; 1017 | const char* m_exception_type; 1018 | 1019 | Result m_result; 1020 | bool m_threw; 1021 | bool m_threw_as; 1022 | bool m_failed; 1023 | 1024 | ResultBuilder(assertType::Enum assert_type, const char* file, int line, const char* expr, 1025 | const char* exception_type = ""); 1026 | 1027 | // to fix gcc 4.7 "-Winline" warnings 1028 | #if defined(__GNUC__) && !defined(__clang__) 1029 | __attribute__((noinline)) 1030 | #endif 1031 | ~ResultBuilder() { 1032 | } 1033 | 1034 | void setResult(const Result& res) { m_result = res; } 1035 | 1036 | template 1037 | void binary_assert(const DOCTEST_REF_WRAP(L) lhs, const DOCTEST_REF_WRAP(R) rhs) { 1038 | m_result.m_passed = RelationalComparator()(lhs, rhs); 1039 | m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); 1040 | } 1041 | 1042 | template 1043 | void unary_assert(const DOCTEST_REF_WRAP(L) val) { 1044 | m_result.m_passed = !!val; 1045 | m_result.m_decomposition = toString(val); 1046 | } 1047 | 1048 | bool log(); 1049 | void react() const; 1050 | }; 1051 | 1052 | namespace assertAction 1053 | { 1054 | enum Enum 1055 | { 1056 | nothing = 0, 1057 | dbgbreak = 1, 1058 | shouldthrow = 2 1059 | }; 1060 | } // namespace assertAction 1061 | 1062 | template 1063 | int fast_binary_assert(assertType::Enum assert_type, const char* file, int line, 1064 | const char* lhs_str, const char* rhs_str, const DOCTEST_REF_WRAP(L) lhs, 1065 | const DOCTEST_REF_WRAP(R) rhs) { 1066 | String expr = String(lhs_str) + ", " + rhs_str; 1067 | const char* expr_str = expr.c_str(); 1068 | ResultBuilder rb(assert_type, file, line, expr_str); 1069 | 1070 | rb.m_result.m_passed = RelationalComparator()(lhs, rhs); 1071 | rb.m_result.m_decomposition = stringifyBinaryExpr(lhs, ", ", rhs); 1072 | 1073 | int res = 0; 1074 | 1075 | if(rb.log()) 1076 | res |= assertAction::dbgbreak; 1077 | 1078 | if(rb.m_failed && checkIfShouldThrow(assert_type)) 1079 | res |= assertAction::shouldthrow; 1080 | 1081 | #ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1082 | // ######################################################################################### 1083 | // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION 1084 | // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED 1085 | // ######################################################################################### 1086 | if(res & assertAction::dbgbreak) 1087 | DOCTEST_BREAK_INTO_DEBUGGER(); 1088 | fastAssertThrowIfFlagSet(res); 1089 | #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1090 | 1091 | return res; 1092 | } 1093 | 1094 | template 1095 | int fast_unary_assert(assertType::Enum assert_type, const char* file, int line, 1096 | const char* val_str, const DOCTEST_REF_WRAP(L) val) { 1097 | ResultBuilder rb(assert_type, file, line, val_str); 1098 | 1099 | rb.m_result.m_passed = !!val; 1100 | rb.m_result.m_decomposition = toString(val); 1101 | 1102 | int res = 0; 1103 | 1104 | if(rb.log()) 1105 | res |= assertAction::dbgbreak; 1106 | 1107 | if(rb.m_failed && checkIfShouldThrow(assert_type)) 1108 | res |= assertAction::shouldthrow; 1109 | 1110 | #ifdef DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1111 | // ######################################################################################### 1112 | // IF THE DEBUGGER BREAKS HERE - GO 1 LEVEL UP IN THE CALLSTACK TO SEE THE FAILING ASSERTION 1113 | // THIS IS THE EFFECT OF HAVING 'DOCTEST_CONFIG_SUPER_FAST_ASSERTS' DEFINED 1114 | // ######################################################################################### 1115 | if(res & assertAction::dbgbreak) 1116 | DOCTEST_BREAK_INTO_DEBUGGER(); 1117 | fastAssertThrowIfFlagSet(res); 1118 | #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1119 | 1120 | return res; 1121 | } 1122 | } // namespace detail 1123 | 1124 | #endif // DOCTEST_CONFIG_DISABLE 1125 | 1126 | class Context 1127 | { 1128 | #if !defined(DOCTEST_CONFIG_DISABLE) 1129 | detail::ContextState* p; 1130 | 1131 | void parseArgs(int argc, const char* const* argv, bool withDefaults = false); 1132 | 1133 | #endif // DOCTEST_CONFIG_DISABLE 1134 | 1135 | public: 1136 | Context(int argc = 0, const char* const* argv = 0); 1137 | 1138 | // to fix gcc 4.7 "-Winline" warnings 1139 | #if defined(__GNUC__) && !defined(__clang__) 1140 | __attribute__((noinline)) 1141 | #endif 1142 | ~Context(); 1143 | 1144 | void applyCommandLine(int argc, const char* const* argv); 1145 | 1146 | void addFilter(const char* filter, const char* value); 1147 | void clearFilters(); 1148 | void setOption(const char* option, int value); 1149 | void setOption(const char* option, const char* value); 1150 | 1151 | bool shouldExit(); 1152 | 1153 | int run(); 1154 | }; 1155 | 1156 | } // namespace doctest 1157 | 1158 | // if registering is not disabled 1159 | #if !defined(DOCTEST_CONFIG_DISABLE) 1160 | 1161 | // registers the test by initializing a dummy var with a function 1162 | #if defined(__GNUC__) && !defined(__clang__) 1163 | #define DOCTEST_REGISTER_FUNCTION(f, name) \ 1164 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ 1165 | doctest::detail::regTest(f, __LINE__, __FILE__, name); 1166 | #elif defined(__clang__) 1167 | #define DOCTEST_REGISTER_FUNCTION(f, name) \ 1168 | _Pragma("clang diagnostic push") \ 1169 | _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ 1170 | DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ 1171 | doctest::detail::regTest(f, __LINE__, __FILE__, name); \ 1172 | _Pragma("clang diagnostic pop") 1173 | #else // MSVC 1174 | #define DOCTEST_REGISTER_FUNCTION(f, name) \ 1175 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ 1176 | doctest::detail::regTest(f, __LINE__, __FILE__, name); 1177 | #endif // MSVC 1178 | 1179 | #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ 1180 | namespace \ 1181 | { \ 1182 | struct der : base \ 1183 | { void f(); }; \ 1184 | static void func() { \ 1185 | der v; \ 1186 | v.f(); \ 1187 | } \ 1188 | DOCTEST_REGISTER_FUNCTION(func, name) \ 1189 | } \ 1190 | inline void der::f() 1191 | 1192 | #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ 1193 | static void f(); \ 1194 | DOCTEST_REGISTER_FUNCTION(f, name) \ 1195 | static void f() 1196 | 1197 | // for registering tests 1198 | #define DOCTEST_TEST_CASE(name) \ 1199 | DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) 1200 | 1201 | // for registering tests with a fixture 1202 | #define DOCTEST_TEST_CASE_FIXTURE(c, name) \ 1203 | DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), c, \ 1204 | DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) 1205 | 1206 | // for subcases 1207 | #if defined(__GNUC__) 1208 | #define DOCTEST_SUBCASE(name) \ 1209 | if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) \ 1210 | __attribute__((unused)) = \ 1211 | doctest::detail::Subcase(name, __FILE__, __LINE__)) 1212 | #else // __GNUC__ 1213 | #define DOCTEST_SUBCASE(name) \ 1214 | if(const doctest::detail::Subcase & DOCTEST_ANONYMOUS(_DOCTEST_ANON_SUBCASE_) = \ 1215 | doctest::detail::Subcase(name, __FILE__, __LINE__)) 1216 | #endif // __GNUC__ 1217 | 1218 | // for starting a testsuite block 1219 | #if defined(__GNUC__) && !defined(__clang__) 1220 | #define DOCTEST_TEST_SUITE(name) \ 1221 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ 1222 | doctest::detail::setTestSuiteName(name); \ 1223 | typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1224 | #elif defined(__clang__) 1225 | #define DOCTEST_TEST_SUITE(name) \ 1226 | _Pragma("clang diagnostic push") \ 1227 | _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ 1228 | DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = \ 1229 | doctest::detail::setTestSuiteName(name); \ 1230 | _Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1231 | #else // MSVC 1232 | #define DOCTEST_TEST_SUITE(name) \ 1233 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(name); \ 1234 | typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1235 | #endif // MSVC 1236 | 1237 | // for ending a testsuite block 1238 | #if defined(__GNUC__) && !defined(__clang__) 1239 | #define DOCTEST_TEST_SUITE_END \ 1240 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) __attribute__((unused)) = \ 1241 | doctest::detail::setTestSuiteName(""); \ 1242 | typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1243 | #elif defined(__clang__) 1244 | #define DOCTEST_TEST_SUITE_END \ 1245 | _Pragma("clang diagnostic push") \ 1246 | _Pragma("clang diagnostic ignored \"-Wglobal-constructors\"") static int \ 1247 | DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(""); \ 1248 | _Pragma("clang diagnostic pop") typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1249 | #else // MSVC 1250 | #define DOCTEST_TEST_SUITE_END \ 1251 | static int DOCTEST_ANONYMOUS(_DOCTEST_ANON_VAR_) = doctest::detail::setTestSuiteName(""); \ 1252 | typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1253 | #endif // MSVC 1254 | 1255 | #define DOCTEST_ASSERT_LOG_AND_REACT(rb) \ 1256 | if(rb.log()) \ 1257 | DOCTEST_BREAK_INTO_DEBUGGER(); \ 1258 | rb.react() 1259 | 1260 | #ifdef DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS 1261 | #define DOCTEST_WRAP_IN_TRY(x) x; 1262 | #else // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS 1263 | #define DOCTEST_WRAP_IN_TRY(x) \ 1264 | try { \ 1265 | x; \ 1266 | } catch(...) { _DOCTEST_RB.m_threw = true; } 1267 | #endif // DOCTEST_CONFIG_NO_TRY_CATCH_IN_ASSERTS 1268 | 1269 | #define DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ 1270 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, __FILE__, \ 1271 | __LINE__, #expr); \ 1272 | DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.setResult(doctest::detail::ExpressionDecomposer() << expr)) \ 1273 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); 1274 | 1275 | #if defined(__clang__) 1276 | #define DOCTEST_ASSERT_PROXY(expr, assert_type) \ 1277 | do { \ 1278 | _Pragma("clang diagnostic push") \ 1279 | _Pragma("clang diagnostic ignored \"-Woverloaded-shift-op-parentheses\"") \ 1280 | DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ 1281 | _Pragma("clang diagnostic pop") \ 1282 | } while(doctest::detail::always_false()) 1283 | #else // __clang__ 1284 | #define DOCTEST_ASSERT_PROXY(expr, assert_type) \ 1285 | do { \ 1286 | DOCTEST_ASSERT_IMPLEMENT(expr, assert_type) \ 1287 | } while(doctest::detail::always_false()) 1288 | #endif // __clang__ 1289 | 1290 | #define DOCTEST_WARN(expr) DOCTEST_ASSERT_PROXY(expr, DT_WARN) 1291 | #define DOCTEST_CHECK(expr) DOCTEST_ASSERT_PROXY(expr, DT_CHECK) 1292 | #define DOCTEST_REQUIRE(expr) DOCTEST_ASSERT_PROXY(expr, DT_REQUIRE) 1293 | 1294 | #define DOCTEST_WARN_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_WARN_FALSE) 1295 | #define DOCTEST_CHECK_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_CHECK_FALSE) 1296 | #define DOCTEST_REQUIRE_FALSE(expr) DOCTEST_ASSERT_PROXY(expr, DT_REQUIRE_FALSE) 1297 | 1298 | #define DOCTEST_ASSERT_THROWS(expr, assert_type) \ 1299 | do { \ 1300 | if(!DOCTEST_GCS().no_throw) { \ 1301 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ 1302 | __FILE__, __LINE__, #expr); \ 1303 | try { \ 1304 | expr; \ 1305 | } catch(...) { _DOCTEST_RB.m_threw = true; } \ 1306 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ 1307 | } \ 1308 | } while(doctest::detail::always_false()) 1309 | 1310 | #define DOCTEST_ASSERT_THROWS_AS(expr, as, assert_type) \ 1311 | do { \ 1312 | if(!DOCTEST_GCS().no_throw) { \ 1313 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ 1314 | __FILE__, __LINE__, #expr, #as); \ 1315 | try { \ 1316 | expr; \ 1317 | } catch(as) { \ 1318 | _DOCTEST_RB.m_threw = true; \ 1319 | _DOCTEST_RB.m_threw_as = true; \ 1320 | } catch(...) { _DOCTEST_RB.m_threw = true; } \ 1321 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ 1322 | } \ 1323 | } while(doctest::detail::always_false()) 1324 | 1325 | #define DOCTEST_ASSERT_NOTHROW(expr, assert_type) \ 1326 | do { \ 1327 | if(!DOCTEST_GCS().no_throw) { \ 1328 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ 1329 | __FILE__, __LINE__, #expr); \ 1330 | try { \ 1331 | expr; \ 1332 | } catch(...) { _DOCTEST_RB.m_threw = true; } \ 1333 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ 1334 | } \ 1335 | } while(doctest::detail::always_false()) 1336 | 1337 | #define DOCTEST_WARN_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_WARN_THROWS) 1338 | #define DOCTEST_CHECK_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_CHECK_THROWS) 1339 | #define DOCTEST_REQUIRE_THROWS(expr) DOCTEST_ASSERT_THROWS(expr, DT_REQUIRE_THROWS) 1340 | 1341 | #define DOCTEST_WARN_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_WARN_THROWS_AS) 1342 | #define DOCTEST_CHECK_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_CHECK_THROWS_AS) 1343 | #define DOCTEST_REQUIRE_THROWS_AS(expr, ex) DOCTEST_ASSERT_THROWS_AS(expr, ex, DT_REQUIRE_THROWS_AS) 1344 | 1345 | #define DOCTEST_WARN_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_WARN_NOTHROW) 1346 | #define DOCTEST_CHECK_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_CHECK_NOTHROW) 1347 | #define DOCTEST_REQUIRE_NOTHROW(expr) DOCTEST_ASSERT_NOTHROW(expr, DT_REQUIRE_NOTHROW) 1348 | 1349 | #define DOCTEST_BINARY_ASSERT(assert_type, lhs, rhs, comp) \ 1350 | do { \ 1351 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ 1352 | __FILE__, __LINE__, #lhs ", " #rhs); \ 1353 | DOCTEST_WRAP_IN_TRY( \ 1354 | _DOCTEST_RB.binary_assert(lhs, \ 1355 | rhs)) \ 1356 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ 1357 | } while(doctest::detail::always_false()) 1358 | 1359 | #define DOCTEST_UNARY_ASSERT(assert_type, val) \ 1360 | do { \ 1361 | doctest::detail::ResultBuilder _DOCTEST_RB(doctest::detail::assertType::assert_type, \ 1362 | __FILE__, __LINE__, #val); \ 1363 | DOCTEST_WRAP_IN_TRY(_DOCTEST_RB.unary_assert(val)) \ 1364 | DOCTEST_ASSERT_LOG_AND_REACT(_DOCTEST_RB); \ 1365 | } while(doctest::detail::always_false()) 1366 | 1367 | #define DOCTEST_WARN_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_EQ, lhs, rhs, eq) 1368 | #define DOCTEST_CHECK_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_EQ, lhs, rhs, eq) 1369 | #define DOCTEST_REQUIRE_EQ(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_EQ, lhs, rhs, eq) 1370 | #define DOCTEST_WARN_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_NE, lhs, rhs, ne) 1371 | #define DOCTEST_CHECK_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_NE, lhs, rhs, ne) 1372 | #define DOCTEST_REQUIRE_NE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_NE, lhs, rhs, ne) 1373 | #define DOCTEST_WARN_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GT, lhs, rhs, gt) 1374 | #define DOCTEST_CHECK_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GT, lhs, rhs, gt) 1375 | #define DOCTEST_REQUIRE_GT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GT, lhs, rhs, gt) 1376 | #define DOCTEST_WARN_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LT, lhs, rhs, lt) 1377 | #define DOCTEST_CHECK_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LT, lhs, rhs, lt) 1378 | #define DOCTEST_REQUIRE_LT(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LT, lhs, rhs, lt) 1379 | #define DOCTEST_WARN_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_GE, lhs, rhs, ge) 1380 | #define DOCTEST_CHECK_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_GE, lhs, rhs, ge) 1381 | #define DOCTEST_REQUIRE_GE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_GE, lhs, rhs, ge) 1382 | #define DOCTEST_WARN_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_WARN_LE, lhs, rhs, le) 1383 | #define DOCTEST_CHECK_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_CHECK_LE, lhs, rhs, le) 1384 | #define DOCTEST_REQUIRE_LE(lhs, rhs) DOCTEST_BINARY_ASSERT(DT_REQUIRE_LE, lhs, rhs, le) 1385 | 1386 | #define DOCTEST_WARN_UNARY(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY, v) 1387 | #define DOCTEST_CHECK_UNARY(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY, v) 1388 | #define DOCTEST_REQUIRE_UNARY(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY, v) 1389 | #define DOCTEST_WARN_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_WARN_UNARY_FALSE, v) 1390 | #define DOCTEST_CHECK_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_CHECK_UNARY_FALSE, v) 1391 | #define DOCTEST_REQUIRE_UNARY_FALSE(v) DOCTEST_UNARY_ASSERT(DT_REQUIRE_UNARY_FALSE, v) 1392 | 1393 | #ifndef DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1394 | 1395 | #define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ 1396 | do { \ 1397 | int _DOCTEST_FAST_RES = doctest::detail::fast_binary_assert< \ 1398 | doctest::detail::binaryAssertComparison::comparison>( \ 1399 | doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs, #rhs, lhs, \ 1400 | rhs); \ 1401 | if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ 1402 | DOCTEST_BREAK_INTO_DEBUGGER(); \ 1403 | doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ 1404 | } while(doctest::detail::always_false()) 1405 | 1406 | #define DOCTEST_FAST_UNARY_ASSERT(assert_type, val) \ 1407 | do { \ 1408 | int _DOCTEST_FAST_RES = doctest::detail::fast_unary_assert( \ 1409 | doctest::detail::assertType::assert_type, __FILE__, __LINE__, #val, val); \ 1410 | if(_DOCTEST_FAST_RES & doctest::detail::assertAction::dbgbreak) \ 1411 | DOCTEST_BREAK_INTO_DEBUGGER(); \ 1412 | doctest::detail::fastAssertThrowIfFlagSet(_DOCTEST_FAST_RES); \ 1413 | } while(doctest::detail::always_false()) 1414 | 1415 | #else // DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1416 | 1417 | #define DOCTEST_FAST_BINARY_ASSERT(assert_type, lhs, rhs, comparison) \ 1418 | doctest::detail::fast_binary_assert( \ 1419 | doctest::detail::assertType::assert_type, __FILE__, __LINE__, #lhs, #rhs, lhs, rhs) 1420 | 1421 | #define DOCTEST_FAST_UNARY_ASSERT(assert_type, val) \ 1422 | doctest::detail::fast_unary_assert(doctest::detail::assertType::assert_type, __FILE__, \ 1423 | __LINE__, #val, val) 1424 | 1425 | #endif // DOCTEST_CONFIG_SUPER_FAST_ASSERTS 1426 | 1427 | #define DOCTEST_FAST_WARN_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_EQ, l, r, eq) 1428 | #define DOCTEST_FAST_CHECK_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_EQ, l, r, eq) 1429 | #define DOCTEST_FAST_REQUIRE_EQ(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_EQ, l, r, eq) 1430 | #define DOCTEST_FAST_WARN_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_NE, l, r, ne) 1431 | #define DOCTEST_FAST_CHECK_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_NE, l, r, ne) 1432 | #define DOCTEST_FAST_REQUIRE_NE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_NE, l, r, ne) 1433 | #define DOCTEST_FAST_WARN_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GT, l, r, gt) 1434 | #define DOCTEST_FAST_CHECK_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GT, l, r, gt) 1435 | #define DOCTEST_FAST_REQUIRE_GT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GT, l, r, gt) 1436 | #define DOCTEST_FAST_WARN_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LT, l, r, lt) 1437 | #define DOCTEST_FAST_CHECK_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LT, l, r, lt) 1438 | #define DOCTEST_FAST_REQUIRE_LT(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LT, l, r, lt) 1439 | #define DOCTEST_FAST_WARN_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_GE, l, r, ge) 1440 | #define DOCTEST_FAST_CHECK_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_GE, l, r, ge) 1441 | #define DOCTEST_FAST_REQUIRE_GE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_GE, l, r, ge) 1442 | #define DOCTEST_FAST_WARN_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_WARN_LE, l, r, le) 1443 | #define DOCTEST_FAST_CHECK_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_CHECK_LE, l, r, le) 1444 | #define DOCTEST_FAST_REQUIRE_LE(l, r) DOCTEST_FAST_BINARY_ASSERT(DT_FAST_REQUIRE_LE, l, r, le) 1445 | 1446 | #define DOCTEST_FAST_WARN_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY, v) 1447 | #define DOCTEST_FAST_CHECK_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY, v) 1448 | #define DOCTEST_FAST_REQUIRE_UNARY(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY, v) 1449 | #define DOCTEST_FAST_WARN_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_WARN_UNARY_FALSE, v) 1450 | #define DOCTEST_FAST_CHECK_UNARY_FALSE(v) DOCTEST_FAST_UNARY_ASSERT(DT_FAST_CHECK_UNARY_FALSE, v) 1451 | #define DOCTEST_FAST_REQUIRE_UNARY_FALSE(v) \ 1452 | DOCTEST_FAST_UNARY_ASSERT(DT_FAST_REQUIRE_UNARY_FALSE, v) 1453 | 1454 | #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS 1455 | 1456 | #undef DOCTEST_WARN_THROWS 1457 | #undef DOCTEST_CHECK_THROWS 1458 | #undef DOCTEST_REQUIRE_THROWS 1459 | #undef DOCTEST_WARN_THROWS_AS 1460 | #undef DOCTEST_CHECK_THROWS_AS 1461 | #undef DOCTEST_REQUIRE_THROWS_AS 1462 | #undef DOCTEST_WARN_NOTHROW 1463 | #undef DOCTEST_CHECK_NOTHROW 1464 | #undef DOCTEST_REQUIRE_NOTHROW 1465 | 1466 | #ifdef DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS 1467 | 1468 | #define DOCTEST_WARN_THROWS(expr) ((void)0) 1469 | #define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) 1470 | #define DOCTEST_WARN_NOTHROW(expr) ((void)0) 1471 | #define DOCTEST_CHECK_THROWS(expr) ((void)0) 1472 | #define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) 1473 | #define DOCTEST_CHECK_NOTHROW(expr) ((void)0) 1474 | #define DOCTEST_REQUIRE_THROWS(expr) ((void)0) 1475 | #define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) 1476 | #define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) 1477 | 1478 | #else // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS 1479 | 1480 | #undef DOCTEST_REQUIRE 1481 | #undef DOCTEST_REQUIRE_FALSE 1482 | #undef DOCTEST_REQUIRE_EQ 1483 | #undef DOCTEST_REQUIRE_NE 1484 | #undef DOCTEST_REQUIRE_GT 1485 | #undef DOCTEST_REQUIRE_LT 1486 | #undef DOCTEST_REQUIRE_GE 1487 | #undef DOCTEST_REQUIRE_LE 1488 | #undef DOCTEST_REQUIRE_UNARY 1489 | #undef DOCTEST_REQUIRE_UNARY_FALSE 1490 | #undef DOCTEST_FAST_REQUIRE_EQ 1491 | #undef DOCTEST_FAST_REQUIRE_NE 1492 | #undef DOCTEST_FAST_REQUIRE_GT 1493 | #undef DOCTEST_FAST_REQUIRE_LT 1494 | #undef DOCTEST_FAST_REQUIRE_GE 1495 | #undef DOCTEST_FAST_REQUIRE_LE 1496 | #undef DOCTEST_FAST_REQUIRE_UNARY 1497 | #undef DOCTEST_FAST_REQUIRE_UNARY_FALSE 1498 | 1499 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS 1500 | 1501 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 1502 | 1503 | // ================================================================================================= 1504 | // == WHAT FOLLOWS IS VERSIONS OF THE MACROS THAT DO NOT DO ANY REGISTERING! == 1505 | // == THIS CAN BE ENABLED BY DEFINING DOCTEST_CONFIG_DISABLE GLOBALLY! == 1506 | // ================================================================================================= 1507 | #else // DOCTEST_CONFIG_DISABLE 1508 | 1509 | #define DOCTEST_IMPLEMENT_FIXTURE(der, base, func, name) \ 1510 | namespace \ 1511 | { \ 1512 | template \ 1513 | struct der : base \ 1514 | { void f(); }; \ 1515 | } \ 1516 | template \ 1517 | inline void der::f() 1518 | 1519 | #define DOCTEST_CREATE_AND_REGISTER_FUNCTION(f, name) \ 1520 | template \ 1521 | static inline void f() 1522 | 1523 | // for registering tests 1524 | #define DOCTEST_TEST_CASE(name) \ 1525 | DOCTEST_CREATE_AND_REGISTER_FUNCTION(DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) 1526 | 1527 | // for registering tests with a fixture 1528 | #define DOCTEST_TEST_CASE_FIXTURE(x, name) \ 1529 | DOCTEST_IMPLEMENT_FIXTURE(DOCTEST_ANONYMOUS(_DOCTEST_ANON_CLASS_), x, \ 1530 | DOCTEST_ANONYMOUS(_DOCTEST_ANON_FUNC_), name) 1531 | 1532 | // for subcases 1533 | #define DOCTEST_SUBCASE(name) 1534 | 1535 | // for starting a testsuite block 1536 | #define DOCTEST_TEST_SUITE(name) typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1537 | 1538 | // for ending a testsuite block 1539 | #define DOCTEST_TEST_SUITE_END typedef int DOCTEST_ANONYMOUS(_DOCTEST_ANON_FOR_SEMICOLON_) 1540 | 1541 | #define DOCTEST_WARN(expr) ((void)0) 1542 | #define DOCTEST_WARN_FALSE(expr) ((void)0) 1543 | #define DOCTEST_WARN_THROWS(expr) ((void)0) 1544 | #define DOCTEST_WARN_THROWS_AS(expr, ex) ((void)0) 1545 | #define DOCTEST_WARN_NOTHROW(expr) ((void)0) 1546 | #define DOCTEST_CHECK(expr) ((void)0) 1547 | #define DOCTEST_CHECK_FALSE(expr) ((void)0) 1548 | #define DOCTEST_CHECK_THROWS(expr) ((void)0) 1549 | #define DOCTEST_CHECK_THROWS_AS(expr, ex) ((void)0) 1550 | #define DOCTEST_CHECK_NOTHROW(expr) ((void)0) 1551 | #define DOCTEST_REQUIRE(expr) ((void)0) 1552 | #define DOCTEST_REQUIRE_FALSE(expr) ((void)0) 1553 | #define DOCTEST_REQUIRE_THROWS(expr) ((void)0) 1554 | #define DOCTEST_REQUIRE_THROWS_AS(expr, ex) ((void)0) 1555 | #define DOCTEST_REQUIRE_NOTHROW(expr) ((void)0) 1556 | 1557 | #define DOCTEST_WARN_EQ(lhs, rhs) ((void)0) 1558 | #define DOCTEST_CHECK_EQ(lhs, rhs) ((void)0) 1559 | #define DOCTEST_REQUIRE_EQ(lhs, rhs) ((void)0) 1560 | #define DOCTEST_WARN_NE(lhs, rhs) ((void)0) 1561 | #define DOCTEST_CHECK_NE(lhs, rhs) ((void)0) 1562 | #define DOCTEST_REQUIRE_NE(lhs, rhs) ((void)0) 1563 | #define DOCTEST_WARN_GT(lhs, rhs) ((void)0) 1564 | #define DOCTEST_CHECK_GT(lhs, rhs) ((void)0) 1565 | #define DOCTEST_REQUIRE_GT(lhs, rhs) ((void)0) 1566 | #define DOCTEST_WARN_LT(lhs, rhs) ((void)0) 1567 | #define DOCTEST_CHECK_LT(lhs, rhs) ((void)0) 1568 | #define DOCTEST_REQUIRE_LT(lhs, rhs) ((void)0) 1569 | #define DOCTEST_WARN_GE(lhs, rhs) ((void)0) 1570 | #define DOCTEST_CHECK_GE(lhs, rhs) ((void)0) 1571 | #define DOCTEST_REQUIRE_GE(lhs, rhs) ((void)0) 1572 | #define DOCTEST_WARN_LE(lhs, rhs) ((void)0) 1573 | #define DOCTEST_CHECK_LE(lhs, rhs) ((void)0) 1574 | #define DOCTEST_REQUIRE_LE(lhs, rhs) ((void)0) 1575 | 1576 | #define DOCTEST_WARN_UNARY(val) ((void)0) 1577 | #define DOCTEST_CHECK_UNARY(val) ((void)0) 1578 | #define DOCTEST_REQUIRE_UNARY(val) ((void)0) 1579 | #define DOCTEST_WARN_UNARY_FALSE(val) ((void)0) 1580 | #define DOCTEST_CHECK_UNARY_FALSE(val) ((void)0) 1581 | #define DOCTEST_REQUIRE_UNARY_FALSE(val) ((void)0) 1582 | 1583 | #define DOCTEST_FAST_WARN_EQ(lhs, rhs) ((void)0) 1584 | #define DOCTEST_FAST_CHECK_EQ(lhs, rhs) ((void)0) 1585 | #define DOCTEST_FAST_REQUIRE_EQ(lhs, rhs) ((void)0) 1586 | #define DOCTEST_FAST_WARN_NE(lhs, rhs) ((void)0) 1587 | #define DOCTEST_FAST_CHECK_NE(lhs, rhs) ((void)0) 1588 | #define DOCTEST_FAST_REQUIRE_NE(lhs, rhs) ((void)0) 1589 | #define DOCTEST_FAST_WARN_GT(lhs, rhs) ((void)0) 1590 | #define DOCTEST_FAST_CHECK_GT(lhs, rhs) ((void)0) 1591 | #define DOCTEST_FAST_REQUIRE_GT(lhs, rhs) ((void)0) 1592 | #define DOCTEST_FAST_WARN_LT(lhs, rhs) ((void)0) 1593 | #define DOCTEST_FAST_CHECK_LT(lhs, rhs) ((void)0) 1594 | #define DOCTEST_FAST_REQUIRE_LT(lhs, rhs) ((void)0) 1595 | #define DOCTEST_FAST_WARN_GE(lhs, rhs) ((void)0) 1596 | #define DOCTEST_FAST_CHECK_GE(lhs, rhs) ((void)0) 1597 | #define DOCTEST_FAST_REQUIRE_GE(lhs, rhs) ((void)0) 1598 | #define DOCTEST_FAST_WARN_LE(lhs, rhs) ((void)0) 1599 | #define DOCTEST_FAST_CHECK_LE(lhs, rhs) ((void)0) 1600 | #define DOCTEST_FAST_REQUIRE_LE(lhs, rhs) ((void)0) 1601 | 1602 | #define DOCTEST_FAST_WARN_UNARY(val) ((void)0) 1603 | #define DOCTEST_FAST_CHECK_UNARY(val) ((void)0) 1604 | #define DOCTEST_FAST_REQUIRE_UNARY(val) ((void)0) 1605 | #define DOCTEST_FAST_WARN_UNARY_FALSE(val) ((void)0) 1606 | #define DOCTEST_FAST_CHECK_UNARY_FALSE(val) ((void)0) 1607 | #define DOCTEST_FAST_REQUIRE_UNARY_FALSE(val) ((void)0) 1608 | 1609 | #endif // DOCTEST_CONFIG_DISABLE 1610 | 1611 | // BDD style macros 1612 | // clang-format off 1613 | #define DOCTEST_SCENARIO(name) TEST_CASE(" Scenario: " name) 1614 | #define DOCTEST_GIVEN(name) SUBCASE(" Given: " name) 1615 | #define DOCTEST_WHEN(name) SUBCASE(" When: " name) 1616 | #define DOCTEST_AND_WHEN(name) SUBCASE("And when: " name) 1617 | #define DOCTEST_THEN(name) SUBCASE(" Then: " name) 1618 | #define DOCTEST_AND_THEN(name) SUBCASE(" And: " name) 1619 | // clang-format on 1620 | 1621 | // == SHORT VERSIONS OF THE MACROS 1622 | #if !defined(DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES) 1623 | 1624 | #define TEST_CASE DOCTEST_TEST_CASE 1625 | #define TEST_CASE_FIXTURE DOCTEST_TEST_CASE_FIXTURE 1626 | #define SUBCASE DOCTEST_SUBCASE 1627 | #define TEST_SUITE DOCTEST_TEST_SUITE 1628 | #define TEST_SUITE_END DOCTEST_TEST_SUITE_END 1629 | #define WARN DOCTEST_WARN 1630 | #define WARN_FALSE DOCTEST_WARN_FALSE 1631 | #define WARN_THROWS DOCTEST_WARN_THROWS 1632 | #define WARN_THROWS_AS DOCTEST_WARN_THROWS_AS 1633 | #define WARN_NOTHROW DOCTEST_WARN_NOTHROW 1634 | #define CHECK DOCTEST_CHECK 1635 | #define CHECK_FALSE DOCTEST_CHECK_FALSE 1636 | #define CHECK_THROWS DOCTEST_CHECK_THROWS 1637 | #define CHECK_THROWS_AS DOCTEST_CHECK_THROWS_AS 1638 | #define CHECK_NOTHROW DOCTEST_CHECK_NOTHROW 1639 | #define REQUIRE DOCTEST_REQUIRE 1640 | #define REQUIRE_FALSE DOCTEST_REQUIRE_FALSE 1641 | #define REQUIRE_THROWS DOCTEST_REQUIRE_THROWS 1642 | #define REQUIRE_THROWS_AS DOCTEST_REQUIRE_THROWS_AS 1643 | #define REQUIRE_NOTHROW DOCTEST_REQUIRE_NOTHROW 1644 | 1645 | #define SCENARIO DOCTEST_SCENARIO 1646 | #define GIVEN DOCTEST_GIVEN 1647 | #define WHEN DOCTEST_WHEN 1648 | #define AND_WHEN DOCTEST_AND_WHEN 1649 | #define THEN DOCTEST_THEN 1650 | #define AND_THEN DOCTEST_AND_THEN 1651 | 1652 | #define WARN_EQ DOCTEST_WARN_EQ 1653 | #define CHECK_EQ DOCTEST_CHECK_EQ 1654 | #define REQUIRE_EQ DOCTEST_REQUIRE_EQ 1655 | #define WARN_NE DOCTEST_WARN_NE 1656 | #define CHECK_NE DOCTEST_CHECK_NE 1657 | #define REQUIRE_NE DOCTEST_REQUIRE_NE 1658 | #define WARN_GT DOCTEST_WARN_GT 1659 | #define CHECK_GT DOCTEST_CHECK_GT 1660 | #define REQUIRE_GT DOCTEST_REQUIRE_GT 1661 | #define WARN_LT DOCTEST_WARN_LT 1662 | #define CHECK_LT DOCTEST_CHECK_LT 1663 | #define REQUIRE_LT DOCTEST_REQUIRE_LT 1664 | #define WARN_GE DOCTEST_WARN_GE 1665 | #define CHECK_GE DOCTEST_CHECK_GE 1666 | #define REQUIRE_GE DOCTEST_REQUIRE_GE 1667 | #define WARN_LE DOCTEST_WARN_LE 1668 | #define CHECK_LE DOCTEST_CHECK_LE 1669 | #define REQUIRE_LE DOCTEST_REQUIRE_LE 1670 | #define WARN_UNARY DOCTEST_WARN_UNARY 1671 | #define CHECK_UNARY DOCTEST_CHECK_UNARY 1672 | #define REQUIRE_UNARY DOCTEST_REQUIRE_UNARY 1673 | #define WARN_UNARY_FALSE DOCTEST_WARN_UNARY_FALSE 1674 | #define CHECK_UNARY_FALSE DOCTEST_CHECK_UNARY_FALSE 1675 | #define REQUIRE_UNARY_FALSE DOCTEST_REQUIRE_UNARY_FALSE 1676 | 1677 | #define FAST_WARN_EQ DOCTEST_FAST_WARN_EQ 1678 | #define FAST_CHECK_EQ DOCTEST_FAST_CHECK_EQ 1679 | #define FAST_REQUIRE_EQ DOCTEST_FAST_REQUIRE_EQ 1680 | #define FAST_WARN_NE DOCTEST_FAST_WARN_NE 1681 | #define FAST_CHECK_NE DOCTEST_FAST_CHECK_NE 1682 | #define FAST_REQUIRE_NE DOCTEST_FAST_REQUIRE_NE 1683 | #define FAST_WARN_GT DOCTEST_FAST_WARN_GT 1684 | #define FAST_CHECK_GT DOCTEST_FAST_CHECK_GT 1685 | #define FAST_REQUIRE_GT DOCTEST_FAST_REQUIRE_GT 1686 | #define FAST_WARN_LT DOCTEST_FAST_WARN_LT 1687 | #define FAST_CHECK_LT DOCTEST_FAST_CHECK_LT 1688 | #define FAST_REQUIRE_LT DOCTEST_FAST_REQUIRE_LT 1689 | #define FAST_WARN_GE DOCTEST_FAST_WARN_GE 1690 | #define FAST_CHECK_GE DOCTEST_FAST_CHECK_GE 1691 | #define FAST_REQUIRE_GE DOCTEST_FAST_REQUIRE_GE 1692 | #define FAST_WARN_LE DOCTEST_FAST_WARN_LE 1693 | #define FAST_CHECK_LE DOCTEST_FAST_CHECK_LE 1694 | #define FAST_REQUIRE_LE DOCTEST_FAST_REQUIRE_LE 1695 | #define FAST_WARN_UNARY DOCTEST_FAST_WARN_UNARY 1696 | #define FAST_CHECK_UNARY DOCTEST_FAST_CHECK_UNARY 1697 | #define FAST_REQUIRE_UNARY DOCTEST_FAST_REQUIRE_UNARY 1698 | #define FAST_WARN_UNARY_FALSE DOCTEST_FAST_WARN_UNARY_FALSE 1699 | #define FAST_CHECK_UNARY_FALSE DOCTEST_FAST_CHECK_UNARY_FALSE 1700 | #define FAST_REQUIRE_UNARY_FALSE DOCTEST_FAST_REQUIRE_UNARY_FALSE 1701 | 1702 | #endif // DOCTEST_CONFIG_NO_SHORT_MACRO_NAMES 1703 | 1704 | // this is here to clear the 'current test suite' for the current translation unit - at the top 1705 | DOCTEST_TEST_SUITE_END(); 1706 | 1707 | #endif // DOCTEST_LIBRARY_INCLUDED 1708 | 1709 | #if defined(__clang__) 1710 | #pragma clang diagnostic pop 1711 | #endif // __clang__ 1712 | 1713 | #if defined(__GNUC__) && !defined(__clang__) 1714 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 1715 | #pragma GCC diagnostic pop 1716 | #endif // > gcc 4.6 1717 | #endif // __GNUC__ 1718 | 1719 | #ifdef _MSC_VER 1720 | #pragma warning(pop) 1721 | #endif // _MSC_VER 1722 | 1723 | #ifndef DOCTEST_SINGLE_HEADER 1724 | #define DOCTEST_SINGLE_HEADER 1725 | #endif // DOCTEST_SINGLE_HEADER 1726 | 1727 | #if defined(__clang__) 1728 | #pragma clang diagnostic push 1729 | #pragma clang diagnostic ignored "-Wunknown-pragmas" 1730 | #pragma clang diagnostic ignored "-Wpadded" 1731 | #pragma clang diagnostic ignored "-Wglobal-constructors" 1732 | #pragma clang diagnostic ignored "-Wexit-time-destructors" 1733 | #pragma clang diagnostic ignored "-Wmissing-prototypes" 1734 | #pragma clang diagnostic ignored "-Wsign-conversion" 1735 | #pragma clang diagnostic ignored "-Wshorten-64-to-32" 1736 | #pragma clang diagnostic ignored "-Wmissing-variable-declarations" 1737 | #pragma clang diagnostic ignored "-Wswitch" 1738 | #pragma clang diagnostic ignored "-Wswitch-enum" 1739 | #pragma clang diagnostic ignored "-Wcovered-switch-default" 1740 | #pragma clang diagnostic ignored "-Wmissing-noreturn" 1741 | #pragma clang diagnostic ignored "-Wunused-local-typedef" 1742 | #endif // __clang__ 1743 | 1744 | #if defined(__GNUC__) && !defined(__clang__) 1745 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 1746 | #pragma GCC diagnostic push 1747 | #endif // > gcc 4.6 1748 | #pragma GCC diagnostic ignored "-Wunknown-pragmas" 1749 | #pragma GCC diagnostic ignored "-Wconversion" 1750 | #pragma GCC diagnostic ignored "-Weffc++" 1751 | #pragma GCC diagnostic ignored "-Wsign-conversion" 1752 | #pragma GCC diagnostic ignored "-Wstrict-overflow" 1753 | #pragma GCC diagnostic ignored "-Wmissing-declarations" 1754 | #pragma GCC diagnostic ignored "-Winline" 1755 | #pragma GCC diagnostic ignored "-Wswitch" 1756 | #pragma GCC diagnostic ignored "-Wswitch-enum" 1757 | #pragma GCC diagnostic ignored "-Wswitch-default" 1758 | #pragma GCC diagnostic ignored "-Wunsafe-loop-optimizations" 1759 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 1760 | #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" 1761 | #endif // > gcc 4.6 1762 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 7) 1763 | #pragma GCC diagnostic ignored "-Wunused-local-typedefs" 1764 | #endif // > gcc 4.7 1765 | #if __GNUC__ > 5 || (__GNUC__ == 5 && __GNUC_MINOR__ > 3) 1766 | #pragma GCC diagnostic ignored "-Wuseless-cast" 1767 | #endif // > gcc 5.3 1768 | #endif // __GNUC__ 1769 | 1770 | #ifdef _MSC_VER 1771 | #pragma warning(push) 1772 | #pragma warning(disable : 4996) // The compiler encountered a deprecated declaration 1773 | #pragma warning(disable : 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data 1774 | #pragma warning(disable : 4706) // assignment within conditional expression 1775 | #pragma warning(disable : 4512) // 'class' : assignment operator could not be generated 1776 | #pragma warning(disable : 4127) // conditional expression is constant 1777 | #pragma warning(disable : 4530) // C++ exception handler used, but unwind semantics are not enabled 1778 | #pragma warning(disable : 4577) // 'noexcept' used with no exception handling mode specified 1779 | #endif // _MSC_VER 1780 | 1781 | #if defined(DOCTEST_CONFIG_IMPLEMENT) || defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) || \ 1782 | !defined(DOCTEST_SINGLE_HEADER) 1783 | #ifndef DOCTEST_LIBRARY_IMPLEMENTATION 1784 | #define DOCTEST_LIBRARY_IMPLEMENTATION 1785 | 1786 | #ifndef DOCTEST_SINGLE_HEADER 1787 | #include "doctest_fwd.h" 1788 | #endif // DOCTEST_SINGLE_HEADER 1789 | 1790 | #if defined(__clang__) && defined(DOCTEST_NO_CPP11_COMPAT) 1791 | #pragma clang diagnostic ignored "-Wc++98-compat" 1792 | #pragma clang diagnostic ignored "-Wc++98-compat-pedantic" 1793 | #endif // __clang__ && DOCTEST_NO_CPP11_COMPAT 1794 | 1795 | // snprintf() not in the C++98 standard 1796 | #ifdef _MSC_VER 1797 | #define DOCTEST_SNPRINTF _snprintf 1798 | #else 1799 | #define DOCTEST_SNPRINTF snprintf 1800 | #endif 1801 | 1802 | #define DOCTEST_LOG_START() \ 1803 | do { \ 1804 | if(!DOCTEST_GCS().hasLoggedCurrentTestStart) { \ 1805 | doctest::detail::logTestStart(DOCTEST_GCS().currentTest->m_name, \ 1806 | DOCTEST_GCS().currentTest->m_file, \ 1807 | DOCTEST_GCS().currentTest->m_line); \ 1808 | DOCTEST_GCS().hasLoggedCurrentTestStart = true; \ 1809 | } \ 1810 | } while(doctest::detail::always_false()) 1811 | 1812 | // required includes - will go only in one translation unit! 1813 | #include 1814 | #include 1815 | // borland (Embarcadero) compiler requires math.h and not cmath - https://github.com/onqtam/doctest/pull/37 1816 | #ifdef __BORLANDC__ 1817 | #include 1818 | #endif // __BORLANDC__ 1819 | #include 1820 | #include 1821 | #include 1822 | #include 1823 | #include 1824 | #include 1825 | #include 1826 | #include 1827 | #include 1828 | #include 1829 | #include 1830 | 1831 | namespace doctest 1832 | { 1833 | namespace detail 1834 | { 1835 | // not using std::strlen() because of valgrind errors when optimizations are turned on 1836 | // 'Invalid read of size 4' when the test suite len (with '\0') is not a multiple of 4 1837 | // for details see http://stackoverflow.com/questions/35671155 1838 | size_t my_strlen(const char* in) { 1839 | const char* temp = in; 1840 | while(temp && *temp) 1841 | ++temp; 1842 | return temp - in; 1843 | } 1844 | 1845 | template 1846 | T my_max(const T& lhs, const T& rhs) { 1847 | return lhs > rhs ? lhs : rhs; 1848 | } 1849 | 1850 | // case insensitive strcmp 1851 | int stricmp(char const* a, char const* b) { 1852 | for(;; a++, b++) { 1853 | int d = tolower(*a) - tolower(*b); 1854 | if(d != 0 || !*a) 1855 | return d; 1856 | } 1857 | } 1858 | 1859 | template 1860 | String fpToString(T value, int precision) { 1861 | std::ostringstream oss; 1862 | oss << std::setprecision(precision) << std::fixed << value; 1863 | std::string d = oss.str(); 1864 | size_t i = d.find_last_not_of('0'); 1865 | if(i != std::string::npos && i != d.size() - 1) { 1866 | if(d[i] == '.') 1867 | i++; 1868 | d = d.substr(0, i + 1); 1869 | } 1870 | return d.c_str(); 1871 | } 1872 | 1873 | struct Endianness 1874 | { 1875 | enum Arch 1876 | { 1877 | Big, 1878 | Little 1879 | }; 1880 | 1881 | static Arch which() { 1882 | union _ 1883 | { 1884 | int asInt; 1885 | char asChar[sizeof(int)]; 1886 | } u; 1887 | 1888 | u.asInt = 1; 1889 | return (u.asChar[sizeof(int) - 1] == 1) ? Big : Little; 1890 | } 1891 | }; 1892 | 1893 | String rawMemoryToString(const void* object, unsigned size) { 1894 | // Reverse order for little endian architectures 1895 | int i = 0, end = static_cast(size), inc = 1; 1896 | if(Endianness::which() == Endianness::Little) { 1897 | i = end - 1; 1898 | end = inc = -1; 1899 | } 1900 | 1901 | unsigned char const* bytes = static_cast(object); 1902 | std::ostringstream os; 1903 | os << "0x" << std::setfill('0') << std::hex; 1904 | for(; i != end; i += inc) 1905 | os << std::setw(2) << static_cast(bytes[i]); 1906 | return os.str().c_str(); 1907 | } 1908 | 1909 | std::ostream* createStream() { return new std::ostringstream(); } 1910 | String getStreamResult(std::ostream* in) { 1911 | return static_cast(in)->str().c_str(); 1912 | } 1913 | void freeStream(std::ostream* in) { delete in; } 1914 | 1915 | #ifndef DOCTEST_CONFIG_DISABLE 1916 | 1917 | // this holds both parameters for the command line and runtime data for tests 1918 | struct ContextState : TestAccessibleContextState 1919 | { 1920 | // == parameters from the command line 1921 | 1922 | std::vector > filters; 1923 | 1924 | String order_by; // how tests should be ordered 1925 | unsigned rand_seed; // the seed for rand ordering 1926 | 1927 | unsigned first; // the first (matching) test to be executed 1928 | unsigned last; // the last (matching) test to be executed 1929 | 1930 | int abort_after; // stop tests after this many failed assertions 1931 | bool case_sensitive; // if filtering should be case sensitive 1932 | bool exit; // if the program should be exited after the tests are ran/whatever 1933 | bool no_exitcode; // if the framework should return 0 as the exitcode 1934 | bool no_run; // to not run the tests at all (can be done with an "*" exclude) 1935 | bool no_version; // to not print the version of the framework 1936 | bool no_colors; // if output to the console should be colorized 1937 | bool force_colors; // forces the use of colors even when a tty cannot be detected 1938 | bool no_path_in_filenames; // if the path to files should be removed from the output 1939 | 1940 | bool help; // to print the help 1941 | bool version; // to print the version 1942 | bool count; // if only the count of matching tests is to be retreived 1943 | bool list_test_cases; // to list all tests matching the filters 1944 | bool list_test_suites; // to list all suites matching the filters 1945 | 1946 | // == data for the tests being ran 1947 | 1948 | int numAssertions; 1949 | int numFailedAssertions; 1950 | int numFailedAssertionsForCurrentTestcase; 1951 | 1952 | // stuff for subcases 1953 | std::set subcasesPassed; 1954 | std::set subcasesEnteredLevels; 1955 | std::vector subcasesStack; 1956 | int subcasesCurrentLevel; 1957 | bool subcasesHasSkipped; 1958 | 1959 | void resetRunData() { 1960 | numAssertions = 0; 1961 | numFailedAssertions = 0; 1962 | } 1963 | 1964 | ContextState() 1965 | : filters(6) // 6 different filters total 1966 | { 1967 | resetRunData(); 1968 | } 1969 | }; 1970 | 1971 | ContextState*& getContextState(); 1972 | #endif // DOCTEST_CONFIG_DISABLE 1973 | } // namespace detail 1974 | 1975 | String::String(const char* in) 1976 | : m_str(static_cast(malloc(detail::my_strlen(in) + 1))) { 1977 | if(in) 1978 | strcpy(m_str, in); 1979 | else 1980 | m_str[0] = '\0'; 1981 | } 1982 | 1983 | String::String(const String& other) 1984 | : m_str(0) { 1985 | copy(other); 1986 | } 1987 | 1988 | void String::copy(const String& other) { 1989 | if(m_str) 1990 | free(m_str); 1991 | m_str = static_cast(malloc(detail::my_strlen(other.m_str) + 1)); 1992 | strcpy(m_str, other.m_str); 1993 | } 1994 | 1995 | String::~String() { free(m_str); } 1996 | 1997 | String& String::operator=(const String& other) { 1998 | if(this != &other) 1999 | copy(other); 2000 | return *this; 2001 | } 2002 | 2003 | String String::operator+(const String& other) const { return String(m_str) += other; } 2004 | 2005 | String& String::operator+=(const String& other) { 2006 | using namespace detail; 2007 | if(other.m_str != 0) { 2008 | char* newStr = static_cast(malloc(my_strlen(m_str) + my_strlen(other.m_str) + 1)); 2009 | strcpy(newStr, m_str); 2010 | strcpy(newStr + my_strlen(m_str), other.m_str); 2011 | free(m_str); 2012 | m_str = newStr; 2013 | } 2014 | return *this; 2015 | } 2016 | 2017 | unsigned String::size() const { return m_str ? detail::my_strlen(m_str) : 0; } 2018 | unsigned String::length() const { return size(); } 2019 | 2020 | int String::compare(const char* other, bool no_case) const { 2021 | if(no_case) 2022 | return detail::stricmp(m_str, other); 2023 | return strcmp(m_str, other); 2024 | } 2025 | 2026 | int String::compare(const String& other, bool no_case) const { 2027 | if(no_case) 2028 | return detail::stricmp(m_str, other.m_str); 2029 | return strcmp(m_str, other.m_str); 2030 | } 2031 | 2032 | std::ostream& operator<<(std::ostream& stream, const String& in) { 2033 | stream << in.c_str(); 2034 | return stream; 2035 | } 2036 | 2037 | Approx::Approx(double value) 2038 | : m_epsilon(static_cast(std::numeric_limits::epsilon()) * 100) 2039 | , m_scale(1.0) 2040 | , m_value(value) {} 2041 | 2042 | bool operator==(double lhs, Approx const& rhs) { 2043 | // Thanks to Richard Harris for his help refining this formula 2044 | return fabs(lhs - rhs.m_value) < 2045 | rhs.m_epsilon * (rhs.m_scale + detail::my_max(fabs(lhs), fabs(rhs.m_value))); 2046 | } 2047 | 2048 | String Approx::toString() const { return String("Approx( ") + doctest::toString(m_value) + " )"; } 2049 | 2050 | #ifdef DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 2051 | String toString(char* in) { return toString(static_cast(in)); } 2052 | String toString(const char* in) { return String("\"") + (in ? in : "{null string}") + "\""; } 2053 | #endif // DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING 2054 | String toString(bool in) { return in ? "true" : "false"; } 2055 | String toString(float in) { return detail::fpToString(in, 5) + "f"; } 2056 | String toString(double in) { return detail::fpToString(in, 10); } 2057 | String toString(double long in) { return detail::fpToString(in, 15); } 2058 | 2059 | String toString(char in) { 2060 | char buf[64]; 2061 | sprintf(buf, "%d", in); 2062 | return buf; 2063 | } 2064 | 2065 | String toString(char unsigned in) { 2066 | char buf[64]; 2067 | sprintf(buf, "%ud", in); 2068 | return buf; 2069 | } 2070 | 2071 | String toString(int short in) { 2072 | char buf[64]; 2073 | sprintf(buf, "%d", in); 2074 | return buf; 2075 | } 2076 | 2077 | String toString(int short unsigned in) { 2078 | char buf[64]; 2079 | sprintf(buf, "%u", in); 2080 | return buf; 2081 | } 2082 | 2083 | String toString(int in) { 2084 | char buf[64]; 2085 | sprintf(buf, "%d", in); 2086 | return buf; 2087 | } 2088 | 2089 | String toString(int unsigned in) { 2090 | char buf[64]; 2091 | sprintf(buf, "%u", in); 2092 | return buf; 2093 | } 2094 | 2095 | String toString(int long in) { 2096 | char buf[64]; 2097 | sprintf(buf, "%ld", in); 2098 | return buf; 2099 | } 2100 | 2101 | String toString(int long unsigned in) { 2102 | char buf[64]; 2103 | sprintf(buf, "%lu", in); 2104 | return buf; 2105 | } 2106 | 2107 | #ifdef DOCTEST_CONFIG_WITH_LONG_LONG 2108 | String toString(int long long in) { 2109 | char buf[64]; 2110 | sprintf(buf, "%lld", in); 2111 | return buf; 2112 | } 2113 | String toString(int long long unsigned in) { 2114 | char buf[64]; 2115 | sprintf(buf, "%llu", in); 2116 | return buf; 2117 | } 2118 | #endif // DOCTEST_CONFIG_WITH_LONG_LONG 2119 | 2120 | #ifdef DOCTEST_CONFIG_WITH_NULLPTR 2121 | String toString(std::nullptr_t) { return "nullptr"; } 2122 | #endif // DOCTEST_CONFIG_WITH_NULLPTR 2123 | 2124 | } // namespace doctest 2125 | 2126 | #if defined(DOCTEST_CONFIG_DISABLE) 2127 | namespace doctest 2128 | { 2129 | Context::Context(int, const char* const*) {} 2130 | Context::~Context() {} 2131 | void Context::applyCommandLine(int, const char* const*) {} 2132 | void Context::addFilter(const char*, const char*) {} 2133 | void Context::clearFilters() {} 2134 | void Context::setOption(const char*, int) {} 2135 | void Context::setOption(const char*, const char*) {} 2136 | bool Context::shouldExit() { return false; } 2137 | int Context::run() { return 0; } 2138 | } // namespace doctest 2139 | #else // DOCTEST_CONFIG_DISABLE 2140 | 2141 | #if !defined(DOCTEST_CONFIG_COLORS_NONE) 2142 | #if !defined(DOCTEST_CONFIG_COLORS_WINDOWS) && !defined(DOCTEST_CONFIG_COLORS_ANSI) 2143 | #ifdef DOCTEST_PLATFORM_WINDOWS 2144 | #define DOCTEST_CONFIG_COLORS_WINDOWS 2145 | #else // linux 2146 | #define DOCTEST_CONFIG_COLORS_ANSI 2147 | #endif // platform 2148 | #endif // DOCTEST_CONFIG_COLORS_WINDOWS && DOCTEST_CONFIG_COLORS_ANSI 2149 | #endif // DOCTEST_CONFIG_COLORS_NONE 2150 | 2151 | #define DOCTEST_PRINTF_COLORED(buffer, color) \ 2152 | do { \ 2153 | if(buffer[0] != 0) { \ 2154 | doctest::detail::Color col(color); \ 2155 | printf("%s", buffer); \ 2156 | } \ 2157 | } while(doctest::detail::always_false()) 2158 | 2159 | // the buffer size used for snprintf() calls 2160 | #if !defined(DOCTEST_SNPRINTF_BUFFER_LENGTH) 2161 | #define DOCTEST_SNPRINTF_BUFFER_LENGTH 1024 2162 | #endif // DOCTEST_SNPRINTF_BUFFER_LENGTH 2163 | 2164 | #if defined(_MSC_VER) || defined(__MINGW32__) 2165 | #if defined(_MSC_VER) && _MSC_VER >= 1700 2166 | #define DOCTEST_WINDOWS_SAL_IN_OPT _In_opt_ 2167 | #else // _MSC_VER 2168 | #define DOCTEST_WINDOWS_SAL_IN_OPT 2169 | #endif // _MSC_VER 2170 | extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( 2171 | DOCTEST_WINDOWS_SAL_IN_OPT const char*); 2172 | extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent(); 2173 | #endif // _MSC_VER || __MINGW32__ 2174 | 2175 | #ifdef DOCTEST_CONFIG_COLORS_ANSI 2176 | #include 2177 | #endif // DOCTEST_CONFIG_COLORS_ANSI 2178 | 2179 | #ifdef DOCTEST_CONFIG_COLORS_WINDOWS 2180 | 2181 | // defines for a leaner windows.h 2182 | #ifndef WIN32_MEAN_AND_LEAN 2183 | #define WIN32_MEAN_AND_LEAN 2184 | #endif // WIN32_MEAN_AND_LEAN 2185 | #ifndef VC_EXTRA_LEAN 2186 | #define VC_EXTRA_LEAN 2187 | #endif // VC_EXTRA_LEAN 2188 | #ifndef NOMINMAX 2189 | #define NOMINMAX 2190 | #endif // NOMINMAX 2191 | 2192 | // not sure what AfxWin.h is for - here I do what Catch does 2193 | #ifdef __AFXDLL 2194 | #include 2195 | #else 2196 | #include 2197 | #endif 2198 | #include 2199 | 2200 | #endif // DOCTEST_CONFIG_COLORS_WINDOWS 2201 | 2202 | namespace doctest 2203 | { 2204 | namespace detail 2205 | { 2206 | bool TestData::operator<(const TestData& other) const { 2207 | if(m_line != other.m_line) 2208 | return m_line < other.m_line; 2209 | return strcmp(m_file, other.m_file) < 0; 2210 | } 2211 | 2212 | const char* getAssertString(assertType::Enum val) { 2213 | switch(val) { 2214 | // clang-format off 2215 | case assertType::DT_WARN : return "WARN"; 2216 | case assertType::DT_CHECK : return "CHECK"; 2217 | case assertType::DT_REQUIRE : return "REQUIRE"; 2218 | 2219 | case assertType::DT_WARN_FALSE : return "WARN_FALSE"; 2220 | case assertType::DT_CHECK_FALSE : return "CHECK_FALSE"; 2221 | case assertType::DT_REQUIRE_FALSE : return "REQUIRE_FALSE"; 2222 | 2223 | case assertType::DT_WARN_THROWS : return "WARN_THROWS"; 2224 | case assertType::DT_CHECK_THROWS : return "CHECK_THROWS"; 2225 | case assertType::DT_REQUIRE_THROWS : return "REQUIRE_THROWS"; 2226 | 2227 | case assertType::DT_WARN_THROWS_AS : return "WARN_THROWS_AS"; 2228 | case assertType::DT_CHECK_THROWS_AS : return "CHECK_THROWS_AS"; 2229 | case assertType::DT_REQUIRE_THROWS_AS : return "REQUIRE_THROWS_AS"; 2230 | 2231 | case assertType::DT_WARN_NOTHROW : return "WARN_NOTHROW"; 2232 | case assertType::DT_CHECK_NOTHROW : return "CHECK_NOTHROW"; 2233 | case assertType::DT_REQUIRE_NOTHROW : return "REQUIRE_NOTHROW"; 2234 | 2235 | case assertType::DT_WARN_EQ : return "WARN_EQ"; 2236 | case assertType::DT_CHECK_EQ : return "CHECK_EQ"; 2237 | case assertType::DT_REQUIRE_EQ : return "REQUIRE_EQ"; 2238 | case assertType::DT_WARN_NE : return "WARN_NE"; 2239 | case assertType::DT_CHECK_NE : return "CHECK_NE"; 2240 | case assertType::DT_REQUIRE_NE : return "REQUIRE_NE"; 2241 | case assertType::DT_WARN_GT : return "WARN_GT"; 2242 | case assertType::DT_CHECK_GT : return "CHECK_GT"; 2243 | case assertType::DT_REQUIRE_GT : return "REQUIRE_GT"; 2244 | case assertType::DT_WARN_LT : return "WARN_LT"; 2245 | case assertType::DT_CHECK_LT : return "CHECK_LT"; 2246 | case assertType::DT_REQUIRE_LT : return "REQUIRE_LT"; 2247 | case assertType::DT_WARN_GE : return "WARN_GE"; 2248 | case assertType::DT_CHECK_GE : return "CHECK_GE"; 2249 | case assertType::DT_REQUIRE_GE : return "REQUIRE_GE"; 2250 | case assertType::DT_WARN_LE : return "WARN_LE"; 2251 | case assertType::DT_CHECK_LE : return "CHECK_LE"; 2252 | case assertType::DT_REQUIRE_LE : return "REQUIRE_LE"; 2253 | 2254 | case assertType::DT_WARN_UNARY : return "WARN_UNARY"; 2255 | case assertType::DT_CHECK_UNARY : return "CHECK_UNARY"; 2256 | case assertType::DT_REQUIRE_UNARY : return "REQUIRE_UNARY"; 2257 | case assertType::DT_WARN_UNARY_FALSE : return "WARN_UNARY_FALSE"; 2258 | case assertType::DT_CHECK_UNARY_FALSE : return "CHECK_UNARY_FALSE"; 2259 | case assertType::DT_REQUIRE_UNARY_FALSE : return "REQUIRE_UNARY_FALSE"; 2260 | 2261 | case assertType::DT_FAST_WARN_EQ : return "FAST_WARN_EQ"; 2262 | case assertType::DT_FAST_CHECK_EQ : return "FAST_CHECK_EQ"; 2263 | case assertType::DT_FAST_REQUIRE_EQ : return "FAST_REQUIRE_EQ"; 2264 | case assertType::DT_FAST_WARN_NE : return "FAST_WARN_NE"; 2265 | case assertType::DT_FAST_CHECK_NE : return "FAST_CHECK_NE"; 2266 | case assertType::DT_FAST_REQUIRE_NE : return "FAST_REQUIRE_NE"; 2267 | case assertType::DT_FAST_WARN_GT : return "FAST_WARN_GT"; 2268 | case assertType::DT_FAST_CHECK_GT : return "FAST_CHECK_GT"; 2269 | case assertType::DT_FAST_REQUIRE_GT : return "FAST_REQUIRE_GT"; 2270 | case assertType::DT_FAST_WARN_LT : return "FAST_WARN_LT"; 2271 | case assertType::DT_FAST_CHECK_LT : return "FAST_CHECK_LT"; 2272 | case assertType::DT_FAST_REQUIRE_LT : return "FAST_REQUIRE_LT"; 2273 | case assertType::DT_FAST_WARN_GE : return "FAST_WARN_GE"; 2274 | case assertType::DT_FAST_CHECK_GE : return "FAST_CHECK_GE"; 2275 | case assertType::DT_FAST_REQUIRE_GE : return "FAST_REQUIRE_GE"; 2276 | case assertType::DT_FAST_WARN_LE : return "FAST_WARN_LE"; 2277 | case assertType::DT_FAST_CHECK_LE : return "FAST_CHECK_LE"; 2278 | case assertType::DT_FAST_REQUIRE_LE : return "FAST_REQUIRE_LE"; 2279 | 2280 | case assertType::DT_FAST_WARN_UNARY : return "FAST_WARN_UNARY"; 2281 | case assertType::DT_FAST_CHECK_UNARY : return "FAST_CHECK_UNARY"; 2282 | case assertType::DT_FAST_REQUIRE_UNARY : return "FAST_REQUIRE_UNARY"; 2283 | case assertType::DT_FAST_WARN_UNARY_FALSE : return "FAST_WARN_UNARY_FALSE"; 2284 | case assertType::DT_FAST_CHECK_UNARY_FALSE : return "FAST_CHECK_UNARY_FALSE"; 2285 | case assertType::DT_FAST_REQUIRE_UNARY_FALSE: return "FAST_REQUIRE_UNARY_FALSE"; 2286 | // clang-format on 2287 | } 2288 | return ""; 2289 | } 2290 | 2291 | bool checkIfShouldThrow(assertType::Enum assert_type) { 2292 | if(assert_type & assertType::is_require) 2293 | return true; 2294 | 2295 | if((assert_type & assertType::is_check) && getContextState()->abort_after > 0) { 2296 | if(getContextState()->numFailedAssertions >= getContextState()->abort_after) 2297 | return true; 2298 | } 2299 | 2300 | return false; 2301 | } 2302 | void fastAssertThrowIfFlagSet(int flags) { 2303 | if(flags & assertAction::shouldthrow) 2304 | throwException(); 2305 | } 2306 | void throwException() { 2307 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS 2308 | throw TestFailureException(); 2309 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 2310 | } 2311 | bool always_false() { return false; } 2312 | 2313 | // lowers ascii letters 2314 | char tolower(const char c) { return ((c >= 'A' && c <= 'Z') ? static_cast(c + 32) : c); } 2315 | 2316 | // matching of a string against a wildcard mask (case sensitivity configurable) taken from 2317 | // http://www.emoticode.net/c/simple-wildcard-string-compare-globbing-function.html 2318 | int wildcmp(const char* str, const char* wild, bool caseSensitive) { 2319 | const char* cp = 0; 2320 | const char* mp = 0; 2321 | 2322 | // rolled my own tolower() to not include more headers 2323 | while((*str) && (*wild != '*')) { 2324 | if((caseSensitive ? (*wild != *str) : (tolower(*wild) != tolower(*str))) && 2325 | (*wild != '?')) { 2326 | return 0; 2327 | } 2328 | wild++; 2329 | str++; 2330 | } 2331 | 2332 | while(*str) { 2333 | if(*wild == '*') { 2334 | if(!*++wild) { 2335 | return 1; 2336 | } 2337 | mp = wild; 2338 | cp = str + 1; 2339 | } else if((caseSensitive ? (*wild == *str) : (tolower(*wild) == tolower(*str))) || 2340 | (*wild == '?')) { 2341 | wild++; 2342 | str++; 2343 | } else { 2344 | wild = mp; 2345 | str = cp++; 2346 | } 2347 | } 2348 | 2349 | while(*wild == '*') { 2350 | wild++; 2351 | } 2352 | return !*wild; 2353 | } 2354 | 2355 | //// C string hash function (djb2) - taken from http://www.cse.yorku.ca/~oz/hash.html 2356 | //unsigned hashStr(unsigned const char* str) { 2357 | // unsigned long hash = 5381; 2358 | // char c; 2359 | // while((c = *str++)) 2360 | // hash = ((hash << 5) + hash) + c; // hash * 33 + c 2361 | // return hash; 2362 | //} 2363 | 2364 | // checks if the name matches any of the filters (and can be configured what to do when empty) 2365 | int matchesAny(const char* name, std::vector filters, int matchEmpty, 2366 | bool caseSensitive) { 2367 | if(filters.size() == 0 && matchEmpty) 2368 | return 1; 2369 | for(unsigned i = 0; i < filters.size(); ++i) 2370 | if(wildcmp(name, filters[i].c_str(), caseSensitive)) 2371 | return 1; 2372 | return 0; 2373 | } 2374 | 2375 | // the current ContextState with which tests are being executed 2376 | ContextState*& getContextState() { 2377 | static ContextState* data = 0; 2378 | return data; 2379 | } 2380 | 2381 | TestAccessibleContextState* getTestsContextState() { return getContextState(); } 2382 | 2383 | bool SubcaseSignature::operator<(const SubcaseSignature& other) const { 2384 | if(m_line != other.m_line) 2385 | return m_line < other.m_line; 2386 | if(strcmp(m_file, other.m_file) != 0) 2387 | return strcmp(m_file, other.m_file) < 0; 2388 | return strcmp(m_name, other.m_name) < 0; 2389 | } 2390 | 2391 | Subcase::Subcase(const char* name, const char* file, int line) 2392 | : m_signature(name, file, line) 2393 | , m_entered(false) { 2394 | ContextState* s = getContextState(); 2395 | 2396 | // if we have already completed it 2397 | if(s->subcasesPassed.count(m_signature) != 0) 2398 | return; 2399 | 2400 | // if a Subcase on the same level has already been entered 2401 | if(s->subcasesEnteredLevels.count(s->subcasesCurrentLevel) != 0) { 2402 | s->subcasesHasSkipped = true; 2403 | return; 2404 | } 2405 | 2406 | s->subcasesStack.push_back(*this); 2407 | if(s->hasLoggedCurrentTestStart) 2408 | logTestEnd(); 2409 | s->hasLoggedCurrentTestStart = false; 2410 | 2411 | s->subcasesEnteredLevels.insert(s->subcasesCurrentLevel++); 2412 | m_entered = true; 2413 | } 2414 | 2415 | Subcase::Subcase(const Subcase& other) 2416 | : m_signature(other.m_signature.m_name, other.m_signature.m_file, 2417 | other.m_signature.m_line) 2418 | , m_entered(other.m_entered) {} 2419 | 2420 | Subcase::~Subcase() { 2421 | if(m_entered) { 2422 | ContextState* s = getContextState(); 2423 | 2424 | s->subcasesCurrentLevel--; 2425 | // only mark the subcase as passed if no subcases have been skipped 2426 | if(s->subcasesHasSkipped == false) 2427 | s->subcasesPassed.insert(m_signature); 2428 | 2429 | if(s->subcasesStack.size() > 0) 2430 | s->subcasesStack.pop_back(); 2431 | if(s->hasLoggedCurrentTestStart) 2432 | logTestEnd(); 2433 | s->hasLoggedCurrentTestStart = false; 2434 | } 2435 | } 2436 | 2437 | // for sorting tests by file/line 2438 | int fileOrderComparator(const void* a, const void* b) { 2439 | const TestData* lhs = *static_cast(a); 2440 | const TestData* rhs = *static_cast(b); 2441 | #ifdef _MSC_VER 2442 | // this is needed because MSVC gives different case for drive letters 2443 | // for __FILE__ when evaluated in a header and a source file 2444 | int res = stricmp(lhs->m_file, rhs->m_file); 2445 | #else // _MSC_VER 2446 | int res = strcmp(lhs->m_file, rhs->m_file); 2447 | #endif // _MSC_VER 2448 | if(res != 0) 2449 | return res; 2450 | return static_cast(lhs->m_line - rhs->m_line); 2451 | } 2452 | 2453 | // for sorting tests by suite/file/line 2454 | int suiteOrderComparator(const void* a, const void* b) { 2455 | const TestData* lhs = *static_cast(a); 2456 | const TestData* rhs = *static_cast(b); 2457 | 2458 | int res = strcmp(lhs->m_suite, rhs->m_suite); 2459 | if(res != 0) 2460 | return res; 2461 | return fileOrderComparator(a, b); 2462 | } 2463 | 2464 | // for sorting tests by name/suite/file/line 2465 | int nameOrderComparator(const void* a, const void* b) { 2466 | const TestData* lhs = *static_cast(a); 2467 | const TestData* rhs = *static_cast(b); 2468 | 2469 | int res = strcmp(lhs->m_name, rhs->m_name); 2470 | if(res != 0) 2471 | return res; 2472 | return suiteOrderComparator(a, b); 2473 | } 2474 | 2475 | // holds the current test suite 2476 | const char*& getCurrentTestSuite() { 2477 | static const char* data = 0; 2478 | return data; 2479 | } 2480 | 2481 | // sets the current test suite 2482 | int setTestSuiteName(const char* name) { 2483 | getCurrentTestSuite() = name; 2484 | return 0; 2485 | } 2486 | 2487 | // all the registered tests 2488 | std::set& getRegisteredTests() { 2489 | static std::set data; 2490 | return data; 2491 | } 2492 | 2493 | // used by the macros for registering tests 2494 | int regTest(funcType f, unsigned line, const char* file, const char* name) { 2495 | getRegisteredTests().insert(TestData(getCurrentTestSuite(), name, f, file, line)); 2496 | return 0; 2497 | } 2498 | 2499 | struct Color 2500 | { 2501 | enum Code 2502 | { 2503 | None = 0, 2504 | White, 2505 | Red, 2506 | Green, 2507 | Blue, 2508 | Cyan, 2509 | Yellow, 2510 | Grey, 2511 | 2512 | Bright = 0x10, 2513 | 2514 | BrightRed = Bright | Red, 2515 | BrightGreen = Bright | Green, 2516 | LightGrey = Bright | Grey, 2517 | BrightWhite = Bright | White 2518 | }; 2519 | Color(Code code) { use(code); } 2520 | ~Color() { use(None); } 2521 | 2522 | void use(Code code); 2523 | 2524 | private: 2525 | Color(Color const& other); 2526 | }; 2527 | 2528 | void Color::use(Code 2529 | #ifndef DOCTEST_CONFIG_COLORS_NONE 2530 | code 2531 | #endif // DOCTEST_CONFIG_COLORS_NONE 2532 | ) { 2533 | ContextState* p = getContextState(); 2534 | if(p->no_colors) 2535 | return; 2536 | #ifdef DOCTEST_CONFIG_COLORS_ANSI 2537 | if(isatty(STDOUT_FILENO) == false && p->force_colors == false) 2538 | return; 2539 | 2540 | const char* col = ""; 2541 | // clang-format off 2542 | switch(code) { 2543 | case Color::Red: col = "[0;31m"; break; 2544 | case Color::Green: col = "[0;32m"; break; 2545 | case Color::Blue: col = "[0;34m"; break; 2546 | case Color::Cyan: col = "[0;36m"; break; 2547 | case Color::Yellow: col = "[0;33m"; break; 2548 | case Color::Grey: col = "[1;30m"; break; 2549 | case Color::LightGrey: col = "[0;37m"; break; 2550 | case Color::BrightRed: col = "[1;31m"; break; 2551 | case Color::BrightGreen: col = "[1;32m"; break; 2552 | case Color::BrightWhite: col = "[1;37m"; break; 2553 | case Color::Bright: // invalid 2554 | case Color::None: 2555 | case Color::White: 2556 | default: col = "[0m"; 2557 | } 2558 | // clang-format on 2559 | printf("\033%s", col); 2560 | #endif // DOCTEST_CONFIG_COLORS_ANSI 2561 | 2562 | #ifdef DOCTEST_CONFIG_COLORS_WINDOWS 2563 | if(isatty(fileno(stdout)) == false && p->force_colors == false) 2564 | return; 2565 | 2566 | static HANDLE stdoutHandle(GetStdHandle(STD_OUTPUT_HANDLE)); 2567 | static WORD originalForegroundAttributes; 2568 | static WORD originalBackgroundAttributes; 2569 | static bool attrsInitted = false; 2570 | if(!attrsInitted) { 2571 | attrsInitted = true; 2572 | CONSOLE_SCREEN_BUFFER_INFO csbiInfo; 2573 | GetConsoleScreenBufferInfo(stdoutHandle, &csbiInfo); 2574 | originalForegroundAttributes = 2575 | csbiInfo.wAttributes & 2576 | ~(BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY); 2577 | originalBackgroundAttributes = 2578 | csbiInfo.wAttributes & 2579 | ~(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY); 2580 | } 2581 | 2582 | #define DOCTEST_SET_ATTR(x) SetConsoleTextAttribute(stdoutHandle, x | originalBackgroundAttributes) 2583 | 2584 | // clang-format off 2585 | switch (code) { 2586 | case Color::White: DOCTEST_SET_ATTR(FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; 2587 | case Color::Red: DOCTEST_SET_ATTR(FOREGROUND_RED); break; 2588 | case Color::Green: DOCTEST_SET_ATTR(FOREGROUND_GREEN); break; 2589 | case Color::Blue: DOCTEST_SET_ATTR(FOREGROUND_BLUE); break; 2590 | case Color::Cyan: DOCTEST_SET_ATTR(FOREGROUND_BLUE | FOREGROUND_GREEN); break; 2591 | case Color::Yellow: DOCTEST_SET_ATTR(FOREGROUND_RED | FOREGROUND_GREEN); break; 2592 | case Color::Grey: DOCTEST_SET_ATTR(0); break; 2593 | case Color::LightGrey: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY); break; 2594 | case Color::BrightRed: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_RED); break; 2595 | case Color::BrightGreen: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN); break; 2596 | case Color::BrightWhite: DOCTEST_SET_ATTR(FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE); break; 2597 | case Color::None: 2598 | case Color::Bright: // invalid 2599 | default: DOCTEST_SET_ATTR(originalForegroundAttributes); 2600 | } 2601 | // clang-format on 2602 | #undef DOCTEST_SET_ATTR 2603 | #endif // DOCTEST_CONFIG_COLORS_WINDOWS 2604 | } 2605 | 2606 | // this is needed because MSVC does not permit mixing 2 exception handling schemes in a function 2607 | int callTestFunc(funcType f) { 2608 | int res = EXIT_SUCCESS; 2609 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS 2610 | try { 2611 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 2612 | f(); 2613 | if(getContextState()->numFailedAssertionsForCurrentTestcase) 2614 | res = EXIT_FAILURE; 2615 | #ifndef DOCTEST_CONFIG_NO_EXCEPTIONS 2616 | } catch(const TestFailureException&) { 2617 | res = EXIT_FAILURE; 2618 | } catch(const std::exception& e) { 2619 | DOCTEST_LOG_START(); 2620 | logTestException(e.what()); 2621 | res = EXIT_FAILURE; 2622 | } catch(...) { 2623 | DOCTEST_LOG_START(); 2624 | logTestCrashed(); 2625 | res = EXIT_FAILURE; 2626 | } 2627 | #endif // DOCTEST_CONFIG_NO_EXCEPTIONS 2628 | return res; 2629 | } 2630 | 2631 | // depending on the current options this will remove the path of filenames 2632 | const char* fileForOutput(const char* file) { 2633 | if(getContextState()->no_path_in_filenames) { 2634 | const char* back = strrchr(file, '\\'); 2635 | const char* forward = strrchr(file, '/'); 2636 | if(back || forward) { 2637 | if(back > forward) 2638 | forward = back; 2639 | return forward + 1; 2640 | } 2641 | } 2642 | return file; 2643 | } 2644 | 2645 | #ifdef DOCTEST_PLATFORM_MAC 2646 | #include 2647 | #include 2648 | #include 2649 | // The following function is taken directly from the following technical note: 2650 | // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html 2651 | // Returns true if the current process is being debugged (either 2652 | // running under the debugger or has a debugger attached post facto). 2653 | bool isDebuggerActive() { 2654 | int mib[4]; 2655 | struct kinfo_proc info; 2656 | size_t size; 2657 | // Initialize the flags so that, if sysctl fails for some bizarre 2658 | // reason, we get a predictable result. 2659 | info.kp_proc.p_flag = 0; 2660 | // Initialize mib, which tells sysctl the info we want, in this case 2661 | // we're looking for information about a specific process ID. 2662 | mib[0] = CTL_KERN; 2663 | mib[1] = KERN_PROC; 2664 | mib[2] = KERN_PROC_PID; 2665 | mib[3] = getpid(); 2666 | // Call sysctl. 2667 | size = sizeof(info); 2668 | if(sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, 0, 0) != 0) { 2669 | fprintf(stderr, "\n** Call to sysctl failed - unable to determine if debugger is " 2670 | "active **\n\n"); 2671 | return false; 2672 | } 2673 | // We're being debugged if the P_TRACED flag is set. 2674 | return ((info.kp_proc.p_flag & P_TRACED) != 0); 2675 | } 2676 | #elif defined(_MSC_VER) || defined(__MINGW32__) 2677 | bool isDebuggerActive() { return ::IsDebuggerPresent() != 0; } 2678 | #else 2679 | bool isDebuggerActive() { return false; } 2680 | #endif // Platform 2681 | 2682 | #ifdef DOCTEST_PLATFORM_WINDOWS 2683 | void myOutputDebugString(const String& text) { ::OutputDebugStringA(text.c_str()); } 2684 | #else 2685 | // TODO: integration with XCode and other IDEs 2686 | void myOutputDebugString(const String&) {} 2687 | #endif // Platform 2688 | 2689 | const char* getSeparator() { 2690 | return "===============================================================================\n"; 2691 | } 2692 | 2693 | void printToDebugConsole(const String& text) { 2694 | if(isDebuggerActive()) 2695 | myOutputDebugString(text.c_str()); 2696 | } 2697 | 2698 | void addFailedAssert(assertType::Enum assert_type) { 2699 | if((assert_type & assertType::is_warn) == 0) { 2700 | getContextState()->numFailedAssertionsForCurrentTestcase++; 2701 | getContextState()->numFailedAssertions++; 2702 | } 2703 | } 2704 | 2705 | void logTestStart(const char* name, const char* file, unsigned line) { 2706 | const char* newLine = "\n"; 2707 | 2708 | char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2709 | DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)\n", fileForOutput(file), line); 2710 | 2711 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2712 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), "%s\n", name); 2713 | 2714 | DOCTEST_PRINTF_COLORED(getSeparator(), Color::Yellow); 2715 | DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); 2716 | DOCTEST_PRINTF_COLORED(msg, Color::None); 2717 | 2718 | String subcaseStuff = ""; 2719 | std::vector& subcasesStack = getContextState()->subcasesStack; 2720 | for(unsigned i = 0; i < subcasesStack.size(); ++i) { 2721 | char subcase[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2722 | DOCTEST_SNPRINTF(subcase, DOCTEST_COUNTOF(loc), " %s\n", 2723 | subcasesStack[i].m_signature.m_name); 2724 | DOCTEST_PRINTF_COLORED(subcase, Color::None); 2725 | subcaseStuff += subcase; 2726 | } 2727 | 2728 | DOCTEST_PRINTF_COLORED(newLine, Color::None); 2729 | 2730 | printToDebugConsole(String(getSeparator()) + loc + msg + subcaseStuff.c_str() + newLine); 2731 | } 2732 | 2733 | void logTestEnd() {} 2734 | 2735 | void logTestCrashed() { 2736 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2737 | 2738 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), "TEST CASE FAILED! (threw exception)\n\n"); 2739 | 2740 | DOCTEST_PRINTF_COLORED(msg, Color::Red); 2741 | 2742 | printToDebugConsole(String(msg)); 2743 | } 2744 | 2745 | void logTestException(const char* what) { 2746 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2747 | 2748 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), "TEST CASE FAILED! (threw exception: %s)\n\n", 2749 | what); 2750 | 2751 | DOCTEST_PRINTF_COLORED(msg, Color::Red); 2752 | 2753 | printToDebugConsole(String(msg)); 2754 | } 2755 | 2756 | void logAssert(bool passed, const char* decomposition, bool threw, const char* expr, 2757 | assertType::Enum assert_type, const char* file, int line) { 2758 | char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2759 | DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); 2760 | 2761 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2762 | if(passed) 2763 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); 2764 | else 2765 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED! %s\n", 2766 | (threw ? "(threw exception)" : "")); 2767 | 2768 | char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2769 | DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n", 2770 | getAssertString(assert_type), expr); 2771 | 2772 | char info2[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2773 | char info3[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2774 | info2[0] = 0; 2775 | info3[0] = 0; 2776 | if(!threw) { 2777 | DOCTEST_SNPRINTF(info2, DOCTEST_COUNTOF(info2), "with expansion:\n"); 2778 | DOCTEST_SNPRINTF(info3, DOCTEST_COUNTOF(info3), " %s( %s )\n", 2779 | getAssertString(assert_type), decomposition); 2780 | } 2781 | 2782 | DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); 2783 | DOCTEST_PRINTF_COLORED(msg, passed ? Color::BrightGreen : Color::Red); 2784 | DOCTEST_PRINTF_COLORED(info1, Color::Cyan); 2785 | DOCTEST_PRINTF_COLORED(info2, Color::None); 2786 | DOCTEST_PRINTF_COLORED(info3, Color::Cyan); 2787 | DOCTEST_PRINTF_COLORED("\n", Color::None); 2788 | 2789 | printToDebugConsole(String(loc) + msg + info1 + info2 + info3 + "\n"); 2790 | } 2791 | 2792 | void logAssertThrows(bool threw, const char* expr, assertType::Enum assert_type, 2793 | const char* file, int line) { 2794 | char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2795 | DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); 2796 | 2797 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2798 | if(threw) 2799 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); 2800 | else 2801 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED!\n"); 2802 | 2803 | char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2804 | DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n\n", 2805 | getAssertString(assert_type), expr); 2806 | 2807 | DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); 2808 | DOCTEST_PRINTF_COLORED(msg, threw ? Color::BrightGreen : Color::Red); 2809 | DOCTEST_PRINTF_COLORED(info1, Color::Cyan); 2810 | 2811 | printToDebugConsole(String(loc) + msg + info1); 2812 | } 2813 | 2814 | void logAssertThrowsAs(bool threw, bool threw_as, const char* as, const char* expr, 2815 | assertType::Enum assert_type, const char* file, int line) { 2816 | char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2817 | DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); 2818 | 2819 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2820 | if(threw_as) 2821 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); 2822 | else 2823 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED! %s\n", 2824 | (threw ? "(threw something else)" : "(didn't throw at all)")); 2825 | 2826 | char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2827 | DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s, %s )\n\n", 2828 | getAssertString(assert_type), expr, as); 2829 | 2830 | DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); 2831 | DOCTEST_PRINTF_COLORED(msg, threw_as ? Color::BrightGreen : Color::Red); 2832 | DOCTEST_PRINTF_COLORED(info1, Color::Cyan); 2833 | 2834 | printToDebugConsole(String(loc) + msg + info1); 2835 | } 2836 | 2837 | void logAssertNothrow(bool threw, const char* expr, assertType::Enum assert_type, 2838 | const char* file, int line) { 2839 | char loc[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2840 | DOCTEST_SNPRINTF(loc, DOCTEST_COUNTOF(loc), "%s(%d)", fileForOutput(file), line); 2841 | 2842 | char msg[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2843 | if(!threw) 2844 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " PASSED!\n"); 2845 | else 2846 | DOCTEST_SNPRINTF(msg, DOCTEST_COUNTOF(msg), " FAILED!\n"); 2847 | 2848 | char info1[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 2849 | DOCTEST_SNPRINTF(info1, DOCTEST_COUNTOF(info1), " %s( %s )\n\n", 2850 | getAssertString(assert_type), expr); 2851 | 2852 | DOCTEST_PRINTF_COLORED(loc, Color::LightGrey); 2853 | DOCTEST_PRINTF_COLORED(msg, !threw ? Color::BrightGreen : Color::Red); 2854 | DOCTEST_PRINTF_COLORED(info1, Color::Cyan); 2855 | 2856 | printToDebugConsole(String(loc) + msg + info1); 2857 | } 2858 | 2859 | ResultBuilder::ResultBuilder(assertType::Enum assert_type, const char* file, int line, 2860 | const char* expr, const char* exception_type) 2861 | : m_assert_type(assert_type) 2862 | , m_file(file) 2863 | , m_line(line) 2864 | , m_expr(expr) 2865 | , m_exception_type(exception_type) 2866 | , m_threw(false) 2867 | , m_threw_as(false) 2868 | , m_failed(false) {} 2869 | 2870 | bool ResultBuilder::log() { 2871 | if((m_assert_type & assertType::is_warn) == 0) 2872 | DOCTEST_GCS().numAssertionsForCurrentTestcase++; 2873 | 2874 | if(m_assert_type & assertType::is_false) { 2875 | m_result.invert(); 2876 | m_failed = m_result; 2877 | } else if(m_assert_type & assertType::is_throws) { 2878 | m_failed = !m_threw; 2879 | } else if(m_assert_type & assertType::is_throws_as) { 2880 | m_failed = !m_threw_as; 2881 | } else if(m_assert_type & assertType::is_nothrow) { 2882 | m_failed = m_threw; 2883 | } else { 2884 | m_failed = m_result; 2885 | } 2886 | 2887 | if(m_failed || DOCTEST_GCS().success) { 2888 | DOCTEST_LOG_START(); 2889 | 2890 | if(m_assert_type & assertType::is_throws) { 2891 | logAssertThrows(m_threw, m_expr, m_assert_type, m_file, m_line); 2892 | } else if(m_assert_type & assertType::is_throws_as) { 2893 | logAssertThrowsAs(m_threw, m_threw_as, m_exception_type, m_expr, m_assert_type, 2894 | m_file, m_line); 2895 | } else if(m_assert_type & assertType::is_nothrow) { 2896 | logAssertNothrow(m_threw, m_expr, m_assert_type, m_file, m_line); 2897 | } else { 2898 | logAssert(m_result.m_passed, m_result.m_decomposition.c_str(), m_threw, m_expr, 2899 | m_assert_type, m_file, m_line); 2900 | } 2901 | } 2902 | 2903 | if(m_failed) { 2904 | addFailedAssert(m_assert_type); 2905 | if(isDebuggerActive() && !DOCTEST_GCS().no_breaks) 2906 | return true; // should break into the debugger 2907 | } 2908 | return false; 2909 | } 2910 | 2911 | void ResultBuilder::react() const { 2912 | if(m_failed && checkIfShouldThrow(m_assert_type)) 2913 | throwException(); 2914 | } 2915 | 2916 | // the implementation of parseFlag() 2917 | bool parseFlagImpl(int argc, const char* const* argv, const char* pattern) { 2918 | for(int i = argc - 1; i >= 0; --i) { 2919 | const char* temp = strstr(argv[i], pattern); 2920 | if(temp && my_strlen(temp) == my_strlen(pattern)) { 2921 | // eliminate strings in which the chars before the option are not '-' 2922 | bool noBadCharsFound = true; 2923 | while(temp != argv[i]) { 2924 | if(*--temp != '-') { 2925 | noBadCharsFound = false; 2926 | break; 2927 | } 2928 | } 2929 | if(noBadCharsFound && argv[i][0] == '-') 2930 | return true; 2931 | } 2932 | } 2933 | return false; 2934 | } 2935 | 2936 | // locates a flag on the command line 2937 | bool parseFlag(int argc, const char* const* argv, const char* pattern) { 2938 | #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2939 | if(!parseFlagImpl(argc, argv, pattern)) 2940 | return parseFlagImpl(argc, argv, pattern + 3); // 3 for "dt-" 2941 | return true; 2942 | #else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2943 | return parseFlagImpl(argc, argv, pattern); 2944 | #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2945 | } 2946 | 2947 | // the implementation of parseOption() 2948 | bool parseOptionImpl(int argc, const char* const* argv, const char* pattern, String& res) { 2949 | for(int i = argc - 1; i >= 0; --i) { 2950 | const char* temp = strstr(argv[i], pattern); 2951 | if(temp) { 2952 | // eliminate matches in which the chars before the option are not '-' 2953 | bool noBadCharsFound = true; 2954 | const char* curr = argv[i]; 2955 | while(curr != temp) { 2956 | if(*curr++ != '-') { 2957 | noBadCharsFound = false; 2958 | break; 2959 | } 2960 | } 2961 | if(noBadCharsFound && argv[i][0] == '-') { 2962 | temp += my_strlen(pattern); 2963 | unsigned len = my_strlen(temp); 2964 | if(len) { 2965 | res = temp; 2966 | return true; 2967 | } 2968 | } 2969 | } 2970 | } 2971 | return false; 2972 | } 2973 | 2974 | // parses an option and returns the string after the '=' character 2975 | bool parseOption(int argc, const char* const* argv, const char* pattern, String& res, 2976 | const String& defaultVal = String()) { 2977 | res = defaultVal; 2978 | #ifndef DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2979 | if(!parseOptionImpl(argc, argv, pattern, res)) 2980 | return parseOptionImpl(argc, argv, pattern + 3, res); // 3 for "dt-" 2981 | return true; 2982 | #else // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2983 | return parseOptionImpl(argc, argv, pattern, res); 2984 | #endif // DOCTEST_CONFIG_NO_UNPREFIXED_OPTIONS 2985 | } 2986 | 2987 | // parses a comma separated list of words after a pattern in one of the arguments in argv 2988 | bool parseCommaSepArgs(int argc, const char* const* argv, const char* pattern, 2989 | std::vector& res) { 2990 | String filtersString; 2991 | if(parseOption(argc, argv, pattern, filtersString)) { 2992 | // tokenize with "," as a separator 2993 | char* pch = strtok(filtersString.c_str(), ","); // modifies the string 2994 | while(pch != 0) { 2995 | if(my_strlen(pch)) 2996 | res.push_back(pch); 2997 | pch = strtok(0, ","); // uses the strtok() internal state to go to the next token 2998 | } 2999 | return true; 3000 | } 3001 | return false; 3002 | } 3003 | 3004 | enum optionType 3005 | { 3006 | option_bool, 3007 | option_int 3008 | }; 3009 | 3010 | // parses an int/bool option from the command line 3011 | bool parseIntOption(int argc, const char* const* argv, const char* pattern, optionType type, 3012 | int& res) { 3013 | String parsedValue; 3014 | if(parseOption(argc, argv, pattern, parsedValue)) { 3015 | if(type == 0) { 3016 | // boolean 3017 | const char positive[][5] = {"1", "true", "on", "yes"}; // 5 - strlen("true") + 1 3018 | const char negative[][6] = {"0", "false", "off", "no"}; // 6 - strlen("false") + 1 3019 | 3020 | // if the value matches any of the positive/negative possibilities 3021 | for(unsigned i = 0; i < 4; i++) { 3022 | if(parsedValue.compare(positive[i], true) == 0) { 3023 | res = 1; 3024 | return true; 3025 | } 3026 | if(parsedValue.compare(negative[i], true) == 0) { 3027 | res = 0; 3028 | return true; 3029 | } 3030 | } 3031 | } else { 3032 | // integer 3033 | int theInt = atoi(parsedValue.c_str()); 3034 | if(theInt != 0) { 3035 | res = theInt; 3036 | return true; 3037 | } 3038 | } 3039 | } 3040 | return false; 3041 | } 3042 | 3043 | void printVersion() { 3044 | if(getContextState()->no_version == false) { 3045 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3046 | printf("doctest version is \"%s\"\n", DOCTEST_VERSION_STR); 3047 | } 3048 | } 3049 | 3050 | void printHelp() { 3051 | printVersion(); 3052 | DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); 3053 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3054 | printf("boolean values: \"1/on/yes/true\" or \"0/off/no/false\"\n"); 3055 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3056 | printf("filter values: \"str1,str2,str3\" (comma separated strings)\n"); 3057 | DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); 3058 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3059 | printf("filters use wildcards for matching strings\n"); 3060 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3061 | printf("something passes a filter if any of the strings in a filter matches\n"); 3062 | DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); 3063 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3064 | printf("ALL FLAGS, OPTIONS AND FILTERS ALSO AVAILABLE WITH A \"dt-\" PREFIX!!!\n"); 3065 | DOCTEST_PRINTF_COLORED("[doctest]\n", Color::Cyan); 3066 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3067 | printf("Query flags - the program quits after them. Available:\n\n"); 3068 | printf(" -?, --help, -h prints this message\n"); 3069 | printf(" -v, --version prints the version\n"); 3070 | printf(" -c, --count prints the number of matching tests\n"); 3071 | printf(" -ltc, --list-test-cases lists all matching tests by name\n"); 3072 | printf(" -lts, --list-test-suites lists all matching test suites\n\n"); 3073 | // ==================================================================================== << 79 3074 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3075 | printf("The available / options/filters are:\n\n"); 3076 | printf(" -tc, --test-case= filters tests by their name\n"); 3077 | printf(" -tce, --test-case-exclude= filters OUT tests by their name\n"); 3078 | printf(" -sf, --source-file= filters tests by their file\n"); 3079 | printf(" -sfe, --source-file-exclude= filters OUT tests by their file\n"); 3080 | printf(" -ts, --test-suite= filters tests by their test suite\n"); 3081 | printf(" -tse, --test-suite-exclude= filters OUT tests by their test suite\n"); 3082 | printf(" -ob, --order-by= how the tests should be ordered\n"); 3083 | printf(" - by [file/suite/name/rand]\n"); 3084 | printf(" -rs, --rand-seed= seed for random ordering\n"); 3085 | printf(" -f, --first= the first test passing the filters to\n"); 3086 | printf(" execute - for range-based execution\n"); 3087 | printf(" -l, --last= the last test passing the filters to\n"); 3088 | printf(" execute - for range-based execution\n"); 3089 | printf(" -aa, --abort-after= stop after failed assertions\n\n"); 3090 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3091 | printf("Bool options - can be used like flags and true is assumed. Available:\n\n"); 3092 | printf(" -s, --success= include successful assertions in output\n"); 3093 | printf(" -cs, --case-sensitive= filters being treated as case sensitive\n"); 3094 | printf(" -e, --exit= exits after the tests finish\n"); 3095 | printf(" -nt, --no-throw= skips exceptions-related assert checks\n"); 3096 | printf(" -ne, --no-exitcode= returns (or exits) always with success\n"); 3097 | printf(" -nr, --no-run= skips all runtime doctest operations\n"); 3098 | printf(" -nv, --no-version= omit the framework version in the output\n"); 3099 | printf(" -nc, --no-colors= disables colors in output\n"); 3100 | printf(" -fc, --force-colors= use colors even when not in a tty\n"); 3101 | printf(" -nb, --no-breaks= disables breakpoints in debuggers\n"); 3102 | printf(" -npf, --no-path-filenames= only filenames and no paths in output\n\n"); 3103 | // ==================================================================================== << 79 3104 | 3105 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3106 | printf("for more information visit the project documentation\n\n"); 3107 | } 3108 | } // namespace detail 3109 | 3110 | Context::Context(int argc, const char* const* argv) 3111 | : p(new detail::ContextState) { 3112 | parseArgs(argc, argv, true); 3113 | } 3114 | 3115 | Context::~Context() { delete p; } 3116 | 3117 | void Context::applyCommandLine(int argc, const char* const* argv) { parseArgs(argc, argv); } 3118 | 3119 | // parses args 3120 | void Context::parseArgs(int argc, const char* const* argv, bool withDefaults) { 3121 | using namespace detail; 3122 | 3123 | // clang-format off 3124 | parseCommaSepArgs(argc, argv, "dt-source-file=", p->filters[0]); 3125 | parseCommaSepArgs(argc, argv, "dt-sf=", p->filters[0]); 3126 | parseCommaSepArgs(argc, argv, "dt-source-file-exclude=",p->filters[1]); 3127 | parseCommaSepArgs(argc, argv, "dt-sfe=", p->filters[1]); 3128 | parseCommaSepArgs(argc, argv, "dt-test-suite=", p->filters[2]); 3129 | parseCommaSepArgs(argc, argv, "dt-ts=", p->filters[2]); 3130 | parseCommaSepArgs(argc, argv, "dt-test-suite-exclude=", p->filters[3]); 3131 | parseCommaSepArgs(argc, argv, "dt-tse=", p->filters[3]); 3132 | parseCommaSepArgs(argc, argv, "dt-test-case=", p->filters[4]); 3133 | parseCommaSepArgs(argc, argv, "dt-tc=", p->filters[4]); 3134 | parseCommaSepArgs(argc, argv, "dt-test-case-exclude=", p->filters[5]); 3135 | parseCommaSepArgs(argc, argv, "dt-tce=", p->filters[5]); 3136 | // clang-format on 3137 | 3138 | int intRes = 0; 3139 | String strRes; 3140 | 3141 | #define DOCTEST_PARSE_AS_BOOL_OR_FLAG(name, sname, var, default) \ 3142 | if(parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), option_bool, intRes) || \ 3143 | parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), option_bool, intRes)) \ 3144 | p->var = !!intRes; \ 3145 | else if(parseFlag(argc, argv, #name) || parseFlag(argc, argv, #sname)) \ 3146 | p->var = 1; \ 3147 | else if(withDefaults) \ 3148 | p->var = default 3149 | 3150 | #define DOCTEST_PARSE_INT_OPTION(name, sname, var, default) \ 3151 | if(parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), option_int, intRes) || \ 3152 | parseIntOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), option_int, intRes)) \ 3153 | p->var = intRes; \ 3154 | else if(withDefaults) \ 3155 | p->var = default 3156 | 3157 | #define DOCTEST_PARSE_STR_OPTION(name, sname, var, default) \ 3158 | if(parseOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(name, =), strRes, default) || \ 3159 | parseOption(argc, argv, DOCTEST_STR_CONCAT_TOSTR(sname, =), strRes, default) || \ 3160 | withDefaults) \ 3161 | p->var = strRes 3162 | 3163 | // clang-format off 3164 | DOCTEST_PARSE_STR_OPTION(dt-order-by, dt-ob, order_by, "file"); 3165 | DOCTEST_PARSE_INT_OPTION(dt-rand-seed, dt-rs, rand_seed, 0); 3166 | 3167 | DOCTEST_PARSE_INT_OPTION(dt-first, dt-f, first, 1); 3168 | DOCTEST_PARSE_INT_OPTION(dt-last, dt-l, last, 0); 3169 | 3170 | DOCTEST_PARSE_INT_OPTION(dt-abort-after, dt-aa, abort_after, 0); 3171 | 3172 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-success, dt-s, success, 0); 3173 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-case-sensitive, dt-cs, case_sensitive, 0); 3174 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-exit, dt-e, exit, 0); 3175 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-throw, dt-nt, no_throw, 0); 3176 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-exitcode, dt-ne, no_exitcode, 0); 3177 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-run, dt-nr, no_run, 0); 3178 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-version, dt-nv, no_version, 0); 3179 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-colors, dt-nc, no_colors, 0); 3180 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-force-colors, dt-fc, force_colors, 0); 3181 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-breaks, dt-nb, no_breaks, 0); 3182 | DOCTEST_PARSE_AS_BOOL_OR_FLAG(dt-no-path-filenames, dt-npf, no_path_in_filenames, 0); 3183 | // clang-format on 3184 | 3185 | #undef DOCTEST_PARSE_STR_OPTION 3186 | #undef DOCTEST_PARSE_INT_OPTION 3187 | #undef DOCTEST_PARSE_AS_BOOL_OR_FLAG 3188 | 3189 | if(withDefaults) { 3190 | p->help = false; 3191 | p->version = false; 3192 | p->count = false; 3193 | p->list_test_cases = false; 3194 | p->list_test_suites = false; 3195 | } 3196 | if(parseFlag(argc, argv, "dt-help") || parseFlag(argc, argv, "dt-h") || 3197 | parseFlag(argc, argv, "dt-?")) { 3198 | p->help = true; 3199 | p->exit = true; 3200 | } 3201 | if(parseFlag(argc, argv, "dt-version") || parseFlag(argc, argv, "dt-v")) { 3202 | p->version = true; 3203 | p->exit = true; 3204 | } 3205 | if(parseFlag(argc, argv, "dt-count") || parseFlag(argc, argv, "dt-c")) { 3206 | p->count = true; 3207 | p->exit = true; 3208 | } 3209 | if(parseFlag(argc, argv, "dt-list-test-cases") || parseFlag(argc, argv, "dt-ltc")) { 3210 | p->list_test_cases = true; 3211 | p->exit = true; 3212 | } 3213 | if(parseFlag(argc, argv, "dt-list-test-suites") || parseFlag(argc, argv, "dt-lts")) { 3214 | p->list_test_suites = true; 3215 | p->exit = true; 3216 | } 3217 | } 3218 | 3219 | // allows the user to add procedurally to the filters from the command line 3220 | void Context::addFilter(const char* filter, const char* value) { setOption(filter, value); } 3221 | 3222 | // allows the user to clear all filters from the command line 3223 | void Context::clearFilters() { 3224 | for(unsigned i = 0; i < p->filters.size(); ++i) 3225 | p->filters[i].clear(); 3226 | } 3227 | 3228 | // allows the user to override procedurally the int/bool options from the command line 3229 | void Context::setOption(const char* option, int value) { 3230 | setOption(option, toString(value).c_str()); 3231 | } 3232 | 3233 | // allows the user to override procedurally the string options from the command line 3234 | void Context::setOption(const char* option, const char* value) { 3235 | String argv = String("-") + option + "=" + value; 3236 | const char* lvalue = argv.c_str(); 3237 | parseArgs(1, &lvalue); 3238 | } 3239 | 3240 | // users should query this in their main() and exit the program if true 3241 | bool Context::shouldExit() { return p->exit; } 3242 | 3243 | // the main function that does all the filtering and test running 3244 | int Context::run() { 3245 | using namespace detail; 3246 | 3247 | getContextState() = p; 3248 | p->resetRunData(); 3249 | 3250 | // handle version, help and no_run 3251 | if(p->no_run || p->version || p->help) { 3252 | if(p->version) 3253 | printVersion(); 3254 | if(p->help) 3255 | printHelp(); 3256 | 3257 | getContextState() = 0; 3258 | 3259 | return EXIT_SUCCESS; 3260 | } 3261 | 3262 | printVersion(); 3263 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3264 | printf("run with \"--help\" for options\n"); 3265 | 3266 | unsigned i = 0; // counter used for loops - here for VC6 3267 | 3268 | std::set& registeredTests = getRegisteredTests(); 3269 | 3270 | std::vector testArray; 3271 | for(std::set::iterator it = registeredTests.begin(); it != registeredTests.end(); 3272 | ++it) 3273 | testArray.push_back(&(*it)); 3274 | 3275 | // sort the collected records 3276 | if(testArray.size() > 0) { 3277 | if(p->order_by.compare("file", true) == 0) { 3278 | qsort(&testArray[0], testArray.size(), sizeof(TestData*), fileOrderComparator); 3279 | } else if(p->order_by.compare("suite", true) == 0) { 3280 | qsort(&testArray[0], testArray.size(), sizeof(TestData*), suiteOrderComparator); 3281 | } else if(p->order_by.compare("name", true) == 0) { 3282 | qsort(&testArray[0], testArray.size(), sizeof(TestData*), nameOrderComparator); 3283 | } else if(p->order_by.compare("rand", true) == 0) { 3284 | srand(p->rand_seed); 3285 | 3286 | // random_shuffle implementation 3287 | const TestData** first = &testArray[0]; 3288 | for(i = testArray.size() - 1; i > 0; --i) { 3289 | int idxToSwap = rand() % (i + 1); 3290 | 3291 | const TestData* temp = first[i]; 3292 | 3293 | first[i] = first[idxToSwap]; 3294 | first[idxToSwap] = temp; 3295 | } 3296 | } 3297 | } 3298 | 3299 | if(p->list_test_cases) { 3300 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3301 | printf("listing all test case names\n"); 3302 | } 3303 | 3304 | std::set testSuitesPassingFilters; 3305 | if(p->list_test_suites) { 3306 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3307 | printf("listing all test suites\n"); 3308 | } 3309 | 3310 | unsigned numTestsPassingFilters = 0; 3311 | unsigned numFailed = 0; 3312 | // invoke the registered functions if they match the filter criteria (or just count them) 3313 | for(i = 0; i < testArray.size(); i++) { 3314 | const TestData& data = *testArray[i]; 3315 | if(!matchesAny(data.m_file, p->filters[0], 1, p->case_sensitive)) 3316 | continue; 3317 | if(matchesAny(data.m_file, p->filters[1], 0, p->case_sensitive)) 3318 | continue; 3319 | if(!matchesAny(data.m_suite, p->filters[2], 1, p->case_sensitive)) 3320 | continue; 3321 | if(matchesAny(data.m_suite, p->filters[3], 0, p->case_sensitive)) 3322 | continue; 3323 | if(!matchesAny(data.m_name, p->filters[4], 1, p->case_sensitive)) 3324 | continue; 3325 | if(matchesAny(data.m_name, p->filters[5], 0, p->case_sensitive)) 3326 | continue; 3327 | 3328 | numTestsPassingFilters++; 3329 | 3330 | // do not execute the test if we are to only count the number of filter passing tests 3331 | if(p->count) 3332 | continue; 3333 | 3334 | // print the name of the test and don't execute it 3335 | if(p->list_test_cases) { 3336 | printf("%s\n", data.m_name); 3337 | continue; 3338 | } 3339 | 3340 | // print the name of the test suite if not done already and don't execute it 3341 | if(p->list_test_suites) { 3342 | if(testSuitesPassingFilters.count(data.m_suite) == 0) { 3343 | printf("%s\n", data.m_suite); 3344 | testSuitesPassingFilters.insert(data.m_suite); 3345 | } 3346 | continue; 3347 | } 3348 | 3349 | // skip the test if it is not in the execution range 3350 | if((p->last < numTestsPassingFilters && p->first <= p->last) || 3351 | (p->first > numTestsPassingFilters)) 3352 | continue; 3353 | 3354 | // execute the test if it passes all the filtering 3355 | { 3356 | #ifdef _MSC_VER 3357 | //__try { 3358 | #endif // _MSC_VER 3359 | 3360 | p->currentTest = &data; 3361 | 3362 | // if logging successful tests - force the start log 3363 | p->hasLoggedCurrentTestStart = false; 3364 | if(p->success) 3365 | DOCTEST_LOG_START(); 3366 | 3367 | unsigned didFail = 0; 3368 | p->subcasesPassed.clear(); 3369 | do { 3370 | // reset the assertion state 3371 | p->numAssertionsForCurrentTestcase = 0; 3372 | p->numFailedAssertionsForCurrentTestcase = 0; 3373 | 3374 | // reset some of the fields for subcases (except for the set of fully passed ones) 3375 | p->subcasesHasSkipped = false; 3376 | p->subcasesCurrentLevel = 0; 3377 | p->subcasesEnteredLevels.clear(); 3378 | 3379 | // execute the test 3380 | didFail += callTestFunc(data.m_f); 3381 | p->numAssertions += p->numAssertionsForCurrentTestcase; 3382 | 3383 | // exit this loop if enough assertions have failed 3384 | if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) 3385 | p->subcasesHasSkipped = false; 3386 | 3387 | // if the start has been logged 3388 | if(p->hasLoggedCurrentTestStart) 3389 | logTestEnd(); 3390 | p->hasLoggedCurrentTestStart = false; 3391 | 3392 | } while(p->subcasesHasSkipped == true); 3393 | 3394 | if(didFail > 0) 3395 | numFailed++; 3396 | 3397 | // stop executing tests if enough assertions have failed 3398 | if(p->abort_after > 0 && p->numFailedAssertions >= p->abort_after) 3399 | break; 3400 | 3401 | #ifdef _MSC_VER 3402 | //} __except(1) { 3403 | // printf("Unknown SEH exception caught!\n"); 3404 | // numFailed++; 3405 | //} 3406 | #endif // _MSC_VER 3407 | } 3408 | } 3409 | 3410 | DOCTEST_PRINTF_COLORED(getSeparator(), numFailed > 0 ? Color::Red : Color::Green); 3411 | if(p->count || p->list_test_cases || p->list_test_suites) { 3412 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3413 | printf("number of tests passing the current filters: %d\n", numTestsPassingFilters); 3414 | } else { 3415 | char buff[DOCTEST_SNPRINTF_BUFFER_LENGTH]; 3416 | 3417 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3418 | 3419 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "test cases: %4d", numTestsPassingFilters); 3420 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3421 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); 3422 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3423 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d passed", 3424 | numTestsPassingFilters - numFailed); 3425 | DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::None : Color::Green); 3426 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); 3427 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3428 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d failed", numFailed); 3429 | DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::Red : Color::None); 3430 | 3431 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); 3432 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3433 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d skipped\n", 3434 | static_cast(testArray.size()) - numTestsPassingFilters); 3435 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3436 | 3437 | DOCTEST_PRINTF_COLORED("[doctest] ", Color::Cyan); 3438 | 3439 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "assertions: %4d", p->numAssertions); 3440 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3441 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); 3442 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3443 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d passed", 3444 | p->numAssertions - p->numFailedAssertions); 3445 | DOCTEST_PRINTF_COLORED(buff, numFailed > 0 ? Color::None : Color::Green); 3446 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " | "); 3447 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3448 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), "%4d failed", p->numFailedAssertions); 3449 | DOCTEST_PRINTF_COLORED(buff, p->numFailedAssertions > 0 ? Color::Red : Color::None); 3450 | 3451 | DOCTEST_SNPRINTF(buff, DOCTEST_COUNTOF(buff), " |\n"); 3452 | DOCTEST_PRINTF_COLORED(buff, Color::None); 3453 | } 3454 | 3455 | // remove any coloring 3456 | DOCTEST_PRINTF_COLORED("", Color::None); 3457 | 3458 | getContextState() = 0; 3459 | 3460 | if(numFailed && !p->no_exitcode) 3461 | return EXIT_FAILURE; 3462 | return EXIT_SUCCESS; 3463 | } 3464 | } // namespace doctest 3465 | 3466 | #endif // DOCTEST_CONFIG_DISABLE 3467 | #endif // DOCTEST_LIBRARY_IMPLEMENTATION 3468 | #endif // DOCTEST_CONFIG_IMPLEMENT 3469 | 3470 | // == THIS SUPPLIES A MAIN FUNCTION AND SHOULD BE DONE ONLY IN ONE TRANSLATION UNIT 3471 | #if defined(DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN) && !defined(DOCTEST_MAIN_CONFIGURED) 3472 | #define DOCTEST_MAIN_CONFIGURED 3473 | int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } 3474 | #endif // DOCTEST_MAIN_CONFIGURED 3475 | 3476 | #if defined(__clang__) 3477 | #pragma clang diagnostic pop 3478 | #endif // __clang__ 3479 | 3480 | #if defined(__GNUC__) && !defined(__clang__) 3481 | #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 6) 3482 | #pragma GCC diagnostic pop 3483 | #endif // > gcc 4.6 3484 | #endif // __GNUC__ 3485 | 3486 | #ifdef _MSC_VER 3487 | #pragma warning(pop) 3488 | #endif // _MSC_VER 3489 | --------------------------------------------------------------------------------