diff --git a/.github/workflows/DevCI.yml b/.github/workflows/DevCI.yml index 378cf395..0db033a4 100644 --- a/.github/workflows/DevCI.yml +++ b/.github/workflows/DevCI.yml @@ -15,9 +15,9 @@ jobs: strategy: fail-fast: false matrix: - os: [ ubuntu-22.04, macos-12, windows-2022 ] + os: [ ubuntu-latest, macos-latest, windows-latest ] library_type: [ HeaderOnly, Static, Shared ] - std: [ 17, 20 ] + std: [ 17, 20, 23 ] build_type: [ Release ] runs-on: ${{matrix.os}} diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index 82f8a637..39909686 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -16,58 +16,98 @@ jobs: fail-fast: false matrix: compiler: - - { tool: gcc, ver: 7 } - - { tool: gcc, ver: 8 } - - { tool: gcc, ver: 9 } - - { tool: gcc, ver: 10 } - - { tool: gcc, ver: 11 } - - { tool: gcc, ver: 12 } - - { tool: gcc, ver: 13 } - - { tool: clang, ver: 7 } - - { tool: clang, ver: 8 } - - { tool: clang, ver: 9 } - - { tool: clang, ver: 10 } - - { tool: clang, ver: 11 } - - { tool: clang, ver: 12 } - - { tool: clang, ver: 13 } - - { tool: clang, ver: 14 } - - { tool: clang, ver: 15 } + - { name: GCC, ver: 7 } + - { name: GCC, ver: 8 } + - { name: GCC, ver: 9 } + - { name: GCC, ver: 10 } + - { name: GCC, ver: 11 } + - { name: GCC, ver: 12 } + - { name: GCC, ver: 13 } + - { name: GCC, ver: 14 } + - { name: Clang, ver: 7 } + - { name: Clang, ver: 8 } + - { name: Clang, ver: 9 } + - { name: Clang, ver: 10 } + - { name: Clang, ver: 11 } + - { name: Clang, ver: 12 } + - { name: Clang, ver: 13 } + - { name: Clang, ver: 14 } + - { name: Clang, ver: 15 } + - { name: Clang, ver: 16 } + - { name: Clang, ver: 17 } + - { name: Clang, ver: 18 } build_type: [ Release ] - os: [ ubuntu-20.04, ubuntu-22.04 ] - std: [ 17 ] + os: [ ubuntu-20.04, ubuntu-22.04, ubuntu-24.04 ] + std: [ 17, 20, 23 ] library_type: [ Static ] include: - - compiler: { tool: gcc } + - compiler: { name: GCC } cxx: g++ cc: gcc + packages: 'gcc-{0} g++-{0}' generator: Ninja - - compiler: { tool: clang } + - compiler: { name: Clang } cxx: clang++ cc: clang + packages: 'clang-{0}' generator: Ninja exclude: - - { os: ubuntu-20.04, compiler: { tool: gcc, ver: 12 } } - - { os: ubuntu-20.04, compiler: { tool: gcc, ver: 13 } } - - { os: ubuntu-20.04, compiler: { tool: clang, ver: 13 } } - - { os: ubuntu-20.04, compiler: { tool: clang, ver: 14 } } - - { os: ubuntu-20.04, compiler: { tool: clang, ver: 15 } } - - { os: ubuntu-22.04, compiler: { tool: gcc, ver: 7 } } - - { os: ubuntu-22.04, compiler: { tool: gcc, ver: 8 } } - - { os: ubuntu-22.04, compiler: { tool: clang, ver: 7 } } - - { os: ubuntu-22.04, compiler: { tool: clang, ver: 8 } } - - { os: ubuntu-22.04, compiler: { tool: clang, ver: 9 } } - - { os: ubuntu-22.04, compiler: { tool: clang, ver: 10 } } + - { os: ubuntu-20.04, compiler: { name: GCC, ver: 11 } } + - { os: ubuntu-20.04, compiler: { name: GCC, ver: 12 } } + - { os: ubuntu-20.04, compiler: { name: GCC, ver: 13 } } + - { os: ubuntu-20.04, compiler: { name: GCC, ver: 14 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 13 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 14 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 15 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 16 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 17 } } + - { os: ubuntu-20.04, compiler: { name: Clang, ver: 18 } } + - { os: ubuntu-22.04, compiler: { name: GCC, ver: 7 } } + - { os: ubuntu-22.04, compiler: { name: GCC, ver: 8 } } + - { os: ubuntu-22.04, compiler: { name: GCC, ver: 13 } } + - { os: ubuntu-22.04, compiler: { name: GCC, ver: 14 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 7 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 8 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 9 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 10 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 16 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 17 } } + - { os: ubuntu-22.04, compiler: { name: Clang, ver: 18 } } + - { os: ubuntu-24.04, compiler: { name: GCC, ver: 7 } } + - { os: ubuntu-24.04, compiler: { name: GCC, ver: 8 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 7 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 8 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 9 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 10 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 11 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 12 } } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 13 } } + - { compiler: { name: GCC, ver: 7 }, std: 20 } + - { compiler: { name: GCC, ver: 7 }, std: 23 } + - { compiler: { name: GCC, ver: 8 }, std: 23 } + - { compiler: { name: GCC, ver: 9 }, std: 23 } + - { compiler: { name: GCC, ver: 10 }, std: 23 } + - { compiler: { name: Clang, ver: 7 }, std: 20 } + - { compiler: { name: Clang, ver: 7 }, std: 23 } + - { compiler: { name: Clang, ver: 8 }, std: 20 } + - { compiler: { name: Clang, ver: 8 }, std: 23 } + - { compiler: { name: Clang, ver: 9 }, std: 23 } + - { compiler: { name: Clang, ver: 10 }, std: 23 } + - { compiler: { name: Clang, ver: 11 }, std: 23 } + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 14 }, std: 20 } # gtest broken for now + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 14 }, std: 23 } # gtest broken for now + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 15 }, std: 20 } # gtest broken for now + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 15 }, std: 23 } # gtest broken for now + - { os: ubuntu-24.04, compiler: { name: Clang, ver: 17 }, std: 23 } # gtest broken for now runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - name: Create Build Environment - env: - PACKAGES: ${{ matrix.compiler.tool == 'gcc' && format('gcc-{0} g++-{0}', matrix.compiler.ver) || format('{0}-{1}', matrix.compiler.tool, matrix.compiler.ver) }} run: | sudo apt update - sudo apt install ${{env.PACKAGES}} ninja-build -y + sudo apt install ${{format(matrix.packages, matrix.compiler.ver)}} ninja-build -y sudo apt install locales-all cmake -E make_directory ${{runner.workspace}}/build diff --git a/.github/workflows/MacOs.yml b/.github/workflows/MacOs.yml index 588d501b..3a15791b 100644 --- a/.github/workflows/MacOs.yml +++ b/.github/workflows/MacOs.yml @@ -2,11 +2,11 @@ name: MacOs on: pull_request: - branches: [ "main" ] + branches: [ 'main' ] paths-ignore: - - "Docs/**" - - ".readthedocs.yaml" - - "README.md" + - 'Docs/**' + - '.readthedocs.yaml' + - 'README.md' jobs: test: @@ -16,36 +16,66 @@ jobs: fail-fast: false matrix: compiler: [ - { tool: apple-clang }, - { tool: gcc, ver: 10 }, - { tool: gcc, ver: 11 }, - { tool: gcc, ver: 12 } ] + { name: 'Apple Clang' }, + { name: Clang, ver: 12 }, + { name: Clang, ver: 13 }, + { name: Clang, ver: 14 }, + { name: Clang, ver: 15 }, + { name: Clang, ver: 16 }, + { name: Clang, ver: 17 }, + { name: Clang, ver: 18 }, + { name: GCC, ver: 10 }, + { name: GCC, ver: 11 }, + { name: GCC, ver: 12 }, + { name: GCC, ver: 13 }, + { name: GCC, ver: 14 } ] build_type: [ Release ] - os: [ macos-12 ] - std: [ 17 ] + os: [ macos-12, macos-13, macos-14 ] + std: [ 17, 20, 23 ] library_type: [ Static ] include: - - compiler: { tool: gcc } - cxx: g++ - cc: gcc - - compiler: { tool: apple-clang } + - compiler: { name: 'Apple Clang' } cxx: '' cc: '' + generator: Ninja + - compiler: { name: Clang } + cxx: clang++ + cc: clang + package: llvm + generator: Ninja + - compiler: { name: GCC } + cxx: 'g++-{0}' + cc: 'gcc-{0}' + package: gcc + generator: Ninja + exclude: + - { os: macos-12, compiler: { name: GCC, ver: 13 } } + - { os: macos-13, compiler: { name: GCC, ver: 10 } } + - { os: macos-13, compiler: { name: GCC, ver: 11 } } + - { os: macos-13, compiler: { name: GCC, ver: 13 } } + - { os: macos-14, compiler: { name: GCC, ver: 10 } } + - { compiler: { name: GCC, ver: 10 }, std: 23 } runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - name: Create Build Environment - if: matrix.compiler.tool != 'apple-clang' + if: matrix.compiler.name != 'Apple Clang' run: | brew update && - brew install ${{matrix.compiler.tool}}@${{matrix.compiler.ver}} ninja + brew install ${{matrix.package}}@${{matrix.compiler.ver}} ninja cmake -E make_directory ${{runner.workspace}}/build - echo "CXX=${{matrix.cxx}}-${{matrix.compiler.ver}}" >> $GITHUB_ENV - echo "CC=${{matrix.cc}}-${{matrix.compiler.ver}}" >> $GITHUB_ENV + + - name: Try Setup LLVM Environment + if: matrix.compiler.name == 'Clang' + run: | + echo "PATH=$(brew --prefix llvm@${{matrix.compiler.ver}})/bin:${PATH}" >> $GITHUB_ENV - name: Configure + env: + CXX: ${{format(matrix.cxx, matrix.compiler.ver)}} + CC: ${{format(matrix.cc, matrix.compiler.ver)}} run: cmake -B ${{runner.workspace}}/build -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_STANDARD=${{matrix.std}} -D_7BIT_DI_LIBRARY_TYPE=${{matrix.library_type}} -D_7BIT_DI_BUILD_ALL_TESTS=ON - name: Build diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 1aff30c6..7f34cc54 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -2,14 +2,14 @@ name: Windows on: pull_request: - branches: [ "main" ] + branches: [ 'main' ] paths-ignore: - - "Docs/**" - - ".readthedocs.yaml" - - "README.md" + - 'Docs/**' + - '.readthedocs.yaml' + - 'README.md' env: - CHOCO_LIB_DIR: C:\\ProgramData\\chocolatey\\lib + CHOCO_MINGW_BIN_DIR: C:\ProgramData\chocolatey\lib\mingw\tools\install\mingw64\bin jobs: test: @@ -19,60 +19,79 @@ jobs: fail-fast: false matrix: compiler: [ - { tool: msvc, ver: 141 }, - { tool: msvc, ver: 142 }, - { tool: mingw, ver: 7.5.0 }, - { tool: mingw, ver: 8.5.0 }, - { tool: mingw, ver: 9.4.0 }, - { tool: mingw, ver: 10.3.0 }, - { tool: mingw, ver: 11.2.0 }, - { tool: mingw, ver: 12.2.0 }, - { tool: mingw, ver: 13.2.0 }, - { tool: LLVM, ver: 11.1.0 }, - { tool: LLVM, ver: 12.0.1 }, - { tool: LLVM, ver: 13.0.1 }, - { tool: LLVM, ver: 14.0.6 }, - { tool: LLVM, ver: 15.0.7 }, - { tool: LLVM, ver: 16.0.6 }, - { tool: LLVM, ver: 17.0.6 }, - { tool: LLVM, ver: 18.1.2 } ] + { name: MSVC, ver: 141 }, + { name: MSVC, ver: 142 }, + { name: MSVC, ver: 143 }, + { name: MinGW, ver: 7.5.0 }, + { name: MinGW, ver: 8.5.0 }, + { name: MinGW, ver: 9.4.0 }, + { name: MinGW, ver: 10.3.0 }, + { name: MinGW, ver: 11.2.0 }, + { name: MinGW, ver: 12.2.0 }, + { name: Clang, ver: 11.1.0 }, + { name: Clang, ver: 12.0.1 }, + { name: Clang, ver: 13.0.1 }, + { name: Clang, ver: 14.0.6 }, + { name: Clang, ver: 15.0.7 }, + { name: Clang, ver: 16.0.6 }, + { name: Clang, ver: 17.0.6 }, + { name: Clang, ver: 18.1.2 }, + { name: Clang, ver: 18.1.8 } ] build_type: [ Release ] - os: [ windows-2019 ] - std: [ 17 ] + os: [ windows-2019, windows-2022 ] + std: [ 17, 20, 23 ] library_type: [ Static ] include: - - compiler: { tool: mingw } + - compiler: { name: MSVC } + cxx: '' + cc: '' + generator: '' + - compiler: { name: MinGW } cxx: g++ cc: gcc + package: mingw generator: 'MinGW Makefiles' - - compiler: { tool: LLVM } + - compiler: { name: Clang } cxx: clang++ cc: clang + package: LLVM generator: Ninja - - compiler: { tool: msvc } - cxx: '' - cc: '' - generator: '' + exclude: + - { os: windows-2019, compiler: { name: MSVC, ver: 143 } } + - { os: windows-2022, compiler: { name: MSVC, ver: 141 } } + - { os: windows-2022, compiler: { name: Clang, ver: 11.1.0 } } + - { os: windows-2022, compiler: { name: Clang, ver: 12.0.1 } } + - { os: windows-2022, compiler: { name: Clang, ver: 13.0.1 } } + - { os: windows-2022, compiler: { name: Clang, ver: 14.0.6 } } + - { os: windows-2022, compiler: { name: Clang, ver: 15.0.7 } } + - { os: windows-2022, compiler: { name: Clang, ver: 16.0.6 } } + - { compiler: { name: MSVC, ver: 141 }, std: 23 } + - { compiler: { name: MinGW, ver: 7.5.0 }, std: 20 } + - { compiler: { name: MinGW, ver: 7.5.0 }, std: 23 } + - { compiler: { name: MinGW, ver: 8.5.0 }, std: 23 } + - { compiler: { name: MinGW, ver: 9.4.0 }, std: 23 } + - { compiler: { name: MinGW, ver: 10.3.0 }, std: 23 } + - { compiler: { name: Clang, ver: 11.1.0 }, std: 23 } runs-on: ${{matrix.os}} steps: - uses: actions/checkout@v4 - name: Create Build Environment - if: matrix.compiler.tool != 'msvc' + if: matrix.compiler.name != 'MSVC' shell: bash - run: choco install ${{matrix.compiler.tool}} --version ${{matrix.compiler.ver}} --allow-downgrade -y && choco install ninja && cmake -E make_directory ${{runner.workspace}}/build + run: choco install ${{matrix.package}} --version ${{matrix.compiler.ver}} --allow-downgrade -y && choco install ninja && cmake -E make_directory ${{runner.workspace}}/build - - name: Update Sys Path - if: matrix.compiler.tool == 'mingw' - run: ("${{env.CHOCO_LIB_DIR}}\\mingw\\tools\\install\\mingw64\\bin;" + (Get-Content -Path $env:GITHUB_PATH)) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 + - name: Try Setup MinGW Environment + if: matrix.compiler.name == 'MinGW' + run: ("${{env.CHOCO_MINGW_BIN_DIR}};" + (Get-Content -Path $env:GITHUB_PATH)) | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 shell: pwsh - name: Configure env: CXX: ${{matrix.cxx}} CC: ${{matrix.cc}} - PARAMETERS: ${{ matrix.compiler.tool == 'msvc' && format('-A x64 -T v{0}', matrix.compiler.ver) || format('-G "{0}"', matrix.generator) }} + PARAMETERS: ${{ matrix.compiler.name == 'MSVC' && format('-A x64 -T v{0}', matrix.compiler.ver) || format('-G "{0}"', matrix.generator) }} run: cmake -B ${{runner.workspace}}/build ${{env.PARAMETERS}} -DCMAKE_BUILD_TYPE=${{matrix.build_type}} -DCMAKE_CXX_STANDARD=${{matrix.std}} -D_7BIT_DI_LIBRARY_TYPE=${{matrix.library_type}} -D_7BIT_DI_BUILD_ALL_TESTS=ON - name: Build diff --git a/CMakeLists.txt b/CMakeLists.txt index 0a394f1d..46a35dd0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.15.0) set(_7BIT_DI_LIBRARY 7bitDI) set(_7BIT_DI_VERSION_MAJOR 3) -set(_7BIT_DI_VERSION_MINOR 3) +set(_7BIT_DI_VERSION_MINOR 4) set(_7BIT_DI_VERSION_PATCH 0) set(_7BIT_DI_VERSION ${_7BIT_DI_VERSION_MAJOR}.${_7BIT_DI_VERSION_MINOR}.${_7BIT_DI_VERSION_PATCH}) diff --git a/Docs/basic-guides/services-lifetime.rst b/Docs/basic-guides/services-lifetime.rst index 5f19a2ea..47ceb9e4 100644 --- a/Docs/basic-guides/services-lifetime.rst +++ b/Docs/basic-guides/services-lifetime.rst @@ -28,19 +28,10 @@ Service can be registered as a singleton, scoped, or transient. :language: C++ .. code-block:: console - :caption: Output - - Singletons comparison - rootProvider == rootProvider: 1 - rootProvider == scopedProvider: 1 - scopedProvider == scopedProvider: 1 - - Scoped comparison - rootProvider == rootProvider: 1 - rootProvider == scopedProvider: 0 - scopedProvider == scopedProvider: 1 - - Transient comparison - rootProvider == rootProvider: 0 - rootProvider == scopedProvider: 0 - scopedProvider == scopedProvider: 0 + :caption: Possible Output + + Service Addresses Table + rootProvider scopedProvider + singleton 0x600003ed0088 0x600003ed0088 + scoped 0x600003ed00a8 0x600003ed00f8 + transient 0x600003ed00c0 0x600003ed0110 diff --git a/Docs/conf.py b/Docs/conf.py index e646c4f4..3c3a0348 100644 --- a/Docs/conf.py +++ b/Docs/conf.py @@ -12,7 +12,7 @@ def createIfNotExists(path): project = "7bitDI" copyright = "2023, 7BitCoder Sylwester Dawida" author = "Sylwester Dawida" -version = "3.3.0" +version = "3.4.0" extensions = [ "sphinx.ext.autodoc", diff --git a/Docs/examples.rst b/Docs/examples.rst index d7fc164f..3f69d75b 100644 --- a/Docs/examples.rst +++ b/Docs/examples.rst @@ -5,6 +5,9 @@ Examples :maxdepth: 2 :titlesonly: - examples/simple - examples/logger examples/cli + examples/logger + examples/message-bus + examples/permissions + examples/simple + examples/tester diff --git a/Docs/examples/message-bus.rst b/Docs/examples/message-bus.rst new file mode 100644 index 00000000..c98d8e49 --- /dev/null +++ b/Docs/examples/message-bus.rst @@ -0,0 +1,6 @@ +MessageBus +======================================== + +.. literalinclude:: ../../Examples/MessageBus.cpp + :caption: Examples/MessageBus + :language: C++ diff --git a/Docs/examples/permissions.rst b/Docs/examples/permissions.rst new file mode 100644 index 00000000..29bf8004 --- /dev/null +++ b/Docs/examples/permissions.rst @@ -0,0 +1,6 @@ +Permissions +======================================== + +.. literalinclude:: ../../Examples/Permissions.cpp + :caption: Examples/Permissions + :language: C++ diff --git a/Docs/examples/tester.rst b/Docs/examples/tester.rst new file mode 100644 index 00000000..8be964e4 --- /dev/null +++ b/Docs/examples/tester.rst @@ -0,0 +1,6 @@ +Tester +======================================== + +.. literalinclude:: ../../Examples/Tester.cpp + :caption: Examples/Tester + :language: C++ diff --git a/Docs/getting-started.rst b/Docs/getting-started.rst index b9429492..cff1334b 100644 --- a/Docs/getting-started.rst +++ b/Docs/getting-started.rst @@ -46,7 +46,7 @@ Installation FetchContent_Declare( 7bitDI GIT_REPOSITORY https://github.com/7bitcoder/7bitDI.git - GIT_TAG v3.3.0 + GIT_TAG v3.4.0 ) FetchContent_MakeAvailable(7bitDI) @@ -58,7 +58,7 @@ Installation .. code-block:: Txt [requires] - 7bitdi/3.3.0 + 7bitdi/3.4.0 change the version to newer if available, then run the command: diff --git a/Docs/reference/di/details/helpers.rst b/Docs/reference/di/details/helpers.rst index fae80b0f..bcb33dfc 100644 --- a/Docs/reference/di/details/helpers.rst +++ b/Docs/reference/di/details/helpers.rst @@ -6,8 +6,9 @@ sb::di::details - Helpers :titlesonly: helpers/circulardependencyguard.rst + helpers/ctorinjector.rst + helpers/formatter.rst + helpers/functorinjector.rst helpers/scopedguard.rst - helpers/servicectorinvoker.rst - helpers/servicectorparamconverter.rst - helpers/servicefactoryinvoker.rst - helpers/serviceparamprovider.rst + helpers/serviceextractor.rst + helpers/servicegetter.rst diff --git a/Docs/reference/di/details/helpers/servicectorinvoker.rst b/Docs/reference/di/details/helpers/ctorinjector.rst similarity index 50% rename from Docs/reference/di/details/helpers/servicectorinvoker.rst rename to Docs/reference/di/details/helpers/ctorinjector.rst index 0ca4a25e..5f4ce643 100644 --- a/Docs/reference/di/details/helpers/servicectorinvoker.rst +++ b/Docs/reference/di/details/helpers/ctorinjector.rst @@ -1,6 +1,6 @@ -ServiceCtorInvoker +CtorInjector ======================================== -.. doxygenclass:: sb::di::details::ServiceCtorInvoker +.. doxygenclass:: sb::di::details::CtorInjector :members: :undoc-members: diff --git a/Docs/reference/di/details/helpers/formatter.rst b/Docs/reference/di/details/helpers/formatter.rst new file mode 100644 index 00000000..ce41bfd2 --- /dev/null +++ b/Docs/reference/di/details/helpers/formatter.rst @@ -0,0 +1,6 @@ +Formatter +======================================== + +.. doxygenclass:: sb::di::details::Formatter + :members: + :undoc-members: diff --git a/Docs/reference/di/details/helpers/functorinjector.rst b/Docs/reference/di/details/helpers/functorinjector.rst new file mode 100644 index 00000000..55a22760 --- /dev/null +++ b/Docs/reference/di/details/helpers/functorinjector.rst @@ -0,0 +1,6 @@ +FunctorInjector +======================================== + +.. doxygenclass:: sb::di::details::FunctorInjector + :members: + :undoc-members: diff --git a/Docs/reference/di/details/helpers/servicectorparamconverter.rst b/Docs/reference/di/details/helpers/servicectorparamconverter.rst deleted file mode 100644 index 7ca80397..00000000 --- a/Docs/reference/di/details/helpers/servicectorparamconverter.rst +++ /dev/null @@ -1,6 +0,0 @@ -ServiceCtorParamConverter -======================================== - -.. doxygenclass:: sb::di::details::ServiceCtorParamConverter - :members: - :undoc-members: diff --git a/Docs/reference/di/utils/serviceextractor.rst b/Docs/reference/di/details/helpers/serviceextractor.rst similarity index 63% rename from Docs/reference/di/utils/serviceextractor.rst rename to Docs/reference/di/details/helpers/serviceextractor.rst index bd157743..9b851a24 100644 --- a/Docs/reference/di/utils/serviceextractor.rst +++ b/Docs/reference/di/details/helpers/serviceextractor.rst @@ -1,6 +1,6 @@ ServiceExtractor ======================================== -.. doxygenstruct:: sb::di::ServiceExtractor +.. doxygenclass:: sb::di::details::ServiceExtractor :members: :undoc-members: diff --git a/Docs/reference/di/details/helpers/servicefactoryinvoker.rst b/Docs/reference/di/details/helpers/servicefactoryinvoker.rst deleted file mode 100644 index b4f0d09b..00000000 --- a/Docs/reference/di/details/helpers/servicefactoryinvoker.rst +++ /dev/null @@ -1,14 +0,0 @@ -ServiceFactoryInvoker -======================================== - -.. doxygenclass:: sb::di::details::ServiceFactoryInvokerInternals::FunctorInvoker - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceFactoryInvokerInternals::BadFunctor - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceFactoryInvokerInternals::FunctorInvokerResolver - :members: - :undoc-members: diff --git a/Docs/reference/di/details/helpers/servicegetter.rst b/Docs/reference/di/details/helpers/servicegetter.rst new file mode 100644 index 00000000..443fee1c --- /dev/null +++ b/Docs/reference/di/details/helpers/servicegetter.rst @@ -0,0 +1,26 @@ +ServiceGetter +======================================== + +.. doxygenstruct:: sb::di::details::ServiceGetter + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::ServiceGetter< T * > + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::ServiceGetter< T & > + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::ServiceGetter< std::unique_ptr< T > > + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::ServiceGetter< std::vector< T * > > + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::ServiceGetter< std::vector< std::unique_ptr< T > > > + :members: + :undoc-members: diff --git a/Docs/reference/di/details/helpers/serviceparamprovider.rst b/Docs/reference/di/details/helpers/serviceparamprovider.rst deleted file mode 100644 index 13b0a416..00000000 --- a/Docs/reference/di/details/helpers/serviceparamprovider.rst +++ /dev/null @@ -1,26 +0,0 @@ -ServiceParamProvider -======================================== - -.. doxygenstruct:: sb::di::details::ServiceParamProvider - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceParamProvider< T * > - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceParamProvider< T & > - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceParamProvider< std::unique_ptr< T > > - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceParamProvider< std::vector< T * > > - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::details::ServiceParamProvider< std::vector< std::unique_ptr< T > > > - :members: - :undoc-members: diff --git a/Docs/reference/di/details/utils.rst b/Docs/reference/di/details/utils.rst index 5bc91f36..9f7f5354 100644 --- a/Docs/reference/di/details/utils.rst +++ b/Docs/reference/di/details/utils.rst @@ -14,3 +14,4 @@ sb::di::details - Utils utils/require.rst utils/requiredescriptor.rst utils/requireinstance.rst + utils/string.rst diff --git a/Docs/reference/di/details/utils/ctorparamsnumber.rst b/Docs/reference/di/details/utils/ctorparamsnumber.rst deleted file mode 100644 index c6e51c65..00000000 --- a/Docs/reference/di/details/utils/ctorparamsnumber.rst +++ /dev/null @@ -1,4 +0,0 @@ -CtorParamsNumber -======================================== - -.. doxygenfunction:: sb::di::details::ctorParamsNumber diff --git a/Docs/reference/di/details/utils/meta.rst b/Docs/reference/di/details/utils/meta.rst index 07ef210e..5c9848bf 100644 --- a/Docs/reference/di/details/utils/meta.rst +++ b/Docs/reference/di/details/utils/meta.rst @@ -21,6 +21,14 @@ Meta :members: :undoc-members: +.. doxygenstruct:: sb::di::details::IsInitializerList + :members: + :undoc-members: + +.. doxygenstruct:: sb::di::details::IsInitializerList< std::initializer_list< T > > + :members: + :undoc-members: + .. doxygenstruct:: sb::di::details::RemoveUniquePtr :members: :undoc-members: diff --git a/Docs/reference/di/details/utils/string.rst b/Docs/reference/di/details/utils/string.rst new file mode 100644 index 00000000..bd1ca968 --- /dev/null +++ b/Docs/reference/di/details/utils/string.rst @@ -0,0 +1,6 @@ +String +======================================== + +.. doxygenstruct:: sb::di::details::String + :members: + :undoc-members: diff --git a/Docs/reference/di/exceptions.rst b/Docs/reference/di/exceptions.rst index 218d287c..44822cef 100644 --- a/Docs/reference/di/exceptions.rst +++ b/Docs/reference/di/exceptions.rst @@ -9,11 +9,7 @@ Exceptions :members: :undoc-members: -.. doxygenstruct:: sb::di::InvalidServiceException - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::CannotReleaseServiceException +.. doxygenstruct:: sb::di::ServiceRegisterException :members: :undoc-members: @@ -21,19 +17,15 @@ Exceptions :members: :undoc-members: -.. doxygenstruct:: sb::di::ServiceNotFoundException - :members: - :undoc-members: - -.. doxygenstruct:: sb::di::ServiceAlreadyRegisteredException +.. doxygenstruct:: sb::di::CannotReleaseServiceException :members: :undoc-members: -.. doxygenstruct:: sb::di::ServiceBaseTypeMismatchException +.. doxygenstruct:: sb::di::ServiceNotFoundException :members: :undoc-members: -.. doxygenstruct:: sb::di::ServiceLifeTimeMismatchException +.. doxygenstruct:: sb::di::InvalidServiceException :members: :undoc-members: diff --git a/Docs/reference/di/utils.rst b/Docs/reference/di/utils.rst index e2968e41..dc53f9be 100644 --- a/Docs/reference/di/utils.rst +++ b/Docs/reference/di/utils.rst @@ -8,4 +8,4 @@ sb::di - Utils utils/globalservices utils/injected utils/register - utils/serviceextractor + utils/serviceinlineextractor diff --git a/Docs/reference/di/utils/serviceinlineextractor.rst b/Docs/reference/di/utils/serviceinlineextractor.rst new file mode 100644 index 00000000..5c69f30c --- /dev/null +++ b/Docs/reference/di/utils/serviceinlineextractor.rst @@ -0,0 +1,6 @@ +ServiceInlineExtractor +======================================== + +.. doxygenstruct:: sb::di::ServiceInlineExtractor + :members: + :undoc-members: diff --git a/Examples/Guides/ServicesLifeTime.cpp b/Examples/Guides/ServicesLifeTime.cpp index a1723f2e..c02bd04d 100644 --- a/Examples/Guides/ServicesLifeTime.cpp +++ b/Examples/Guides/ServicesLifeTime.cpp @@ -1,4 +1,5 @@ #include +#include #include using namespace sb::di; @@ -13,24 +14,6 @@ struct TransientService { }; -template -bool compareServicePtrs(ServiceProvider &provider1, ServiceProvider &provider2) -{ - return CreateService ? provider1.createService() == provider2.createService() - : &provider1.getService() == &provider2.getService(); -} - -template -void compareServices(ServiceProvider &root, ServiceProvider &scoped) -{ - std::cout << "rootProvider \t == rootProvider:\t"; - std::cout << compareServicePtrs(root, root) << std::endl; - std::cout << "rootProvider \t == scopedProvider:\t"; - std::cout << compareServicePtrs(root, scoped) << std::endl; - std::cout << "scopedProvider \t == scopedProvider:\t"; - std::cout << compareServicePtrs(scoped, scoped) << std::endl; -} - int main() { ServiceProvider rootProvider = ServiceCollection{} @@ -39,20 +22,26 @@ int main() .addTransient() .buildServiceProvider(); - // Accessing Services - SingletonService &singleton = rootProvider.getService(); - ScopedService &scoped = rootProvider.getService(); - std::unique_ptr transient = rootProvider.createService(); + // Accessing services + SingletonService &rootSingleton = rootProvider.getService(); + ScopedService &rootScoped = rootProvider.getService(); + std::unique_ptr rootTransient = rootProvider.createService(); ServiceProvider scopedProvider = rootProvider.createScope(); - std::cout << std::endl << "Singletons comparison" << std::endl; - compareServices(rootProvider, scopedProvider); + // Accessing scoped services + SingletonService &singleton = scopedProvider.getService(); + ScopedService &scoped = scopedProvider.getService(); + std::unique_ptr transient = scopedProvider.createService(); - std::cout << std::endl << "Scoped comparison" << std::endl; - compareServices(rootProvider, scopedProvider); + assert(&rootSingleton == &singleton); // The same service for root and scoped provider + assert(&rootScoped != &scoped); // Different service for root and scoped provider + assert(rootTransient != transient); // Always different service (trivially different unique ptrs) - std::cout << std::endl << "Transient comparison" << std::endl; - compareServices(rootProvider, scopedProvider); + std::cout << "Service Addresses Table" << std::endl; + std::cout << "\t\t\trootProvider\tscopedProvider" << std::endl; + std::cout << "singleton\t" << &rootSingleton << "\t" << &singleton << std::endl; + std::cout << "scoped\t\t" << &rootScoped << "\t" << &scoped << std::endl; + std::cout << "transient\t" << rootTransient.get() << "\t" << transient.get() << std::endl; return 0; } diff --git a/Examples/MessageBus.cpp b/Examples/MessageBus.cpp new file mode 100644 index 00000000..47c6f174 --- /dev/null +++ b/Examples/MessageBus.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include + +using namespace sb::di; +using namespace std::chrono_literals; + +struct IMessageBus +{ + virtual void send(const std::any &message) = 0; + + virtual void on(std::type_index typeId, std::function callback) = 0; + + template void on(F f) + { + on(typeid(T), [f](const std::any &msg) { f(std::any_cast(msg)); }); + } + + virtual ~IMessageBus() = default; +}; + +class MessageBus final : public IMessageBus +{ + std::unordered_map>> _callbacks; + + public: + void send(const std::any &message) override + { + if (const auto it = _callbacks.find(message.type()); it != _callbacks.end()) + { + for (const auto &callback : it->second) + { + callback(message); + } + } + } + + void on(const std::type_index typeId, std::function callback) override + { + _callbacks[typeId].emplace_back(std::move(callback)); + } +}; + +struct TickMessage +{ + int number; + std::chrono::milliseconds delay; +}; + +class SenderService +{ + IMessageBus &_messageBus; + + public: + explicit SenderService(IMessageBus &messageBus) : _messageBus(messageBus) {} + + void run(const int ticksCount, const std::chrono::milliseconds delay) const + { + for (int i = 1; i <= ticksCount; ++i) + { + const auto realDelay = sleepFor(delay); + _messageBus.send(TickMessage{i, realDelay}); + } + } + + private: + [[nodiscard]] std::chrono::milliseconds sleepFor(const std::chrono::milliseconds delay) const + { + const auto start = std::chrono::high_resolution_clock::now(); + std::this_thread::sleep_for(delay); + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - start); + } +}; + +class ReceiverService +{ + IMessageBus &_messageBus; + + public: + explicit ReceiverService(IMessageBus &messageBus) : _messageBus(messageBus) + { + _messageBus.on([&](const TickMessage &message) { onReceived(message); }); + } + + void onReceived(const TickMessage &message) const + { + std::cout << "Received tick message no: " << message.number << ", delay: " << message.delay.count() << "ms" + << std::endl; + } +}; + +int main() +{ + ServiceProvider provider = ServiceCollection{} + .addSingleton() + .addSingleton() + .addSingleton() + .buildServiceProvider(); + + const auto &receiver = provider.getService(); // force construction + const auto &sender = provider.getService(); + sender.run(5, 200ms); + return 0; +} diff --git a/Examples/Permissions.cpp b/Examples/Permissions.cpp new file mode 100644 index 00000000..4391e9b3 --- /dev/null +++ b/Examples/Permissions.cpp @@ -0,0 +1,143 @@ +#include +#include + +using namespace sb::di; + +enum class Permission : int +{ + NONE = 0, + READ = 1, + UPDATE = 2, + ALL = READ | UPDATE +}; + +struct IUserPermission +{ + virtual Permission getPermissions(int userId) = 0; + + virtual ~IUserPermission() = default; +}; + +struct UserPermission final : IUserPermission +{ + // normally fetch from database + Permission getPermissions(int userId) override { return Permission::READ; } +}; + +struct AdminPermission final : IUserPermission +{ + Permission getPermissions(int userId) override { return Permission::ALL; } +}; + +struct Data +{ + std::string name; + std::string payload; +}; + +struct IDataService +{ + virtual const Data &getData() = 0; + virtual const Data &updateData(Data &&data) = 0; + + virtual ~IDataService() = default; +}; + +// normally service would interact with database +class DataService final : public IDataService +{ + IUserPermission &_userPermission; + Data _data = {"test name", "It is a long established fact that a reader will be distracted"}; + + public: + explicit DataService(IUserPermission &userPermission) : _userPermission(userPermission) {} + + const Data &getData() override + { + assertPermission(Permission::READ); + return _data; + } + + const Data &updateData(Data &&data) override + { + assertPermission(Permission::UPDATE); + _data = std::move(data); + return _data; + } + + private: + void assertPermission(const Permission permission) + { + auto userPermission = _userPermission.getPermissions(1); + if (int check = static_cast(userPermission) & static_cast(permission); + static_cast(check) != permission) + { + throw std::runtime_error("Insufficient permissions"); + } + } +}; + +class Application +{ + IDataService *_dataService; + + public: + explicit Application(IDataService *dataService) : _dataService(dataService) {} + + void run(const int argc, char *argv[]) + { + try + { + processCmd(argc, argv); + } + catch (std::exception &e) + { + std::cout << "Error: " << e.what(); + } + } + + private: + void processCmd(const int argc, char *argv[]) + { + const std::string_view operation = argc > 1 ? argv[1] : "read"; + if (operation == "read") + { + printData(_dataService->getData()); + } + else if (operation == "update") + { + if (argc < 4) + { + throw std::invalid_argument("Books args not provided"); + } + printData(_dataService->updateData({argv[2], argv[3]})); + } + else + { + throw std::invalid_argument("Command not recognized"); + } + } + + void printData(const Data &book) + { + std::cout << "Name: " << book.name << ", Payload: " << book.payload << std::endl; + } +}; + +int main(int argc, char *argv[]) +{ + ServiceCollection services; + services.addSingleton(); + services.addSingleton(); + services.addSingleton(); + + if (const auto appMode = std::getenv("APP_MODE"); appMode && appMode == std::string_view{"DEVELOPMENT"}) + { + services.removeAll(); + services.addSingleton(); + } + auto provider = services.buildServiceProvider(); + + auto &application = provider.getService(); + application.run(argc, argv); +} diff --git a/Examples/Tester.cpp b/Examples/Tester.cpp new file mode 100644 index 00000000..162b9c2a --- /dev/null +++ b/Examples/Tester.cpp @@ -0,0 +1,120 @@ +#include +#include + +using namespace sb::di; + +struct TestFailed final : std::runtime_error +{ + explicit TestFailed(const std::string &message) : std::runtime_error(message) {} +}; + +class Expect +{ + public: + template void static equal(const L &lhs, const R &rhs) + { + throwIfFalse(lhs == rhs, "Expected values to be equal"); + } + template void static notEqual(const L &lhs, const R &rhs) + { + throwIfFalse(lhs != rhs, "Expected values not to be equal"); + } + + template void static truthy(const T &value) + { + throwIfFalse(static_cast(value), "Expected value to be true"); + } + template void static falsy(const T &value) + { + throwIfFalse(!static_cast(value), "Expected value to be false"); + } + + private: + static void throwIfFalse(const bool value, const std::string_view message) + { + if (!value) + { + throw TestFailed(std::string{message}); + } + } +}; + +struct ITest +{ + virtual std::string name() = 0; + + virtual void run() = 0; + + virtual ~ITest() = default; +}; + +class TestRunner +{ + std::vector tests; + + public: + explicit TestRunner(std::vector tests) : tests(std::move(tests)) {} + + int run() + { + const size_t total = tests.size(); + size_t passed = 0; + for (const auto test : tests) + { + passed += runTest(*test); + } + std::cout << "Tests run: " << passed << "/" << total << std::endl; + return passed != total; + } + + private: + bool runTest(ITest &test) + { + try + { + test.run(); + std::cout << "Test '" + test.name() + "' passed" << std::endl; + return true; + } + catch (std::exception &fail) + { + std::cerr << "Test '" + test.name() + "' failed: " << fail.what() << std::endl; + } + return false; + } +}; + +template struct Test : ITest, RegisterScoped +{ + std::string name() override { return typeid(TestImpl).name(); } +}; + +struct AddTest final : Test +{ + void run() override + { + Expect::equal(2 + 2, 4); + Expect::notEqual(2 + 1, 4); + Expect::falsy(1 + -1); + Expect::truthy(1 + 2); + } +}; + +struct MultiplyTest final : Test +{ + void run() override + { + Expect::equal(2 * 2, 4); + Expect::notEqual(2 * 3, 4); + Expect::falsy(1 * 0); + Expect::truthy(1 * 2); + } +}; + +int main() +{ + ServiceProvider provider = GlobalServices::instance().addSingleton().buildServiceProvider(); + + auto &runner = provider.getService(); + return runner.run(); +} diff --git a/Include/SevenBit/DI/CmakeDef.hpp b/Include/SevenBit/DI/CmakeDef.hpp index 56f8e83e..0b7a3c95 100644 --- a/Include/SevenBit/DI/CmakeDef.hpp +++ b/Include/SevenBit/DI/CmakeDef.hpp @@ -13,5 +13,5 @@ #endif #define _7BIT_DI_VERSION_MAJOR 3 -#define _7BIT_DI_VERSION_MINOR 3 +#define _7BIT_DI_VERSION_MINOR 4 /* #undef _7BIT_DI_VERSION_PATCH */ diff --git a/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorList.hpp b/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorList.hpp index 57885670..f5c538ed 100644 --- a/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorList.hpp +++ b/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorList.hpp @@ -14,7 +14,10 @@ namespace sb::di::details checkBaseType(descriptor); checkKey(descriptor); checkAlias(descriptor); - checkLifeTime(descriptor); + if (!isAlias()) + { + checkLifeTime(descriptor); + } } OneOrList::add(std::move(descriptor)); } @@ -29,18 +32,18 @@ namespace sb::di::details INLINE void ServiceDescriptorList::checkBaseType(const ServiceDescriptor &descriptor) const { - if (getServiceTypeId() != descriptor.getServiceTypeId()) + if (getServiceTypeId() != descriptor.getServiceTypeId()) // should not happen { - throw InjectorException{"Service base type does not match"}; + throw ServiceRegisterException{descriptor.getImplementationTypeId(), "Service base type does not match"}; } } INLINE void ServiceDescriptorList::checkKey(const ServiceDescriptor &descriptor) const { if (static_cast(getServiceKey()) != static_cast(descriptor.getServiceKey()) || - (getServiceKey() && *getServiceKey() != *descriptor.getServiceKey())) + (getServiceKey() && *getServiceKey() != *descriptor.getServiceKey())) // should not happen { - throw InjectorException{"Service key does not match"}; + throw ServiceRegisterException{descriptor.getImplementationTypeId(), "Service key does not match"}; } } @@ -48,15 +51,21 @@ namespace sb::di::details { if (isAlias() != descriptor.isAlias()) { - throw ServiceAliasMismatchException{descriptor.getImplementationTypeId(), getServiceTypeId(), isAlias()}; + auto reason = details::String::fmt( + "Service was expected to be registered as {}, like other services registered with this base type '{}'", + (isAlias() ? "alias" : "not alias"), getServiceTypeId().name()); + throw ServiceRegisterException{descriptor.getImplementationTypeId(), reason}; } } INLINE void ServiceDescriptorList::checkLifeTime(const ServiceDescriptor &descriptor) const { - if (!isAlias() && !descriptor.isAlias() && getLifeTime() != descriptor.getLifeTime()) + if (getLifeTime() != descriptor.getLifeTime()) { - throw ServiceLifeTimeMismatchException{descriptor.getImplementationTypeId(), getServiceTypeId()}; + auto reason = details::String::fmt( + "Service was expected to be registered as {}, like other services registered with this base type '{}'", + getLifeTime().toString(), getServiceTypeId().name()); + throw ServiceRegisterException{descriptor.getImplementationTypeId(), reason}; } } } // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorsMap.hpp b/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorsMap.hpp index 2ad5b5be..cbe3cfbe 100644 --- a/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorsMap.hpp +++ b/Include/SevenBit/DI/Details/Containers/Impl/ServiceDescriptorsMap.hpp @@ -40,7 +40,7 @@ namespace sb::di::details const ServiceId id{descriptor.getImplementationTypeId(), descriptor.getServiceKey()}; if (_registeredServices->count(id)) { - throw ServiceAlreadyRegisteredException{descriptor.getImplementationTypeId()}; + throw ServiceRegisterException{descriptor.getImplementationTypeId(), "Service was already registered"}; } addDescriptor(std::move(descriptor)); _registeredServices->insert(id); diff --git a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp index 365eb3f6..975eb298 100644 --- a/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp +++ b/Include/SevenBit/DI/Details/Core/Impl/ServiceInstanceProvider.hpp @@ -138,7 +138,7 @@ namespace sb::di::details INLINE ServiceInstanceList *ServiceInstanceProvider::findInstances(const ServiceId &id) { - const auto singletonsFirst = getOptions().searchInSigletonsFirst; + const auto singletonsFirst = getOptions().searchInSingletonsFirst; auto &first = singletonsFirst ? _root.getSingletons() : _scoped; auto &second = singletonsFirst ? _scoped : _root.getSingletons(); const auto instances = first.findInstances(id); diff --git a/Include/SevenBit/DI/Details/Factories/ServiceFactory.hpp b/Include/SevenBit/DI/Details/Factories/ServiceFactory.hpp index a31f88bd..9c3f3564 100644 --- a/Include/SevenBit/DI/Details/Factories/ServiceFactory.hpp +++ b/Include/SevenBit/DI/Details/Factories/ServiceFactory.hpp @@ -14,15 +14,18 @@ namespace sb::di::details { template class ServiceFactory final : public IServiceFactory { + private: + using Injector = CtorInjector; + public: IServiceInstance::Ptr createInstance(ServiceProvider &serviceProvider, const bool inPlaceRequest) const override { - CtorInjector injector{serviceProvider}; + Injector injector{serviceProvider}; if (inPlaceRequest) { - return injector.template makeUnique>(); + return injector([](auto... ctorParams) { return std::make_unique>(ctorParams...); }); } - return injector.template makeUnique>(); + return injector([](auto... ctorParams) { return std::make_unique>(ctorParams...); }); } }; diff --git a/Include/SevenBit/DI/Details/Factories/ServiceFcnFactory.hpp b/Include/SevenBit/DI/Details/Factories/ServiceFcnFactory.hpp index 68ee336b..ac0c2a2d 100644 --- a/Include/SevenBit/DI/Details/Factories/ServiceFcnFactory.hpp +++ b/Include/SevenBit/DI/Details/Factories/ServiceFcnFactory.hpp @@ -15,40 +15,30 @@ namespace sb::di::details { template class ServiceFcnFactory final : public IServiceFactory { + using Injector = FunctorInjector; + using ReturnType = decltype(Injector{nullptr, nullptr}()); + + static_assert(IsUniquePtrV || IsInPlaceServiceV || notSupportedType, + "Service factory return type must be std::unique_ptr or copyable/movable object"); + mutable FactoryFcn _factoryFunction; public: - using FunctorReturnType = typename FunctorInjector::ReturnType; - using ServiceType = RemoveUniquePtrT; + using ServiceType = RemoveUniquePtrT; explicit ServiceFcnFactory(FactoryFcn &&factoryFunction) : _factoryFunction{std::move(factoryFunction)} {} IServiceInstance::Ptr createInstance(ServiceProvider &serviceProvider, const bool inPlaceRequest) const override { - FunctorInjector injector{_factoryFunction, serviceProvider}; - if constexpr (IsUniquePtrV) - { - return std::make_unique>(injector.call()); - } - else if constexpr (IsInPlaceServiceV) + Injector injector{_factoryFunction, serviceProvider}; + if constexpr (!IsUniquePtrV) { if (inPlaceRequest) { - return std::make_unique>(injector.call()); + return std::make_unique>(injector()); } - return std::make_unique>(injector.call()); } - else - { - badFunctor(); - return nullptr; - } - } - - static void badFunctor() - { - static_assert(notSupportedType, - "Service factory return type must be std::unique_ptr or copyable/movable object"); + return std::make_unique>(injector()); } }; } // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Helpers/CtorInjector.hpp b/Include/SevenBit/DI/Details/Helpers/CtorInjector.hpp index 20148b9c..cf53fd63 100644 --- a/Include/SevenBit/DI/Details/Helpers/CtorInjector.hpp +++ b/Include/SevenBit/DI/Details/Helpers/CtorInjector.hpp @@ -4,28 +4,48 @@ #include "SevenBit/DI/LibraryConfig.hpp" -#include "SevenBit/DI/Details/Helpers/ServiceCtorArgExtractor.hpp" -#include "SevenBit/DI/Details/Utils/CtorParamsNumber.hpp" +#include "SevenBit/DI/Details/Helpers/ServiceExtractor.hpp" #include "SevenBit/DI/ServiceProvider.hpp" namespace sb::di::details { template class CtorInjector { + template + static constexpr auto parametersNumber(std::size_t) -> decltype(T{ServiceExtractor{nullptr, Ns}...}, 0) + { + return sizeof...(Ns); + } + + template static constexpr std::size_t parametersNumber(...) + { + if constexpr (sizeof...(Ns) > _7BIT_DI_CTOR_PARAMS_LIMIT) + { + static_assert( + details::notSupportedType, + "Proper constructor for specified type was not found, reached maximum constructor params number " + "limit, to bump limit define macro _7BIT_DI_CTOR_PARAMS_LIMIT with new value before including lib"); + return 0; + } + else + { + return parametersNumber(0); + } + } + ServiceProvider &_serviceProvider; public: + static constexpr std::size_t paramsNumber = parametersNumber(0); + explicit CtorInjector(ServiceProvider &serviceProvider) : _serviceProvider(serviceProvider) {} - template auto makeUnique() - { - return makeUnique(std::make_index_sequence()>{}); - }; + template auto operator()(F &&f) { return injectInto(f, std::make_index_sequence{}); }; private: - template auto makeUnique(std::index_sequence) + template auto injectInto(F &&f, std::index_sequence) { - return std::make_unique(ServiceCtorArgExtractor{_serviceProvider, Index}...); + return f(ServiceExtractor(&_serviceProvider, ParamNumber)...); } }; diff --git a/Include/SevenBit/DI/Details/Helpers/Formatter.hpp b/Include/SevenBit/DI/Details/Helpers/Formatter.hpp new file mode 100644 index 00000000..8bd9c93e --- /dev/null +++ b/Include/SevenBit/DI/Details/Helpers/Formatter.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include +#include +#include +#include + +#include "SevenBit/DI/LibraryConfig.hpp" + +namespace sb::di::details +{ + class EXPORT Formatter + { + std::string_view formatString; + std::string_view::size_type current = 0; + std::string result; + + public: + explicit Formatter(std::string_view formatString); + + template bool format(Args &&...args) + { + volatile auto processed = (... && process(args)); + append(formatString.substr(current)); + return processed; + } + + std::string getResult() &&; + + private: + template bool process(Arg &&arg) + { + if (auto start = formatString.find_first_of('{', current); start != std::string_view::npos) + { + append(formatString.substr(current, start - current)); + const auto end = formatString.find_first_of('}', start++); + if (end == std::string_view::npos) + { + throw std::runtime_error("Invalid fmt string '{' should end with '}'"); + } + append(std::forward(arg), formatString.substr(start, end - start)); + current = end + 1; + return true; + } + return false; + } + + void append(const char *arg, std::string_view fmt = ""); + void append(const std::string &arg, std::string_view fmt = ""); + void append(std::string_view arg, std::string_view fmt = ""); + void append(int arg, std::string_view fmt = ""); + void append(long arg, std::string_view fmt = ""); + void append(long long arg, std::string_view fmt = ""); + void append(unsigned arg, std::string_view fmt = ""); + void append(unsigned long arg, std::string_view fmt = ""); + void append(unsigned long long arg, std::string_view fmt = ""); + void append(float arg, std::string_view fmt = ""); + void append(double arg, std::string_view fmt = ""); + void append(long double arg, std::string_view fmt = ""); + }; +} // namespace sb::di::details + +#ifdef _7BIT_DI_ADD_IMPL +#include "SevenBit/DI/Details/Helpers/Impl/Formatter.hpp" +#endif diff --git a/Include/SevenBit/DI/Details/Helpers/FunctorInjector.hpp b/Include/SevenBit/DI/Details/Helpers/FunctorInjector.hpp index fdb2b8d2..74d88778 100644 --- a/Include/SevenBit/DI/Details/Helpers/FunctorInjector.hpp +++ b/Include/SevenBit/DI/Details/Helpers/FunctorInjector.hpp @@ -2,53 +2,28 @@ #include "SevenBit/DI/LibraryConfig.hpp" -#include "SevenBit/DI/Details/Helpers/ServiceGetter.hpp" +#include "ServiceGetter.hpp" namespace sb::di::details { - template class InternalFunctorInjector + template class FunctorInjector { + static_assert(IsFunctorV || notSupportedType, "Object is not functor/lambda"); + F &_functor; ServiceProvider &_serviceProvider; public: - using ReturnType = R; - - InternalFunctorInjector(F &functor, ServiceProvider &serviceProvider) - : _functor(functor), _serviceProvider(serviceProvider) - { - } - - R call() { return _functor(ServiceGetter::get(_serviceProvider)...); } - }; - - template struct InternalBadFunctor - { - using ReturnType = int; - - InternalBadFunctor(F &, ServiceProvider &) - { - static_assert(notSupportedType, "Object is not functor/lambda"); - } + FunctorInjector(F &functor, ServiceProvider &provider) : _functor(functor), _serviceProvider(provider) {} + FunctorInjector(F *functor, ServiceProvider *provider) : FunctorInjector(*functor, *provider) {} - int call() { return 0; } - }; + auto operator()() { return matchCall(&F::operator()); } - template struct FunctorInjectorResolver - { - using Injector = InternalBadFunctor; - }; + private: + template R matchCall(R (T::*)(Args...)) { return call(); } - template struct FunctorInjectorResolver - { - using Injector = InternalFunctorInjector; - }; + template R matchCall(R (T::*)(Args...) const) { return call(); } - template struct FunctorInjectorResolver - { - using Injector = InternalFunctorInjector; + template R call() { return _functor(ServiceGetter::get(_serviceProvider)...); } }; - - template - using FunctorInjector = typename FunctorInjectorResolver::Injector; } // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Helpers/Impl/Formatter.hpp b/Include/SevenBit/DI/Details/Helpers/Impl/Formatter.hpp new file mode 100644 index 00000000..4f581cc0 --- /dev/null +++ b/Include/SevenBit/DI/Details/Helpers/Impl/Formatter.hpp @@ -0,0 +1,131 @@ +#pragma once + +#include + +#include "SevenBit/DI/LibraryConfig.hpp" + +#include "SevenBit/DI/Details/Helpers/Formatter.hpp" + +namespace sb::di::details +{ + namespace FormatterInternal + { + inline int assertFormatRes(int result, const char *fmt) + { + if (result < 0) + { + throw std::runtime_error(std::string{"Format string error: "} + fmt); + } + return result; + } + + template void appendFormatted(std::string &result, T data, const char *fmt) + { + constexpr size_t buffSize = 100; + char buffer[buffSize]; + auto size = assertFormatRes(std::snprintf(buffer, buffSize, fmt, data), fmt); + if (size < buffSize) + { + result += std::string_view(buffer, size); + } + else + { + std::vector largeBuff(size + 1); + assertFormatRes(std::snprintf(largeBuff.data(), size + 1, fmt, data), fmt); + result += std::string_view(largeBuff.data(), size); + } + } + + inline std::string makeArgFmt(std::string_view coreFmt, std::string_view baseFmt) + { + std::string fmt = "%"; + fmt += coreFmt; + // base fmt contains % at the beginning + fmt += baseFmt.substr(1); + return fmt; + } + + template + void appendNum(std::string &result, N arg, const std::string_view coreFmt, const char *baseFmt) + { + if (!coreFmt.empty()) + { + const auto format = makeArgFmt(coreFmt, baseFmt); + return appendFormatted(result, arg, format.c_str()); + } + return appendFormatted(result, arg, baseFmt); + } + } // namespace FormatterInternal + + INLINE Formatter::Formatter(const std::string_view formatString) : formatString(formatString) + { + result.reserve(formatString.size()); + } + + INLINE std::string Formatter::getResult() && { return std::move(result); } + + INLINE void Formatter::append(const char *arg, std::string_view fmt) + { + if (!fmt.empty()) + { + const auto format = FormatterInternal::makeArgFmt(fmt, "%s"); + return FormatterInternal::appendFormatted(result, arg, format.c_str()); + } + result += arg; + } + + INLINE void Formatter::append(const std::string &arg, std::string_view fmt) + { + if (!fmt.empty()) + { + return append(arg.c_str(), fmt); + } + result += arg; + } + + INLINE void Formatter::append(std::string_view arg, std::string_view fmt) + { + if (!fmt.empty()) + { + return append(std::string{arg}, fmt); + } + result += arg; + } + + INLINE void Formatter::append(int arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%d"); + } + INLINE void Formatter::append(long arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%ld"); + } + INLINE void Formatter::append(long long arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%lld"); + } + INLINE void Formatter::append(unsigned arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%u"); + } + INLINE void Formatter::append(unsigned long arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%lu"); + } + INLINE void Formatter::append(unsigned long long arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%llu"); + } + INLINE void Formatter::append(float arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%f"); + } + INLINE void Formatter::append(double arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%f"); + } + INLINE void Formatter::append(long double arg, std::string_view fmt) + { + return FormatterInternal::appendNum(result, arg, fmt, "%Lf"); + } +} // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Helpers/ServiceCtorArgExtractor.hpp b/Include/SevenBit/DI/Details/Helpers/ServiceExtractor.hpp similarity index 51% rename from Include/SevenBit/DI/Details/Helpers/ServiceCtorArgExtractor.hpp rename to Include/SevenBit/DI/Details/Helpers/ServiceExtractor.hpp index fa93d277..ca27e204 100644 --- a/Include/SevenBit/DI/Details/Helpers/ServiceCtorArgExtractor.hpp +++ b/Include/SevenBit/DI/Details/Helpers/ServiceExtractor.hpp @@ -2,25 +2,25 @@ #include "SevenBit/DI/LibraryConfig.hpp" -#include "SevenBit/DI/Details/Helpers/ServiceGetter.hpp" +#include "ServiceGetter.hpp" #include "SevenBit/DI/Details/Utils/Meta.hpp" namespace sb::di::details { - template class ServiceCtorArgExtractor + template class ServiceExtractor { - ServiceProvider &_provider; + ServiceProvider *_provider = nullptr; public: - explicit ServiceCtorArgExtractor(ServiceProvider &provider, std::size_t) : _provider(provider) {} + explicit ServiceExtractor(ServiceProvider *provider, std::size_t paramNumber = 0) : _provider(provider) {} template >> operator S() { - return ServiceGetter>::get(_provider); + return ServiceGetter>::get(*_provider); } template >> operator S &() const { - return _provider.getService>(); + return _provider->getService>(); } }; } // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Utils/Assert.hpp b/Include/SevenBit/DI/Details/Utils/Assert.hpp index d4d2900e..af73adce 100644 --- a/Include/SevenBit/DI/Details/Utils/Assert.hpp +++ b/Include/SevenBit/DI/Details/Utils/Assert.hpp @@ -6,7 +6,7 @@ namespace sb::di::details { - struct EXPORT Assert + struct Assert { template static void serviceType() { @@ -40,7 +40,6 @@ namespace sb::di::details serviceType(); static_assert(InheritanceV, "TService must inherit from alias type: TAlias"); - static_assert(!std::is_same_v, "Alias type: TAlias cannot be same as TService"); } }; diff --git a/Include/SevenBit/DI/Details/Utils/Cast.hpp b/Include/SevenBit/DI/Details/Utils/Cast.hpp index b7a43add..d4d9f0c2 100644 --- a/Include/SevenBit/DI/Details/Utils/Cast.hpp +++ b/Include/SevenBit/DI/Details/Utils/Cast.hpp @@ -8,14 +8,14 @@ namespace sb::di::details { struct Cast { - template static constexpr ptrdiff_t getCastOffset() + template static constexpr ptrdiff_t getOffset() { auto implementation = reinterpret_cast(std::numeric_limits::max() / 2); auto service = static_cast(implementation); return reinterpret_cast(service) - reinterpret_cast(implementation); }; - static void *applyCastOffset(void *ptr, const ptrdiff_t offset) + static void *applyOffset(void *ptr, const ptrdiff_t offset) { const auto casted = reinterpret_cast(ptr) + offset; return reinterpret_cast(casted); diff --git a/Include/SevenBit/DI/Details/Utils/CtorParamsNumber.hpp b/Include/SevenBit/DI/Details/Utils/CtorParamsNumber.hpp deleted file mode 100644 index e07eeb5a..00000000 --- a/Include/SevenBit/DI/Details/Utils/CtorParamsNumber.hpp +++ /dev/null @@ -1,47 +0,0 @@ -#pragma once - -#include "SevenBit/DI/LibraryConfig.hpp" - -#include "SevenBit/DI/Details/Utils/Meta.hpp" - -namespace sb::di::details -{ - namespace ctorParamsNumberInternals - { - template struct Conv - { - explicit Conv(std::size_t paramNumber) {} - - template >> operator U(); - template >> operator U &() const; - }; - - template constexpr auto paramsNumber(std::size_t) -> decltype(T{Conv{Ns}...}, 0) - { - return sizeof...(Ns); - } - - template constexpr std::size_t paramsNumber(...) - { - - if constexpr (sizeof...(Ns) > _7BIT_DI_CTOR_PARAMS_LIMIT) - { - static_assert( - details::notSupportedType, - "Proper constructor for specified type was not found, reached maximum constructor params number " - "limit, to bump limit define macro _7BIT_DI_CTOR_PARAMS_LIMIT with new value befor including lib"); - return 0; - } - else - { - return paramsNumber(0); - } - } - } // namespace ctorParamsNumberInternals - - template constexpr std::size_t ctorParamsNumber() - { - return ctorParamsNumberInternals::paramsNumber(0); - }; - -} // namespace sb::di::details diff --git a/Include/SevenBit/DI/Details/Utils/Meta.hpp b/Include/SevenBit/DI/Details/Utils/Meta.hpp index ed81d5a0..4b8fb112 100644 --- a/Include/SevenBit/DI/Details/Utils/Meta.hpp +++ b/Include/SevenBit/DI/Details/Utils/Meta.hpp @@ -7,6 +7,16 @@ namespace sb::di::details { + template struct IsFunctor : std::false_type + { + }; + template struct IsFunctor : std::true_type + { + }; + template struct IsFunctor : std::true_type + { + }; + template inline constexpr bool IsFunctorV = IsFunctor::value; template struct IsCopyCtor : std::false_type { diff --git a/Include/SevenBit/DI/Details/Utils/Require.hpp b/Include/SevenBit/DI/Details/Utils/Require.hpp index 1c3a5291..da0b8032 100644 --- a/Include/SevenBit/DI/Details/Utils/Require.hpp +++ b/Include/SevenBit/DI/Details/Utils/Require.hpp @@ -5,6 +5,7 @@ #include "SevenBit/DI/LibraryConfig.hpp" #include "SevenBit/DI/Details/Utils/Check.hpp" +#include "SevenBit/DI/Details/Utils/String.hpp" #include "SevenBit/DI/Exceptions.hpp" namespace sb::di::details @@ -45,9 +46,9 @@ namespace sb::di::details { if (!ptr) { - const auto message = !failMessage.empty() - ? std::string{failMessage} - : std::string{"Object of type: '"} + typeid(T).name() + "' cannot be null"; + const auto message = failMessage.empty() + ? details::String::fmt("Object of type: '{}' cannot be null", typeid(T).name()) + : std::string{failMessage}; throw NullPointerException(message); } } @@ -64,8 +65,8 @@ namespace sb::di::details { auto index = static_cast>(value); auto count = static_cast>(TEnum::Count); - throw InjectorException{"enum value: " + std::to_string(index) + " is invalid, shoud be in range [0" + - std::to_string(count) + ")"}; + throw InjectorException{ + details::String::fmt("Enum value: {} is invalid, should be in range [0 {})", index, count)}; } } }; diff --git a/Include/SevenBit/DI/Details/Utils/String.hpp b/Include/SevenBit/DI/Details/Utils/String.hpp new file mode 100644 index 00000000..384ee852 --- /dev/null +++ b/Include/SevenBit/DI/Details/Utils/String.hpp @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#include "SevenBit/DI/LibraryConfig.hpp" + +#include "SevenBit/DI/Details/Helpers/Formatter.hpp" + +namespace sb::di::details +{ + struct String + { + template static std::string fmt(const std::string_view formatString, Args &&...args) + { + Formatter formatter{formatString}; + formatter.format(args...); + return std::move(formatter).getResult(); + } + + template static std::string toString(T &&value) { return fmt("{}", value); } + }; +} // namespace sb::di::details diff --git a/Include/SevenBit/DI/Exceptions.hpp b/Include/SevenBit/DI/Exceptions.hpp index 4d398ff6..ddb26711 100644 --- a/Include/SevenBit/DI/Exceptions.hpp +++ b/Include/SevenBit/DI/Exceptions.hpp @@ -2,6 +2,7 @@ #include #include +#include #include "SevenBit/DI/LibraryConfig.hpp" @@ -22,45 +23,35 @@ namespace sb::di explicit NullPointerException(const std::string &why); }; - struct EXPORT InvalidServiceException : InjectorException - { - explicit InvalidServiceException(); - explicit InvalidServiceException(TypeId typeId); - }; - - struct EXPORT CannotReleaseServiceException : InjectorException + struct EXPORT ServiceRegisterException : InjectorException { - CannotReleaseServiceException(TypeId typeId, const std::string &reason); + explicit ServiceRegisterException(TypeId typeId, std::string_view reason); }; struct EXPORT CannotMoveOutServiceException : InjectorException { - CannotMoveOutServiceException(TypeId typeId, const std::string &reason); - }; - - struct EXPORT ServiceNotFoundException : InjectorException - { - ServiceNotFoundException(TypeId typeIndex, const std::string &reason); + CannotMoveOutServiceException(TypeId typeId, std::string_view reason); }; - struct EXPORT ServiceAlreadyRegisteredException : InjectorException + struct EXPORT CannotReleaseServiceException : InjectorException { - explicit ServiceAlreadyRegisteredException(TypeId typeIndex); + CannotReleaseServiceException(TypeId typeId, std::string_view reason); }; - struct EXPORT ServiceLifeTimeMismatchException : InjectorException + struct EXPORT ServiceNotFoundException : InjectorException { - ServiceLifeTimeMismatchException(TypeId typeIndex, TypeId interface); + ServiceNotFoundException(TypeId typeId, std::string_view reason); }; - struct EXPORT ServiceAliasMismatchException : InjectorException + struct EXPORT InvalidServiceException : InjectorException { - ServiceAliasMismatchException(TypeId typeIndex, TypeId interface, bool shoudBeAlias); + explicit InvalidServiceException(); + explicit InvalidServiceException(TypeId typeId); }; struct EXPORT CircularDependencyException : InjectorException { - explicit CircularDependencyException(TypeId typeIndex); + explicit CircularDependencyException(TypeId typeId); }; } // namespace sb::di diff --git a/Include/SevenBit/DI/Impl/Exceptions.hpp b/Include/SevenBit/DI/Impl/Exceptions.hpp index 0fbe748f..a6e04c0e 100644 --- a/Include/SevenBit/DI/Impl/Exceptions.hpp +++ b/Include/SevenBit/DI/Impl/Exceptions.hpp @@ -4,6 +4,7 @@ #include "SevenBit/DI/LibraryConfig.hpp" +#include "SevenBit/DI/Details/Utils/String.hpp" #include "SevenBit/DI/Exceptions.hpp" namespace sb::di @@ -12,57 +13,40 @@ namespace sb::di INLINE NullPointerException::NullPointerException(const std::string &why) : InjectorException{why} {} - INLINE InvalidServiceException::InvalidServiceException() - : InjectorException{std::string{"Service is in not valid state."}} - { - } - - INLINE InvalidServiceException::InvalidServiceException(const TypeId typeId) - : InjectorException{std::string{"Service: '"} + typeId.name() + "' is in not valid state."} + INLINE ServiceRegisterException::ServiceRegisterException(const TypeId typeId, std::string_view reason) + : InjectorException{details::String::fmt("Cannot register service '{}', reason: {}.", typeId.name(), reason)} { } - INLINE CannotReleaseServiceException::CannotReleaseServiceException(const TypeId typeId, const std::string &reason) - : InjectorException{std::string{"Cannot release ownership of service: '"} + typeId.name() + - "', reason: " + reason + "."} + INLINE ServiceNotFoundException::ServiceNotFoundException(const TypeId typeId, std::string_view reason) + : InjectorException{details::String::fmt("Service '{}' was not found, reason: {}.", typeId.name(), reason)} { } - INLINE CannotMoveOutServiceException::CannotMoveOutServiceException(const TypeId typeId, const std::string &reason) - : InjectorException{std::string{"Cannot move out service: '"} + typeId.name() + "', reason: " + reason + "."} + INLINE CannotMoveOutServiceException::CannotMoveOutServiceException(const TypeId typeId, std::string_view reason) + : InjectorException{details::String::fmt("Cannot move out service '{}', reason: {}.", typeId.name(), reason)} { } - INLINE ServiceNotFoundException::ServiceNotFoundException(const TypeId typeIndex, const std::string &reason) - : InjectorException{std::string{"Service: '"} + typeIndex.name() + "' was not found, reason: " + reason + "."} + INLINE CannotReleaseServiceException::CannotReleaseServiceException(const TypeId typeId, std::string_view reason) + : InjectorException{ + details::String::fmt("Cannot release ownership of service '{}', reason: {}.", typeId.name(), reason)} { } - INLINE CircularDependencyException::CircularDependencyException(const TypeId typeIndex) - : InjectorException{std::string{"Circular dependency detected while creating service: '"} + typeIndex.name() + - "'."} - { - } - - INLINE ServiceAlreadyRegisteredException::ServiceAlreadyRegisteredException(const TypeId typeIndex) - : InjectorException{std::string{"Service: '"} + typeIndex.name() + "' was already registered."} + INLINE InvalidServiceException::InvalidServiceException() + : InjectorException{std::string{"Service is not in valid state."}} { } - INLINE ServiceAliasMismatchException::ServiceAliasMismatchException(const TypeId typeIndex, const TypeId interface, - const bool shoudBeAlias) - : InjectorException{std::string{"Service: '"} + typeIndex.name() + - (shoudBeAlias ? "' should be" : "' should not be") + - " alias as other services implementing this interface '" + interface.name() + - "' that are already registered."} + INLINE InvalidServiceException::InvalidServiceException(const TypeId typeId) + : InjectorException{details::String::fmt("Service: '{}' is not in valid state.", typeId.name())} { } - INLINE ServiceLifeTimeMismatchException::ServiceLifeTimeMismatchException(const TypeId typeIndex, - const TypeId interface) - : InjectorException{std::string{"Service: '"} + typeIndex.name() + - "' should have same scope as other services implementing this interface '" + - interface.name() + "' that are already registered."} + INLINE CircularDependencyException::CircularDependencyException(const TypeId typeId) + : InjectorException{ + details::String::fmt("Circular dependency detected while creating service: '{}'.", typeId.name())} { } } // namespace sb::di diff --git a/Include/SevenBit/DI/ServiceCollection.hpp b/Include/SevenBit/DI/ServiceCollection.hpp index cfe4bc46..19355fb9 100644 --- a/Include/SevenBit/DI/ServiceCollection.hpp +++ b/Include/SevenBit/DI/ServiceCollection.hpp @@ -43,8 +43,7 @@ namespace sb::di /** * @brief Builds service provider with specified options * @details might throw exceptions - * @throws sb::di::ServiceAlreadyRegisteredException if service was already registered - * @throws sb::di::ServiceLifeTimeMismatchException if service has different lifetime than other already + * @throws sb::di::ServiceRegisterException if an error occurs during service registration * registered with same base type */ ServiceProvider buildServiceProvider(ServiceProviderOptions options = {}); @@ -52,8 +51,7 @@ namespace sb::di /** * @brief Builds service provider as unique_ptr with specified options * @details might throw exceptions - * @throws sb::di::ServiceAlreadyRegisteredException if service was already registered - * @throws sb::di::ServiceLifeTimeMismatchException if service has different lifetime than other already + * @throws sb::di::ServiceRegisterException if an error occurs during service registration * registered with same base type */ ServiceProvider::Ptr buildServiceProviderAsPtr(ServiceProviderOptions options = {}); diff --git a/Include/SevenBit/DI/ServiceDescriber.hpp b/Include/SevenBit/DI/ServiceDescriber.hpp index fd3dfb45..dc5b4fb3 100644 --- a/Include/SevenBit/DI/ServiceDescriber.hpp +++ b/Include/SevenBit/DI/ServiceDescriber.hpp @@ -134,7 +134,7 @@ namespace sb::di nullptr, lifeTime, std::make_unique>(), - details::Cast::getCastOffset()}; + details::Cast::getOffset()}; } /** @@ -206,7 +206,7 @@ namespace sb::di nullptr, ServiceLifeTime::singleton(), std::make_unique>(service), - details::Cast::getCastOffset()}; + details::Cast::getOffset()}; } /** @@ -457,7 +457,7 @@ namespace sb::di nullptr, lifeTime, std::make_unique(std::forward(factory)), - details::Cast::getCastOffset()}; + details::Cast::getOffset()}; } /** @@ -492,7 +492,7 @@ namespace sb::di std::move(serviceKey), ServiceLifeTime::scoped(), nullptr, - details::Cast::getCastOffset()}; + details::Cast::getOffset()}; } }; } // namespace sb::di diff --git a/Include/SevenBit/DI/ServiceInstance.hpp b/Include/SevenBit/DI/ServiceInstance.hpp index 68115aba..39b75d7a 100644 --- a/Include/SevenBit/DI/ServiceInstance.hpp +++ b/Include/SevenBit/DI/ServiceInstance.hpp @@ -160,6 +160,6 @@ namespace sb::di } private: - void *applyOffset(void *ptr) const { return details::Cast::applyCastOffset(ptr, _castOffset); } + void *applyOffset(void *ptr) const { return details::Cast::applyOffset(ptr, _castOffset); } }; } // namespace sb::di diff --git a/Include/SevenBit/DI/ServiceLifeTime.hpp b/Include/SevenBit/DI/ServiceLifeTime.hpp index 48d7b5c2..59dc0ff6 100644 --- a/Include/SevenBit/DI/ServiceLifeTime.hpp +++ b/Include/SevenBit/DI/ServiceLifeTime.hpp @@ -68,5 +68,20 @@ namespace sb::di constexpr bool operator!=(const ServiceLifeTime &lifeTime) const { return _type != lifeTime._type; } constexpr bool operator==(const ServiceLifeTime &lifeTime) const { return _type == lifeTime._type; } + + [[nodiscard]] std::string_view toString() const + { + switch (_type) + { + case Type::Singleton: + return "Singleton"; + case Type::Scoped: + return "Scoped"; + case Type::Transient: + return "Transient"; + default: + return "Unknown"; + } + } }; } // namespace sb::di diff --git a/Include/SevenBit/DI/ServiceProviderOptions.hpp b/Include/SevenBit/DI/ServiceProviderOptions.hpp index 8eea4516..7f6f2dbe 100644 --- a/Include/SevenBit/DI/ServiceProviderOptions.hpp +++ b/Include/SevenBit/DI/ServiceProviderOptions.hpp @@ -32,7 +32,7 @@ namespace sb::di * @brief Set service search strategy * @details If set to true provider will search for service in singleton container first then in scoped */ - bool searchInSigletonsFirst = true; + bool searchInSingletonsFirst = true; /** * @brief Enables thread safe mode diff --git a/Include/SevenBit/DI/Utils/Injected.hpp b/Include/SevenBit/DI/Utils/Injected.hpp index ea3a0d24..3bfc5da8 100644 --- a/Include/SevenBit/DI/Utils/Injected.hpp +++ b/Include/SevenBit/DI/Utils/Injected.hpp @@ -3,7 +3,7 @@ #include "SevenBit/DI/LibraryConfig.hpp" #include "SevenBit/DI/Utils/Register.hpp" -#include "SevenBit/DI/Utils/ServiceExtractor.hpp" +#include "SevenBit/DI/Utils/ServiceInlineExtractor.hpp" namespace sb::di { @@ -18,7 +18,7 @@ namespace sb::di protected: [[nodiscard]] ServiceProvider &getProvider() const { return _provider; } - [[nodiscard]] ServiceExtractor inject() const { return ServiceExtractor{getProvider()}; } + [[nodiscard]] ServiceInlineExtractor inject() const { return ServiceInlineExtractor{getProvider()}; } }; template diff --git a/Include/SevenBit/DI/Utils/ServiceExtractor.hpp b/Include/SevenBit/DI/Utils/ServiceInlineExtractor.hpp similarity index 95% rename from Include/SevenBit/DI/Utils/ServiceExtractor.hpp rename to Include/SevenBit/DI/Utils/ServiceInlineExtractor.hpp index eba0b536..8256f063 100644 --- a/Include/SevenBit/DI/Utils/ServiceExtractor.hpp +++ b/Include/SevenBit/DI/Utils/ServiceInlineExtractor.hpp @@ -9,7 +9,7 @@ namespace sb::di { - struct ServiceExtractor + struct ServiceInlineExtractor { ServiceProvider &provider; diff --git a/README.md b/README.md index 6aafa3b4..996717eb 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ include(FetchContent) FetchContent_Declare( 7bitDI GIT_REPOSITORY https://github.com/7bitcoder/7bitDI.git - GIT_TAG v3.3.0 + GIT_TAG v3.4.0 ) FetchContent_MakeAvailable(7bitDI) @@ -83,7 +83,7 @@ Download and install A [Conan](https://conan.io/), and create conanfile.txt in t ``` [requires] -7bitdi/3.3.0 +7bitdi/3.4.0 ``` change the version to newer if available, then run the command: diff --git a/SingleHeader/CMakeLists.txt b/SingleHeader/CMakeLists.txt index b0e7a08a..2bd83ff4 100644 --- a/SingleHeader/CMakeLists.txt +++ b/SingleHeader/CMakeLists.txt @@ -11,5 +11,4 @@ add_custom_command(OUTPUT ${_7BIT_DI_SINGLE_OUT} add_custom_target(GenerateSingleHeader ALL DEPENDS ${_7BIT_DI_SINGLE_OUT} - ${_7BIT_DI_MAIN_HEADER} ) diff --git a/Source/Source.cpp b/Source/Source.cpp index 32a7f149..5940a432 100644 --- a/Source/Source.cpp +++ b/Source/Source.cpp @@ -4,11 +4,12 @@ #include #include #include -#include +#include #include #include -#include +#include #include +#include #include #include #include diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index 50d5b565..1f418e19 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -2,7 +2,7 @@ include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git - GIT_TAG v1.14.0 + GIT_TAG v1.15.0 ) set(gtest_build_tests OFF) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) diff --git a/Tests/E2E/Examples/expected_test_data.json b/Tests/E2E/Examples/expected_test_data.json index 4f5458c1..042ab9fa 100644 --- a/Tests/E2E/Examples/expected_test_data.json +++ b/Tests/E2E/Examples/expected_test_data.json @@ -11,9 +11,12 @@ "InjectionRules": "", "KeyedServices": "^action, action, action executed.", "Logger": "^Initializing\nProcessing\nFinalizing", + "MessageBus": "^Received tick message no:", + "Permissions": "Name: test name, Payload: It is a long established fact that a reader will be distracted", "RegisterUtilityClass": "^actionA, actionB executed.", "SeparateImplementation": "^Hello from service.", - "ServicesLifeTime": "\nSingletons comparison\nrootProvider\\s+== rootProvider:\\s+1\nrootProvider\\s+== scopedProvider:\\s+1\nscopedProvider\\s+== scopedProvider:\\s+1\n\nScoped comparison\nrootProvider\\s+== rootProvider:\\s+1\nrootProvider\\s+== scopedProvider:\\s+0\nscopedProvider\\s+== scopedProvider:\\s+1\n\nTransient comparison\nrootProvider\\s+== rootProvider:\\s+0\nrootProvider\\s+== scopedProvider:\\s+0\nscopedProvider\\s+== scopedProvider:\\s+0\n", + "ServicesLifeTime": "^Service Addresses Table\\n\\s+rootProvider\\s+scopedProvider\\nsingleton\\s+\\w+\\s+\\w+\\sscoped\\s+\\w+\\s+\\w+\\stransient\\s+\\w+\\s+\\w+", "ServiceAliases": "actionA from top service, actionB from top service executed.", - "Simple": "^part a done!\npart b done!\n" + "Simple": "^part a done!\npart b done!\n", + "Tester": "Tests run: 2\/2" } diff --git a/Tests/Helpers/Classes/CirularDependency.hpp b/Tests/Helpers/Classes/CirularDependency.hpp index 53f35ca4..bb63ff24 100644 --- a/Tests/Helpers/Classes/CirularDependency.hpp +++ b/Tests/Helpers/Classes/CirularDependency.hpp @@ -17,10 +17,19 @@ struct CircularDependencyUniqueB; struct CircularDependencyUniqueA { - explicit CircularDependencyUniqueA(std::unique_ptr b) {} + explicit CircularDependencyUniqueA(std::unique_ptr); + + ~CircularDependencyUniqueA(); }; struct CircularDependencyUniqueB { - explicit CircularDependencyUniqueB(std::unique_ptr a) {} + explicit CircularDependencyUniqueB(std::unique_ptr); + + ~CircularDependencyUniqueB(); }; + +inline CircularDependencyUniqueA::CircularDependencyUniqueA(std::unique_ptr b) {} +inline CircularDependencyUniqueA::~CircularDependencyUniqueA() = default; +inline CircularDependencyUniqueB::CircularDependencyUniqueB(std::unique_ptr a) {} +inline CircularDependencyUniqueB::~CircularDependencyUniqueB() = default; diff --git a/Tests/Integration/AliasTest.cpp b/Tests/Integration/AliasTest.cpp index dca1adfa..e1ccaad3 100644 --- a/Tests/Integration/AliasTest.cpp +++ b/Tests/Integration/AliasTest.cpp @@ -27,7 +27,7 @@ TEST_F(AliasTest, ShouldFailGetServiceDueToAliasMissmatchService) collection.addSingleton(); collection.addAlias(); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(AliasTest, ShouldFailGetServiceDueToAliasMissmatchServiceOpposite) @@ -38,7 +38,7 @@ TEST_F(AliasTest, ShouldFailGetServiceDueToAliasMissmatchServiceOpposite) collection.addAlias(); collection.addSingleton(); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(AliasTest, ShouldTryGetAliasesService) diff --git a/Tests/Integration/BasicExternalTest.cpp b/Tests/Integration/BasicExternalTest.cpp index 0628d581..f6516512 100644 --- a/Tests/Integration/BasicExternalTest.cpp +++ b/Tests/Integration/BasicExternalTest.cpp @@ -35,7 +35,7 @@ TEST_F(BasicExternalTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicExternalTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/BasicFactoryTest.cpp b/Tests/Integration/BasicFactoryTest.cpp index dc2da933..2a7284a7 100644 --- a/Tests/Integration/BasicFactoryTest.cpp +++ b/Tests/Integration/BasicFactoryTest.cpp @@ -34,7 +34,7 @@ TEST_F(BasicFactoryTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicFactoryTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/BasicTest.cpp b/Tests/Integration/BasicTest.cpp index 9b3752e0..e93d468c 100644 --- a/Tests/Integration/BasicTest.cpp +++ b/Tests/Integration/BasicTest.cpp @@ -34,7 +34,7 @@ TEST_F(BasicTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/BasicUniqFactoryTest.cpp b/Tests/Integration/BasicUniqFactoryTest.cpp index 33d27f4a..8eeaceaa 100644 --- a/Tests/Integration/BasicUniqFactoryTest.cpp +++ b/Tests/Integration/BasicUniqFactoryTest.cpp @@ -35,7 +35,7 @@ TEST_F(BasicUniqFactoryTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicUniqFactoryTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/InheritanceExternalTest.cpp b/Tests/Integration/InheritanceExternalTest.cpp index 6d1bf63e..3929f087 100644 --- a/Tests/Integration/InheritanceExternalTest.cpp +++ b/Tests/Integration/InheritanceExternalTest.cpp @@ -35,7 +35,7 @@ TEST_F(InheritanceExternalTest, ShouldFailGetServiceDueToAlreadyRegisteredServic sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceExternalTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/InheritanceFactoryTest.cpp b/Tests/Integration/InheritanceFactoryTest.cpp index e0d5d36b..80cb918f 100644 --- a/Tests/Integration/InheritanceFactoryTest.cpp +++ b/Tests/Integration/InheritanceFactoryTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceFactoryTest, ShouldFailGetServiceDueToAlreadyRegisteredService sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceFactoryTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceFactoryTest, ShouldFailGetServiceDueToLifetimeMissmatchService collection.addSingleton([] { return TestInheritClass5{}; }); collection.addTransient([] { return TestInheritClass4{}; }); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceFactoryTest, ShouldTryGetService) diff --git a/Tests/Integration/InheritanceTest.cpp b/Tests/Integration/InheritanceTest.cpp index fcee6f64..d22f477b 100644 --- a/Tests/Integration/InheritanceTest.cpp +++ b/Tests/Integration/InheritanceTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceTest, ShouldFailGetServiceDueToLifetimeMissmatchService) collection.addSingleton(); collection.addTransient(); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceTest, ShouldTryGetService) diff --git a/Tests/Integration/InheritanceUniqFactoryTest.cpp b/Tests/Integration/InheritanceUniqFactoryTest.cpp index 5f1236e0..ce65c69e 100644 --- a/Tests/Integration/InheritanceUniqFactoryTest.cpp +++ b/Tests/Integration/InheritanceUniqFactoryTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceUniqFactoryTest, ShouldFailGetServiceDueToAlreadyRegisteredSer sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceUniqFactoryTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceUniqFactoryTest, ShouldFailGetServiceDueToLifetimeMissmatchSer collection.addSingleton([] { return std::make_unique(); }); collection.addTransient([] { return std::make_unique(); }); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceUniqFactoryTest, ShouldTryGetService) diff --git a/Tests/Integration/Keyed/AliasKeyedTest.cpp b/Tests/Integration/Keyed/AliasKeyedTest.cpp index b1269328..fc7e2693 100644 --- a/Tests/Integration/Keyed/AliasKeyedTest.cpp +++ b/Tests/Integration/Keyed/AliasKeyedTest.cpp @@ -27,7 +27,7 @@ TEST_F(AliasKeyedTest, ShouldFailGetServiceDueToAliasMissmatchService) collection.addKeyedSingleton("key"); collection.addKeyedAlias("key", "key"); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(AliasKeyedTest, ShouldFailGetServiceDueToAliasMissmatchServiceOpposite) @@ -38,7 +38,7 @@ TEST_F(AliasKeyedTest, ShouldFailGetServiceDueToAliasMissmatchServiceOpposite) collection.addKeyedAlias("key", "key"); collection.addKeyedSingleton("key"); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(AliasKeyedTest, ShouldTryGetAliasesService) diff --git a/Tests/Integration/Keyed/BasicExternalKeyedTest.cpp b/Tests/Integration/Keyed/BasicExternalKeyedTest.cpp index d7373dda..30990544 100644 --- a/Tests/Integration/Keyed/BasicExternalKeyedTest.cpp +++ b/Tests/Integration/Keyed/BasicExternalKeyedTest.cpp @@ -35,7 +35,7 @@ TEST_F(BasicExternalKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredService sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicExternalKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/Keyed/BasicFactoryKeyedTest.cpp b/Tests/Integration/Keyed/BasicFactoryKeyedTest.cpp index 6eeea59a..1276a3b7 100644 --- a/Tests/Integration/Keyed/BasicFactoryKeyedTest.cpp +++ b/Tests/Integration/Keyed/BasicFactoryKeyedTest.cpp @@ -33,7 +33,7 @@ TEST_F(BasicFactoryKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicFactoryKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/Keyed/BasicKeyedTest.cpp b/Tests/Integration/Keyed/BasicKeyedTest.cpp index d44b0777..15a2dd3e 100644 --- a/Tests/Integration/Keyed/BasicKeyedTest.cpp +++ b/Tests/Integration/Keyed/BasicKeyedTest.cpp @@ -34,7 +34,7 @@ TEST_F(BasicKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/Keyed/BasicUniqFactoryKeyedTest.cpp b/Tests/Integration/Keyed/BasicUniqFactoryKeyedTest.cpp index 00403505..6e576677 100644 --- a/Tests/Integration/Keyed/BasicUniqFactoryKeyedTest.cpp +++ b/Tests/Integration/Keyed/BasicUniqFactoryKeyedTest.cpp @@ -34,7 +34,7 @@ TEST_F(BasicUniqFactoryKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredServ sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(BasicUniqFactoryKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/Keyed/InheritanceExternalKeyedTest.cpp b/Tests/Integration/Keyed/InheritanceExternalKeyedTest.cpp index 7cb2146f..2a2e0338 100644 --- a/Tests/Integration/Keyed/InheritanceExternalKeyedTest.cpp +++ b/Tests/Integration/Keyed/InheritanceExternalKeyedTest.cpp @@ -35,7 +35,7 @@ TEST_F(InheritanceExternalKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredS sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceExternalKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) diff --git a/Tests/Integration/Keyed/InheritanceFactoryKeyedTest.cpp b/Tests/Integration/Keyed/InheritanceFactoryKeyedTest.cpp index 836b9b47..2ca7fe27 100644 --- a/Tests/Integration/Keyed/InheritanceFactoryKeyedTest.cpp +++ b/Tests/Integration/Keyed/InheritanceFactoryKeyedTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceFactoryKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredSe sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceFactoryKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceFactoryKeyedTest, ShouldFailGetServiceDueToLifetimeMissmatchSe collection.addKeyedSingleton("key", [] { return TestInheritClass5{}; }); collection.addKeyedTransient("key", [] { return TestInheritClass4{}; }); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceFactoryKeyedTest, ShouldTryGetService) diff --git a/Tests/Integration/Keyed/InheritanceKeyedTest.cpp b/Tests/Integration/Keyed/InheritanceKeyedTest.cpp index 4e6d1b41..e179fc5f 100644 --- a/Tests/Integration/Keyed/InheritanceKeyedTest.cpp +++ b/Tests/Integration/Keyed/InheritanceKeyedTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceKeyedTest, ShouldFailGetServiceDueToAlreadyRegisteredService) sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceKeyedTest, ShouldFailGetServiceDueToLifetimeMissmatchService) collection.addKeyedSingleton("key"); collection.addKeyedTransient("key"); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceKeyedTest, ShouldTryGetService) diff --git a/Tests/Integration/Keyed/InheritanceUniqFactoryKeyedTest.cpp b/Tests/Integration/Keyed/InheritanceUniqFactoryKeyedTest.cpp index dac22168..4c220752 100644 --- a/Tests/Integration/Keyed/InheritanceUniqFactoryKeyedTest.cpp +++ b/Tests/Integration/Keyed/InheritanceUniqFactoryKeyedTest.cpp @@ -31,7 +31,7 @@ TEST_F(InheritanceUniqFactoryKeyedTest, ShouldFailGetServiceDueToAlreadyRegister sb::di::ServiceProviderOptions options; options.checkServiceGlobalUniqueness = true; - EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(collection.buildServiceProvider(options), sb::di::ServiceRegisterException); } TEST_F(InheritanceUniqFactoryKeyedTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -55,7 +55,7 @@ TEST_F(InheritanceUniqFactoryKeyedTest, ShouldFailGetServiceDueToLifetimeMissmat collection.addKeyedSingleton("key", [] { return std::make_unique(); }); collection.addKeyedTransient("key", [] { return std::make_unique(); }); - EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(collection.buildServiceProvider(), sb::di::ServiceRegisterException); } TEST_F(InheritanceUniqFactoryKeyedTest, ShouldTryGetService) diff --git a/Tests/Unit/Containers/ServiceDescriptorListTest.cpp b/Tests/Unit/Containers/ServiceDescriptorListTest.cpp index 8c84c0ce..011b1a56 100644 --- a/Tests/Unit/Containers/ServiceDescriptorListTest.cpp +++ b/Tests/Unit/Containers/ServiceDescriptorListTest.cpp @@ -56,7 +56,7 @@ TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorAliasMismatch) auto act = [&] { list.add(sb::di::ServiceDescriber::describeScoped()); }; - EXPECT_THROW(act(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorAliasMismatchOpposite) @@ -68,7 +68,7 @@ TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorAliasMismatchOpp auto act = [&] { list.add(sb::di::ServiceDescriber::describeAlias()); }; - EXPECT_THROW(act(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorLifeTimeMismatch) @@ -80,7 +80,7 @@ TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorLifeTimeMismatch auto act = [&] { list.add(sb::di::ServiceDescriber::describeScoped()); }; - EXPECT_THROW(act(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorListTest, ShouldFailAddServiceDescriptorBaseTypeMismatch) diff --git a/Tests/Unit/Containers/ServiceDescriptorsMapTest.cpp b/Tests/Unit/Containers/ServiceDescriptorsMapTest.cpp index 7f2e5702..f215e4c3 100644 --- a/Tests/Unit/Containers/ServiceDescriptorsMapTest.cpp +++ b/Tests/Unit/Containers/ServiceDescriptorsMapTest.cpp @@ -54,7 +54,7 @@ TEST_F(ServiceDescriptorsMapTest, ShouldCheckUniqeness) auto act = [&] { map.add(sb::di::ServiceDescriber::describeSingleton()); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorsMapTest, ShouldCheckUniqenessForKeyed) @@ -78,7 +78,7 @@ TEST_F(ServiceDescriptorsMapTest, ShouldCheckUniqenessForKeyed) map.add(desc); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorsMapTest, ShouldCheckUniqenessForAlias) @@ -136,7 +136,7 @@ TEST_F(ServiceDescriptorsMapTest, ShouldFailAddServiceDescriptorAlreadyRegistere auto act = [&] { sb::di::details::ServiceDescriptorsMap map{_descriptors.begin(), _descriptors.end(), true}; }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorsMapTest, ShouldFailAddKeyedServiceDescriptorAlreadyRegistered) @@ -157,7 +157,7 @@ TEST_F(ServiceDescriptorsMapTest, ShouldFailAddKeyedServiceDescriptorAlreadyRegi auto act = [&] { sb::di::details::ServiceDescriptorsMap map{_descriptors.begin(), _descriptors.end(), true}; }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceDescriptorsMapTest, ShouldSealDescriptors) diff --git a/Tests/Unit/Core/ServiceInstanceProviderRootTest.cpp b/Tests/Unit/Core/ServiceInstanceProviderRootTest.cpp index e90cd2fe..1cd04f1c 100644 --- a/Tests/Unit/Core/ServiceInstanceProviderRootTest.cpp +++ b/Tests/Unit/Core/ServiceInstanceProviderRootTest.cpp @@ -54,7 +54,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegister provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegisteredKeyedService) @@ -74,7 +74,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegister provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegisteredInheritedService) @@ -91,7 +91,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegister provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegisteredKeyedInheritedService) @@ -111,7 +111,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAlreadyRegister provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAlreadyRegisteredException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAliasMissmatchInheritedService) @@ -128,7 +128,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAliasMissmatchI provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAliasMissmatchOpositeInheritedService) @@ -145,7 +145,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToAliasMissmatchO provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceAliasMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldNotFailGetServiceDueToAlreadyRegisteredService) @@ -248,7 +248,7 @@ TEST_F(ServiceInstanceProviderRootTest, ShouldFailGetServiceDueToLifetimeMissmat provider.init(mock); }; - EXPECT_THROW(act(), sb::di::ServiceLifeTimeMismatchException); + EXPECT_THROW(act(), sb::di::ServiceRegisterException); } TEST_F(ServiceInstanceProviderRootTest, ShouldPrebuildSingletons) diff --git a/Tests/Unit/Helpers/CtorInjectorTest.cpp b/Tests/Unit/Helpers/CtorInjectorTest.cpp index 0c83131f..7f1993d0 100644 --- a/Tests/Unit/Helpers/CtorInjectorTest.cpp +++ b/Tests/Unit/Helpers/CtorInjectorTest.cpp @@ -1,5 +1,6 @@ #include +#include "../../Helpers/Classes/Complex.hpp" #include "../../Helpers/Classes/Dependencies.hpp" #include "../../Helpers/Mocks/ServiceProviderMock.hpp" #include @@ -21,6 +22,36 @@ class CtorInjectorTest : public testing::Test static void TearDownTestSuite() {} }; +struct LotOfParams +{ + LotOfParams(int a, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, + int a12) + { + } +}; + +struct LotOfRefs +{ + int &a1; + int &a2; + int &a3; + int &a4; + int &a5; + int &a6; + int &a7; + int &a8; + int &a9; + int &a10; + int &a11; +}; + +struct Ambigious +{ + Ambigious(int a, int b) {} + Ambigious(int a, int b, int d) {} + Ambigious(int a, int b, int d, int e) {} +}; + TEST_F(CtorInjectorTest, ShouldInvokeFuncWithCtorParams) { ServiceProviderMock mock; @@ -31,5 +62,18 @@ TEST_F(CtorInjectorTest, ShouldInvokeFuncWithCtorParams) sb::di::details::CtorInjector invoker{mock}; - EXPECT_TRUE(invoker.makeUnique()); + auto result = invoker([](auto... params) { return TestDependencyPtrClass1{params...}; }); + EXPECT_EQ(result._test1, test1.getAs()); +} + +TEST_F(CtorInjectorTest, ShouldGetProperCtorParamsNumber) +{ + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 0); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 1); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 2); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 3); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 3); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 13); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 11); + EXPECT_EQ(sb::di::details::CtorInjector::paramsNumber, 2); } diff --git a/Tests/Unit/Helpers/FunctorInjectorTest.cpp b/Tests/Unit/Helpers/FunctorInjectorTest.cpp index ae848e96..3dcb1b4b 100644 --- a/Tests/Unit/Helpers/FunctorInjectorTest.cpp +++ b/Tests/Unit/Helpers/FunctorInjectorTest.cpp @@ -36,5 +36,5 @@ TEST_F(FunctorInjectorTest, ShouldInvokeFuncFactory) sb::di::details::FunctorInjector invoker{func, mock}; - EXPECT_EQ(invoker.call(), 1); + EXPECT_EQ(invoker(), 1); } diff --git a/Tests/Unit/Helpers/ServiceGetterTest.cpp b/Tests/Unit/Helpers/ServiceGetterTest.cpp index 54699937..3be60a9a 100644 --- a/Tests/Unit/Helpers/ServiceGetterTest.cpp +++ b/Tests/Unit/Helpers/ServiceGetterTest.cpp @@ -2,7 +2,7 @@ #include "../../Helpers/Classes/Dependencies.hpp" #include "../../Helpers/Mocks/ServiceProviderMock.hpp" -#include +#include "SevenBit/DI/Details/Helpers/ServiceGetter.hpp" #include #include diff --git a/Tests/Unit/Utils/CastTest.cpp b/Tests/Unit/Utils/CastTest.cpp index cf57e394..565c8255 100644 --- a/Tests/Unit/Utils/CastTest.cpp +++ b/Tests/Unit/Utils/CastTest.cpp @@ -22,36 +22,32 @@ class CastTest : public testing::Test TEST_F(CastTest, ShouldGetCastOffset) { - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_FALSE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); - EXPECT_TRUE((sb::di::details::Cast::getCastOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_FALSE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); + EXPECT_TRUE((sb::di::details::Cast::getOffset())); } TEST_F(CastTest, ShouldApplyCastOffset) { - EXPECT_EQ((sb::di::details::Cast::applyCastOffset(reinterpret_cast(1), 0)), - reinterpret_cast(1)); - EXPECT_EQ((sb::di::details::Cast::applyCastOffset(reinterpret_cast(1), 1)), - reinterpret_cast(2)); - EXPECT_EQ((sb::di::details::Cast::applyCastOffset(reinterpret_cast(22), 11)), - reinterpret_cast(33)); - EXPECT_EQ((sb::di::details::Cast::applyCastOffset(reinterpret_cast(22), -11)), - reinterpret_cast(11)); + EXPECT_EQ((sb::di::details::Cast::applyOffset(reinterpret_cast(1), 0)), reinterpret_cast(1)); + EXPECT_EQ((sb::di::details::Cast::applyOffset(reinterpret_cast(1), 1)), reinterpret_cast(2)); + EXPECT_EQ((sb::di::details::Cast::applyOffset(reinterpret_cast(22), 11)), reinterpret_cast(33)); + EXPECT_EQ((sb::di::details::Cast::applyOffset(reinterpret_cast(22), -11)), reinterpret_cast(11)); } diff --git a/Tests/Unit/Utils/CtorParamsNumberTest.cpp b/Tests/Unit/Utils/CtorParamsNumberTest.cpp deleted file mode 100644 index 85892124..00000000 --- a/Tests/Unit/Utils/CtorParamsNumberTest.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include - -#include "../../Helpers/Classes/Complex.hpp" -#include - -class CtorParamsNumberTest : public testing::Test -{ - protected: - static void TearUpTestSuite() {} - - CtorParamsNumberTest() {} - - void SetUp() override {} - - void TearDown() override {} - - ~CtorParamsNumberTest() override = default; - - static void TearDownTestSuite() {} -}; - -struct LotOfParams -{ - LotOfParams(int a, int a1, int a2, int a3, int a4, int a5, int a6, int a7, int a8, int a9, int a10, int a11, - int a12) - { - } -}; - -struct LotOfRefs -{ - int &a1; - int &a2; - int &a3; - int &a4; - int &a5; - int &a6; - int &a7; - int &a8; - int &a9; - int &a10; - int &a11; -}; - -struct Ambigious -{ - Ambigious(int a, int b) {} - Ambigious(int a, int b, int d) {} - Ambigious(int a, int b, int d, int e) {} -}; - -TEST_F(CtorParamsNumberTest, ShouldGetProperCtorParamsNumber) -{ - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 0); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 1); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 2); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 3); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 3); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 13); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 11); - EXPECT_EQ(sb::di::details::ctorParamsNumber(), 2); -} diff --git a/Tests/Unit/Utils/StringTest.cpp b/Tests/Unit/Utils/StringTest.cpp new file mode 100644 index 00000000..41f17dc1 --- /dev/null +++ b/Tests/Unit/Utils/StringTest.cpp @@ -0,0 +1,161 @@ +#include + +#include "../../Helpers/Classes/Basic.hpp" +#include +#include + +class StringTest : public testing::Test +{ + protected: + static void TearUpTestSuite() {} + + StringTest() {} + + void SetUp() override {} + + void TearDown() override {} + + ~StringTest() override = default; + + static void TearDownTestSuite() {} +}; + +TEST_F(StringTest, ShouldFail) +{ + EXPECT_THROW(sb::di::details::String::fmt("{", 8), std::runtime_error); + EXPECT_THROW(sb::di::details::String::fmt("{}{", 8, 4), std::runtime_error); +} + +TEST_F(StringTest, ShouldFormatInt) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{+}", 999), "+999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", -999), "-999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8, 2), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8, 2), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8, 2), "8 n 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8, 2), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8, 2), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8, 2), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8, 2), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatLong) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8l), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999l), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{+}", 999l), "+999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", -999l), "-999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0l), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8l, 2l), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8l, 2l), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8l, 2l), "8 n 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8l, 2l), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8l, 2l), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8l, 2l), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8l, 2l), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatLongLong) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8ll), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999ll), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{+}", 999ll), "+999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", -999ll), "-999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0ll), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8ll, 2ll), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8ll, 2ll), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} no {}", 8ll, 2ll), "8 no 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8ll, 2ll), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8ll, 2ll), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8ll, 2ll), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8ll, 2ll), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatUnsigned) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8u), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999u), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0u), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8u, 2u), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8u, 2u), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8u, 2u), "8 n 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8u, 2u), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8u, 2u), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8u, 2u), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8u, 2u), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatUnsignedLong) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8ul), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999ul), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0ul), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8ul, 2ul), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8ul, 2ul), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8ul, 2ul), "8 n 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8ul, 2ul), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8ul, 2ul), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8ul, 2ul), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8ul, 2ul), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatUnsignedLongLong) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8ull), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999ull), "999"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0ull), "0"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8ull, 2ull), "82"); + EXPECT_EQ(sb::di::details::String::fmt("{04}{}", 8ull, 2ull), "00082"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8ull, 2ull), "8 n 2"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8ull, 2ull), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8ull, 2ull), "alice 8"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8ull, 2ull), "8 alice '2'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8ull, 2ull), "8 alice '2' {} hop"); +} + +TEST_F(StringTest, ShouldFormatDouble) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8.1), ""); + EXPECT_EQ(sb::di::details::String::fmt("{}", 999.9), "999.900000"); + EXPECT_EQ(sb::di::details::String::fmt("{+}", 999.1), "+999.100000"); + EXPECT_EQ(sb::di::details::String::fmt("{.2}", -999.8), "-999.80"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0.0), "0.000000"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8.2, 2.2), "8.2000002.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{08.3}{}", 8.2, 2.2), "0008.2002.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8.2, 2.2), "8.200000 n 2.200000"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8.2, 2.2), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8.2, 2.2), "alice 8.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8.2, 2.2), "8.200000 alice '2.200000'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8.2, 2.2), "8.200000 alice '2.200000' {} hop"); +} + +TEST_F(StringTest, ShouldFormatFloat) +{ + EXPECT_EQ(sb::di::details::String::fmt("", 8.1f), ""); + EXPECT_EQ(sb::di::details::String::fmt("{.2}", 999.9f), "999.90"); + EXPECT_EQ(sb::di::details::String::fmt("{+.3}", 999.1f), "+999.100"); + EXPECT_EQ(sb::di::details::String::fmt("{.2}", -999.8f), "-999.80"); + EXPECT_EQ(sb::di::details::String::fmt("{}", 0.0f), "0.000000"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", 8.2f, 2.2f), "8.2000002.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{08.3}{}", 8.2f, 2.2f), "0008.2002.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{} n {}", 8.2f, 2.2f), "8.200000 n 2.200000"); + EXPECT_EQ(sb::di::details::String::fmt("alice", 8.2f, 2.2f), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", 8.2f, 2.2f), "alice 8.200000"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", 8.2f, 2.2f), "8.200000 alice '2.200000'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", 8.2f, 2.2f), "8.200000 alice '2.200000' {} hop"); +} + +TEST_F(StringTest, ShouldFormatString) +{ + EXPECT_EQ(sb::di::details::String::fmt("", ""), ""); + EXPECT_EQ(sb::di::details::String::fmt("yes {-20}", std::string(101, '1')), ("yes " + std::string(101, '1'))); + EXPECT_EQ(sb::di::details::String::fmt("{}", "yes"), "yes"); + EXPECT_EQ(sb::di::details::String::fmt("{}{}", "yes", std::string_view{"no"}), "yesno"); + EXPECT_EQ(sb::di::details::String::fmt("alice", std::string("yes"), "no"), "alice"); + EXPECT_EQ(sb::di::details::String::fmt("alice {}", std::string("yes"), "no"), "alice yes"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}'", "yes", "no"), "yes alice 'no'"); + EXPECT_EQ(sb::di::details::String::fmt("{} alice '{}' {} hop", std::string("yes"), "no"), "yes alice 'no' {} hop"); +}