diff --git a/.github/scripts/prepare_doxygen.sh b/.github/scripts/prepare_doxygen.sh deleted file mode 100644 index f87b122..0000000 --- a/.github/scripts/prepare_doxygen.sh +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh - -project_version=$1 - -project_name="$(head -n 1 README.md | sed 's/#//')" - -repository_name=$(git rev-parse --show-toplevel | xargs basename) - -echo "Clone $repository_name..." -git clone --branch doc https://github.com/eclipse/"$repository_name".git - -cd "$repository_name" || exit - -echo "Delete existing SNAPSHOT directory..." -rm -rf ./*-SNAPSHOT - -echo "Create target directory $project_version..." -mkdir "$project_version" - -echo "Copy Doxygen doc..." -cp -rf ../.github/doxygen/out/html/* "$project_version"/ - -echo "Update versions list..." -echo "| Version | Documents |" >list_versions.md -echo "|:---:|---|" >>list_versions.md -for directory in $(ls -rvd [0-9]*/ | sort -t. -k 1,1nr -k 2,2nr -k 3,3nr -k 4,4nr | cut -f1 -d'/'); do - echo "| $directory | [API documentation]($directory) |" >>list_versions.md -done - -echo "Computed all versions:" -cat list_versions.md - -echo "Update project name to $project_name" -sed -i "2s/.*/title: $project_name/" _config.yml - -cd .. - -echo "Local docs update finished." diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 248a504..8778107 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,4 +1,4 @@ -name: Build and test code +name: Build and Test code on: push: @@ -6,45 +6,9 @@ on: - main pull_request: -jobs: - build: - - strategy: - matrix: - env: - - toolchain: "toolchain/gcc-linux.cmake" - runner: ubuntu-latest - generator: "" - - toolchain: "toolchain/clang-macos.cmake" - runner: macos-latest - generator: "" - - toolchain: "\"toolchain/clang-windows.cmake\"" - runner: windows-latest - generator: "-G \"Visual Studio 17 2022\"" - - runs-on: ${{ matrix.env.runner }} - - steps: - - name: Check out repository - uses: actions/checkout@v4 - - name: Install Linux reqs - if: ${{ matrix.env.runner == 'ubuntu-latest' }} - run: | - sudo apt-get update - sudo apt-get install -y clang cmake cppcheck clang-format clang-tidy gcc pre-commit - - - name: Install macOS reqs - if: ${{ matrix.env.runner == 'macos-latest' }} - run: | - brew install llvm cppcheck clang-format gcc pre-commit - - - name: Build - run: | - cmake ${{ matrix.env.generator }} -B build -S . -DCMAKE_TOOLCHAIN_FILE=${{ matrix.env.toolchain }} - cmake --build build -j8 - - - name: Run Linux/macOS tests - if: ${{ matrix.env.runner == 'ubuntu-latest' || matrix.env.runner == 'macos-latest' }} - run: | - ./build/bin/keypleservicecpplib_ut +jobs: + call-reusable-workflow: + uses: eclipse-keyple/keyple-actions/.github/workflows/reusable-cpp-build-and-test.yml@main # NOSONAR - Same organization, trusted source + with: + test_executable_name: 'build/bin/keypleservicecpplib_ut' diff --git a/.github/workflows/publish-doc-release.yml b/.github/workflows/publish-doc-release.yml index 8e558fe..d26dd8d 100644 --- a/.github/workflows/publish-doc-release.yml +++ b/.github/workflows/publish-doc-release.yml @@ -1,47 +1,14 @@ -name: Publish API documentation - +name: Publish API documentation (release) on: release: types: [published] +permissions: + checks: write + jobs: publish-doc-release: - runs-on: ubuntu-latest - steps: - - name: Check out repository code from ${{ github.repository }}/${{ github.ref }} - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Make scripts executable - run: chmod +x ./.github/scripts/*.sh - - - name: Check version - working-directory: . - run: ./.github/scripts/check_version.sh $(echo "${{ github.ref }}" | sed -e "s,^refs/tags/,,") - - - name: Patch Doxyfile - working-directory: . - run: ./.github/scripts/patch_doxyfile.sh ${{ env.PROJECT_VERSION }} - - - name: Generate project documentation with Doxygen - uses: eclipse-keyple/keyple-actions/doxygen@0c8593c4ed6b393642a1732af1fdef84d5e59540 - with: - working-directory: .github/doxygen/ - doxyfile-path: ./Doxyfile - - - name: Prepare Doxygen doc page locally - working-directory: . - run: ./.github/scripts/prepare_doxygen.sh ${{ env.PROJECT_VERSION }} - - - name: Deploy to doc branch - run: | - git config --global user.name "Eclipse Keypop Bot" - git config --global user.email "${{ github.repository }}-bot@eclipse.org" - cd ${{ github.event.repository.name }} - git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git add . - git commit -m "docs: update ${{ github.event.inputs.version || github.ref_name }} documentation" - git push origin doc --force - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: eclipse-keyple/keyple-actions/.github/workflows/reusable-publish-doxygen.yml@main # NOSONAR - Same organization, trusted source + with: + version: ${{ github.event.inputs.version || github.ref_name }} + secrets: inherit # NOSONAR - Same organization, trusted source diff --git a/.github/workflows/publish-doc-snapshot.yml b/.github/workflows/publish-doc-snapshot.yml index 7094036..d5d29a6 100644 --- a/.github/workflows/publish-doc-snapshot.yml +++ b/.github/workflows/publish-doc-snapshot.yml @@ -1,50 +1,14 @@ name: Publish API documentation (snapshot) - on: push: branches: - main - - master - - doxygen + workflow_dispatch: + +permissions: + checks: write jobs: publish-doc-snapshot: - runs-on: ubuntu-latest - steps: - - name: Check out repository code from ${{ github.repository }}/${{ github.ref }} - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - - name: Make scripts executable - run: chmod +x ./.github/scripts/*.sh - - - name: Check version - working-directory: . - run: ./.github/scripts/check_version.sh - - - name: Patch Doxyfile - working-directory: . - run: ./.github/scripts/patch_doxyfile.sh ${{ env.PROJECT_VERSION }} - - - name: Generate project documentation with Doxygen - uses: eclipse-keyple/keyple-actions/doxygen@0c8593c4ed6b393642a1732af1fdef84d5e59540 - with: - working-directory: .github/doxygen/ - doxyfile-path: ./Doxyfile - - - name: Prepare Doxygen doc page locally - working-directory: . - run: ./.github/scripts/prepare_doxygen.sh ${{ env.PROJECT_VERSION }} - - - name: Deploy to doc branch - run: | - git config --global user.name "Eclipse Keypop Bot" - git config --global user.email "${{ github.repository }}-bot@eclipse.org" - cd ${{ github.event.repository.name }} - git remote set-url origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" - git add . - git diff --quiet && git diff --staged --quiet || git commit -m "docs: update snapshot documentation" - git push origin doc --force - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: eclipse-keyple/keyple-actions/.github/workflows/reusable-publish-doxygen.yml@main # NOSONAR - Same organization, trusted source + secrets: inherit # NOSONAR - Same organization, trusted source diff --git a/CMakeLists.txt b/CMakeLists.txt index a99e38c..4cbc283 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,12 +13,12 @@ CMAKE_MINIMUM_REQUIRED(VERSION 3.5) PROJECT(KeypleServiceCppLib - VERSION 3.2.3 + VERSION 3.3.5 LANGUAGES C CXX) SET(CMAKE_PROJECT_VERSION_MAJOR "3") -SET(CMAKE_PROJECT_VERSION_MINOR "2") -SET(CMAKE_PROJECT_VERSION_PATCH "3") +SET(CMAKE_PROJECT_VERSION_MINOR "3") +SET(CMAKE_PROJECT_VERSION_PATCH "5") SET(CMAKE_PROJECT_VERSION "${CMAKE_PROJECT_VERSION_MAJOR}. ${CMAKE_PROJECT_VERSION_MINOR}. diff --git a/include/keyple/core/service/AbstractReaderAdapter.hpp b/include/keyple/core/service/AbstractReaderAdapter.hpp index 08dd728..ac62b26 100644 --- a/include/keyple/core/service/AbstractReaderAdapter.hpp +++ b/include/keyple/core/service/AbstractReaderAdapter.hpp @@ -81,6 +81,22 @@ class KEYPLESERVICE_API AbstractReaderAdapter : virtual public CardReader, */ const std::string& getPluginName() const; + /** + * Returns the {@link KeypleReaderExtension} that is reader-specific. + * + *

