From d799492f1a9505f54565e6a3cb346419abefccfc Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 14:34:26 +0000 Subject: [PATCH 01/15] add to conan --- cmake/dependencies.cmake | 1 + conanfile.py | 4 +++- src/tests/CMakeLists.txt | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 59d265051..6ece79c4e 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -71,6 +71,7 @@ endif() # ===================== Snitch =================== if (RPP_BUILD_TESTS) rpp_fetch_library(snitch https://github.com/cschreib/snitch.git main) + find_package(trompeloeil REQUIRED) endif() diff --git a/conanfile.py b/conanfile.py index 60cce2bd7..74737c9ee 100644 --- a/conanfile.py +++ b/conanfile.py @@ -5,7 +5,9 @@ class Config(ConanFile): generators = "CMakeDeps", "CMakeToolchain" def requirements(self): - self.requires("sfml/2.6.1") + self.requires("trompeloeil/47") + self.tool_requires("cmake/3.29.3") + # self.requires("sfml/2.6.1") # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) # self.requires("protobuf/3.21.12") # self.requires("libmount/2.39", override=True) diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 45c99fabe..71ae46e80 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -14,7 +14,7 @@ macro(add_test_target target_name module files) set(TARGET ${target_name}) add_executable(${TARGET} ${files}) - target_link_libraries(${TARGET} PRIVATE snitch::snitch rpp_tests_utils ${module}) + target_link_libraries(${TARGET} PRIVATE snitch::snitch trompeloeil::trompeloeil rpp_tests_utils ${module}) set_target_properties(${TARGET} PROPERTIES FOLDER Tests/Suites/${module}) add_test_with_coverage(${TARGET}) From 190321170541030742effaece5a0191127431541 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 14:37:06 +0000 Subject: [PATCH 02/15] add header --- src/tests/utils/rpp_trompeloil.hpp | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 src/tests/utils/rpp_trompeloil.hpp diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp new file mode 100644 index 000000000..52a6efc5c --- /dev/null +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -0,0 +1,38 @@ +#pragma once + +#include +#include + +#include + +namespace trompeloeil +{ + template <> + inline void reporter::send( + severity s, + const char* file, + unsigned long line, + const char* msg) + { + std::ostringstream os; + if (line) os << file << ':' << line << '\n'; + os << msg; + auto failure = os.str(); + if (s == severity::fatal) + { + FAIL(failure); + } + else + { + CAPTURE(failure); + CHECK(failure.empty()); + } + } + + template <> + inline void reporter::sendOk( + const char* trompeloeil_mock_calls_done_correctly) + { + REQUIRE(trompeloeil_mock_calls_done_correctly != 0); + } +} \ No newline at end of file From e66dca3210e7a7bfcf9e614891c2a07c0cf2ad2b Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 14:38:04 +0000 Subject: [PATCH 03/15] one more --- src/tests/utils/rpp_trompeloil.hpp | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp index 52a6efc5c..84a015228 100644 --- a/src/tests/utils/rpp_trompeloil.hpp +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -5,6 +5,10 @@ #include +#include +#include + + namespace trompeloeil { template <> @@ -35,4 +39,23 @@ namespace trompeloeil { REQUIRE(trompeloeil_mock_calls_done_correctly != 0); } -} \ No newline at end of file +} + +template +struct mock_observer +{ + mock_observer() + { + ALLOW_CALL(*this, is_disposed()).RETURN(false); + ALLOW_CALL(*this, set_upstream(trompeloeil::_)); + } + + static constexpr bool trompeloeil_movable_mock = true; + + MAKE_MOCK1(on_next, void(const T&), const); + MAKE_MOCK1(on_next, void(T&&), const); + MAKE_MOCK1(on_error, void(const std::exception_ptr& err), const); + MAKE_MOCK0(on_completed, void(), const); + MAKE_MOCK0(is_disposed, bool(), const); + MAKE_MOCK1(set_upstream, void(const rpp::disposable_wrapper&), const); +}; \ No newline at end of file From 7008a0b38289625791ccc978eba9754409c9132d Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 14:44:31 +0000 Subject: [PATCH 04/15] add mock observer --- src/tests/utils/rpp_trompeloil.hpp | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp index 84a015228..c2501e132 100644 --- a/src/tests/utils/rpp_trompeloil.hpp +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -44,18 +44,13 @@ namespace trompeloeil template struct mock_observer { - mock_observer() - { - ALLOW_CALL(*this, is_disposed()).RETURN(false); - ALLOW_CALL(*this, set_upstream(trompeloeil::_)); - } - static constexpr bool trompeloeil_movable_mock = true; MAKE_MOCK1(on_next, void(const T&), const); MAKE_MOCK1(on_next, void(T&&), const); MAKE_MOCK1(on_error, void(const std::exception_ptr& err), const); MAKE_MOCK0(on_completed, void(), const); - MAKE_MOCK0(is_disposed, bool(), const); - MAKE_MOCK1(set_upstream, void(const rpp::disposable_wrapper&), const); + + static bool is_disposed() noexcept { return false; } + static void set_upstream(const rpp::disposable_wrapper&) noexcept {} }; \ No newline at end of file From f99eeb407e8fb0316ebe806dbc6699c4259fdb6b Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 15:06:26 +0000 Subject: [PATCH 05/15] adapt reporter --- src/tests/utils/rpp_trompeloil.hpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp index c2501e132..6e87685e4 100644 --- a/src/tests/utils/rpp_trompeloil.hpp +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -14,22 +14,14 @@ namespace trompeloeil template <> inline void reporter::send( severity s, - const char* file, - unsigned long line, + const char* , + unsigned long , const char* msg) { - std::ostringstream os; - if (line) os << file << ':' << line << '\n'; - os << msg; - auto failure = os.str(); + FAIL_CHECK(msg); if (s == severity::fatal) { - FAIL(failure); - } - else - { - CAPTURE(failure); - CHECK(failure.empty()); + std::terminate(); // terminate due to rpp could catch exceptions but we dont want it } } From 3778a6aeb93116f6e35d0fad377c9120615da4f1 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 15:18:10 +0000 Subject: [PATCH 06/15] write some tests --- src/tests/rpp/test_map.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/tests/rpp/test_map.cpp b/src/tests/rpp/test_map.cpp index 0058b3bac..ee479f1bd 100644 --- a/src/tests/rpp/test_map.cpp +++ b/src/tests/rpp/test_map.cpp @@ -17,6 +17,8 @@ #include "copy_count_tracker.hpp" #include "disposable_observable.hpp" +#include "rpp_trompeloil.hpp" + #include #include @@ -26,27 +28,27 @@ TEMPLATE_TEST_CASE("map modifies values and forward errors/completions", "", rpp SECTION("map changes value") { - mock_observer_strategy mock{}; + mock_observer mock{}; + trompeloeil::sequence seq; - obs | rpp::operators::map([](auto v) { return std::string("TEST ") + std::to_string(v); }) | rpp::operators::subscribe(mock); + REQUIRE_CALL(mock, on_next("TEST 1")).IN_SEQUENCE(seq); + REQUIRE_CALL(mock, on_next("TEST 2")).IN_SEQUENCE(seq); + REQUIRE_CALL(mock, on_completed()).IN_SEQUENCE(seq); - CHECK(mock.get_received_values() == std::vector{"TEST 1", "TEST 2"}); - CHECK(mock.get_on_error_count() == 0); - CHECK(mock.get_on_completed_count() == 1); + obs | rpp::operators::map([](auto v) { return std::string("TEST ") + std::to_string(v); }) | rpp::operators::subscribe(std::move(mock)); } SECTION("map with exception value") { - mock_observer_strategy mock{}; + mock_observer mock{}; + trompeloeil::sequence seq; - auto map = rpp::operators::map([](int) -> int { throw std::runtime_error{""}; }); + REQUIRE_CALL(mock, on_error(trompeloeil::_)).IN_SEQUENCE(seq); - obs | map | rpp::operators::subscribe(mock); // NOLINT + auto map = rpp::operators::map([](int) -> int { throw std::runtime_error{"map failed"}; }); - CHECK(mock.get_received_values() == std::vector{}); - CHECK(mock.get_on_error_count() == 1); - CHECK(mock.get_on_completed_count() == 0); + obs | map | rpp::operators::subscribe(std::move(mock)); // NOLINT } } From 108fc6cf702ede41ab1f797b80b0a54067096989 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 18:20:59 +0300 Subject: [PATCH 07/15] Update conanfile.py --- conanfile.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/conanfile.py b/conanfile.py index 74737c9ee..45bfb4a77 100644 --- a/conanfile.py +++ b/conanfile.py @@ -6,8 +6,9 @@ class Config(ConanFile): def requirements(self): self.requires("trompeloeil/47") - self.tool_requires("cmake/3.29.3") - # self.requires("sfml/2.6.1") + self.requires("sfml/2.6.1") # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) # self.requires("protobuf/3.21.12") # self.requires("libmount/2.39", override=True) + + self.tool_requires("cmake/3.29.3") From 6b7d6593e236bf0fbebe3811342221b2f7101d76 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 15:24:38 +0000 Subject: [PATCH 08/15] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- conanfile.py | 2 +- src/tests/rpp/test_map.cpp | 5 ++-- src/tests/utils/rpp_trompeloil.hpp | 41 +++++++++++++++--------------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/conanfile.py b/conanfile.py index 45bfb4a77..798ca63cb 100644 --- a/conanfile.py +++ b/conanfile.py @@ -10,5 +10,5 @@ def requirements(self): # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) # self.requires("protobuf/3.21.12") # self.requires("libmount/2.39", override=True) - + self.tool_requires("cmake/3.29.3") diff --git a/src/tests/rpp/test_map.cpp b/src/tests/rpp/test_map.cpp index ee479f1bd..668a6921a 100644 --- a/src/tests/rpp/test_map.cpp +++ b/src/tests/rpp/test_map.cpp @@ -16,7 +16,6 @@ #include "copy_count_tracker.hpp" #include "disposable_observable.hpp" - #include "rpp_trompeloil.hpp" #include @@ -29,7 +28,7 @@ TEMPLATE_TEST_CASE("map modifies values and forward errors/completions", "", rpp SECTION("map changes value") { mock_observer mock{}; - trompeloeil::sequence seq; + trompeloeil::sequence seq; REQUIRE_CALL(mock, on_next("TEST 1")).IN_SEQUENCE(seq); REQUIRE_CALL(mock, on_next("TEST 2")).IN_SEQUENCE(seq); @@ -41,7 +40,7 @@ TEMPLATE_TEST_CASE("map modifies values and forward errors/completions", "", rpp SECTION("map with exception value") { - mock_observer mock{}; + mock_observer mock{}; trompeloeil::sequence seq; REQUIRE_CALL(mock, on_error(trompeloeil::_)).IN_SEQUENCE(seq); diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp index 6e87685e4..0538250c4 100644 --- a/src/tests/utils/rpp_trompeloil.hpp +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -3,35 +3,36 @@ #include #include +#include + #include -#include #include namespace trompeloeil { - template <> - inline void reporter::send( - severity s, - const char* , - unsigned long , - const char* msg) - { - FAIL_CHECK(msg); - if (s == severity::fatal) + template<> + inline void reporter::send( + severity s, + const char*, + unsigned long, + const char* msg) { - std::terminate(); // terminate due to rpp could catch exceptions but we dont want it + FAIL_CHECK(msg); + if (s == severity::fatal) + { + std::terminate(); // terminate due to rpp could catch exceptions but we dont want it + } } - } - template <> - inline void reporter::sendOk( - const char* trompeloeil_mock_calls_done_correctly) - { - REQUIRE(trompeloeil_mock_calls_done_correctly != 0); - } -} + template<> + inline void reporter::sendOk( + const char* trompeloeil_mock_calls_done_correctly) + { + REQUIRE(trompeloeil_mock_calls_done_correctly != 0); + } +} // namespace trompeloeil template struct mock_observer @@ -45,4 +46,4 @@ struct mock_observer static bool is_disposed() noexcept { return false; } static void set_upstream(const rpp::disposable_wrapper&) noexcept {} -}; \ No newline at end of file +}; From 243b1c665f0ad65e32dfaa5e764fba16442ec656 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 22:59:08 +0300 Subject: [PATCH 09/15] configure conan properly --- HACKING.md | 6 +----- Readme.md | 1 + cmake/dev-mode.cmake | 1 + cmake/variables.cmake | 9 +++++++++ conanfile.py | 33 +++++++++++++++++++++++++-------- 5 files changed, 37 insertions(+), 13 deletions(-) diff --git a/HACKING.md b/HACKING.md index cce820222..ac900abf4 100644 --- a/HACKING.md +++ b/HACKING.md @@ -133,8 +133,4 @@ variable. --> ### conan -If you are going to build/run grpc/sfml related parts of code, then you can use conan to install all required dependecies. Install conan and just call cmd -```cmd -conan install . --output-folder=build --build=missing -s compiler.cppstd=gnu20 -c tools.system.package_manager:mode=install -c tools.system.package_manager:sudo=True --settings=build_type=Release -``` -or if your cmake version is >= 3.24, then cmake would do it by itself if you set variable `RPP_USE_CONAN`. +if your cmake version is >= 3.24, you can use conan to install RPP's CI dependencies. To use it your Cmake preset should be inherited from `use-conan`. CMake would configure conan properly. diff --git a/Readme.md b/Readme.md index 832d625d3..b34ad10c2 100644 --- a/Readme.md +++ b/Readme.md @@ -183,6 +183,7 @@ DEALINGS IN THE SOFTWARE. ReactivePlusPlus library uses: - [PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code. - [snitch](https://github.com/cschreib/snitch) for unit testing only, fetched automatically in case of `RPP_BUILD_TESTS` enabled +- [trompeloeil](https://github.com/rollbear/trompeloeil) for mocking in unit teting only, fetched automatically in case of using conan together with `RPP_BUILD_TESTS` flag - [RxCpp](https://github.com/ReactiveX/RxCpp) only for comparison of performance between RPP and RxCpp in CI benchmarks. Used as cmake dependency under option - [reactivex.io](https://reactivex.io) as source for insipration and definition of entities used in RPP. Some comments used in RPP source code taken from [reactivex.io](https://reactivex.io) - [rxmarbles python](https://pypi.org/project/rxmarbles/) as generator of marbles graphs in doxygen documentation diff --git a/cmake/dev-mode.cmake b/cmake/dev-mode.cmake index 740f1631c..cb6cc6d92 100644 --- a/cmake/dev-mode.cmake +++ b/cmake/dev-mode.cmake @@ -9,6 +9,7 @@ if(POLICY CMP0091) cmake_policy(SET CMP0091 NEW) endif() + if(POLICY CMP0144) cmake_policy(SET CMP0144 NEW) endif() diff --git a/cmake/variables.cmake b/cmake/variables.cmake index a3c403f6b..a2e0fbebe 100644 --- a/cmake/variables.cmake +++ b/cmake/variables.cmake @@ -90,6 +90,15 @@ if (RPP_DEVELOPER_MODE) option(RPP_ENABLE_COVERAGE "Enable coverage support separate from CTest's" OFF) option(RPP_BUILD_RXCPP "Build RxCpp to compare results with it." OFF) + if (DEFINED CONAN_ARGS) + if (RPP_BUILD_TESTS) + set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_tests=True") + endif() + if (RPP_BUILD_SFML_CODE) + set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_sfml=True") + endif() + endif() + if(RPP_ENABLE_COVERAGE) include(cmake/coverage.cmake) endif() diff --git a/conanfile.py b/conanfile.py index 798ca63cb..28fe61fe4 100644 --- a/conanfile.py +++ b/conanfile.py @@ -1,14 +1,31 @@ from conan import ConanFile -class Config(ConanFile): +class RppConan(ConanFile): + name = "rpp" settings = "os", "compiler", "build_type", "arch" generators = "CMakeDeps", "CMakeToolchain" - def requirements(self): - self.requires("trompeloeil/47") - self.requires("sfml/2.6.1") - # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) - # self.requires("protobuf/3.21.12") - # self.requires("libmount/2.39", override=True) + options = { + "with_grpc" : [False, True], + "with_sfml" : [False, True], + "with_tests" : [False, True], + "with_cmake" : [False, True], + } + default_options = { + "with_grpc" : False, + "with_sfml" : False, + "with_tests": False, + "with_cmake": False, + } - self.tool_requires("cmake/3.29.3") + def requirements(self): + if self.options.with_tests: + self.requires("trompeloeil/47") + if self.options.with_sfml: + self.requires("sfml/2.6.1") + # if self.options.with_grpc: + # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) + # self.requires("protobuf/3.21.12") + # self.requires("libmount/2.39", override=True) + if self.options.with_cmake: + self.tool_requires("cmake/3.29.3") From 624a5a31c7e5561469912f33e98d6cba4571480f Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 23:12:45 +0300 Subject: [PATCH 10/15] adapt new mock --- src/tests/rpp/test_buffer.cpp | 115 +++++++++++------------------ src/tests/rpp/test_map.cpp | 9 +-- src/tests/utils/rpp_trompeloil.hpp | 34 +++++++-- 3 files changed, 74 insertions(+), 84 deletions(-) diff --git a/src/tests/rpp/test_buffer.cpp b/src/tests/rpp/test_buffer.cpp index 3a5e50342..629388a49 100644 --- a/src/tests/rpp/test_buffer.cpp +++ b/src/tests/rpp/test_buffer.cpp @@ -11,81 +11,65 @@ #include #include -#include #include #include #include #include #include "disposable_observable.hpp" +#include "rpp_trompeloil.hpp" TEST_CASE("buffer bundles items") { + trompeloeil::sequence s{}; + auto mock = mock_observer>{}; + SECTION("observable of -1-2-3-|") { - auto mock = mock_observer_strategy>{}; - auto obs = rpp::source::just(1, 2, 3); - SECTION("subscribe on it via buffer(0)") + auto obs = rpp::source::just(1, 2, 3); + SECTION("buffer(0) - shall see -{1}-{2}-{3}-|") { - obs | rpp::ops::buffer(0) - | rpp::ops::subscribe(mock); - SECTION("shall see -{1}-{2}-{3}-|") - { - CHECK(mock.get_received_values() == std::vector{std::vector{1}, std::vector{2}, std::vector{3}}); - CHECK(mock.get_on_completed_count() == 1); - CHECK(mock.get_on_error_count() == 0); - } + REQUIRE_CALL(*mock, on_next(std::vector{1})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_next(std::vector{2})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_next(std::vector{3})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(s); + + obs | rpp::ops::buffer(0) | rpp::ops::subscribe(mock); } - SECTION("subscribe on it via buffer(1)") + SECTION("buffer(1) - shall see -{1}-{2}-{3}-|") { + REQUIRE_CALL(*mock, on_next(std::vector{1})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_next(std::vector{2})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_next(std::vector{3})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(s); + obs | rpp::ops::buffer(1) | rpp::ops::subscribe(mock); - SECTION("shall see -{1}-{2}-{3}-|") - { - CHECK(mock.get_received_values() == std::vector{std::vector{1}, std::vector{2}, std::vector{3}}); - CHECK(mock.get_on_completed_count() == 1); - CHECK(mock.get_on_error_count() == 0); - } } - SECTION("subscribe on it via buffer(2)") + SECTION("buffer(2) - shall see -{1,2}-{3}|") { + REQUIRE_CALL(*mock, on_next(std::vector{1, 2})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_next(std::vector{3})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(s); + obs | rpp::ops::buffer(2) | rpp::ops::subscribe(mock); - SECTION("shall see -{1,2}-{3}|") - { - CHECK(mock.get_received_values() == std::vector>{ - std::vector{1, 2}, - std::vector{3}, - }); - CHECK(mock.get_on_completed_count() == 1); - CHECK(mock.get_on_error_count() == 0); - } } - SECTION("subscribe on it via buffer(3)") + SECTION("buffer(3) - shall see -{1,2,3}-|") { + REQUIRE_CALL(*mock, on_next(std::vector{1, 2, 3})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(s); + obs | rpp::ops::buffer(3) | rpp::ops::subscribe(mock); - SECTION("shall see -{1,2,3}-|") - { - CHECK(mock.get_received_values() == std::vector>{ - std::vector{1, 2, 3}, - }); - CHECK(mock.get_on_completed_count() == 1); - CHECK(mock.get_on_error_count() == 0); - } } - SECTION("subscribe on it via buffer(4)") + SECTION("buffer(4) - shall see -{1,2,3}-|") { + REQUIRE_CALL(*mock, on_next(std::vector{1, 2, 3})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(s); + obs | rpp::ops::buffer(4) | rpp::ops::subscribe(mock); - SECTION("shall see -{1,2,3}-|") - { - CHECK(mock.get_received_values() == std::vector>{ - std::vector{1, 2, 3}, - }); - CHECK(mock.get_on_completed_count() == 1); - CHECK(mock.get_on_error_count() == 0); - } } } @@ -95,43 +79,28 @@ TEST_CASE("buffer bundles items") rpp::source::error(std::make_exception_ptr(std::runtime_error{""})).as_dynamic(), rpp::source::just(2).as_dynamic()) | rpp::ops::merge(); - auto mock = mock_observer_strategy>{}; - SECTION("subscribe on it via buffer(0)") + SECTION("buffer(0) - shall see -{1}-x, which means error event is through") { + REQUIRE_CALL(*mock, on_next(std::vector{1})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_error(trompeloeil::_)).IN_SEQUENCE(s); + obs | rpp::ops::buffer(0) | rpp::ops::subscribe(mock); - SECTION("shall see -{1}-x, which means error event is through") - { - CHECK(mock.get_received_values() == std::vector>{ - std::vector{1}, - }); - CHECK(mock.get_on_completed_count() == 0); - CHECK(mock.get_on_error_count() == 1); - } } - SECTION("subscribe on it via buffer(1)") + SECTION("buffer(1) - shall see -{1}-x, which means error event is through") { + REQUIRE_CALL(*mock, on_next(std::vector{1})).IN_SEQUENCE(s); + REQUIRE_CALL(*mock, on_error(trompeloeil::_)).IN_SEQUENCE(s); + obs | rpp::ops::buffer(1) | rpp::ops::subscribe(mock); - SECTION("shall see -{1}-x, which means error event is through") - { - CHECK(mock.get_received_values() == std::vector>{ - std::vector{1}, - }); - CHECK(mock.get_on_completed_count() == 0); - CHECK(mock.get_on_error_count() == 1); - } } - SECTION("subscribe on it via buffer(2)") + SECTION("buffer(2) - shall see --x, which means error event is through") { + REQUIRE_CALL(*mock, on_error(trompeloeil::_)).IN_SEQUENCE(s); + obs | rpp::ops::buffer(2) | rpp::ops::subscribe(mock); - SECTION("shall see --x, which means error event is through") - { - CHECK(mock.get_received_values().empty()); - CHECK(mock.get_on_completed_count() == 0); - CHECK(mock.get_on_error_count() == 1); - } } } } diff --git a/src/tests/rpp/test_map.cpp b/src/tests/rpp/test_map.cpp index 668a6921a..12a469a48 100644 --- a/src/tests/rpp/test_map.cpp +++ b/src/tests/rpp/test_map.cpp @@ -10,7 +10,6 @@ #include -#include #include #include @@ -30,9 +29,9 @@ TEMPLATE_TEST_CASE("map modifies values and forward errors/completions", "", rpp mock_observer mock{}; trompeloeil::sequence seq; - REQUIRE_CALL(mock, on_next("TEST 1")).IN_SEQUENCE(seq); - REQUIRE_CALL(mock, on_next("TEST 2")).IN_SEQUENCE(seq); - REQUIRE_CALL(mock, on_completed()).IN_SEQUENCE(seq); + REQUIRE_CALL(*mock, on_next("TEST 1")).IN_SEQUENCE(seq); + REQUIRE_CALL(*mock, on_next("TEST 2")).IN_SEQUENCE(seq); + REQUIRE_CALL(*mock, on_completed()).IN_SEQUENCE(seq); obs | rpp::operators::map([](auto v) { return std::string("TEST ") + std::to_string(v); }) | rpp::operators::subscribe(std::move(mock)); } @@ -43,7 +42,7 @@ TEMPLATE_TEST_CASE("map modifies values and forward errors/completions", "", rpp mock_observer mock{}; trompeloeil::sequence seq; - REQUIRE_CALL(mock, on_error(trompeloeil::_)).IN_SEQUENCE(seq); + REQUIRE_CALL(*mock, on_error(trompeloeil::_)).IN_SEQUENCE(seq); auto map = rpp::operators::map([](int) -> int { throw std::runtime_error{"map failed"}; }); diff --git a/src/tests/utils/rpp_trompeloil.hpp b/src/tests/utils/rpp_trompeloil.hpp index 0538250c4..6018c97c6 100644 --- a/src/tests/utils/rpp_trompeloil.hpp +++ b/src/tests/utils/rpp_trompeloil.hpp @@ -35,15 +35,37 @@ namespace trompeloeil } // namespace trompeloeil template -struct mock_observer +class mock_observer { - static constexpr bool trompeloeil_movable_mock = true; +public: + struct impl_t + { + impl_t() = default; + + MAKE_MOCK1(on_next, void(const T&), const); + MAKE_MOCK1(on_next, void(T&&), const); + MAKE_MOCK1(on_error, void(const std::exception_ptr& err), const); + MAKE_MOCK0(on_completed, void(), const); + }; + + impl_t& operator*() const noexcept { return *impl; } + + void on_next(const T& v) const noexcept + { + impl->on_next(v); + } - MAKE_MOCK1(on_next, void(const T&), const); - MAKE_MOCK1(on_next, void(T&&), const); - MAKE_MOCK1(on_error, void(const std::exception_ptr& err), const); - MAKE_MOCK0(on_completed, void(), const); + void on_next(T&& v) const noexcept + { + impl->on_next(std::move(v)); + } + + void on_error(const std::exception_ptr& err) const noexcept { impl->on_error(err); } + void on_completed() const noexcept { impl->on_completed(); } static bool is_disposed() noexcept { return false; } static void set_upstream(const rpp::disposable_wrapper&) noexcept {} + +private: + std::shared_ptr impl = std::make_shared(); }; From 7f54c0a941f212e6b7c2891004dcc1d34732b763 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Wed, 22 May 2024 23:17:56 +0300 Subject: [PATCH 11/15] try to add qt --- cmake/variables.cmake | 3 +++ conanfile.py | 8 ++++++++ 2 files changed, 11 insertions(+) diff --git a/cmake/variables.cmake b/cmake/variables.cmake index a2e0fbebe..361517731 100644 --- a/cmake/variables.cmake +++ b/cmake/variables.cmake @@ -97,6 +97,9 @@ if (RPP_DEVELOPER_MODE) if (RPP_BUILD_SFML_CODE) set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_sfml=True") endif() + if (RPP_BUILD_QT_CODE) + set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_qt=True") + endif() endif() if(RPP_ENABLE_COVERAGE) diff --git a/conanfile.py b/conanfile.py index 28fe61fe4..369d83789 100644 --- a/conanfile.py +++ b/conanfile.py @@ -10,19 +10,27 @@ class RppConan(ConanFile): "with_sfml" : [False, True], "with_tests" : [False, True], "with_cmake" : [False, True], + "with_qt" : [False, True], } default_options = { "with_grpc" : False, "with_sfml" : False, "with_tests": False, "with_cmake": False, + "with_qt": False, } def requirements(self): if self.options.with_tests: self.requires("trompeloeil/47") + if self.options.with_sfml: self.requires("sfml/2.6.1") + + if self.options.with_qt: + self.requires("qt/6.3.2") + self.requires("libpng/1.6.42", override=True) + # if self.options.with_grpc: # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) # self.requires("protobuf/3.21.12") From 7991e828f7eca5c967b71f95302013ba838022a3 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Thu, 23 May 2024 00:02:18 +0300 Subject: [PATCH 12/15] simplify --- CMakePresets.json | 2 +- conanfile.py | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 8a5aa475a..27354c7fc 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -144,7 +144,7 @@ "cacheVariables": { "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake/conan_provider.cmake", "CONAN_ARGS": "", - "CONAN_INSTALL_ARGS": "--build=missing;-s=compiler.cppstd=20;-c=tools.system.package_manager:mode=install;-c=tools.system.package_manager:sudo=True" + "CONAN_INSTALL_ARGS": "--build=missing;-s=compiler.cppstd=20;-c=tools.system.package_manager:mode=install;-c=tools.system.package_manager:sudo=True;-o *:shared=True" } }, { diff --git a/conanfile.py b/conanfile.py index 369d83789..e40c6e4f9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -25,10 +25,16 @@ def requirements(self): self.requires("trompeloeil/47") if self.options.with_sfml: - self.requires("sfml/2.6.1") + self.requires("sfml/2.6.1", options={"audio": False}) if self.options.with_qt: - self.requires("qt/6.3.2") + self.requires("qt/6.3.2", options={"with_libjpeg": False, + "with_md4c": False, + "with_mysql": False, + "with_odbc": False, + "with_openal": False, + "with_pq": False, + "with_sqlite3":False}) self.requires("libpng/1.6.42", override=True) # if self.options.with_grpc: From 26a4db0862378fc531a95fe072ecacaec6f4f320 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Thu, 23 May 2024 00:08:26 +0300 Subject: [PATCH 13/15] simplify --- cmake/dependencies.cmake | 5 ++--- cmake/variables.cmake | 4 ++-- conanfile.py | 19 +++++++------------ 3 files changed, 11 insertions(+), 17 deletions(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 6ece79c4e..5895fd3e4 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -64,18 +64,17 @@ endmacro() # ==================== RXCPP ======================= if (RPP_BUILD_RXCPP AND RPP_BUILD_BENCHMARKS) set(RXCPP_DISABLE_TESTS_AND_EXAMPLES 1) - rpp_fetch_library(rxcpp https://github.com/ReactiveX/RxCpp.git origin/main) endif() # ===================== Snitch =================== if (RPP_BUILD_TESTS) - rpp_fetch_library(snitch https://github.com/cschreib/snitch.git main) + find_package(snitch REQUIRED) find_package(trompeloeil REQUIRED) endif() # ==================== Nanobench ================= if (RPP_BUILD_BENCHMARKS) - rpp_fetch_library(nanobench https://github.com/martinus/nanobench.git master) + find_package(nanobench REQUIRED) endif() diff --git a/cmake/variables.cmake b/cmake/variables.cmake index 361517731..8d91fdb67 100644 --- a/cmake/variables.cmake +++ b/cmake/variables.cmake @@ -97,8 +97,8 @@ if (RPP_DEVELOPER_MODE) if (RPP_BUILD_SFML_CODE) set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_sfml=True") endif() - if (RPP_BUILD_QT_CODE) - set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_qt=True") + if (RPP_BUILD_BENCHMARKS) + set(CONAN_ARGS "${CONAN_ARGS};-o rpp/*:with_benchmarks=True") endif() endif() diff --git a/conanfile.py b/conanfile.py index e40c6e4f9..bc7892cd9 100644 --- a/conanfile.py +++ b/conanfile.py @@ -10,36 +10,31 @@ class RppConan(ConanFile): "with_sfml" : [False, True], "with_tests" : [False, True], "with_cmake" : [False, True], - "with_qt" : [False, True], + "with_benchmarks" : [False, True] } default_options = { "with_grpc" : False, "with_sfml" : False, "with_tests": False, "with_cmake": False, - "with_qt": False, + "with_benchmarks" : False } def requirements(self): if self.options.with_tests: self.requires("trompeloeil/47") + self.requires("snitch/1.2.3") + + if self.options.with_benchmarks: + self.requires("nanobench/4.3.11") if self.options.with_sfml: self.requires("sfml/2.6.1", options={"audio": False}) - if self.options.with_qt: - self.requires("qt/6.3.2", options={"with_libjpeg": False, - "with_md4c": False, - "with_mysql": False, - "with_odbc": False, - "with_openal": False, - "with_pq": False, - "with_sqlite3":False}) - self.requires("libpng/1.6.42", override=True) - # if self.options.with_grpc: # self.requires("grpc/1.54.3", transitive_libs=True, transitive_headers=True) # self.requires("protobuf/3.21.12") # self.requires("libmount/2.39", override=True) + if self.options.with_cmake: self.tool_requires("cmake/3.29.3") From e76a056002a6954994d2c2d17b5532d6fdfbeb21 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Thu, 23 May 2024 00:13:01 +0300 Subject: [PATCH 14/15] adapt multiple approaches --- cmake/dependencies.cmake | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 5895fd3e4..7a9bdfa03 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -58,7 +58,11 @@ macro(rpp_fetch_library_extended NAME URL TAG TARGET_NAME) endmacro() macro(rpp_fetch_library NAME URL TAG) - rpp_fetch_library_extended(${NAME} ${URL} ${TAG} ${NAME}) + find_package(${NAME} QUIET) + if (NOT ${NAME}_FOUND) + message("-- RPP: Fetching ${NAME}...") + rpp_fetch_library_extended(${NAME} ${URL} ${TAG} ${NAME}) + endif() endmacro() # ==================== RXCPP ======================= @@ -69,12 +73,12 @@ endif() # ===================== Snitch =================== if (RPP_BUILD_TESTS) - find_package(snitch REQUIRED) - find_package(trompeloeil REQUIRED) + rpp_fetch_library(snitch https://github.com/cschreib/snitch.git main) + rpp_fetch_library(trompeloeil https://github.com/rollbear/trompeloeil.git main) endif() # ==================== Nanobench ================= if (RPP_BUILD_BENCHMARKS) - find_package(nanobench REQUIRED) + rpp_fetch_library(nanobench https://github.com/martinus/nanobench.git master) endif() From ccb10a3822909b0ffeff8042dd4a7b43343bc5b3 Mon Sep 17 00:00:00 2001 From: Aleksey Loginov Date: Thu, 23 May 2024 00:29:15 +0300 Subject: [PATCH 15/15] fix nanobench --- CMakePresets.json | 2 +- HACKING.md | 2 +- Readme.md | 3 ++- src/benchmarks/CMakeLists.txt | 2 +- src/benchmarks/benchmarks.cpp | 1 + 5 files changed, 6 insertions(+), 4 deletions(-) diff --git a/CMakePresets.json b/CMakePresets.json index 27354c7fc..8a5aa475a 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -144,7 +144,7 @@ "cacheVariables": { "CMAKE_PROJECT_TOP_LEVEL_INCLUDES": "cmake/conan_provider.cmake", "CONAN_ARGS": "", - "CONAN_INSTALL_ARGS": "--build=missing;-s=compiler.cppstd=20;-c=tools.system.package_manager:mode=install;-c=tools.system.package_manager:sudo=True;-o *:shared=True" + "CONAN_INSTALL_ARGS": "--build=missing;-s=compiler.cppstd=20;-c=tools.system.package_manager:mode=install;-c=tools.system.package_manager:sudo=True" } }, { diff --git a/HACKING.md b/HACKING.md index ac900abf4..e85482528 100644 --- a/HACKING.md +++ b/HACKING.md @@ -133,4 +133,4 @@ variable. --> ### conan -if your cmake version is >= 3.24, you can use conan to install RPP's CI dependencies. To use it your Cmake preset should be inherited from `use-conan`. CMake would configure conan properly. +if your cmake version is >= 3.24, you can use conan to install RPP's dependencies. To use it your Cmake preset should be inherited from `use-conan`. CMake would configure conan properly. diff --git a/Readme.md b/Readme.md index b34ad10c2..f1a3866df 100644 --- a/Readme.md +++ b/Readme.md @@ -183,7 +183,8 @@ DEALINGS IN THE SOFTWARE. ReactivePlusPlus library uses: - [PVS-Studio](https://pvs-studio.com/pvs-studio/?utm_source=website&utm_medium=github&utm_campaign=open_source) - static analyzer for C, C++, C#, and Java code. - [snitch](https://github.com/cschreib/snitch) for unit testing only, fetched automatically in case of `RPP_BUILD_TESTS` enabled -- [trompeloeil](https://github.com/rollbear/trompeloeil) for mocking in unit teting only, fetched automatically in case of using conan together with `RPP_BUILD_TESTS` flag +- [trompeloeil](https://github.com/rollbear/trompeloeil) for mocking in unit testing only, fetched automatically in case of `RPP_BUILD_TESTS` enabled +- [nanobench](https://github.com/martinus/nanobench) for benchmarking only, fetched automatically in case of `RPP_BUILD_BENCHMARKS` enabled - [RxCpp](https://github.com/ReactiveX/RxCpp) only for comparison of performance between RPP and RxCpp in CI benchmarks. Used as cmake dependency under option - [reactivex.io](https://reactivex.io) as source for insipration and definition of entities used in RPP. Some comments used in RPP source code taken from [reactivex.io](https://reactivex.io) - [rxmarbles python](https://pypi.org/project/rxmarbles/) as generator of marbles graphs in doxygen documentation diff --git a/src/benchmarks/CMakeLists.txt b/src/benchmarks/CMakeLists.txt index 77c272e4d..38ffd201f 100644 --- a/src/benchmarks/CMakeLists.txt +++ b/src/benchmarks/CMakeLists.txt @@ -12,7 +12,7 @@ set(TARGET benchmarks) add_executable(${TARGET} benchmarks.cpp) -target_link_libraries(${TARGET} PRIVATE rpp nanobench) +target_link_libraries(${TARGET} PRIVATE rpp nanobench::nanobench) if (RPP_BUILD_RXCPP) target_link_libraries(${TARGET} PRIVATE rxcpp) target_compile_definitions(${TARGET} PRIVATE RPP_BUILD_RXCPP) diff --git a/src/benchmarks/benchmarks.cpp b/src/benchmarks/benchmarks.cpp index 23024edab..796d019d5 100644 --- a/src/benchmarks/benchmarks.cpp +++ b/src/benchmarks/benchmarks.cpp @@ -1,3 +1,4 @@ +#define ANKERL_NANOBENCH_IMPLEMENT #include #include