diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index af898f768..5100bf1ad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,6 +13,7 @@ env: CATCH2_VERSION: v3.1.0 Catch2_DIR: ~/Catch2_BIN + jobs: download_deps: strategy: @@ -60,6 +61,9 @@ jobs: - name: Install LCov run: sudo apt-get update -q && sudo apt-get install lcov -q -y + - name: Install Qt + uses: jurplel/install-qt-action@v3 + - name: Restore Catch2 uses: actions/cache@v3 id: cache-catch2 @@ -92,6 +96,9 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Install Qt + uses: jurplel/install-qt-action@v3 + - name: Restore Catch2 uses: actions/cache@v3 id: cache-catch2 @@ -125,10 +132,16 @@ jobs: with: fetch-depth: 0 + - name: Install Qt + if: matrix.type == 'tests' + uses: jurplel/install-qt-action@v3 + - name: Install deps if: matrix.config.os != 'windows-latest' - run: sudo apt-get update -q && sudo apt-get install clang-tidy cppcheck libsfml-dev -y -q - + run: | + sudo apt-get update -q && sudo apt-get install clang-tidy cppcheck libsfml-dev -y -q + pip install pyyaml + - name: Restore Catch2 uses: actions/cache@v3 id: cache-catch2 @@ -182,6 +195,9 @@ jobs: with: path: ${{env.Catch2_DIR}} key: catch2-${{env.CATCH2_VERSION}}-ubuntu-latest + + - name: Install Qt + uses: jurplel/install-qt-action@v3 - name: Cache SonarCloud packages uses: actions/cache@v3 @@ -205,7 +221,7 @@ jobs: CXX: g++-10 run: | mkdir build - cmake -S . -B build -DRPP_BUILD_TESTS=1 + cmake -S . -B build -DRPP_BUILD_TESTS=1 -DRPP_BUILD_QT_CODE=1 build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} cmake --build build/ --config Release --parallel 2 - name: Upload results @@ -216,13 +232,8 @@ jobs: docs: name: Build Doxygen Docs - - needs: [sanitize, tests] - runs-on: ubuntu-latest - if: github.event_name == 'push' && github.repository_owner == 'victimsnino' - steps: - uses: actions/checkout@v3 @@ -232,13 +243,27 @@ jobs: - name: Install deps run: | pip3 install rxmarbles - sudo apt-get install doxygen + export CC=clang + export CXX=clang++ + sudo apt install llvm-11 clang-11 libclang-11-dev flex bison -q -y + git clone https://github.com/doxygen/doxygen.git --depth 1 + cd doxygen && mkdir build && cd build + cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr .. + make -j4 + sudo make install - name: Doxygen run: doxygen ./Doxyfile + - name: Update docs + run: | + grep -rl "rpp::details::member_overload" gen_docs | xargs sed -i 's/rpp::details::member_overload< Type, SpecificObservable, [a-zA-Z_]*_tag >/observable/g' + grep -rl "rpp::details::member_overload" gen_docs | xargs sed -i 's/rpp::details::member_overload<\/a>< Type, SpecificObservable, [a-zA-Z_]*_tag >/observable<\/a>/g' + grep -rl "rpp::details::member_overload" gen_docs | xargs sed -i 's/rpp::details::member_overload< Type, SpecificObservable, [a-zA-Z_]*_tag >:://g' + - name: Deploy uses: peaceiris/actions-gh-pages@v3 + if: github.event_name == 'push' && github.repository_owner == 'victimsnino' with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./gen_docs @@ -264,6 +289,6 @@ jobs: cmake -B build sudo cmake --build build --target install --parallel 2 --config Release - cmake -B sample_build -S src/examples/package + cmake -B sample_build -S src/examples/rpp/package cmake --build sample_build --parallel 2 --config Release diff --git a/.github/workflows/sonarcloud_analyze.yml b/.github/workflows/sonarcloud_analyze.yml index 62e8db26e..0f98d2017 100644 --- a/.github/workflows/sonarcloud_analyze.yml +++ b/.github/workflows/sonarcloud_analyze.yml @@ -23,7 +23,7 @@ jobs: ref: ${{ github.event.workflow_run.head_branch }} - name: Cmake - run: cmake -S . -B build -DRPP_BUILD_TESTS=1 + run: cmake -S . -B build -DRPP_BUILD_TESTS=1 -DRPP_BUILD_QT_CODE=1 - name: Set up JDK 11 uses: actions/setup-java@v3 diff --git a/CMakePresets.json b/CMakePresets.json index dcfccf8df..f2f01e677 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -114,14 +114,16 @@ "name" : "ci-build-tests", "hidden": true, "cacheVariables": { - "RPP_BUILD_TESTS" : "ON" + "RPP_BUILD_TESTS" : "ON", + "RPP_BUILD_QT_CODE" : "ON" } }, { "name" : "ci-build-examples", "hidden": true, "cacheVariables": { - "RPP_BUILD_EXAMPLES" : "ON" + "RPP_BUILD_EXAMPLES" : "ON", + "RPP_BUILD_QT_CODE" : "ON" } }, { diff --git a/Doxyfile b/Doxyfile index 0e6ff41e4..78c20cf8d 100644 --- a/Doxyfile +++ b/Doxyfile @@ -874,7 +874,7 @@ WARN_LOGFILE = # spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. -INPUT = src/rpp src/examples/doxygen docs +INPUT = src/rpp src/rppqt src/examples/rpp/doxygen src/examples/rppqt/doxygen docs # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses @@ -996,7 +996,7 @@ EXCLUDE_SYMBOLS = # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = src/examples/doxygen +EXAMPLE_PATH = src/examples/rpp/doxygen src/examples/rppqt/doxygen # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -1308,6 +1308,19 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a color-wheel, see diff --git a/cmake/dependencies.cmake b/cmake/dependencies.cmake index 5f6175617..9e3306e43 100644 --- a/cmake/dependencies.cmake +++ b/cmake/dependencies.cmake @@ -1,12 +1,34 @@ find_package(Threads REQUIRED) # ===================== SFML ======================= -if (RPP_BUILD_SFML_CODE) +if (RPP_BUILD_SFML_CODE AND RPP_BUILD_EXAMPLES) find_package(SFML COMPONENTS graphics system window REQUIRED) endif() +# ==================== QT ========================== +if (RPP_BUILD_QT_CODE AND (RPP_BUILD_TESTS OR RPP_BUILD_EXAMPLES)) + find_package(Qt6 COMPONENTS Widgets) + if (Qt6_FOUND) + SET(RPP_QT_TARGET Qt6) + else() + find_package(Qt5 REQUIRED COMPONENTS Widgets) + SET(RPP_QT_TARGET Qt5) + endif() + + message("-- RPP: Found QT version: ${RPP_QT_TARGET}") + macro(rpp_add_qt_support_to_executable TARGET) + target_link_libraries(${TARGET} PRIVATE ${RPP_QT_TARGET}::Widgets) + set_target_properties(${TARGET} PROPERTIES AUTOMOC TRUE) + if (WIN32) + add_custom_command (TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) + add_custom_command (TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) + add_custom_command (TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) + endif() + endmacro() +endif() + # ==================== RXCPP ======================= -if (RPP_BUILD_RXCPP) +if (RPP_BUILD_RXCPP AND RPP_BUILD_BENCHMARKS) set(RXCPP_DISABLE_TESTS_AND_EXAMPLES 1) Include(FetchContent) @@ -36,4 +58,4 @@ if (RPP_BUILD_TESTS OR RPP_BUILD_BENCHMARKS) ) FetchContent_MakeAvailable(Catch2) endif() -endif() \ No newline at end of file +endif() diff --git a/cmake/variables.cmake b/cmake/variables.cmake index be21a8d9a..72f62b94a 100644 --- a/cmake/variables.cmake +++ b/cmake/variables.cmake @@ -37,6 +37,7 @@ endif() # ------------ Options to tweak --------------------- option(RPP_BUILD_SFML_CODE "Enable SFML support in examples/code." OFF) +option(RPP_BUILD_QT_CODE "Enable QT support and add rppqt library." OFF) if (RPP_DEVELOPER_MODE) option(RPP_BUILD_TESTS "Build unit tests tree." OFF) diff --git a/sonar-project.properties b/sonar-project.properties index 0f44e8ad2..b29aba21f 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -3,7 +3,7 @@ sonar.organization=victimsnino sonar.projectName=ReactivePlusPlus # SQ standard properties -sonar.sources=src/rpp,src/tests/ +sonar.sources=src/rpp,src/rppqt,src/tests/ sonar.coverage.exclusions=src/tests/**/* sonar.cpd.exclusions=src/tests/**/* sonar.issue.ignore.allfile=a1 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f287f0088..415455101 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -10,9 +10,14 @@ add_subdirectory(rpp) +if(RPP_BUILD_QT_CODE) + add_subdirectory(rppqt) +endif() + if (RPP_BUILD_BENCHMARKS) add_subdirectory(benchmarks) endif() + if(RPP_BUILD_TESTS) add_subdirectory(tests) endif() diff --git a/src/examples/CMakeLists.txt b/src/examples/CMakeLists.txt index 6f5fc7369..b8cf680a9 100644 --- a/src/examples/CMakeLists.txt +++ b/src/examples/CMakeLists.txt @@ -1,7 +1,4 @@ -add_subdirectory(basic) -add_subdirectory(doxygen) -add_subdirectory(petri) - -if (RPP_BUILD_SFML_CODE) - add_subdirectory(sfml) +add_subdirectory(rpp) +if(RPP_BUILD_QT_CODE) + add_subdirectory(rppqt) endif() \ No newline at end of file diff --git a/src/examples/rpp/CMakeLists.txt b/src/examples/rpp/CMakeLists.txt new file mode 100644 index 000000000..6f5fc7369 --- /dev/null +++ b/src/examples/rpp/CMakeLists.txt @@ -0,0 +1,7 @@ +add_subdirectory(basic) +add_subdirectory(doxygen) +add_subdirectory(petri) + +if (RPP_BUILD_SFML_CODE) + add_subdirectory(sfml) +endif() \ No newline at end of file diff --git a/src/examples/basic/CMakeLists.txt b/src/examples/rpp/basic/CMakeLists.txt similarity index 59% rename from src/examples/basic/CMakeLists.txt rename to src/examples/rpp/basic/CMakeLists.txt index d094456bc..1a31985f7 100644 --- a/src/examples/basic/CMakeLists.txt +++ b/src/examples/rpp/basic/CMakeLists.txt @@ -3,4 +3,4 @@ add_executable(basic_sample ) target_link_libraries(basic_sample PRIVATE RPP::rpp) -set_target_properties(basic_sample PROPERTIES FOLDER Examples) +set_target_properties(basic_sample PROPERTIES FOLDER Examples/rpp) diff --git a/src/examples/basic/basic.cpp b/src/examples/rpp/basic/basic.cpp similarity index 100% rename from src/examples/basic/basic.cpp rename to src/examples/rpp/basic/basic.cpp diff --git a/src/examples/doxygen/CMakeLists.txt b/src/examples/rpp/doxygen/CMakeLists.txt similarity index 77% rename from src/examples/doxygen/CMakeLists.txt rename to src/examples/rpp/doxygen/CMakeLists.txt index 28c583b3d..cda4acbdd 100644 --- a/src/examples/doxygen/CMakeLists.txt +++ b/src/examples/rpp/doxygen/CMakeLists.txt @@ -5,6 +5,6 @@ foreach(SOURCE ${FILES}) set(TARGET ${BASE_NAME}_doxygen_sample) add_executable(${TARGET} ${SOURCE}) target_link_libraries(${TARGET} PRIVATE rpp) - set_target_properties(${TARGET} PROPERTIES FOLDER Examples/Doxygen) + set_target_properties(${TARGET} PROPERTIES FOLDER Examples/rpp/Doxygen) endforeach() diff --git a/src/examples/doxygen/buffer.cpp b/src/examples/rpp/doxygen/buffer.cpp similarity index 100% rename from src/examples/doxygen/buffer.cpp rename to src/examples/rpp/doxygen/buffer.cpp diff --git a/src/examples/doxygen/combine_latest.cpp b/src/examples/rpp/doxygen/combine_latest.cpp similarity index 100% rename from src/examples/doxygen/combine_latest.cpp rename to src/examples/rpp/doxygen/combine_latest.cpp diff --git a/src/examples/doxygen/concat.cpp b/src/examples/rpp/doxygen/concat.cpp similarity index 100% rename from src/examples/doxygen/concat.cpp rename to src/examples/rpp/doxygen/concat.cpp diff --git a/src/examples/doxygen/create.cpp b/src/examples/rpp/doxygen/create.cpp similarity index 100% rename from src/examples/doxygen/create.cpp rename to src/examples/rpp/doxygen/create.cpp diff --git a/src/examples/doxygen/delay.cpp b/src/examples/rpp/doxygen/delay.cpp similarity index 100% rename from src/examples/doxygen/delay.cpp rename to src/examples/rpp/doxygen/delay.cpp diff --git a/src/examples/doxygen/distinct_until_changed.cpp b/src/examples/rpp/doxygen/distinct_until_changed.cpp similarity index 100% rename from src/examples/doxygen/distinct_until_changed.cpp rename to src/examples/rpp/doxygen/distinct_until_changed.cpp diff --git a/src/examples/doxygen/do.cpp b/src/examples/rpp/doxygen/do.cpp similarity index 100% rename from src/examples/doxygen/do.cpp rename to src/examples/rpp/doxygen/do.cpp diff --git a/src/examples/doxygen/filter.cpp b/src/examples/rpp/doxygen/filter.cpp similarity index 100% rename from src/examples/doxygen/filter.cpp rename to src/examples/rpp/doxygen/filter.cpp diff --git a/src/examples/doxygen/first.cpp b/src/examples/rpp/doxygen/first.cpp similarity index 100% rename from src/examples/doxygen/first.cpp rename to src/examples/rpp/doxygen/first.cpp diff --git a/src/examples/doxygen/flat_map.cpp b/src/examples/rpp/doxygen/flat_map.cpp similarity index 100% rename from src/examples/doxygen/flat_map.cpp rename to src/examples/rpp/doxygen/flat_map.cpp diff --git a/src/examples/doxygen/from.cpp b/src/examples/rpp/doxygen/from.cpp similarity index 100% rename from src/examples/doxygen/from.cpp rename to src/examples/rpp/doxygen/from.cpp diff --git a/src/examples/doxygen/group_by.cpp b/src/examples/rpp/doxygen/group_by.cpp similarity index 100% rename from src/examples/doxygen/group_by.cpp rename to src/examples/rpp/doxygen/group_by.cpp diff --git a/src/examples/doxygen/interval.cpp b/src/examples/rpp/doxygen/interval.cpp similarity index 100% rename from src/examples/doxygen/interval.cpp rename to src/examples/rpp/doxygen/interval.cpp diff --git a/src/examples/doxygen/just.cpp b/src/examples/rpp/doxygen/just.cpp similarity index 100% rename from src/examples/doxygen/just.cpp rename to src/examples/rpp/doxygen/just.cpp diff --git a/src/examples/doxygen/last.cpp b/src/examples/rpp/doxygen/last.cpp similarity index 100% rename from src/examples/doxygen/last.cpp rename to src/examples/rpp/doxygen/last.cpp diff --git a/src/examples/doxygen/map.cpp b/src/examples/rpp/doxygen/map.cpp similarity index 100% rename from src/examples/doxygen/map.cpp rename to src/examples/rpp/doxygen/map.cpp diff --git a/src/examples/doxygen/merge.cpp b/src/examples/rpp/doxygen/merge.cpp similarity index 100% rename from src/examples/doxygen/merge.cpp rename to src/examples/rpp/doxygen/merge.cpp diff --git a/src/examples/doxygen/multicast.cpp b/src/examples/rpp/doxygen/multicast.cpp similarity index 100% rename from src/examples/doxygen/multicast.cpp rename to src/examples/rpp/doxygen/multicast.cpp diff --git a/src/examples/doxygen/observe_on.cpp b/src/examples/rpp/doxygen/observe_on.cpp similarity index 100% rename from src/examples/doxygen/observe_on.cpp rename to src/examples/rpp/doxygen/observe_on.cpp diff --git a/src/examples/doxygen/on_error_resume_next.cpp b/src/examples/rpp/doxygen/on_error_resume_next.cpp similarity index 100% rename from src/examples/doxygen/on_error_resume_next.cpp rename to src/examples/rpp/doxygen/on_error_resume_next.cpp diff --git a/src/examples/doxygen/publish.cpp b/src/examples/rpp/doxygen/publish.cpp similarity index 100% rename from src/examples/doxygen/publish.cpp rename to src/examples/rpp/doxygen/publish.cpp diff --git a/src/examples/doxygen/ref_count.cpp b/src/examples/rpp/doxygen/ref_count.cpp similarity index 100% rename from src/examples/doxygen/ref_count.cpp rename to src/examples/rpp/doxygen/ref_count.cpp diff --git a/src/examples/doxygen/repeat.cpp b/src/examples/rpp/doxygen/repeat.cpp similarity index 100% rename from src/examples/doxygen/repeat.cpp rename to src/examples/rpp/doxygen/repeat.cpp diff --git a/src/examples/doxygen/run_loop.cpp b/src/examples/rpp/doxygen/run_loop.cpp similarity index 100% rename from src/examples/doxygen/run_loop.cpp rename to src/examples/rpp/doxygen/run_loop.cpp diff --git a/src/examples/doxygen/sample.cpp b/src/examples/rpp/doxygen/sample.cpp similarity index 100% rename from src/examples/doxygen/sample.cpp rename to src/examples/rpp/doxygen/sample.cpp diff --git a/src/examples/doxygen/scan.cpp b/src/examples/rpp/doxygen/scan.cpp similarity index 100% rename from src/examples/doxygen/scan.cpp rename to src/examples/rpp/doxygen/scan.cpp diff --git a/src/examples/doxygen/skip.cpp b/src/examples/rpp/doxygen/skip.cpp similarity index 100% rename from src/examples/doxygen/skip.cpp rename to src/examples/rpp/doxygen/skip.cpp diff --git a/src/examples/doxygen/start_with.cpp b/src/examples/rpp/doxygen/start_with.cpp similarity index 100% rename from src/examples/doxygen/start_with.cpp rename to src/examples/rpp/doxygen/start_with.cpp diff --git a/src/examples/doxygen/subscribe_on.cpp b/src/examples/rpp/doxygen/subscribe_on.cpp similarity index 100% rename from src/examples/doxygen/subscribe_on.cpp rename to src/examples/rpp/doxygen/subscribe_on.cpp diff --git a/src/examples/doxygen/switch_map.cpp b/src/examples/rpp/doxygen/switch_map.cpp similarity index 100% rename from src/examples/doxygen/switch_map.cpp rename to src/examples/rpp/doxygen/switch_map.cpp diff --git a/src/examples/doxygen/switch_on_next.cpp b/src/examples/rpp/doxygen/switch_on_next.cpp similarity index 100% rename from src/examples/doxygen/switch_on_next.cpp rename to src/examples/rpp/doxygen/switch_on_next.cpp diff --git a/src/examples/doxygen/take.cpp b/src/examples/rpp/doxygen/take.cpp similarity index 100% rename from src/examples/doxygen/take.cpp rename to src/examples/rpp/doxygen/take.cpp diff --git a/src/examples/doxygen/take_last.cpp b/src/examples/rpp/doxygen/take_last.cpp similarity index 100% rename from src/examples/doxygen/take_last.cpp rename to src/examples/rpp/doxygen/take_last.cpp diff --git a/src/examples/doxygen/take_until.cpp b/src/examples/rpp/doxygen/take_until.cpp similarity index 100% rename from src/examples/doxygen/take_until.cpp rename to src/examples/rpp/doxygen/take_until.cpp diff --git a/src/examples/doxygen/take_while.cpp b/src/examples/rpp/doxygen/take_while.cpp similarity index 100% rename from src/examples/doxygen/take_while.cpp rename to src/examples/rpp/doxygen/take_while.cpp diff --git a/src/examples/doxygen/timeout.cpp b/src/examples/rpp/doxygen/timeout.cpp similarity index 100% rename from src/examples/doxygen/timeout.cpp rename to src/examples/rpp/doxygen/timeout.cpp diff --git a/src/examples/doxygen/trampoline.cpp b/src/examples/rpp/doxygen/trampoline.cpp similarity index 100% rename from src/examples/doxygen/trampoline.cpp rename to src/examples/rpp/doxygen/trampoline.cpp diff --git a/src/examples/doxygen/window.cpp b/src/examples/rpp/doxygen/window.cpp similarity index 100% rename from src/examples/doxygen/window.cpp rename to src/examples/rpp/doxygen/window.cpp diff --git a/src/examples/doxygen/with_latest_from.cpp b/src/examples/rpp/doxygen/with_latest_from.cpp similarity index 100% rename from src/examples/doxygen/with_latest_from.cpp rename to src/examples/rpp/doxygen/with_latest_from.cpp diff --git a/src/examples/package/CMakeLists.txt b/src/examples/rpp/package/CMakeLists.txt similarity index 100% rename from src/examples/package/CMakeLists.txt rename to src/examples/rpp/package/CMakeLists.txt diff --git a/src/examples/petri/CMakeLists.txt b/src/examples/rpp/petri/CMakeLists.txt similarity index 58% rename from src/examples/petri/CMakeLists.txt rename to src/examples/rpp/petri/CMakeLists.txt index d5426b0a2..ad9a53283 100644 --- a/src/examples/petri/CMakeLists.txt +++ b/src/examples/rpp/petri/CMakeLists.txt @@ -3,4 +3,4 @@ add_executable(petri_executor ) target_link_libraries(petri_executor PRIVATE rpp) -set_target_properties(petri_executor PROPERTIES FOLDER Examples) +set_target_properties(petri_executor PROPERTIES FOLDER Examples/rpp) diff --git a/src/examples/petri/petri.cpp b/src/examples/rpp/petri/petri.cpp similarity index 100% rename from src/examples/petri/petri.cpp rename to src/examples/rpp/petri/petri.cpp diff --git a/src/examples/sfml/CMakeLists.txt b/src/examples/rpp/sfml/CMakeLists.txt similarity index 100% rename from src/examples/sfml/CMakeLists.txt rename to src/examples/rpp/sfml/CMakeLists.txt diff --git a/src/examples/sfml/snake/CMakeLists.txt b/src/examples/rpp/sfml/snake/CMakeLists.txt similarity index 90% rename from src/examples/sfml/snake/CMakeLists.txt rename to src/examples/rpp/sfml/snake/CMakeLists.txt index 8600e8f02..06366b221 100644 --- a/src/examples/sfml/snake/CMakeLists.txt +++ b/src/examples/rpp/sfml/snake/CMakeLists.txt @@ -13,7 +13,7 @@ add_executable(${TARGET} ) target_link_libraries(${TARGET} PRIVATE rpp sfml-graphics) -set_target_properties(${TARGET} PROPERTIES FOLDER Examples/SFML) +set_target_properties(${TARGET} PROPERTIES FOLDER Examples/rpp/SFML) if (WIN32) add_custom_command (TARGET ${TARGET} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) diff --git a/src/examples/sfml/snake/canvas.cpp b/src/examples/rpp/sfml/snake/canvas.cpp similarity index 100% rename from src/examples/sfml/snake/canvas.cpp rename to src/examples/rpp/sfml/snake/canvas.cpp diff --git a/src/examples/sfml/snake/canvas.hpp b/src/examples/rpp/sfml/snake/canvas.hpp similarity index 100% rename from src/examples/sfml/snake/canvas.hpp rename to src/examples/rpp/sfml/snake/canvas.hpp diff --git a/src/examples/sfml/snake/main.cpp b/src/examples/rpp/sfml/snake/main.cpp similarity index 100% rename from src/examples/sfml/snake/main.cpp rename to src/examples/rpp/sfml/snake/main.cpp diff --git a/src/examples/sfml/snake/snake.cpp b/src/examples/rpp/sfml/snake/snake.cpp similarity index 100% rename from src/examples/sfml/snake/snake.cpp rename to src/examples/rpp/sfml/snake/snake.cpp diff --git a/src/examples/sfml/snake/snake.hpp b/src/examples/rpp/sfml/snake/snake.hpp similarity index 100% rename from src/examples/sfml/snake/snake.hpp rename to src/examples/rpp/sfml/snake/snake.hpp diff --git a/src/examples/sfml/snake/utils.hpp b/src/examples/rpp/sfml/snake/utils.hpp similarity index 100% rename from src/examples/sfml/snake/utils.hpp rename to src/examples/rpp/sfml/snake/utils.hpp diff --git a/src/examples/rppqt/CMakeLists.txt b/src/examples/rppqt/CMakeLists.txt new file mode 100644 index 000000000..63ad10165 --- /dev/null +++ b/src/examples/rppqt/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(interactive_window) +add_subdirectory(doxygen) diff --git a/src/examples/rppqt/doxygen/CMakeLists.txt b/src/examples/rppqt/doxygen/CMakeLists.txt new file mode 100644 index 000000000..3d13e37ec --- /dev/null +++ b/src/examples/rppqt/doxygen/CMakeLists.txt @@ -0,0 +1,11 @@ +file(GLOB_RECURSE FILES "*.cpp") + +foreach(SOURCE ${FILES}) + get_filename_component(BASE_NAME ${SOURCE} NAME_WE) + set(TARGET ${BASE_NAME}_doxygen_sample) + add_executable(${TARGET} ${SOURCE}) + target_link_libraries(${TARGET} PRIVATE rpp rppqt) + set_target_properties(${TARGET} PROPERTIES FOLDER Examples/rppqt/Doxygen) + rpp_add_qt_support_to_executable(${TARGET}) +endforeach() + diff --git a/src/examples/rppqt/doxygen/from_signal.cpp b/src/examples/rppqt/doxygen/from_signal.cpp new file mode 100644 index 000000000..465443ba7 --- /dev/null +++ b/src/examples/rppqt/doxygen/from_signal.cpp @@ -0,0 +1,33 @@ +#include +#include + +#include +#include +#include + +/** + * \example from_signal.cpp + **/ + +int main(int argc, char* argv[]) +{ + QApplication app{argc, argv}; + + //! [from_signal] + QTextEdit* text_edit = new QTextEdit(); + rppqt::source::from_signal(*text_edit, &QTextEdit::textChanged).map([&](const auto&) + { + return text_edit->toPlainText(); + }).subscribe([](const QString& text) { std::cout << "text changed: " << text.toStdString() << std::endl;}, + [](){ std::cout << "text_edit destroyed!" << std::endl; }); + text_edit->setText("123"); + text_edit->setText("temp"); + delete text_edit; + // Output: + // text changed: 123 + // text changed: temp + // text_edit destroyed! + //! [from_signal] + + return 0; +} diff --git a/src/examples/rppqt/interactive_window/CMakeLists.txt b/src/examples/rppqt/interactive_window/CMakeLists.txt new file mode 100644 index 000000000..8e9a3ec8f --- /dev/null +++ b/src/examples/rppqt/interactive_window/CMakeLists.txt @@ -0,0 +1,9 @@ +SET(TARGET interactive_window) +add_executable(${TARGET} + ${TARGET}.cpp +) + +target_link_libraries(${TARGET} PRIVATE rppqt ${RPP_QT_TARGET}::Widgets) +set_target_properties(${TARGET} PROPERTIES FOLDER Examples/rppqt) + +rpp_add_qt_support_to_executable(${TARGET}) \ No newline at end of file diff --git a/src/examples/rppqt/interactive_window/interactive_window.cpp b/src/examples/rppqt/interactive_window/interactive_window.cpp new file mode 100644 index 000000000..5b7c2eb12 --- /dev/null +++ b/src/examples/rppqt/interactive_window/interactive_window.cpp @@ -0,0 +1,106 @@ +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char* argv[]) +{ + QApplication app{argc, argv}; + QMainWindow window{}; + QVBoxLayout vbox{}; + QHBoxLayout hbox{}; + + QCheckBox lower_checkbox{"Insert all characters as upper"}; + QCheckBox remove_spaces_checkbox{"Insert text without spaces"}; + QTextEdit text_input{}; + text_input.setPlaceholderText("Text from this area would be inserted to result with effects based on flags"); + QPushButton push_text{"Push text to result"}; + QLabel result_separator{"Result: \n(Red text is preview of text which would be appended)"}; + QTextEdit result{}; + result.setReadOnly(true); + + hbox.addWidget(&lower_checkbox); + hbox.addWidget(&remove_spaces_checkbox); + vbox.addLayout(&hbox); + vbox.addWidget(&text_input); + vbox.addWidget(&push_text); + vbox.addWidget(&result_separator); + vbox.addWidget(&result); + + + window.setCentralWidget(new QWidget); + window.centralWidget()->setLayout(&vbox); + + window.show(); + + auto remove_spaces_obs = rppqt::source::from_signal(remove_spaces_checkbox, &QCheckBox::stateChanged). + start_with(static_cast(remove_spaces_checkbox.isChecked())); + auto lower_case_obs = rppqt::source::from_signal(lower_checkbox, &QCheckBox::stateChanged). + start_with(static_cast(lower_checkbox.isChecked())); + + auto text_to_append_obs = rppqt::source::from_signal(text_input, &QTextEdit::textChanged) + .map([&](const auto&) + { + return text_input.toPlainText(); + }) + .combine_latest([](const QString& current_string, bool is_remove_spaces) + { + return is_remove_spaces ? current_string.simplified().remove(' ') : current_string; + }, + std::move(remove_spaces_obs)) + .combine_latest([](const QString& current_string, bool is_lower) + { + return is_lower ? current_string.toUpper() : current_string; + }, + std::move(lower_case_obs)) + .tap([](const QString& text) { std::cout << "Text to append: " << text.toStdString() << std::endl; }) + .publish() + .ref_count(); + + + rppqt::source::from_signal(push_text, &QPushButton::pressed) + .with_latest_from([&](const auto&, const QString& text_to_append) + { + return text_to_append; + }, + text_to_append_obs) + .tap([&](const auto&) { text_input.setText(""); }) + .scan(QString{}, + [](QString&& seed, const QString& end_text) + { + seed.append(end_text); + return std::move(seed); + }) + .start_with(QString{}) + .combine_latest([&](const QString& current_text, const QString& preview_text_to_append) + { + return current_text + QString("%1").arg(preview_text_to_append); + }, + text_to_append_obs) + .subscribe([&](const QString& current_text) + { + result.setText(current_text); + }, + [](const std::exception_ptr& err) + { + try + { + std::rethrow_exception(err); + } + catch (const std::exception& e) + { + qCritical("Unhandled exception:\n%s", e.what()); + } + }); + + return app.exec(); +} diff --git a/src/rpp/rpp/fwd.hpp b/src/rpp/rpp/fwd.hpp index 3fd577c0c..d475e1d71 100644 --- a/src/rpp/rpp/fwd.hpp +++ b/src/rpp/rpp/fwd.hpp @@ -10,6 +10,11 @@ #pragma once +/** +* \defgroup rpp RPP +* \brief Rpp is Reactive extension for C++20 +*/ + #include #include #include diff --git a/src/rpp/rpp/observables.hpp b/src/rpp/rpp/observables.hpp index ea04e4f61..c5ce59c9d 100644 --- a/src/rpp/rpp/observables.hpp +++ b/src/rpp/rpp/observables.hpp @@ -14,6 +14,7 @@ * \defgroup observables Observables * \brief Observable is the source of any Reactive Stream. Observable provides ability to subscribe observer on some events. * \see https://reactivex.io/documentation/observable.html + * \ingroup rpp */ #include diff --git a/src/rpp/rpp/observers.hpp b/src/rpp/rpp/observers.hpp index be7d19fe6..679c040d2 100644 --- a/src/rpp/rpp/observers.hpp +++ b/src/rpp/rpp/observers.hpp @@ -13,6 +13,7 @@ /** * \defgroup observers Observers * \brief Observer subscribe on observable and obtains values provided by observable. + * \ingroup rpp */ #include diff --git a/src/rpp/rpp/operators.hpp b/src/rpp/rpp/operators.hpp index cb5e97aa2..1febf5363 100644 --- a/src/rpp/rpp/operators.hpp +++ b/src/rpp/rpp/operators.hpp @@ -14,6 +14,7 @@ * \defgroup operators Operators * \brief Operators is way to modify observables and extend with some extra custom logic * \see https://reactivex.io/documentation/operators.html +* \ingroup rpp */ /** diff --git a/src/rpp/rpp/schedulers.hpp b/src/rpp/rpp/schedulers.hpp index 6121105ce..4dec3db5e 100644 --- a/src/rpp/rpp/schedulers.hpp +++ b/src/rpp/rpp/schedulers.hpp @@ -14,6 +14,7 @@ * \defgroup schedulers Schedulers * \brief Scheduler is the way to introduce multi-threading in your application via RPP * \see https://reactivex.io/documentation/scheduler.html + * \ingroup rpp */ #include diff --git a/src/rpp/rpp/sources/from.hpp b/src/rpp/rpp/sources/from.hpp index 4f0d3f295..fa10e5151 100644 --- a/src/rpp/rpp/sources/from.hpp +++ b/src/rpp/rpp/sources/from.hpp @@ -213,7 +213,7 @@ auto just(T&& item, Ts&& ...items) requires (rpp::details::is_header_included auto from_iterable(std::ranges::range auto&& iterable, const TScheduler& scheduler /* = TScheduler{} */) requires rpp::details::is_header_included { @@ -236,7 +236,7 @@ auto from_iterable(std::ranges::range auto&& iterable, const TScheduler& schedul * * \ingroup creational_operators * \see https://reactivex.io/documentation/operators/from.html -*/ + */ template auto from_callable(std::invocable<> auto&& callable) requires rpp::details::is_header_included { diff --git a/src/rpp/rpp/subjects.hpp b/src/rpp/rpp/subjects.hpp index 00b276248..58fc1aafd 100644 --- a/src/rpp/rpp/subjects.hpp +++ b/src/rpp/rpp/subjects.hpp @@ -14,6 +14,7 @@ * \defgroup subjects Subjects * \brief Observable is the observable and observer at the same time. Uses as a bridge and for manual sending of values. * \see https://reactivex.io/documentation/subject.html + * \ingroup rpp */ #include \ No newline at end of file diff --git a/src/rppqt/CMakeLists.txt b/src/rppqt/CMakeLists.txt new file mode 100644 index 000000000..26f2404f4 --- /dev/null +++ b/src/rppqt/CMakeLists.txt @@ -0,0 +1,41 @@ +# ReactivePlusPlus library +# +# Copyright Aleksey Loginov 2022 - present. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# https://www.boost.org/LICENSE_1_0.txt) +# +# Project home: https://github.com/victimsnino/ReactivePlusPlus +# + +file(GLOB_RECURSE FILES "*.hpp") + +if(${CMAKE_VERSION} VERSION_LESS "3.19.0") + add_library(rppqt INTERFACE) +else() + add_library(rppqt INTERFACE ${FILES}) +endif() + +add_library(RPP::rppqt ALIAS rppqt) + +target_include_directories(rppqt ${RPP_WARNING_GUARD} + INTERFACE + "$" + # "$" +) + +target_link_libraries(rppqt INTERFACE Threads::Threads RPP::rpp) +target_compile_features(rppqt INTERFACE cxx_std_20) + +if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" OR CMAKE_CXX_COMPILER_ID MATCHES "GNU") + target_compile_options(rppqt INTERFACE -fsized-deallocation) +endif() + +foreach(FILE ${FILES}) + get_filename_component(PARENT_DIR "${FILE}" PATH) + file(RELATIVE_PATH REL_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/rppqt" ${PARENT_DIR}) + set(REL_PARENT_DIR "Header Files\\${REL_PARENT_DIR}") + + string(REPLACE "/" "\\" GROUP ${REL_PARENT_DIR}) + source_group("${GROUP}" FILES "${FILE}") +endforeach() diff --git a/src/rppqt/rppqt/fwd.hpp b/src/rppqt/rppqt/fwd.hpp new file mode 100644 index 000000000..fe87166d5 --- /dev/null +++ b/src/rppqt/rppqt/fwd.hpp @@ -0,0 +1,24 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#pragma once + +/** +* \defgroup rppqt RPPQT +* \brief RppQt is extension of RPP which enables support of Qt library. +*/ + +/** +* \defgroup qt_operators QT Operators +* \brief QT Operators is way to modify observables and extend with some extra custom logic but applied for QObjects +* \ingroup rppqt +*/ + +#include \ No newline at end of file diff --git a/src/rppqt/rppqt/rppqt.hpp b/src/rppqt/rppqt/rppqt.hpp new file mode 100644 index 000000000..0fefc0e95 --- /dev/null +++ b/src/rppqt/rppqt/rppqt.hpp @@ -0,0 +1,14 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#pragma once + +#include +#include \ No newline at end of file diff --git a/src/rppqt/rppqt/sources.hpp b/src/rppqt/rppqt/sources.hpp new file mode 100644 index 000000000..07d9842f4 --- /dev/null +++ b/src/rppqt/rppqt/sources.hpp @@ -0,0 +1,19 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#pragma once + +/** + * \defgroup qt_creational_operators QT Creational Operators + * \brief QT creational operators are operators that create new observable from QObjects + * \ingroup qt_operators + */ + +#include \ No newline at end of file diff --git a/src/rppqt/rppqt/sources/from_signal.hpp b/src/rppqt/rppqt/sources/from_signal.hpp new file mode 100644 index 000000000..52f7081db --- /dev/null +++ b/src/rppqt/rppqt/sources/from_signal.hpp @@ -0,0 +1,94 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#pragma once + +#include + +#include +#include + +#include + +IMPLEMENTATION_FILE(from_signal_qt_tag); + +namespace rppqt::observable::details +{ +template +struct from_signal_on_event_base +{ + using Subject = rpp::subjects::publish_subject; + using Subscriber = decltype(std::declval().get_subscriber()); + + from_signal_on_event_base(const Subscriber& subscriber) + : subscriber{subscriber} {} + + from_signal_on_event_base(Subscriber&& subscriber) + : subscriber{std::move(subscriber)} {} + + Subscriber subscriber; +}; + +template +struct from_signal_on_event : from_signal_on_event_base...>> +{ + template + void operator()(Vals&&... vals) const + { + from_signal_on_event_base...>>::subscriber.on_next(std::make_tuple(std::forward(vals)...)); + } +}; + +template +struct from_signal_on_event : from_signal_on_event_base> +{ + template Val> + void operator()(Val&& val) const + { + from_signal_on_event_base>::subscriber.on_next(std::forward(val)); + } +}; + +template<> +struct from_signal_on_event<> : from_signal_on_event_base +{ + void operator()() const + { + subscriber.on_next(rpp::utils::none{}); + } +}; + +} +namespace rppqt::observable +{ +/** + * \brief Creates rpp::specific_observable that emits a items from provided QT signal + * + * \param object is QObject which would emit signals + * \param signal is interested signal which would generate emissions for observable. Expected to obtain pointer to member function representing signal + * + * \par Examples: + * \snippet from_signal.cpp from_signal + * + * \ingroup qt_creational_operators + */ +template TSignalQObject, std::derived_from TObject, typename R,typename ...Args> +auto from_signal(const TObject& object, R (TSignalQObject::*signal)(Args...)) requires rpp::details::is_header_included +{ + using on_next_impl = details::from_signal_on_event; + const auto subj = typename on_next_impl::Subject{}; + + const auto subscriber = subj.get_subscriber(); + QObject::connect(&object, signal, on_next_impl{subscriber}); + QObject::connect(&object, &QObject::destroyed, [subscriber] { subscriber.on_completed(); }); + + return subj.get_observable(); +} +} // namespace rppqt::observable \ No newline at end of file diff --git a/src/rppqt/rppqt/sources/fwd.hpp b/src/rppqt/rppqt/sources/fwd.hpp new file mode 100644 index 000000000..c391f59a0 --- /dev/null +++ b/src/rppqt/rppqt/sources/fwd.hpp @@ -0,0 +1,31 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#pragma once + +#include + +class QObject; + +namespace rpp::details +{ +struct from_signal_qt_tag; +} // namespace rpp::details + +namespace rppqt::observable +{ +template TSignalQObject, std::derived_from TObject, typename R,typename ...Args> +auto from_signal(const TObject& object, R (TSignalQObject::*signal)(Args...)) requires rpp::details::is_header_included; +} // namespace rppqt::observable + +namespace rppqt +{ +namespace source = observable; +} // namespace rppqt \ No newline at end of file diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 54f6ee38c..1461ab1e3 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -8,25 +8,36 @@ # Project home: https://github.com/victimsnino/ReactivePlusPlus # -file(GLOB_RECURSE FILES "test_*.cpp") +add_subdirectory(utils) -foreach(SOURCE ${FILES}) - get_filename_component(BASE_NAME ${SOURCE} NAME_WE) +macro(rpp_register_tests module) + file(GLOB_RECURSE RPP_FILES "${module}/test_*.cpp") + foreach(SOURCE ${RPP_FILES}) + get_filename_component(BASE_NAME ${SOURCE} NAME_WE) - set(TARGET ${BASE_NAME}) + set(TARGET ${BASE_NAME}) - add_executable(${TARGET} ${SOURCE} mock_observer.hpp copy_count_tracker.hpp test_scheduler.hpp) - target_link_libraries(${TARGET} PRIVATE rpp Catch2::Catch2WithMain) - set_target_properties(${TARGET} PROPERTIES FOLDER Tests/Suites) + add_executable(${TARGET} ${SOURCE}) + target_link_libraries(${TARGET} PRIVATE Catch2::Catch2WithMain rpp_tests_utils ${module}) + set_target_properties(${TARGET} PROPERTIES FOLDER Tests/Suites/${module}) - add_test(NAME ${TARGET} COMMAND $ -r junit -o ${RPP_TEST_RESULTS_DIR}/${TARGET}.xml) + add_test(NAME ${TARGET} COMMAND $ -r junit -o ${RPP_TEST_RESULTS_DIR}/${TARGET}.xml) - if(MSVC) - target_compile_options(${TARGET} PRIVATE /W4 /WX) - else() - target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wpedantic -Werror -Wconversion) - endif() + if (${module} STREQUAL rppqt) + rpp_add_qt_support_to_executable(${TARGET}) + endif() -endforeach() + if(MSVC) + target_compile_options(${TARGET} PRIVATE /W4 /WX) + else() + target_compile_options(${TARGET} PRIVATE -Wall -Wextra -Wpedantic -Werror -Wconversion) + endif() + endforeach() +endmacro() +rpp_register_tests(rpp) + +if (RPP_BUILD_QT_CODE) + rpp_register_tests(rppqt) +endif() \ No newline at end of file diff --git a/src/tests/null.cpp b/src/tests/null.cpp deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/tests/test_buffer.cpp b/src/tests/rpp/test_buffer.cpp similarity index 100% rename from src/tests/test_buffer.cpp rename to src/tests/rpp/test_buffer.cpp diff --git a/src/tests/test_combine_latest.cpp b/src/tests/rpp/test_combine_latest.cpp similarity index 100% rename from src/tests/test_combine_latest.cpp rename to src/tests/rpp/test_combine_latest.cpp diff --git a/src/tests/test_concat.cpp b/src/tests/rpp/test_concat.cpp similarity index 100% rename from src/tests/test_concat.cpp rename to src/tests/rpp/test_concat.cpp diff --git a/src/tests/test_delay.cpp b/src/tests/rpp/test_delay.cpp similarity index 100% rename from src/tests/test_delay.cpp rename to src/tests/rpp/test_delay.cpp diff --git a/src/tests/test_distinct_until_changed.cpp b/src/tests/rpp/test_distinct_until_changed.cpp similarity index 100% rename from src/tests/test_distinct_until_changed.cpp rename to src/tests/rpp/test_distinct_until_changed.cpp diff --git a/src/tests/test_do.cpp b/src/tests/rpp/test_do.cpp similarity index 100% rename from src/tests/test_do.cpp rename to src/tests/rpp/test_do.cpp diff --git a/src/tests/test_filter.cpp b/src/tests/rpp/test_filter.cpp similarity index 100% rename from src/tests/test_filter.cpp rename to src/tests/rpp/test_filter.cpp diff --git a/src/tests/test_first.cpp b/src/tests/rpp/test_first.cpp similarity index 100% rename from src/tests/test_first.cpp rename to src/tests/rpp/test_first.cpp diff --git a/src/tests/test_flat_map.cpp b/src/tests/rpp/test_flat_map.cpp similarity index 100% rename from src/tests/test_flat_map.cpp rename to src/tests/rpp/test_flat_map.cpp diff --git a/src/tests/test_from.cpp b/src/tests/rpp/test_from.cpp similarity index 100% rename from src/tests/test_from.cpp rename to src/tests/rpp/test_from.cpp diff --git a/src/tests/test_group_by.cpp b/src/tests/rpp/test_group_by.cpp similarity index 100% rename from src/tests/test_group_by.cpp rename to src/tests/rpp/test_group_by.cpp diff --git a/src/tests/test_interval.cpp b/src/tests/rpp/test_interval.cpp similarity index 100% rename from src/tests/test_interval.cpp rename to src/tests/rpp/test_interval.cpp diff --git a/src/tests/test_last.cpp b/src/tests/rpp/test_last.cpp similarity index 100% rename from src/tests/test_last.cpp rename to src/tests/rpp/test_last.cpp diff --git a/src/tests/test_lift.cpp b/src/tests/rpp/test_lift.cpp similarity index 100% rename from src/tests/test_lift.cpp rename to src/tests/rpp/test_lift.cpp diff --git a/src/tests/test_map.cpp b/src/tests/rpp/test_map.cpp similarity index 100% rename from src/tests/test_map.cpp rename to src/tests/rpp/test_map.cpp diff --git a/src/tests/test_merge.cpp b/src/tests/rpp/test_merge.cpp similarity index 100% rename from src/tests/test_merge.cpp rename to src/tests/rpp/test_merge.cpp diff --git a/src/tests/test_multicast.cpp b/src/tests/rpp/test_multicast.cpp similarity index 100% rename from src/tests/test_multicast.cpp rename to src/tests/rpp/test_multicast.cpp diff --git a/src/tests/test_observable.cpp b/src/tests/rpp/test_observable.cpp similarity index 100% rename from src/tests/test_observable.cpp rename to src/tests/rpp/test_observable.cpp diff --git a/src/tests/test_observe_on.cpp b/src/tests/rpp/test_observe_on.cpp similarity index 100% rename from src/tests/test_observe_on.cpp rename to src/tests/rpp/test_observe_on.cpp diff --git a/src/tests/test_observer.cpp b/src/tests/rpp/test_observer.cpp similarity index 100% rename from src/tests/test_observer.cpp rename to src/tests/rpp/test_observer.cpp diff --git a/src/tests/test_on_error_resume_next.cpp b/src/tests/rpp/test_on_error_resume_next.cpp similarity index 100% rename from src/tests/test_on_error_resume_next.cpp rename to src/tests/rpp/test_on_error_resume_next.cpp diff --git a/src/tests/test_ref_count.cpp b/src/tests/rpp/test_ref_count.cpp similarity index 100% rename from src/tests/test_ref_count.cpp rename to src/tests/rpp/test_ref_count.cpp diff --git a/src/tests/test_repeat.cpp b/src/tests/rpp/test_repeat.cpp similarity index 100% rename from src/tests/test_repeat.cpp rename to src/tests/rpp/test_repeat.cpp diff --git a/src/tests/test_sample.cpp b/src/tests/rpp/test_sample.cpp similarity index 100% rename from src/tests/test_sample.cpp rename to src/tests/rpp/test_sample.cpp diff --git a/src/tests/test_scan.cpp b/src/tests/rpp/test_scan.cpp similarity index 100% rename from src/tests/test_scan.cpp rename to src/tests/rpp/test_scan.cpp diff --git a/src/tests/test_schedulers.cpp b/src/tests/rpp/test_schedulers.cpp similarity index 100% rename from src/tests/test_schedulers.cpp rename to src/tests/rpp/test_schedulers.cpp diff --git a/src/tests/test_skip.cpp b/src/tests/rpp/test_skip.cpp similarity index 100% rename from src/tests/test_skip.cpp rename to src/tests/rpp/test_skip.cpp diff --git a/src/tests/test_start_with.cpp b/src/tests/rpp/test_start_with.cpp similarity index 100% rename from src/tests/test_start_with.cpp rename to src/tests/rpp/test_start_with.cpp diff --git a/src/tests/test_subjects.cpp b/src/tests/rpp/test_subjects.cpp similarity index 100% rename from src/tests/test_subjects.cpp rename to src/tests/rpp/test_subjects.cpp diff --git a/src/tests/test_subscribe_on.cpp b/src/tests/rpp/test_subscribe_on.cpp similarity index 100% rename from src/tests/test_subscribe_on.cpp rename to src/tests/rpp/test_subscribe_on.cpp diff --git a/src/tests/test_subscriber.cpp b/src/tests/rpp/test_subscriber.cpp similarity index 100% rename from src/tests/test_subscriber.cpp rename to src/tests/rpp/test_subscriber.cpp diff --git a/src/tests/test_subscriptions.cpp b/src/tests/rpp/test_subscriptions.cpp similarity index 100% rename from src/tests/test_subscriptions.cpp rename to src/tests/rpp/test_subscriptions.cpp diff --git a/src/tests/test_switch_map.cpp b/src/tests/rpp/test_switch_map.cpp similarity index 100% rename from src/tests/test_switch_map.cpp rename to src/tests/rpp/test_switch_map.cpp diff --git a/src/tests/test_switch_on_next.cpp b/src/tests/rpp/test_switch_on_next.cpp similarity index 100% rename from src/tests/test_switch_on_next.cpp rename to src/tests/rpp/test_switch_on_next.cpp diff --git a/src/tests/test_take.cpp b/src/tests/rpp/test_take.cpp similarity index 100% rename from src/tests/test_take.cpp rename to src/tests/rpp/test_take.cpp diff --git a/src/tests/test_take_last.cpp b/src/tests/rpp/test_take_last.cpp similarity index 100% rename from src/tests/test_take_last.cpp rename to src/tests/rpp/test_take_last.cpp diff --git a/src/tests/test_take_until.cpp b/src/tests/rpp/test_take_until.cpp similarity index 100% rename from src/tests/test_take_until.cpp rename to src/tests/rpp/test_take_until.cpp diff --git a/src/tests/test_take_while.cpp b/src/tests/rpp/test_take_while.cpp similarity index 100% rename from src/tests/test_take_while.cpp rename to src/tests/rpp/test_take_while.cpp diff --git a/src/tests/test_timeout.cpp b/src/tests/rpp/test_timeout.cpp similarity index 100% rename from src/tests/test_timeout.cpp rename to src/tests/rpp/test_timeout.cpp diff --git a/src/tests/test_window.cpp b/src/tests/rpp/test_window.cpp similarity index 100% rename from src/tests/test_window.cpp rename to src/tests/rpp/test_window.cpp diff --git a/src/tests/test_with_latest_from.cpp b/src/tests/rpp/test_with_latest_from.cpp similarity index 100% rename from src/tests/test_with_latest_from.cpp rename to src/tests/rpp/test_with_latest_from.cpp diff --git a/src/tests/rppqt/test_from_signal.cpp b/src/tests/rppqt/test_from_signal.cpp new file mode 100644 index 000000000..d7771ea1d --- /dev/null +++ b/src/tests/rppqt/test_from_signal.cpp @@ -0,0 +1,139 @@ +// ReactivePlusPlus library +// +// Copyright Aleksey Loginov 2022 - present. +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) +// +// Project home: https://github.com/victimsnino/ReactivePlusPlus +// + +#include + +struct TestQObject : public QObject +{ + Q_OBJECT +public: + using QObject::QObject; + + void EmitSingleValueSignal(int v) + { + emit SingleValueSignal(v); + } + + void EmitMultipleValueSignal(int v, double d, const std::string& s) + { + emit MultipleValueSignal(v, d, s); + } + + void EmitNoValueSignal() + { + emit NoValueSignal(); + } + +Q_SIGNALS: + void SingleValueSignal(int v); + void MultipleValueSignal(int v, double d, const std::string& s); + void NoValueSignal(); +}; + +#include "test_from_signal.moc" + + +#include "copy_count_tracker.hpp" +#include "mock_observer.hpp" + +#include + +#include + +SCENARIO("from_signal can see object value from object signal", "[source][from][rppqt]") +{ + GIVEN("qobject with signal with 1 argument and observable from signal from this object") + { + mock_observer mock_observer{}; + auto testobject = std::make_unique(); + auto obs = rppqt::source::from_signal(*testobject, &TestQObject::SingleValueSignal); + WHEN("emit signal, subscribe on it and emit signal") + { + testobject->EmitSingleValueSignal(1); + obs.subscribe(mock_observer); + testobject->EmitSingleValueSignal(2); + THEN("subscriber sees only emission after subscribe") + { + CHECK(mock_observer.get_received_values() == std::vector{2}); + CHECK(mock_observer.get_on_error_count() == 0); + CHECK(mock_observer.get_on_completed_count() == 0); + } + AND_WHEN("object destroyed") + { + testobject.reset(); + THEN("subscriber sees completion") + { + CHECK(mock_observer.get_received_values() == std::vector{2}); + CHECK(mock_observer.get_on_error_count() == 0); + CHECK(mock_observer.get_on_completed_count() == 1); + } + } + } + WHEN("object destroyed before subscription") + { + testobject.reset(); + AND_WHEN("then subscriber subscribed") + { + obs.subscribe(mock_observer); + + THEN("subscriber sees only completion") + { + CHECK(mock_observer.get_received_values() == std::vector{}); + CHECK(mock_observer.get_on_error_count() == 0); + CHECK(mock_observer.get_on_completed_count() == 1); + } + } + } + } +} + +SCENARIO("from_signal sends tuple if multiple values", "[source][from][rppqt]") +{ + GIVEN("object with signal with multiple values and observable from this signal") + { + mock_observer> mock_observer{}; + auto testobject = std::make_unique(); + auto obs = rppqt::source::from_signal(*testobject, &TestQObject::MultipleValueSignal); + WHEN("subscribe on it and emit signal") + { + obs.subscribe(mock_observer); + testobject->EmitMultipleValueSignal(1, 2, "31"); + THEN("subscriber sees values") + { + CHECK(mock_observer.get_received_values() == std::vector>{std::tuple{1, 2.0, "31"}}); + CHECK(mock_observer.get_on_error_count() == 0); + CHECK(mock_observer.get_on_completed_count() == 0); + } + } + } +} + +SCENARIO("from_signal sends special struct if no args in signal", "[source][from][rppqt]") +{ + GIVEN("object with signal with zero values and observable from this signal") + { + mock_observer mock_observer{}; + auto testobject = std::make_unique(); + auto obs = rppqt::source::from_signal(*testobject, &TestQObject::NoValueSignal); + WHEN("subscribe on it and emit signal") + { + obs.subscribe(mock_observer); + testobject->EmitNoValueSignal(); + THEN("subscriber sees values") + { + CHECK(mock_observer.get_received_values().size() == 1); + CHECK(mock_observer.get_on_error_count() == 0); + CHECK(mock_observer.get_on_completed_count() == 0); + } + } + } +} + + diff --git a/src/tests/utils/CMakeLists.txt b/src/tests/utils/CMakeLists.txt new file mode 100644 index 000000000..38191e13f --- /dev/null +++ b/src/tests/utils/CMakeLists.txt @@ -0,0 +1,3 @@ +add_library(rpp_tests_utils INTERFACE) +target_include_directories(rpp_tests_utils INTERFACE .) +target_link_libraries(rpp_tests_utils INTERFACE rpp) \ No newline at end of file diff --git a/src/tests/copy_count_tracker.hpp b/src/tests/utils/copy_count_tracker.hpp similarity index 100% rename from src/tests/copy_count_tracker.hpp rename to src/tests/utils/copy_count_tracker.hpp diff --git a/src/tests/mock_observer.hpp b/src/tests/utils/mock_observer.hpp similarity index 100% rename from src/tests/mock_observer.hpp rename to src/tests/utils/mock_observer.hpp diff --git a/src/tests/test_scheduler.hpp b/src/tests/utils/test_scheduler.hpp similarity index 100% rename from src/tests/test_scheduler.hpp rename to src/tests/utils/test_scheduler.hpp