Note: the provided argument is used at compile time to check the type + * consistency. + * + * @param readerExtensionClass The specific class of the reader. + * @param The type of the reader extension. + * @return A {@link KeypleReaderExtension}. + * @throw IllegalStateException If reader is no longer registered. + * @since 2.0.0 + */ + std::shared_ptr + getExtension(const std::type_info& readerExtensionClass) const; + // FIXME? should be final? + /** * Performs a selection scenario following a card detection. * @@ -194,14 +210,6 @@ class KEYPLESERVICE_API AbstractReaderAdapter : virtual public CardReader, */ const std::string& getName() const final; - /** - * {@inheritDoc} - * - * @since 2.0.0 - */ - std::shared_ptr - getExtension(const std::type_info& readerExtensionClass) const; - /** * {@inheritDoc} * diff --git a/include/keyple/core/service/ApduResponseAdapter.hpp b/include/keyple/core/service/ApduResponseAdapter.hpp index 75cd7c9..b727a2a 100644 --- a/include/keyple/core/service/ApduResponseAdapter.hpp +++ b/include/keyple/core/service/ApduResponseAdapter.hpp @@ -60,7 +60,14 @@ class KEYPLESERVICE_API ApduResponseAdapter final : public ApduResponseApi { * * @since 2.0.0 */ - const std::vector getDataOut() const override; + void setApdu(const std::vector& apdu) override; + + /** + * {@inheritDoc} + * + * @since 2.0.0 + */ + std::vector getDataOut() const override; /** * {@inheritDoc} @@ -85,7 +92,7 @@ class KEYPLESERVICE_API ApduResponseAdapter final : public ApduResponseApi { /** * */ - const std::vector mApdu; + std::vector mApdu; /** * diff --git a/include/keyple/core/service/InternalDto.hpp b/include/keyple/core/service/InternalDto.hpp index cab0f78..6e04383 100644 --- a/include/keyple/core/service/InternalDto.hpp +++ b/include/keyple/core/service/InternalDto.hpp @@ -74,9 +74,9 @@ class KEYPLESERVICE_API InternalDto { /** * */ - const std::shared_ptr - parse(const std::shared_ptr - cardSelectionResponseApi) const override; + const std::shared_ptr parse( + const std::shared_ptr + cardSelectionResponseApi) const override; private: /** diff --git a/include/keyple/core/service/InternalLegacyDto.hpp b/include/keyple/core/service/InternalLegacyDto.hpp index 51b761c..6087916 100644 --- a/include/keyple/core/service/InternalLegacyDto.hpp +++ b/include/keyple/core/service/InternalLegacyDto.hpp @@ -80,6 +80,22 @@ class KEYPLESERVICE_API InternalLegacyDto final { std::vector mSuccessfulSelectionStatusWords; }; + /** + * @since 3.3.1 + */ + class LegacyCardRequestV0 final { + public: + /** + * + */ + std::vector> mApduRequests; + + /** + * + */ + bool mIsStatusCodesVerificationEnabled; + }; + /** * @since 2.1.1 */ @@ -104,7 +120,7 @@ class KEYPLESERVICE_API InternalLegacyDto final { /** * @since 2.1.1 */ - class LegacyCardRequest final { + class LegacyCardRequestV1 final { public: /** * @@ -117,10 +133,26 @@ class KEYPLESERVICE_API InternalLegacyDto final { bool mStopOnUnsuccessfulStatusWord; }; + /** + * @since 3.3.1 + */ + class LegacyCardSelectionRequestV0 final { + public: + /** + * + */ + std::shared_ptr mCardSelector; + + /** + * + */ + std::shared_ptr mCardRequest; + }; + /** * @since 2.1.1 */ - class LegacyCardSelectionRequest final { + class LegacyCardSelectionRequestV1 final { public: /** * @@ -130,14 +162,23 @@ class KEYPLESERVICE_API InternalLegacyDto final { /** * */ - std::shared_ptr mCardRequest; + std::shared_ptr mCardRequest; }; /** * */ - static const std::vector> - mapToLegacyCardSelectionRequests( + static const std::vector> + mapToLegacyCardSelectionRequestsV0( + const std::vector>& cardSelectors, + const std::vector>& + cardSelectionRequests); + + /** + * + */ + static const std::vector> + mapToLegacyCardSelectionRequestsV1( const std::vector>& cardSelectors, const std::vector>& cardSelectionRequests); @@ -145,8 +186,16 @@ class KEYPLESERVICE_API InternalLegacyDto final { /** * */ - static std::shared_ptr - mapToLegacyCardSelectionRequest( + static std::shared_ptr + mapToLegacyCardSelectionRequestV0( + std::shared_ptr cardSelector, + std::shared_ptr cardSelectionRequestSpi); + + /** + * + */ + static std::shared_ptr + mapToLegacyCardSelectionRequestV1( std::shared_ptr cardSelector, std::shared_ptr cardSelectionRequestSpi); @@ -161,7 +210,13 @@ class KEYPLESERVICE_API InternalLegacyDto final { * */ static std::shared_ptr - mapToLegacyCardRequest(const std::shared_ptr cardRequest); + mapToLegacyCardRequestV0(const std::shared_ptr cardRequest); + + /** + * + */ + static std::shared_ptr + mapToLegacyCardRequestV1(const std::shared_ptr cardRequest); /** * diff --git a/include/keyple/core/service/LocalReaderAdapter.hpp b/include/keyple/core/service/LocalReaderAdapter.hpp index c33104d..63dec5f 100644 --- a/include/keyple/core/service/LocalReaderAdapter.hpp +++ b/include/keyple/core/service/LocalReaderAdapter.hpp @@ -172,7 +172,6 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { void releaseChannel() final; /** - * (private)
* Local implementation of ApduRequestSpi. */ class ApduRequest : public ApduRequestSpi { @@ -187,7 +186,12 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { /** * */ - std::vector getApdu() const override; + const std::vector& getApdu() const override; + + /** + * C++ + */ + void setApdu(const std::vector& apdu) override; /** * @@ -442,8 +446,10 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { * @param cardSelector A not null CardSelector. * @param cardSelectionRequest A not null CardSelectionRequestSpi. * @return A not null {@link SelectionStatus}. - * @throw ReaderIOException if the communication with the reader has failed. - * @throw CardIOException if the communication with the card has failed. + * @throw ReaderBrokenCommunicationException If the communication with the + * reader has failed. + * @throw CardBrokenCommunicationException If the communication with the + * card has failed. */ std::shared_ptr processSelection( std::shared_ptr cardSelector, @@ -453,6 +459,7 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { * Attempts to select the card and executes the optional requests if any. * * @param cardSelectionRequest The CardSelectionRequestSpi to be processed. + * @param channelControl The channelControl. * @return A not null reference. * @throw ReaderBrokenCommunicationException If the communication with the * reader has failed. @@ -463,7 +470,8 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { */ std::shared_ptr processCardSelectionRequest( std::shared_ptr cardSelector, - std::shared_ptr cardSelectionRequest); + std::shared_ptr cardSelectionRequest, + const ChannelControl channelControl); /** * Transmits an ApduRequestSpi and receives the ApduResponseAdapter. @@ -479,21 +487,6 @@ class KEYPLESERVICE_API LocalReaderAdapter : public AbstractReaderAdapter { std::shared_ptr processApduRequest(const std::shared_ptr apduRequest); - /** - * Transmits a CardRequestSpi and returns a CardResponseAdapter. - * - * @param cardRequest The card request to transmit. - * @return A not null reference. - * @throw ReaderBrokenCommunicationException If the communication with the - * reader has failed. - * @throw CardBrokenCommunicationException If the communication with the - * card has failed. - * @throw UnexpectedStatusWordException If status word verification is - * enabled in the card request and the card returned an unexpected code. - */ - std::shared_ptr - processCardRequest(const std::shared_ptr cardRequest); - /** * */ diff --git a/include/keyple/core/service/ObservableLocalReaderAdapter.hpp b/include/keyple/core/service/ObservableLocalReaderAdapter.hpp index 883e6dd..defbe6b 100644 --- a/include/keyple/core/service/ObservableLocalReaderAdapter.hpp +++ b/include/keyple/core/service/ObservableLocalReaderAdapter.hpp @@ -469,6 +469,43 @@ class KEYPLESERVICE_API ObservableLocalReaderAdapter cardSelectionResponses); }; +/** + * Operator << for InternalEvent enum to enable readable logging. + * + * @param os The output stream. + * @param event The internal event. + * @return The output stream. + */ +inline std::ostream& +operator<<(std::ostream& os, + const ObservableLocalReaderAdapter::InternalEvent event) +{ + switch (event) { + case ObservableLocalReaderAdapter::InternalEvent::CARD_INSERTED: + os << "CARD_INSERTED"; + break; + case ObservableLocalReaderAdapter::InternalEvent::CARD_REMOVED: + os << "CARD_REMOVED"; + break; + case ObservableLocalReaderAdapter::InternalEvent::CARD_PROCESSED: + os << "CARD_PROCESSED"; + break; + case ObservableLocalReaderAdapter::InternalEvent::START_DETECT: + os << "START_DETECT"; + break; + case ObservableLocalReaderAdapter::InternalEvent::STOP_DETECT: + os << "STOP_DETECT"; + break; + case ObservableLocalReaderAdapter::InternalEvent::TIME_OUT: + os << "TIME_OUT"; + break; + default: + os << "UNKNOWN_EVENT(" << static_cast(event) << ")"; + break; + } + return os; +} + } /* namespace service */ } /* namespace core */ } /* namespace keyple */ diff --git a/include/keyple/core/service/PluginEvent.hpp b/include/keyple/core/service/PluginEvent.hpp index 6a2bcee..ae09794 100644 --- a/include/keyple/core/service/PluginEvent.hpp +++ b/include/keyple/core/service/PluginEvent.hpp @@ -93,20 +93,27 @@ class KEYPLESERVICE_API PluginEvent { virtual Type getType() const = 0; /** + * Operator << for PluginEvent::Type enum to enable readable logging. * + * @param os The output stream. + * @param t The event type. + * @return The output stream. */ friend std::ostream& operator<<(std::ostream& os, const Type t) { switch (t) { case Type::READER_CONNECTED: - os << "TYPE = READER_CONNECTED"; + os << "READER_CONNECTED"; break; case Type::READER_DISCONNECTED: - os << "TYPE = READER_DISCONNECTED"; + os << "READER_DISCONNECTED"; break; case Type::UNAVAILABLE: - os << "TYPE = UNAVAILABLE"; + os << "UNAVAILABLE"; + break; + default: + os << "UNKNOWN_TYPE(" << static_cast(t) << ")"; break; } diff --git a/include/keyple/core/service/SmartCardService.hpp b/include/keyple/core/service/SmartCardService.hpp index bddfc79..f4afb9b 100644 --- a/include/keyple/core/service/SmartCardService.hpp +++ b/include/keyple/core/service/SmartCardService.hpp @@ -20,6 +20,7 @@ #include "keyple/core/common/KeypleCardExtension.hpp" #include "keyple/core/common/KeyplePluginExtensionFactory.hpp" #include "keyple/core/service/KeypleServiceExport.hpp" +#include "keyple/core/service/Plugin.hpp" #include "keypop/reader/ReaderApiFactory.hpp" namespace keyple { @@ -28,6 +29,7 @@ namespace service { using keyple::core::common::KeypleCardExtension; using keyple::core::common::KeyplePluginExtensionFactory; +using keyple::core::service::Plugin; using keypop::reader::ReaderApiFactory; /** @@ -134,7 +136,8 @@ class KEYPLESERVICE_API SmartCardService { * @since 2.0.0 */ virtual void checkCardExtension( - const std::shared_ptr cardExtension) const = 0; + const std::shared_ptr cardExtension) const + = 0; /** * Registers a new distributed local service to the service. diff --git a/include/keyple/core/service/cpp/ExecutorService.hpp b/include/keyple/core/service/cpp/ExecutorService.hpp index eae19b1..6a4c068 100644 --- a/include/keyple/core/service/cpp/ExecutorService.hpp +++ b/include/keyple/core/service/cpp/ExecutorService.hpp @@ -13,7 +13,9 @@ #pragma once +#include #include +#include #include #include #include @@ -74,25 +76,35 @@ class KEYPLESERVICE_API ExecutorService final { /** * */ - void run(); + std::mutex mMutex; + + /** + * + */ + std::condition_variable mCondition; /** * */ - std::atomic mRunning; + bool mRunning; /** * */ - std::atomic mTerminated; + bool mTerminated; /** * */ - std::thread* mThread; + std::unique_ptr mThread; + + /** + * + */ + void run(); }; } /* namespace cpp */ } /* namespace service */ } /* namespace core */ -} /* namespace keyple */ +} /* namespace keyple */ \ No newline at end of file diff --git a/src/main/AbstractReaderAdapter.cpp b/src/main/AbstractReaderAdapter.cpp index ac15b62..2731545 100644 --- a/src/main/AbstractReaderAdapter.cpp +++ b/src/main/AbstractReaderAdapter.cpp @@ -53,6 +53,15 @@ AbstractReaderAdapter::getPluginName() const return mPluginName; } +std::shared_ptr +AbstractReaderAdapter::getExtension( + const std::type_info& /*readerExtensionClass*/) const +{ + checkStatus(); + + return mReaderExtension; +} + const std::vector> AbstractReaderAdapter::transmitCardSelectionRequests( const std::vector>& cardSelectors, @@ -130,17 +139,6 @@ AbstractReaderAdapter::getName() const return mReaderName; } -std::shared_ptr -AbstractReaderAdapter::getExtension( - const std::type_info& readerExtensionClass) const -{ - (void)readerExtensionClass; - - checkStatus(); - - return mReaderExtension; -} - const std::shared_ptr AbstractReaderAdapter::transmitCardRequest( const std::shared_ptr cardRequest, diff --git a/src/main/ApduResponseAdapter.cpp b/src/main/ApduResponseAdapter.cpp index 41d25b0..3199b75 100644 --- a/src/main/ApduResponseAdapter.cpp +++ b/src/main/ApduResponseAdapter.cpp @@ -39,7 +39,13 @@ ApduResponseAdapter::getApdu() const return mApdu; } -const std::vector +void +ApduResponseAdapter::setApdu(const std::vector& apdu) +{ + mApdu = apdu; +} + +std::vector ApduResponseAdapter::getDataOut() const { return Arrays::copyOfRange(mApdu, 0, static_cast(mApdu.size()) - 2); diff --git a/src/main/CardRemovalPassiveMonitoringJobAdapter.cpp b/src/main/CardRemovalPassiveMonitoringJobAdapter.cpp index 32e6da5..e6bde18 100644 --- a/src/main/CardRemovalPassiveMonitoringJobAdapter.cpp +++ b/src/main/CardRemovalPassiveMonitoringJobAdapter.cpp @@ -59,6 +59,8 @@ void CardRemovalPassiveMonitoringJobAdapter::CardRemovalPassiveMonitoringJob:: execute() { + bool isTaskCanceled = false; + auto cardRemovalWaiterBlockingSpi = std::dynamic_pointer_cast( mParent->mReaderSpi); @@ -92,6 +94,7 @@ CardRemovalPassiveMonitoringJobAdapter::CardRemovalPassiveMonitoringJob:: mParent->getReader()->getName(), e.getMessage()); } catch (const TaskCanceledException& e) { + isTaskCanceled = true; mParent->mLogger->warn( "Monitoring job process cancelled: %\n", e.getMessage()); } catch (const RuntimeException& e) { @@ -104,7 +107,9 @@ CardRemovalPassiveMonitoringJobAdapter::CardRemovalPassiveMonitoringJob:: } /* Finally */ - mMonitoringState->onEvent(InternalEvent::CARD_REMOVED); + if (!isTaskCanceled) { + mMonitoringState->onEvent(InternalEvent::CARD_REMOVED); + } } /* CARD REMOVAL PASSIVE MONITORING JOB ADAPTER diff --git a/src/main/InternalLegacyDto.cpp b/src/main/InternalLegacyDto.cpp index e506823..9ceb673 100644 --- a/src/main/InternalLegacyDto.cpp +++ b/src/main/InternalLegacyDto.cpp @@ -26,32 +26,66 @@ InternalLegacyDto::InternalLegacyDto() { } -const std::vector> -InternalLegacyDto::mapToLegacyCardSelectionRequests( +const std::vector> +InternalLegacyDto::mapToLegacyCardSelectionRequestsV0( const std::vector>& cardSelectors, const std::vector>& cardSelectionRequests) { - std::vector> result; + std::vector> result; for (int i = 0; i < cardSelectors.size(); i++) { - result.push_back(mapToLegacyCardSelectionRequest( + result.push_back(mapToLegacyCardSelectionRequestV0( cardSelectors[i], cardSelectionRequests[i])); } return result; } -std::shared_ptr -InternalLegacyDto::mapToLegacyCardSelectionRequest( +const std::vector> +InternalLegacyDto::mapToLegacyCardSelectionRequestsV1( + const std::vector>& cardSelectors, + const std::vector>& + cardSelectionRequests) +{ + std::vector> result; + + for (int i = 0; i < cardSelectors.size(); i++) { + result.push_back(mapToLegacyCardSelectionRequestV1( + cardSelectors[i], cardSelectionRequests[i])); + } + + return result; +} + +std::shared_ptr +InternalLegacyDto::mapToLegacyCardSelectionRequestV0( + std::shared_ptr cardSelector, + std::shared_ptr cardSelectionRequestSpi) +{ + auto result = std::make_shared(); + + result->mCardRequest = cardSelectionRequestSpi->getCardRequest() != nullptr + ? mapToLegacyCardRequestV0( + cardSelectionRequestSpi->getCardRequest()) + : nullptr; + + result->mCardSelector + = mapToLegacyCardSelector(cardSelector, cardSelectionRequestSpi); + + return result; +} + +std::shared_ptr +InternalLegacyDto::mapToLegacyCardSelectionRequestV1( std::shared_ptr cardSelector, std::shared_ptr cardSelectionRequestSpi) { - auto result = std::make_shared(); + auto result = std::make_shared(); result->mCardRequest = cardSelectionRequestSpi->getCardRequest() != nullptr - ? mapToLegacyCardRequest( - cardSelectionRequestSpi->getCardRequest()) + ? mapToLegacyCardRequestV1( + cardSelectionRequestSpi->getCardRequest()) : nullptr; result->mCardSelector @@ -92,10 +126,24 @@ InternalLegacyDto::mapToLegacyCardSelector( } std::shared_ptr -InternalLegacyDto::mapToLegacyCardRequest( +InternalLegacyDto::mapToLegacyCardRequestV0( + const std::shared_ptr cardRequest) +{ + auto result = std::make_shared(); + + result->mApduRequests + = mapToLegacyApduRequests(cardRequest->getApduRequests()); + result->mIsStatusCodesVerificationEnabled + = cardRequest->stopOnUnsuccessfulStatusWord(); + + return result; +} + +std::shared_ptr +InternalLegacyDto::mapToLegacyCardRequestV1( const std::shared_ptr cardRequest) { - auto result = std::make_shared(); + auto result = std::make_shared(); result->mApduRequests = mapToLegacyApduRequests(cardRequest->getApduRequests()); diff --git a/src/main/LocalReaderAdapter.cpp b/src/main/LocalReaderAdapter.cpp index 5fa32bc..6b9c96b 100644 --- a/src/main/LocalReaderAdapter.cpp +++ b/src/main/LocalReaderAdapter.cpp @@ -280,80 +280,71 @@ LocalReaderAdapter::processSelection( std::shared_ptr cardSelector, std::shared_ptr cardSelectionRequest) { - /* RL-CLA-CHAAUTO.1 */ - std::string powerOnData = ""; - std::shared_ptr fciResponse = nullptr; - bool hasMatched = true; - - auto internalSelector - = std::dynamic_pointer_cast(cardSelector); - if (!internalSelector) { - throw RuntimeException( - "cardSelector is not of type InternalCardSelector."); - } + try { + /* RL-CLA-CHAAUTO.1 */ + std::string powerOnData = ""; + std::shared_ptr fciResponse = nullptr; + bool hasMatched = true; + + auto internalSelector + = std::dynamic_pointer_cast(cardSelector); + if (!internalSelector) { + throw RuntimeException( + "cardSelector is not of type InternalCardSelector."); + } - const std::string& logicalProtocolName - = internalSelector->getLogicalProtocolName(); - if (logicalProtocolName != "" && mUseDefaultProtocol) { - throw IllegalStateException( - "Protocol " + logicalProtocolName - + " not associated to a reader protocol."); - } + const std::string& logicalProtocolName + = internalSelector->getLogicalProtocolName(); + if (logicalProtocolName != "" && mUseDefaultProtocol) { + throw IllegalStateException( + "Protocol " + logicalProtocolName + + " not associated to a reader protocol."); + } - /* Check protocol if enabled */ - if (logicalProtocolName == "" - || logicalProtocolName == mCurrentLogicalProtocolName) { - /* - * Protocol check succeeded, check power-on data if enabled - * RL-ATR-FILTER - * RL-SEL-USAGE.1 - */ - powerOnData = mReaderSpi->getPowerOnData(); - if (checkPowerOnData(powerOnData, internalSelector)) { - /* No power-on data filter or power-on data check succeeded, select - * by AID if enabled */ - const auto internalIsoCardSelector - = std::dynamic_pointer_cast( - cardSelector); - if (internalIsoCardSelector - && internalIsoCardSelector->getAid().size() != 0) { - fciResponse = selectByAid(internalIsoCardSelector); - const std::vector& statusWords - = cardSelectionRequest->getSuccessfulSelectionStatusWords(); - hasMatched = std::find( - statusWords.begin(), - statusWords.end(), - fciResponse->getStatusWord()) - != statusWords.end(); + /* Check protocol if enabled */ + if (logicalProtocolName == "" + || logicalProtocolName == mCurrentLogicalProtocolName) { + /* + * Protocol check succeeded, check power-on data if enabled + * RL-ATR-FILTER + * RL-SEL-USAGE.1 + */ + powerOnData = mReaderSpi->getPowerOnData(); + if (checkPowerOnData(powerOnData, internalSelector)) { + /* No power-on data filter or power-on data check succeeded, + * select by AID if enabled */ + const auto internalIsoCardSelector + = std::dynamic_pointer_cast( + cardSelector); + if (internalIsoCardSelector + && internalIsoCardSelector->getAid().size() != 0) { + fciResponse = selectByAid(internalIsoCardSelector); + const std::vector& statusWords + = cardSelectionRequest + ->getSuccessfulSelectionStatusWords(); + hasMatched = std::find( + statusWords.begin(), + statusWords.end(), + fciResponse->getStatusWord()) + != statusWords.end(); + } else { + fciResponse = nullptr; + } } else { + /* Check failed */ + hasMatched = false; fciResponse = nullptr; } } else { - /* Check failed */ - hasMatched = false; + /* Protocol failed */ + powerOnData = ""; fciResponse = nullptr; + hasMatched = false; } - } else { - /* Protocol failed */ - powerOnData = ""; - fciResponse = nullptr; - hasMatched = false; - } - return std::make_shared( - powerOnData, fciResponse, hasMatched); -} + return std::make_shared( + powerOnData, fciResponse, hasMatched); -std::shared_ptr -LocalReaderAdapter::processCardSelectionRequest( - std::shared_ptr cardSelector, - std::shared_ptr cardSelectionRequest) -{ - mIsLogicalChannelOpen = false; - std::shared_ptr selectionStatus = nullptr; - - try { - selectionStatus = processSelection(cardSelector, cardSelectionRequest); } catch (const ReaderIOException& e) { throw ReaderBrokenCommunicationException( std::make_shared( @@ -361,6 +352,7 @@ LocalReaderAdapter::processCardSelectionRequest( false, e.getMessage(), std::make_shared(e)); + } catch (const CardIOException& e) { throw CardBrokenCommunicationException( std::make_shared( @@ -369,7 +361,18 @@ LocalReaderAdapter::processCardSelectionRequest( e.getMessage(), std::make_shared(e)); } +} +std::shared_ptr +LocalReaderAdapter::processCardSelectionRequest( + std::shared_ptr cardSelector, + std::shared_ptr cardSelectionRequest, + const ChannelControl channelControl) +{ + mIsLogicalChannelOpen = false; + + std::shared_ptr selectionStatus( + processSelection(cardSelector, cardSelectionRequest)); if (!selectionStatus->mHasMatched) { /* The selection failed, return an empty response having the selection * status */ @@ -387,7 +390,8 @@ LocalReaderAdapter::processCardSelectionRequest( if (cardSelectionRequest->getCardRequest() != nullptr) { cardResponse - = processCardRequest(cardSelectionRequest->getCardRequest()); + = std::dynamic_pointer_cast(processCardRequest( + cardSelectionRequest->getCardRequest(), channelControl)); } else { cardResponse = nullptr; } @@ -449,8 +453,10 @@ LocalReaderAdapter::processApduRequest( * RL-SW-6CXX.1 * Update the last command with the provided "le" */ - apduRequest->getApdu()[apduRequest->getApdu().size() - 1] + std::vector apdu = apduRequest->getApdu(); + apdu[apduRequest->getApdu().size() - 1] = (apduResponse->getStatusWord() & SW2_MASK); + apduRequest->setApdu(apdu); /* Replay the last command APDU */ apduResponse = processApduRequest(apduRequest); @@ -481,66 +487,6 @@ LocalReaderAdapter::processApduRequest( return apduResponse; } -std::shared_ptr -LocalReaderAdapter::processCardRequest( - const std::shared_ptr cardRequest) -{ - std::vector> apduResponses; - - /* Proceeds with the APDU requests present in the CardRequest */ - for (const auto& apduRequest : cardRequest->getApduRequests()) { - try { - const auto apduResponse = processApduRequest(apduRequest); - apduResponses.push_back(apduResponse); - - const std::vector& successfulSW - = apduRequest->getSuccessfulStatusWords(); - if (cardRequest->stopOnUnsuccessfulStatusWord() - && std::find( - successfulSW.begin(), - successfulSW.end(), - apduResponse->getStatusWord()) - == apduRequest->getSuccessfulStatusWords().end()) { - throw UnexpectedStatusWordException( - std::make_shared(apduResponses, false), - cardRequest->getApduRequests().size() - == apduResponses.size(), - "Unexpected status word"); - } - } catch (const ReaderIOException& e) { - /* - * The process has been interrupted. We close the logical channel - * and launch a KeypleReaderException with the Apdu responses - * collected so far. - */ - closeLogicalAndPhysicalChannelsSilently(); - - throw ReaderBrokenCommunicationException( - std::make_shared(apduResponses, false), - false, - "Reader communication failure while transmitting a card " - "request", - std::make_shared(e)); - } catch (const CardIOException& e) { - /* - * The process has been interrupted. We close the logical channel - * and launch a KeypleReaderException with the Apdu responses - * collected so far. - */ - closeLogicalAndPhysicalChannelsSilently(); - - throw CardBrokenCommunicationException( - std::make_shared(apduResponses, false), - false, - "Card communication failure while transmitting a card request", - std::make_shared(e)); - } - } - - return std::make_shared( - apduResponses, mIsLogicalChannelOpen); -} - void LocalReaderAdapter::releaseChannel() { @@ -627,17 +573,54 @@ LocalReaderAdapter::processCardRequest( { checkStatus(); - std::shared_ptr cardResponse = nullptr; + /* Proceeds with the APDU requests present in the CardRequest */ + std::vector> apduResponses; + + for (const auto& apduRequest : cardRequest->getApduRequests()) { + try { + const std::shared_ptr apduResponse( + processApduRequest(apduRequest)); + apduResponses.push_back(apduResponse); + if (cardRequest->stopOnUnsuccessfulStatusWord() + && !Arrays::contains( + apduRequest->getSuccessfulStatusWords(), + apduResponse->getStatusWord())) { + if (channelControl == ChannelControl::CLOSE_AFTER) { + closeLogicalAndPhysicalChannelsSilently(); + } + throw UnexpectedStatusWordException( + std::make_shared(apduResponses, false), + cardRequest->getApduRequests().size() + == apduResponses.size(), + "Unexpected status word"); + } + + } catch (const ReaderIOException& e) { + closeLogicalAndPhysicalChannelsSilently(); + throw ReaderBrokenCommunicationException( + std::make_shared(apduResponses, false), + false, + "Reader communication failure while transmitting a card " + "request", + std::make_shared(e)); - /* Process the CardRequest and keep the CardResponse */ - cardResponse = processCardRequest(cardRequest); + } catch (const CardIOException& e) { + closeLogicalAndPhysicalChannelsSilently(); + throw CardBrokenCommunicationException( + std::make_shared(apduResponses, false), + false, + "Card communication failure while transmitting a card request", + std::make_shared(e)); + } + } /* Close the channel if requested */ if (channelControl == ChannelControl::CLOSE_AFTER) { releaseChannel(); } - return cardResponse; + return std::make_shared( + apduResponses, mIsLogicalChannelOpen); } std::vector> @@ -681,7 +664,7 @@ LocalReaderAdapter::processCardSelectionRequests( ++p.first, ++p.second) { /* Process the CardRequest and append the CardResponse list */ const auto cardSelectionResponse - = processCardSelectionRequest(*p.first, *p.second); + = processCardSelectionRequest(*p.first, *p.second, channelControl); cardSelectionResponses.push_back(cardSelectionResponse); if (multiSelectionProcessing == MultiSelectionProcessing::PROCESS_ALL) { @@ -795,12 +778,18 @@ LocalReaderAdapter::ApduRequest::setInfo(const std::string& info) return *this; } -std::vector +const std::vector& LocalReaderAdapter::ApduRequest::getApdu() const { return mApdu; } +void +LocalReaderAdapter::ApduRequest::setApdu(const std::vector& apdu) +{ + mApdu = apdu; +} + const std::vector& LocalReaderAdapter::ApduRequest::getSuccessfulStatusWords() const { diff --git a/src/main/MonitoringState.cpp b/src/main/MonitoringState.cpp index 3d9cf70..c5f0659 100644 --- a/src/main/MonitoringState.cpp +++ b/src/main/MonitoringState.cpp @@ -22,16 +22,16 @@ operator<<(std::ostream& os, const MonitoringState ms) { switch (ms) { case MonitoringState::WAIT_FOR_START_DETECTION: - os << "MONITORING_STATE = WAIT_FOR_START_DETECTION"; + os << "WAIT_FOR_START_DETECTION"; break; case MonitoringState::WAIT_FOR_CARD_PROCESSING: - os << "MONITORING_STATE = WAIT_FOR_CARD_PROCESSING"; + os << "WAIT_FOR_CARD_PROCESSING"; break; case MonitoringState::WAIT_FOR_CARD_REMOVAL: - os << "MONITORING_STATE = WAIT_FOR_CARD_REMOVAL"; + os << "WAIT_FOR_CARD_REMOVAL"; break; case MonitoringState::WAIT_FOR_CARD_INSERTION: - os << "MONITORING_STATE = WAIT_FOR_CARD_INSERTION"; + os << "WAIT_FOR_CARD_INSERTION"; break; } diff --git a/src/main/SmartCardServiceAdapter.cpp b/src/main/SmartCardServiceAdapter.cpp index 4e1ae41..0f48446 100644 --- a/src/main/SmartCardServiceAdapter.cpp +++ b/src/main/SmartCardServiceAdapter.cpp @@ -292,16 +292,10 @@ std::shared_ptr SmartCardServiceAdapter::findReader(const std::string& readerNameRegex) const { for (const auto& plugin : mPlugins) { - for (const auto& reader : plugin.second->getReaders()) { - try { - if (StringUtils::matches(reader->getName(), readerNameRegex)) { - return reader; - } - } catch (const PatternSyntaxException& e) { - throw IllegalArgumentException( - "readerNameRegex is invalid: " + e.getMessage(), - std::make_shared(e)); - } + std::shared_ptr reader( + plugin.second->findReader(readerNameRegex)); + if (reader != nullptr) { + return reader; } } diff --git a/src/main/WaitForCardInsertionStateAdapter.cpp b/src/main/WaitForCardInsertionStateAdapter.cpp index dc7845f..bfd57fb 100644 --- a/src/main/WaitForCardInsertionStateAdapter.cpp +++ b/src/main/WaitForCardInsertionStateAdapter.cpp @@ -24,10 +24,10 @@ WaitForCardInsertionStateAdapter::WaitForCardInsertionStateAdapter( std::shared_ptr monitoringJob, std::shared_ptr executorService) : AbstractObservableStateAdapter( - MonitoringState::WAIT_FOR_CARD_INSERTION, - reader, - monitoringJob, - executorService) + MonitoringState::WAIT_FOR_CARD_INSERTION, + reader, + monitoringJob, + executorService) { } @@ -42,8 +42,8 @@ WaitForCardInsertionStateAdapter::onEvent(const InternalEvent event) { mLogger->trace( "Internal event [%] received for reader [%] in current state [%]\n", - getReader()->getName(), event, + getReader()->getName(), getMonitoringState()); /* Process InternalEvent */ @@ -72,16 +72,6 @@ WaitForCardInsertionStateAdapter::onEvent(const InternalEvent event) case InternalEvent::STOP_DETECT: switchState(MonitoringState::WAIT_FOR_START_DETECTION); break; - - case InternalEvent::CARD_REMOVED: - /* The card has been removed during default selection */ - if (getReader()->getDetectionMode() == DetectionMode::REPEATING) { - switchState(MonitoringState::WAIT_FOR_CARD_INSERTION); - } else { - switchState(MonitoringState::WAIT_FOR_START_DETECTION); - } - break; - default: mLogger->trace("Event ignored\n"); break; diff --git a/src/main/WaitForCardProcessingStateAdapter.cpp b/src/main/WaitForCardProcessingStateAdapter.cpp index 3f25677..2c697e3 100644 --- a/src/main/WaitForCardProcessingStateAdapter.cpp +++ b/src/main/WaitForCardProcessingStateAdapter.cpp @@ -44,8 +44,8 @@ WaitForCardProcessingStateAdapter::onEvent(const InternalEvent event) { mLogger->trace( "Internal event [%] received for reader [%] in current state [%]\n", - getReader()->getName(), event, + getReader()->getName(), getMonitoringState()); /* Process InternalEvent */ diff --git a/src/main/WaitForCardRemovalStateAdapter.cpp b/src/main/WaitForCardRemovalStateAdapter.cpp index d326108..8cbf5ad 100644 --- a/src/main/WaitForCardRemovalStateAdapter.cpp +++ b/src/main/WaitForCardRemovalStateAdapter.cpp @@ -42,8 +42,8 @@ WaitForCardRemovalStateAdapter::onEvent(const InternalEvent event) { mLogger->trace( "Internal event [%] received for reader [%] in current state [%]\n", - getReader()->getName(), event, + getReader()->getName(), getMonitoringState()); /* Process InternalEvent */ diff --git a/src/main/WaitForStartDetectStateAdapter.cpp b/src/main/WaitForStartDetectStateAdapter.cpp index 2f7826c..41b268a 100644 --- a/src/main/WaitForStartDetectStateAdapter.cpp +++ b/src/main/WaitForStartDetectStateAdapter.cpp @@ -42,8 +42,8 @@ WaitForStartDetectStateAdapter::onEvent(const InternalEvent event) { mLogger->trace( "Internal event [%] received for reader [%] in current state [%]\n", - getReader()->getName(), event, + getReader()->getName(), getMonitoringState()); /* Process InternalEvent */ diff --git a/src/main/cpp/ExecutorService.cpp b/src/main/cpp/ExecutorService.cpp index 721ab80..9ffa028 100644 --- a/src/main/cpp/ExecutorService.cpp +++ b/src/main/cpp/ExecutorService.cpp @@ -14,6 +14,9 @@ #include "keyple/core/service/cpp/ExecutorService.hpp" #include +#include +#include +#include #include "keyple/core/service/AbstractObservableStateAdapter.hpp" #include "keyple/core/util/cpp/Thread.hpp" @@ -27,37 +30,43 @@ using keyple::core::service::AbstractObservableStateAdapter; using keyple::core::util::cpp::Thread; ExecutorService::ExecutorService() -: mRunning(true) +: mRunning(false) , mTerminated(false) { - mThread = new std::thread(&ExecutorService::run, this); } ExecutorService::~ExecutorService() { - mRunning = false; - - while (!mTerminated) { - Thread::sleep(10); - } + shutdown(); } void ExecutorService::run() { - /* Emulates a SingleThreadExecutor (e.g. only one thread at a time) */ + while (true) { + std::unique_lock lock(mMutex); - while (mRunning) { - if (mPool.size()) { - /* Start first service and wait until completion */ - std::shared_ptr job = mPool[0]; - job->run(); + // Wait until there's a job or the service is shutting down + mCondition.wait(lock, [this]{ + return !mPool.empty() || !mRunning; + }); - /* Remove from vector */ - mPool.erase(mPool.begin()); + // Check if we should terminate + if (!mRunning && mPool.empty()) { + break; } - Thread::sleep(100); + // Get the job and remove it from the pool + std::shared_ptr job = mPool.front(); + mPool.erase(mPool.begin()); + + // Unlock the mutex before running the job + // This allows other threads to submit new jobs while one is being processed + lock.unlock(); + + if (!job->isCancelled()) { + job->run(); + } } mTerminated = true; @@ -66,28 +75,47 @@ ExecutorService::run() void ExecutorService::execute(std::shared_ptr job) { - mPool.push_back(job); + { + std::lock_guard lock(mMutex); + if (!mThread) { + mRunning = true; + mThread = std::unique_ptr(new std::thread(&ExecutorService::run, this)); + } + mPool.push_back(job); + } + mCondition.notify_one(); } std::shared_ptr ExecutorService::submit(std::shared_ptr job) { - mPool.push_back(job); - + execute(job); + std::lock_guard lock(mMutex); return mPool.back(); } void ExecutorService::shutdown() { - mRunning = false; + { + std::lock_guard lock(mMutex); + if (!mThread) { + return; + } + mRunning = false; + } - while (!mTerminated) { - Thread::sleep(10); + mCondition.notify_one(); + + if (mThread->joinable()) { + mThread->join(); } + + mThread.reset(); + mTerminated = true; } } /* namespace cpp */ } /* namespace service */ } /* namespace core */ -} /* namespace keyple */ +} /* namespace keyple */ \ No newline at end of file diff --git a/src/main/cpp/Job.cpp b/src/main/cpp/Job.cpp index da2349a..de2958f 100644 --- a/src/main/cpp/Job.cpp +++ b/src/main/cpp/Job.cpp @@ -39,12 +39,12 @@ Job::cancel(const bool mayInterruptIfRunning) "Unsupported value for mayInterruptIfRunning (true)"); } + mCancelled = true; + if (!isAlive()) { return false; } - mCancelled = true; - return true; } diff --git a/src/main/mainpage.dox b/src/main/mainpage.dox new file mode 100644 index 0000000..4dbccbb --- /dev/null +++ b/src/main/mainpage.dox @@ -0,0 +1,23 @@ +/** + * @mainpage Keyple Service C++ Library + * + * @section overview Overview + * + * The **Keyple Service C++ Library** contains the Keyple core components, + * providing the fundamental services and orchestration layer for the + * Keyple middleware architecture. + * + * @section key_features Key Features + * + * - Core Keyple service components + * - Plugin and reader management + * - Card selection and transaction orchestration + * - Event-driven architecture support + * - Service layer coordination + * + * @section resources Resources + * + * - **Documentation**: [keyple.org](https://keyple.org) + * - **API Documentation**: [docs.keyple.org/keyple-service-cpp-lib](https://docs.keyple.org/keyple-service-cpp-lib) + * - **Examples**: [github.com/eclipse/keyple-cpp-example](https://github.com/eclipse/keyple-cpp-example) + */ diff --git a/src/test/LocalReaderAdapterTest.cpp b/src/test/LocalReaderAdapterTest.cpp index e3277bd..c68b899 100644 --- a/src/test/LocalReaderAdapterTest.cpp +++ b/src/test/LocalReaderAdapterTest.cpp @@ -144,7 +144,7 @@ setUp() EXPECT_CALL(*apduRequestSpi.get(), getInfo()) .WillRepeatedly(ReturnRef(info)); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(ok_rapdu)); + .WillRepeatedly(ReturnRef(ok_rapdu)); apduRequests.push_back(apduRequestSpi); cardRequestSpi = std::make_shared(); @@ -680,7 +680,7 @@ TEST(LocalReaderAdapterTest, transmitCardRequest_shouldReturnResponse) EXPECT_CALL(*readerSpi.get(), transmitApdu(_)) .WillRepeatedly(Return(responseApdu)); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(requestApdu)); + .WillRepeatedly(ReturnRef(requestApdu)); LocalConfigurableReaderAdapter localReaderAdapter(readerSpi, PLUGIN_NAME); localReaderAdapter.doRegister(); @@ -710,7 +710,7 @@ TEST(LocalReaderAdapterTest, transmitCardRequest_isCase4) = HexUtil::toByteArray("00009000"); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(requestApdu)); + .WillRepeatedly(ReturnRef(requestApdu)); EXPECT_CALL(*readerSpi.get(), transmitApdu(requestApdu)) .WillRepeatedly(Return(responseApdu)); EXPECT_CALL(*readerSpi.get(), transmitApdu(getResponseRApdu)) @@ -740,7 +740,7 @@ TEST( EXPECT_CALL(*readerSpi.get(), transmitApdu(_)) .WillRepeatedly(Return(responseApdu)); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(requestApdu)); + .WillRepeatedly(ReturnRef(requestApdu)); EXPECT_CALL(*apduRequestSpi.get(), getSuccessfulStatusWords()) .WillRepeatedly(ReturnRef(resp)); EXPECT_CALL(*cardRequestSpi.get(), stopOnUnsuccessfulStatusWord()) @@ -768,7 +768,7 @@ TEST( EXPECT_CALL(*readerSpi.get(), transmitApdu(_)) .WillRepeatedly(Throw(CardIOException(""))); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(requestApdu)); + .WillRepeatedly(ReturnRef(requestApdu)); LocalReaderAdapter localReaderAdapter(readerSpi, PLUGIN_NAME); localReaderAdapter.doRegister(); @@ -792,7 +792,7 @@ TEST( EXPECT_CALL(*readerSpi.get(), transmitApdu(_)) .WillRepeatedly(Throw(ReaderIOException(""))); EXPECT_CALL(*apduRequestSpi.get(), getApdu()) - .WillRepeatedly(Return(requestApdu)); + .WillRepeatedly(ReturnRef(requestApdu)); LocalReaderAdapter localReaderAdapter(readerSpi, PLUGIN_NAME); localReaderAdapter.doRegister(); diff --git a/src/test/mock/ApduRequestSpiMock.hpp b/src/test/mock/ApduRequestSpiMock.hpp index 8ea0758..a989004 100644 --- a/src/test/mock/ApduRequestSpiMock.hpp +++ b/src/test/mock/ApduRequestSpiMock.hpp @@ -19,13 +19,16 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" +#include "keyple/core/util/cpp/Any.hpp" #include "keypop/card/spi/ApduRequestSpi.hpp" +using keyple::core::util::cpp::any; using keypop::card::spi::ApduRequestSpi; class ApduRequestSpiMock final : public ApduRequestSpi { public: - MOCK_METHOD(std::vector, getApdu, (), (const, override)); + MOCK_METHOD(const std::vector&, getApdu, (), (const, override)); + MOCK_METHOD(void, setApdu, (const std::vector&), (override)); MOCK_METHOD( const std::vector&, getSuccessfulStatusWords, diff --git a/src/test/mock/ApduResponseApiMock.hpp b/src/test/mock/ApduResponseApiMock.hpp index 94dd493..e0b6785 100644 --- a/src/test/mock/ApduResponseApiMock.hpp +++ b/src/test/mock/ApduResponseApiMock.hpp @@ -25,7 +25,7 @@ using keypop::card::ApduResponseApi; class ApduResponseApiMock final : public ApduResponseApi { public: MOCK_METHOD((const std::vector&), getApdu, (), (const, override)); - MOCK_METHOD( - (const std::vector), getDataOut, (), (const, override)); + MOCK_METHOD(void, setApdu, ((const std::vector&)), (override)); + MOCK_METHOD((std::vector), getDataOut, (), (const, override)); MOCK_METHOD(int, getStatusWord, (), (const, override)); };