diff options
Diffstat (limited to 'battleNetApi')
| -rw-r--r-- | battleNetApi/include/apiUrl.hpp | 7 | ||||
| -rw-r--r-- | battleNetApi/include/hearthstoneApi.hpp | 11 | ||||
| -rw-r--r-- | battleNetApi/include/token.hpp | 4 | ||||
| -rw-r--r-- | battleNetApi/src/apiUrl.cpp | 44 | ||||
| -rw-r--r-- | battleNetApi/src/hearthstoneApi.cpp | 56 | ||||
| -rw-r--r-- | battleNetApi/src/hearthstoneTokenBuilder.cpp | 3 | ||||
| -rw-r--r-- | battleNetApi/tests/CMakeLists.txt | 26 | ||||
| -rw-r--r-- | battleNetApi/tests/resources/dumb_credentials.json | 10 | ||||
| -rw-r--r-- | battleNetApi/tests/src/hearthstoneApiTests.cpp | 156 | ||||
| -rw-r--r-- | battleNetApi/tests/src/tests.cpp | 144 | ||||
| -rw-r--r-- | battleNetApi/tests/src/tokenTests.cpp | 2 |
11 files changed, 248 insertions, 215 deletions
diff --git a/battleNetApi/include/apiUrl.hpp b/battleNetApi/include/apiUrl.hpp index e936b6c..ece4d17 100644 --- a/battleNetApi/include/apiUrl.hpp +++ b/battleNetApi/include/apiUrl.hpp @@ -3,16 +3,18 @@ #include <string> #include <unordered_map> +namespace bnet { +enum class GameMode { constructed, battlegrounds, mercenaries }; + class ApiUrl { public: ApiUrl(const std::string &iContentType, const std::string &iRegion); void setRegion(const std::string &iRegion); void setLocale(const std::string &iLocale); - void setGameMode(const std::string &iGameMode); + void setGameMode(const GameMode &iGameMode); void setPage(const std::string &iPage); void setPage(uint64_t iPage); - void setPageSize(const std::string &iPageSize); void setPageSize(uint64_t iPageSize); bool hasRegion() const; @@ -35,3 +37,4 @@ class ApiUrl { void setValue(const std::string &iKey, const std::string &iValue); bool hasValue(const std::string &iKey) const; }; +}; // namespace bnet diff --git a/battleNetApi/include/hearthstoneApi.hpp b/battleNetApi/include/hearthstoneApi.hpp index 59cd336..2810204 100644 --- a/battleNetApi/include/hearthstoneApi.hpp +++ b/battleNetApi/include/hearthstoneApi.hpp @@ -4,20 +4,25 @@ #include <nlohmann/json.hpp> #include <string> +namespace bnet { using json = nlohmann::json; class HearthstoneApi { public: static json makeApiRequest(const ApiUrl &iApiUrl, const std::string &iTokenText); - static std::vector<json> makeApiRequest(const std::vector<ApiUrl> &iApiUrls, const std::string &iTokenText); - static std::vector<json> makeApiRequest(const std::vector<std::string> &iUrls, const std::string &iTokenText); + static std::vector<json> makeApiRequest(const std::vector<ApiUrl> &iApiUrls, + const std::string &iTokenText); + static std::vector<json> makeApiRequest(const std::vector<std::string> &iUrls, + const std::string &iTokenText); static json downloadCards(ApiUrl iApiUrl, const Token &iToken); private: static std::string authorizationHeader(const std::string &iTokenText); - static size_t curlCallbackStringOutput(void *iContent, size_t iSize, size_t iNmemb, std::string *iS); + static size_t curlCallbackStringOutput(void *iContent, size_t iSize, size_t iNmemb, + std::string *iS); std::string mAuthorizationHeader; //<! Bearer authorization string for OAuth 2.0 header friend class HearthstoneApiMock; }; +}; // namespace bnet diff --git a/battleNetApi/include/token.hpp b/battleNetApi/include/token.hpp index f943b81..479cb29 100644 --- a/battleNetApi/include/token.hpp +++ b/battleNetApi/include/token.hpp @@ -22,9 +22,9 @@ class Token { }; namespace { -auto currentTime = [] { +auto currentTime = [] -> std::chrono::seconds { return std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::steady_clock::now().time_since_epoch()); + std::chrono::system_clock::now().time_since_epoch()); }; } // namespace } // namespace bnet diff --git a/battleNetApi/src/apiUrl.cpp b/battleNetApi/src/apiUrl.cpp index fa07372..5ef109c 100644 --- a/battleNetApi/src/apiUrl.cpp +++ b/battleNetApi/src/apiUrl.cpp @@ -2,6 +2,20 @@ #include <cstdint> #include <format> +namespace bnet { +namespace { +std::string gamemodeToString(const GameMode &iGameMode) { + switch (iGameMode) { + case GameMode::constructed: + return "constructed"; + case GameMode::battlegrounds: + return "battlegrounds"; + case GameMode::mercenaries: + return "mercenaries"; + } +} +}; // namespace + ApiUrl::ApiUrl(const std::string &iContentType, const std::string &iRegion) : mContentType{iContentType}, mRegion{iRegion} {} void ApiUrl::setRegion(const std::string &iRegion) { @@ -16,13 +30,11 @@ void ApiUrl::setLocale(const std::string &iLocale) { setValue(kLOCALE_KEY, iLocale); } } -void ApiUrl::setGameMode(const std::string &iGameMode) { - if (not iGameMode.empty()) { - //!< A recognized game mode, e.g. "constructed" - //!< @see - //!< https://community.developer.battle.net/documentation/hearthstone/guides/game-modes - setValue(kGAME_MODE_KEY, iGameMode); - } +void ApiUrl::setGameMode(const GameMode &iGameMode) { + //!< A recognized game mode, e.g. "constructed" + //!< @see + //!< https://community.developer.battle.net/documentation/hearthstone/guides/game-modes + setValue(kGAME_MODE_KEY, gamemodeToString(iGameMode)); } void ApiUrl::setPage(const std::string &iPage) { if (not iPage.empty()) { @@ -31,14 +43,8 @@ void ApiUrl::setPage(const std::string &iPage) { } } void ApiUrl::setPage(uint64_t iPage) { setPage(std::to_string(iPage)); } -void ApiUrl::setPageSize(const std::string &iPageSize) { - if (not iPageSize.empty()) { - //!< The number of results to choose per page, e.g. "40" - setValue(kPAGE_SIZE_KEY, iPageSize); - } -} void ApiUrl::setPageSize(uint64_t iPageSize) { - return setPageSize(std::to_string(iPageSize)); + setValue(kPAGE_SIZE_KEY, std::to_string(iPageSize)); } bool ApiUrl::hasLocale() const { return hasValue(kLOCALE_KEY); } bool ApiUrl::hasGameMode() const { return hasValue(kGAME_MODE_KEY); } @@ -47,9 +53,7 @@ bool ApiUrl::hasPageSize() const { return hasValue(kPAGE_SIZE_KEY); } void ApiUrl::setValue(const std::string &iKey, const std::string &iValue) { aParameters[iKey] = iValue; } -bool ApiUrl::hasValue(const std::string &iKey) const { - return aParameters.count(iKey) > 0; -} +bool ApiUrl::hasValue(const std::string &iKey) const { return aParameters.count(iKey) > 0; } std::string ApiUrl::text() const { std::string aFormattedParameters; for (const auto &[key, value] : aParameters) { @@ -58,8 +62,8 @@ std::string ApiUrl::text() const { if (not aFormattedParameters.empty()) { aFormattedParameters[0] = '?'; } - aFormattedParameters = - std::format("https://{}.api.blizzard.com/hearthstone/{}/{}", mRegion, - mContentType, aFormattedParameters); + aFormattedParameters = std::format("https://{}.api.blizzard.com/hearthstone/{}/{}", mRegion, + mContentType, aFormattedParameters); return aFormattedParameters; } +}; // namespace bnet diff --git a/battleNetApi/src/hearthstoneApi.cpp b/battleNetApi/src/hearthstoneApi.cpp index 1341f74..4dd8fac 100644 --- a/battleNetApi/src/hearthstoneApi.cpp +++ b/battleNetApi/src/hearthstoneApi.cpp @@ -5,13 +5,14 @@ #include <curl/multi.h> #include <format> #include <iostream> +#include <stdexcept> +namespace bnet { std::string HearthstoneApi::authorizationHeader(const std::string &iTokenText) { return std::format("Authorization: Bearer {}", iTokenText); } -size_t HearthstoneApi::curlCallbackStringOutput(void *iContent, size_t iSize, - size_t iNmemb, +size_t HearthstoneApi::curlCallbackStringOutput(void *iContent, size_t iSize, size_t iNmemb, std::string *iS) { const size_t kNewLength = iSize * iNmemb; try { @@ -23,8 +24,7 @@ size_t HearthstoneApi::curlCallbackStringOutput(void *iContent, size_t iSize, return kNewLength; } -json HearthstoneApi::makeApiRequest(const ApiUrl &iApiUrl, - const std::string &iTokenText) { +json HearthstoneApi::makeApiRequest(const ApiUrl &iApiUrl, const std::string &iTokenText) { CURL *curl = curl_easy_init(); std::string aRequestOutput; if (curl) { @@ -34,8 +34,7 @@ json HearthstoneApi::makeApiRequest(const ApiUrl &iApiUrl, curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallbackStringOutput); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &aRequestOutput); struct curl_slist *chunk = nullptr; - chunk = - curl_slist_append(chunk, authorizationHeader(iTokenText).c_str()); + chunk = curl_slist_append(chunk, authorizationHeader(iTokenText).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_easy_perform(curl); curl_easy_cleanup(curl); @@ -44,34 +43,28 @@ json HearthstoneApi::makeApiRequest(const ApiUrl &iApiUrl, return aOutputJson; } -std::vector<json> -HearthstoneApi::makeApiRequest(const std::vector<ApiUrl> &iApiUrls, - const std::string &iTokenText) { +std::vector<json> HearthstoneApi::makeApiRequest(const std::vector<ApiUrl> &iApiUrls, + const std::string &iTokenText) { std::vector<std::string> aApiUrls(iApiUrls.size()); - std::ranges::transform( - iApiUrls, aApiUrls.begin(), - [](const ApiUrl &iApiUrl) { return iApiUrl.text(); }); + std::ranges::transform(iApiUrls, aApiUrls.begin(), + [](const ApiUrl &iApiUrl) { return iApiUrl.text(); }); return makeApiRequest(aApiUrls, iTokenText); } -std::vector<json> -HearthstoneApi::makeApiRequest(const std::vector<std::string> &iUrls, - const std::string &iTokenText) { +std::vector<json> HearthstoneApi::makeApiRequest(const std::vector<std::string> &iUrls, + const std::string &iTokenText) { std::vector<std::string> aResponses(iUrls.size()); CURLM *curlm = curl_multi_init(); if (curlm) { - for (std::vector<std::string>::size_type i{0}; i < aResponses.size(); - ++i) { + for (std::vector<std::string>::size_type i{0}; i < aResponses.size(); ++i) { CURL *curl = curl_easy_init(); curl_easy_setopt(curl, CURLOPT_URL, iUrls[i].c_str()); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, - curlCallbackStringOutput); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlCallbackStringOutput); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &(aResponses[i])); struct curl_slist *chunk = nullptr; - chunk = curl_slist_append(chunk, - authorizationHeader(iTokenText).c_str()); + chunk = curl_slist_append(chunk, authorizationHeader(iTokenText).c_str()); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk); curl_multi_add_handle(curlm, curl); } @@ -82,8 +75,7 @@ HearthstoneApi::makeApiRequest(const std::vector<std::string> &iUrls, int numfds = 0; int res = curl_multi_wait(curlm, NULL, 0, kMaxWaitMs, &numfds); if (res != CURLM_OK) { - std::cerr << std::format( - "error: curl_multi_wait() returned {}\n", res); + std::cerr << std::format("error: curl_multi_wait() returned {}\n", res); } curl_multi_perform(curlm, &aStillRunning); } while (aStillRunning); @@ -98,17 +90,15 @@ HearthstoneApi::makeApiRequest(const std::vector<std::string> &iUrls, aHandle = aMessage->easy_handle; aReturnCode = aMessage->data.result; if (aReturnCode != CURLE_OK) { - fprintf(stderr, "CURL error code: %d\n", - aMessage->data.result); + fprintf(stderr, "CURL error code: %d\n", aMessage->data.result); continue; } curl_multi_remove_handle(curlm, aHandle); curl_easy_cleanup(aHandle); aHandle = nullptr; } else { - std::cerr << std::format( - "error: after curl_multi_info_read(), CURLMsg={}\n", - static_cast<int>(aMessage->msg)); + std::cerr << std::format("error: after curl_multi_info_read(), CURLMsg={}\n", + static_cast<int>(aMessage->msg)); } } curl_multi_cleanup(curlm); @@ -121,20 +111,23 @@ HearthstoneApi::makeApiRequest(const std::vector<std::string> &iUrls, } json HearthstoneApi::downloadCards(ApiUrl iApiUrl, const Token &iToken) { + if (!iToken.text().has_value() || iToken.text().value().empty()) { + throw std::invalid_argument("Token text does not exist or is empty"); + } if (iApiUrl.hasPage()) { - return makeApiRequest(iApiUrl, iToken.text()); + return makeApiRequest(iApiUrl, *iToken.text()); } iApiUrl.setPage("1"); std::vector<std::string> aRequests; - json aFirstPageJson = makeApiRequest(iApiUrl, iToken.text()); + json aFirstPageJson = makeApiRequest(iApiUrl, *iToken.text()); int kNumberOfPages{aFirstPageJson["pageCount"]}; for (int i{1}; i < kNumberOfPages; ++i) { iApiUrl.setPage(std::to_string(i + 1)); aRequests.push_back(iApiUrl.text()); } json::reference &aOutputJson = aFirstPageJson["cards"]; - std::vector<json> kApiResponses = makeApiRequest(aRequests, iToken.text()); + std::vector<json> kApiResponses = makeApiRequest(aRequests, *iToken.text()); for (json &aPage : kApiResponses) { for (json::reference &aCard : aPage["cards"]) { aOutputJson.push_back(std::move(aCard)); @@ -142,3 +135,4 @@ json HearthstoneApi::downloadCards(ApiUrl iApiUrl, const Token &iToken) { } return aOutputJson; } +}; // namespace bnet diff --git a/battleNetApi/src/hearthstoneTokenBuilder.cpp b/battleNetApi/src/hearthstoneTokenBuilder.cpp index 668aaa5..96e3aa8 100644 --- a/battleNetApi/src/hearthstoneTokenBuilder.cpp +++ b/battleNetApi/src/hearthstoneTokenBuilder.cpp @@ -1,3 +1,4 @@ +#include <chrono> #include <curl/curl.h> #include <fstream> #include <hearthstoneTokenBuilder.hpp> @@ -69,7 +70,7 @@ bool HearthstoneTokenBuilder::isTokenValid(const json &iTokenJson) const { const std::uint64_t kExpirationTime{iTokenJson["Token"]["ExpirationTime"]}; const std::uint64_t kCurrentTime{ static_cast<std::uint64_t>(std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::high_resolution_clock::now().time_since_epoch()) + std::chrono::system_clock::now().time_since_epoch()) .count())}; return kCurrentTime <= kExpirationTime; } diff --git a/battleNetApi/tests/CMakeLists.txt b/battleNetApi/tests/CMakeLists.txt index b59fd8a..6281f6b 100644 --- a/battleNetApi/tests/CMakeLists.txt +++ b/battleNetApi/tests/CMakeLists.txt @@ -21,17 +21,21 @@ execute_process( ) set(BATTLE_NET_API_DIR ${GIT_REPOSITORY_FOLDER_PATH}/battleNetApi) -#set(SRC_TESTS -# ${PROJECT_SOURCE_DIR}/src/hearthstoneApi.cpp -# ${PROJECT_SOURCE_DIR}/src/token.cpp -# ${PROJECT_SOURCE_DIR}/src/tokenBuilder.cpp -# ${PROJECT_SOURCE_DIR}/src/hearthstoneTokenBuilder.cpp -# ${PROJECT_SOURCE_DIR}/src/apiUrl.cpp -# ${PROJECT_SOURCE_DIR}/tests/src/tests.cpp -#) -#add_executable(tests ${SRC_TESTS}) -#target_include_directories(tests PRIVATE ${INCLUDE_DIR}) -#target_link_libraries(tests PRIVATE Catch2::Catch2WithMain curl) +set(SRC_HEARTHSTONE_API_TESTS + ${BATTLE_NET_API_DIR}/src/hearthstoneApi.cpp + ${BATTLE_NET_API_DIR}/src/token.cpp + ${BATTLE_NET_API_DIR}/src/tokenBuilder.cpp + ${BATTLE_NET_API_DIR}/src/hearthstoneTokenBuilder.cpp + ${BATTLE_NET_API_DIR}/src/apiUrl.cpp + ${BATTLE_NET_API_DIR}/tests/src/hearthstoneApiTests.cpp +) +add_executable(hearthstoneApiTests ${SRC_HEARTHSTONE_API_TESTS}) +set(INCLUDE_HEARTHSTONE_API_DIR ${BATTLE_NET_API_DIR}/include) +target_include_directories( + hearthstoneApiTests + PRIVATE ${INCLUDE_HEARTHSTONE_API_DIR} +) +target_link_libraries(hearthstoneApiTests PRIVATE Catch2::Catch2WithMain curl) set(INCLUDE_TOKEN_DIR ${BATTLE_NET_API_DIR}/include) set(SRC_TOKEN_TESTS diff --git a/battleNetApi/tests/resources/dumb_credentials.json b/battleNetApi/tests/resources/dumb_credentials.json new file mode 100644 index 0000000..e919770 --- /dev/null +++ b/battleNetApi/tests/resources/dumb_credentials.json @@ -0,0 +1,10 @@ +{ + "Agent": { + "Password": "MrMkhVMNdOeqPL4Q4XVQAsRPR14J7Yq6", + "Username": "2b50f1123b424d5e9c21971a110fdd04" + }, + "Token": { + "Content": "ThisIsTheContentOfTokenContenthehe", + "ExpirationTime": 0 + } +} diff --git a/battleNetApi/tests/src/hearthstoneApiTests.cpp b/battleNetApi/tests/src/hearthstoneApiTests.cpp new file mode 100644 index 0000000..2c39d0c --- /dev/null +++ b/battleNetApi/tests/src/hearthstoneApiTests.cpp @@ -0,0 +1,156 @@ +#include "apiUrl.hpp" +#include "hearthstoneApi.hpp" +#include "hearthstoneTokenBuilder.hpp" +#include <catch2/benchmark/catch_benchmark.hpp> +#include <catch2/benchmark/catch_chronometer.hpp> +#include <catch2/benchmark/detail/catch_analyse.hpp> +#include <catch2/benchmark/detail/catch_benchmark_function.hpp> +#include <catch2/benchmark/detail/catch_estimate_clock.hpp> +#include <catch2/catch_approx.hpp> +#include <catch2/catch_config.hpp> +#include <catch2/catch_test_macros.hpp> +#include <cstdint> +#include <fstream> +#include <nlohmann/json.hpp> +#include <string> +#include <tokenBuilder.hpp> + +TEST_CASE("Retrieve number of cards", "[countCards]") { + const std::string aContentType{"cards"}; + const std::string aRegion{"eu"}; + bnet::ApiUrl aApiUrl(aContentType, aRegion); + aApiUrl.setLocale("fr_FR"); + aApiUrl.setGameMode(bnet::GameMode::constructed); + aApiUrl.setPageSize(1); + bnet::HearthstoneTokenBuilder aHearthstoneTokenBuilder("resources/credentials.json"); + const nlohmann::json aResponse = bnet::HearthstoneApi::makeApiRequest( + aApiUrl, aHearthstoneTokenBuilder.allowBattleNetApiCall() + .allowUpdateSourceFile() + .buildToken() + .getToken() + ->text() + .value()); + REQUIRE(aResponse.size() > 0); + REQUIRE(aResponse.contains("pageCount")); + std::uint64_t aNumberOfCards{aResponse["pageCount"]}; + std::uint64_t aExpectedNumberOfCards{6000}; + REQUIRE(aNumberOfCards >= aExpectedNumberOfCards); +} + +TEST_CASE("Retrieve page once", "[retrievePageOnce]") { + const std::string aContentType{"cards"}; + const std::string aRegion{"eu"}; + bnet::ApiUrl aApiUrl(aContentType, aRegion); + aApiUrl.setLocale("fr_FR"); + aApiUrl.setGameMode(bnet::GameMode::constructed); + aApiUrl.setPageSize(16); + bnet::HearthstoneTokenBuilder aHearthstoneTokenBuilder("resources/credentials.json"); + const std::string aTokenText{aHearthstoneTokenBuilder.allowBattleNetApiCall() + .allowUpdateSourceFile() + .buildToken() + .getToken() + ->text() + .value()}; + const nlohmann::json aApiResponse = bnet::HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); + REQUIRE(aApiResponse["cards"].size() == 16); +} + +TEST_CASE("Retrieve pages 10 times without parallelization", "[retrievePagesNoParallel]") { + const std::string aContentType{"cards"}; + const std::string aRegion{"eu"}; + bnet::ApiUrl aApiUrl(aContentType, aRegion); + aApiUrl.setLocale("fr_FR"); + aApiUrl.setGameMode(bnet::GameMode::constructed); + aApiUrl.setPageSize(16); + aApiUrl.setPage("1"); + bnet::HearthstoneTokenBuilder aHearthstoneTokenBuilder("resources/credentials.json"); + const std::string aTokenText{aHearthstoneTokenBuilder.allowBattleNetApiCall() + .allowUpdateSourceFile() + .buildToken() + .getToken() + ->text() + .value()}; + bnet::json aApiResponse = bnet::HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); + + // Retrieve number of pages + const int aNumberOfRetrievals{10}; + const int aNumberOfPages{aApiResponse["pageCount"]}; + REQUIRE(aNumberOfPages >= aNumberOfRetrievals); + for (int i{1}; i < aNumberOfRetrievals; ++i) { + REQUIRE(aApiResponse["cards"].size() == 16); + aApiUrl.setPage(std::to_string(i + 1)); + aApiResponse = bnet::HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); + } + REQUIRE(aApiResponse["cards"].size() >= 1); + REQUIRE(aApiResponse["cards"].size() <= 16); +} + +TEST_CASE("Retrieve pages 10 times with parallelization", "[retrievePagesParallel]") { + const std::string aContentType{"cards"}; + const std::string aRegion{"eu"}; + bnet::ApiUrl aApiUrl(aContentType, aRegion); + aApiUrl.setLocale("fr_FR"); + aApiUrl.setGameMode(bnet::GameMode::constructed); + aApiUrl.setPageSize(16); + aApiUrl.setPage("1"); + std::vector<std::string> aRequests; + bnet::HearthstoneTokenBuilder aHearthstoneTokenBuilder("resources/credentials.json"); + const std::string aTokenText{aHearthstoneTokenBuilder.allowBattleNetApiCall() + .allowUpdateSourceFile() + .buildToken() + .getToken() + ->text() + .value()}; + bnet::json aFirstPageJson = bnet::HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); + + const int aNumberOfPages{aFirstPageJson["pageCount"]}; + const int aNumberOfRetrievals{10}; + REQUIRE(aNumberOfPages >= aNumberOfRetrievals); + for (int i{1}; i < aNumberOfRetrievals; ++i) { + aApiUrl.setPage(std::to_string(i + 1)); + aRequests.emplace_back(aApiUrl.text()); + } + std::vector<nlohmann::json> aApiResponses = + bnet::HearthstoneApi::makeApiRequest(aRequests, aTokenText); + aApiResponses.emplace(aApiResponses.begin(), aFirstPageJson); + REQUIRE(aApiResponses.size() == aNumberOfRetrievals); + for (const nlohmann::json &aApiResponse : aApiResponses) { + REQUIRE(aApiResponse["cards"].size() == 16); + } +} + +TEST_CASE("Merge two card lists from two page requests", "[Merge pages]") { + std::ifstream aFirstPageFile{"resources/page_merge_00.json"}; + nlohmann::json aFirstPageJson = nlohmann::json::parse(aFirstPageFile); + std::ifstream aSecondPageFile{"resources/page_merge_01.json"}; + const nlohmann::json aSecondPageJson = nlohmann::json::parse(aSecondPageFile); + + nlohmann::json::reference aMergedCards = aFirstPageJson["cards"]; + for (auto &card : aSecondPageJson["cards"]) { + aMergedCards.emplace_back(std::move(card)); + } + REQUIRE(aMergedCards.size() == 32); + std::ofstream aOutputJson("build/output_pages_merge.json"); + aOutputJson << aMergedCards.dump(4); +} + +TEST_CASE("Retrieve a single page with HearthstoneApi::downloadCards", + "[retrievePageOnceHearthstoneApi]") { + const std::string aContentType{"cards"}; + const std::string aRegion{"eu"}; + bnet::ApiUrl aApiUrl(aContentType, aRegion); + aApiUrl.setPage(3); + bnet::HearthstoneTokenBuilder aHearthstoneTokenBuilder("resources/credentials.json"); + const std::string aTokenText{aHearthstoneTokenBuilder.allowBattleNetApiCall() + .allowUpdateSourceFile() + .buildToken() + .getToken() + ->text() + .value()}; + nlohmann::json aApiResponse = bnet::HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); + const nlohmann::json::size_type aExpectedNumberOfCards{aApiResponse["cards"].size()}; + aApiResponse = + bnet::HearthstoneApi::downloadCards(aApiUrl, *aHearthstoneTokenBuilder.getToken()); + const nlohmann::json::size_type aCurrentNumberOfCards{aApiResponse["cards"].size()}; + REQUIRE(aCurrentNumberOfCards == aExpectedNumberOfCards); +} diff --git a/battleNetApi/tests/src/tests.cpp b/battleNetApi/tests/src/tests.cpp deleted file mode 100644 index edc0641..0000000 --- a/battleNetApi/tests/src/tests.cpp +++ /dev/null @@ -1,144 +0,0 @@ -#include "apiUrl.hpp" -#include "hearthstoneApi.hpp" -#include <catch2/benchmark/catch_benchmark.hpp> -#include <catch2/benchmark/catch_chronometer.hpp> -#include <catch2/benchmark/detail/catch_analyse.hpp> -#include <catch2/benchmark/detail/catch_benchmark_function.hpp> -#include <catch2/benchmark/detail/catch_estimate_clock.hpp> -#include <catch2/catch_approx.hpp> -#include <catch2/catch_config.hpp> -#include <catch2/catch_test_macros.hpp> -#include <cstdint> -#include <fstream> -#include <nlohmann/json.hpp> -#include <string> -#include <tokenBuilder.hpp> - -TEST_CASE("Retrieve API Token", "[generateApiToken]") { - const std::string aCredentialsFile{"tests/resources/credentials.json"}; - Token aToken(aCredentialsFile); - const std::string aTokenContent{aToken.text()}; - const std::string::size_type aTokenSize{aTokenContent.size()}; - REQUIRE(aTokenSize >= 30); - REQUIRE(aTokenSize <= 40); -} - -TEST_CASE("Retrieve number of cards", "[countCards]") { - const std::string aCredentialsFile{}; - const std::string aContentType{"cards"}; - const std::string aRegion{"eu"}; - ApiUrl aApiUrl(aContentType, aRegion); - aApiUrl.setLocale("fr_FR"); - aApiUrl.setGameMode("constructed"); - aApiUrl.setPageSize("1"); - TokenPool::feedTokenSource("tests/resources/credentials.json"); - const json aResponse = - HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::build().value().text()); - REQUIRE(aResponse.size() > 0); - REQUIRE(aResponse.contains("pageCount")); - std::uint64_t aNumberOfCards{aResponse["pageCount"]}; - std::uint64_t aExpectedNumberOfCards{6178}; - REQUIRE(aNumberOfCards == aExpectedNumberOfCards); -} - -TEST_CASE("Retrieve page once", "[retrievePageOnce]") { - const std::string aCredentialsFile{"tests/resources/credentials.json"}; - Token aToken(kCredentialsFile); - const std::string aContentType{"cards"}; - const std::string aRegion{"eu"}; - ApiUrl aApiUrl(aContentType, aRegion); - aApiUrl.setLocale("fr_FR"); - aApiUrl.setGameMode("constructed"); - aApiUrl.setPageSize("16"); - TokenPool::feedTokenSource("tests/resources/credentials.json"); - const json aApiResponse = - HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::build().value().text()); - REQUIRE(aApiResponse["cards"].size() == 16); -} - -TEST_CASE("Retrieve pages 10 times without parallelization", "[retrievePagesNoParallel]") { - const std::string aCredentialsFile{"tests/resources/credentials.json"}; - Token aToken(aCredentialsFile); - const std::string aContentType{"cards"}; - const std::string aRegion{"eu"}; - ApiUrl aApiUrl(aContentType, aRegion); - aApiUrl.setLocale("fr_FR"); - aApiUrl.setGameMode("constructed"); - aApiUrl.setPageSize("16"); - aApiUrl.setPage("1"); - TokenPool::feedTokenSource("tests/resources/credentials.json"); - std::string aTokenText{TokenPool::build().value().text()}; - json aApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); - - // Retrieve number of pages - const int aNumberOfRetrievals{10}; - const int aNumberOfPages{aApiResponse["pageCount"]}; - REQUIRE(aNumberOfPages >= aNumberOfRetrievals); - for (int i{1}; i < aNumberOfRetrievals; ++i) { - REQUIRE(aApiResponse["cards"].size() == 16); - aApiUrl.setPage(std::to_string(i + 1)); - aApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); - } - REQUIRE(aApiResponse["cards"].size() >= 1); - REQUIRE(aApiResponse["cards"].size() <= 16); -} - -TEST_CASE("Retrieve pages 10 times with parallelization", "[retrievePagesParallel]") { - const std::string aCredentialsFile{"tests/resources/credentials.json"}; - Token aToken(kCredentialsFile); - const std::string aContentType{"cards"}; - const std::string aRegion{"eu"}; - ApiUrl aApiUrl(aContentType, aRegion); - aApiUrl.setLocale("fr_FR"); - aApiUrl.setGameMode("constructed"); - aApiUrl.setPageSize("16"); - aApiUrl.setPage("1"); - std::vector<std::string> aRequests; - TokenPool::feedTokenSource("tests/resources/credentials.json"); - std::string aTokenText{TokenPool::build().value().text()}; - json aFirstPageJson = HearthstoneApi::makeApiRequest(aApiUrl, aTokenText); - - int kNumberOfPages{aFirstPageJson["pageCount"]}; - const int aNumberOfRetrievals{10}; - REQUIRE(aNumberOfPages >= aNumberOfRetrievals); - for (int i{1}; i < aNumberOfRetrievals; ++i) { - aApiUrl.setPage(std::to_string(i + 1)); - aRequests.emplace_back(aApiUrl.text()); - } - std::vector<json> aApiResponses = HearthstoneApi::makeApiRequest(aRequests, aTokenText); - aApiResponses.emplace(aApiResponses.begin(), aFirstPageJson); - REQUIRE(aApiResponses.size() == aNumberOfRetrievals); - for (const json &aApiResponse : aApiResponses) { - REQUIRE(aApiResponse["cards"].size() == 16); - } -} - -TEST_CASE("Merge two card lists from two page requests", "[Merge pages]") { - std::ifstream aFirstPageFile{"tests/resources/page_merge_00.json"}; - json aFirstPageJson = json::parse(aFirstPageFile); - std::ifstream aSecondPageFile{"tests/resources/page_merge_01.json"}; - const json aSecondPageJson = json::parse(aSecondPageFile); - - json::reference aMergedCards = aFirstPageJson["cards"]; - for (auto &card : aSecondPageJson["cards"]) { - aMergedCards.emplace_back(std::move(card)); - } - REQUIRE(aMergedCards.size() == 32); - std::ofstream aOutputJson("build/output_pages_merge.json"); - aOutputJson << aMergedCards.dump(4); -} - -TEST_CASE("Retrieve a single page with HearthstoneApi::downloadCards", - "[retrievePageOnceHearthstoneApi]") { - const std::string aContentType{"cards"}; - const std::string aRegion{"eu"}; - ApiUrl aApiUrl(aContentType, aRegion); - aApiUrl.setPage(3); - TokenPool::feedTokenSource("tests/resources/credentials.json"); - json aApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::build().value().text()); - const json::size_type aExpectedNumberOfCards{aApiResponse["cards"].size()}; - TokenPool::feedTokenSource("tests/resources/credentials.json"); - aApiResponse = HearthstoneApi::downloadCards(aApiUrl, TokenPool::build().value()); - const json::size_type aCurrentNumberOfCards{aApiResponse["cards"].size()}; - REQUIRE(aCurrentNumberOfCards == aExpectedNumberOfCards); -} diff --git a/battleNetApi/tests/src/tokenTests.cpp b/battleNetApi/tests/src/tokenTests.cpp index b702024..49e8350 100644 --- a/battleNetApi/tests/src/tokenTests.cpp +++ b/battleNetApi/tests/src/tokenTests.cpp @@ -35,7 +35,7 @@ TEST_CASE("Token", "[Change token text]") { } TEST_CASE("TokenBuilder", "[Retrieve token from JSON]") { - bnet::HearthstoneTokenBuilder aTokenBuilder{"resources/credentials.json"}; + bnet::HearthstoneTokenBuilder aTokenBuilder{"resources/dumb_credentials.json"}; REQUIRE(aTokenBuilder.allowExpiredToken().buildToken().getToken()); REQUIRE(aTokenBuilder.getToken()->text() == "ThisIsTheContentOfTokenContenthehe"); } |
