diff options
Diffstat (limited to 'battleNetApi')
| -rw-r--r-- | battleNetApi/include/apiUrl.hpp | 18 | ||||
| -rw-r--r-- | battleNetApi/include/hearthstoneApi.hpp | 2 | ||||
| -rw-r--r-- | battleNetApi/include/token.hpp | 2 | ||||
| -rw-r--r-- | battleNetApi/include/tokenPool.hpp | 7 | ||||
| -rw-r--r-- | battleNetApi/src/apiUrl.cpp | 22 | ||||
| -rw-r--r-- | battleNetApi/src/hearthstoneApi.cpp | 5 | ||||
| -rw-r--r-- | battleNetApi/src/main.cpp | 6 | ||||
| -rw-r--r-- | battleNetApi/src/tokenPool.cpp | 17 | ||||
| -rw-r--r-- | battleNetApi/tests/tests.cpp | 33 |
9 files changed, 77 insertions, 35 deletions
diff --git a/battleNetApi/include/apiUrl.hpp b/battleNetApi/include/apiUrl.hpp index 881e593..e936b6c 100644 --- a/battleNetApi/include/apiUrl.hpp +++ b/battleNetApi/include/apiUrl.hpp @@ -1,4 +1,5 @@ #pragma once +#include <cstdint> #include <string> #include <unordered_map> @@ -10,12 +11,27 @@ class ApiUrl { void setLocale(const std::string &iLocale); void setGameMode(const std::string &iGameMode); void setPage(const std::string &iPage); + void setPage(uint64_t iPage); void setPageSize(const std::string &iPageSize); - void setValue(const std::string &iKey, const std::string &iValue); + void setPageSize(uint64_t iPageSize); + + bool hasRegion() const; + bool hasLocale() const; + bool hasGameMode() const; + bool hasPage() const; + bool hasPageSize() const; + std::string text() const; private: + static constexpr std::string kLOCALE_KEY{"locale"}; + static constexpr std::string kGAME_MODE_KEY{"gameMode"}; + static constexpr std::string kPAGE_KEY{"page"}; + static constexpr std::string kPAGE_SIZE_KEY{"pageSize"}; std::string mContentType; std::string mRegion; std::unordered_map<std::string, std::string> aParameters; + + void setValue(const std::string &iKey, const std::string &iValue); + bool hasValue(const std::string &iKey) const; }; diff --git a/battleNetApi/include/hearthstoneApi.hpp b/battleNetApi/include/hearthstoneApi.hpp index f2bdf04..59cd336 100644 --- a/battleNetApi/include/hearthstoneApi.hpp +++ b/battleNetApi/include/hearthstoneApi.hpp @@ -11,7 +11,7 @@ class HearthstoneApi { 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 json downloadCards(ApiUrl &iApiUrl, Token &iToken); + static json downloadCards(ApiUrl iApiUrl, const Token &iToken); private: static std::string authorizationHeader(const std::string &iTokenText); diff --git a/battleNetApi/include/token.hpp b/battleNetApi/include/token.hpp index 23d1f49..bcb4926 100644 --- a/battleNetApi/include/token.hpp +++ b/battleNetApi/include/token.hpp @@ -5,7 +5,7 @@ class Token { public: - Token(const std::string &iTokenFilePath); + explicit Token(const std::string &iTokenFilePath); std::string text() const; const bool hasExpired() const; void updateToken(); diff --git a/battleNetApi/include/tokenPool.hpp b/battleNetApi/include/tokenPool.hpp index 6f5dffc..0b1e4cc 100644 --- a/battleNetApi/include/tokenPool.hpp +++ b/battleNetApi/include/tokenPool.hpp @@ -3,7 +3,7 @@ #include <queue> #include <token.hpp> -static std::queue<Token> mTokenContainer; +static std::queue<Token> aTokenContainer; class TokenPool { private: @@ -14,6 +14,7 @@ class TokenPool { TokenPool &operator=(TokenPool &&) = delete; public: - static void fillTokenSource(const std::string &iJsonPath); - static std::optional<std::string> unusedToken(); + static void feedTokenSource(const std::span<std::string> &iJsonPaths); + static void feedTokenSource(const std::string &iJsonPath); + static std::optional<Token> availableToken(); }; diff --git a/battleNetApi/src/apiUrl.cpp b/battleNetApi/src/apiUrl.cpp index ac8171b..1f11add 100644 --- a/battleNetApi/src/apiUrl.cpp +++ b/battleNetApi/src/apiUrl.cpp @@ -1,4 +1,5 @@ #include "apiUrl.hpp" +#include <cstdint> #include <format> ApiUrl::ApiUrl(const std::string &iContentType, const std::string &iRegion) @@ -12,35 +13,36 @@ void ApiUrl::setLocale(const std::string &iLocale) { if (not iLocale.empty()) { //!< The locale to reflect in localized data, e.g. "fr_FR" or "ko_KR" //!< If you do not supply a value, all translations are returned. - const std::string kKey{"locale"}; - setValue(kKey, 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 - const std::string kKey{"gameMode"}; - setValue(kKey, iGameMode); + setValue(kGAME_MODE_KEY, iGameMode); } } void ApiUrl::setPage(const std::string &iPage) { if (not iPage.empty()) { //!< The page to retrieve, e.g. "9" - const std::string kKey{"page"}; - setValue(kKey, iPage); + setValue(kPAGE_KEY, 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" - const std::string kKey{"pageSize"}; - setValue(kKey, iPageSize); + setValue(kPAGE_SIZE_KEY, iPageSize); } } - +void ApiUrl::setPageSize(uint64_t iPageSize) { return setPageSize(std::to_string(iPageSize)); } +bool ApiUrl::hasLocale() const { return hasValue(kLOCALE_KEY); } +bool ApiUrl::hasGameMode() const { return hasValue(kGAME_MODE_KEY); } +bool ApiUrl::hasPage() const { return hasValue(kPAGE_KEY); } +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; } std::string ApiUrl::text() const { std::string aFormattedParameters; for (const auto &[key, value] : aParameters) { diff --git a/battleNetApi/src/hearthstoneApi.cpp b/battleNetApi/src/hearthstoneApi.cpp index d6becc1..133f38d 100644 --- a/battleNetApi/src/hearthstoneApi.cpp +++ b/battleNetApi/src/hearthstoneApi.cpp @@ -104,7 +104,10 @@ std::vector<json> HearthstoneApi::makeApiRequest(const std::vector<std::string> return aJsonOutputs; } -json HearthstoneApi::downloadCards(ApiUrl &iApiUrl, Token &iToken) { +json HearthstoneApi::downloadCards(ApiUrl iApiUrl, const Token &iToken) { + if (iApiUrl.hasPage()) { + return makeApiRequest(iApiUrl, iToken.text()); + } iApiUrl.setPage("1"); std::vector<std::string> aRequests; diff --git a/battleNetApi/src/main.cpp b/battleNetApi/src/main.cpp index 4a5594c..2b6596a 100644 --- a/battleNetApi/src/main.cpp +++ b/battleNetApi/src/main.cpp @@ -21,7 +21,7 @@ class DefaultDownloadMethod : public DownloadMethod { aApiUrl.setLocale("fr_FR"); aApiUrl.setGameMode("constructed"); aApiUrl.setPageSize("100"); - std::optional<Token> aToken{TokenPool::unusedToken()}; + std::optional<Token> aToken{TokenPool::availableToken()}; if (aToken.has_value()) { HearthstoneApi::downloadCards(aApiUrl, aToken.value()); } @@ -51,12 +51,12 @@ int main(int argc, char *argv[]) { DownloaderContext aDownloaderContext; std::string aOutputJsonPath; if (argc < 4) { - TokenPool::fillTokenSource("tests/resources/credentials.json"); + TokenPool::feedTokenSource("tests/resources/credentials.json"); aDownloaderContext.setDownloadMethod(std::make_unique<DefaultDownloadMethod>()); aOutputJsonPath = "tests/output/list_of_cards.json"; } else { std::string aCredentialsFilePath{argv[1]}; - TokenPool::fillTokenSource(aCredentialsFilePath); + TokenPool::feedTokenSource(aCredentialsFilePath); aOutputJsonPath = argv[2]; } std::ofstream aOutputJsonFile(aOutputJsonPath); diff --git a/battleNetApi/src/tokenPool.cpp b/battleNetApi/src/tokenPool.cpp index f8a6256..08770e8 100644 --- a/battleNetApi/src/tokenPool.cpp +++ b/battleNetApi/src/tokenPool.cpp @@ -1,13 +1,18 @@ #include <tokenPool.hpp> -std::optional<std::string> TokenPool::unusedToken() { - if (mTokenContainer.empty()) { +std::optional<Token> TokenPool::availableToken() { + if (aTokenContainer.empty()) { return std::nullopt; } - Token aOutputToken{mTokenContainer.front()}; - mTokenContainer.pop(); - return aOutputToken.text(); + Token aOutputToken{aTokenContainer.front()}; + aTokenContainer.pop(); + return aOutputToken; } -void TokenPool::fillTokenSource(const std::string &iJsonPath) { // mTokenContainer.emplace(Token(iJsonPath)); +void TokenPool::feedTokenSource(const std::string &iJsonPath) { aTokenContainer.emplace(iJsonPath); } + +void TokenPool::feedTokenSource(const std::span<std::string> &iJsonPaths) { + for (const std::string &iJsonPath : iJsonPaths) { + feedTokenSource(iJsonPath); + } } diff --git a/battleNetApi/tests/tests.cpp b/battleNetApi/tests/tests.cpp index e669506..5efb1f0 100644 --- a/battleNetApi/tests/tests.cpp +++ b/battleNetApi/tests/tests.cpp @@ -31,12 +31,13 @@ TEST_CASE("Retrieve number of cards", "[countCards]") { aApiUrl.setLocale("fr_FR"); aApiUrl.setGameMode("constructed"); aApiUrl.setPageSize("1"); - TokenPool::fillTokenSource("tests/resources/credentials.json"); - const json kResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::unusedToken().value()); + TokenPool::feedTokenSource("tests/resources/credentials.json"); + const json kResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text()); REQUIRE(kResponse.size() > 0); REQUIRE(kResponse.contains("pageCount")); std::uint64_t kNumberOfCards{kResponse["pageCount"]}; - REQUIRE(kNumberOfCards == 6048); + std::uint64_t kExpectedNumberOfCards{6178}; + REQUIRE(kNumberOfCards == kExpectedNumberOfCards); } TEST_CASE("Retrieve page once", "[retrievePageOnce]") { @@ -48,8 +49,8 @@ TEST_CASE("Retrieve page once", "[retrievePageOnce]") { aApiUrl.setLocale("fr_FR"); aApiUrl.setGameMode("constructed"); aApiUrl.setPageSize("16"); - TokenPool::fillTokenSource("tests/resources/credentials.json"); - const json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::unusedToken().value()); + TokenPool::feedTokenSource("tests/resources/credentials.json"); + const json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text()); REQUIRE(kApiResponse["cards"].size() == 16); } @@ -63,8 +64,8 @@ TEST_CASE("Retrieve pages 10 times without parallelization", "[retrievePagesNoPa aApiUrl.setGameMode("constructed"); aApiUrl.setPageSize("16"); aApiUrl.setPage("1"); - TokenPool::fillTokenSource("tests/resources/credentials.json"); - std::string kTokenText{TokenPool::unusedToken().value()}; + TokenPool::feedTokenSource("tests/resources/credentials.json"); + std::string kTokenText{TokenPool::availableToken().value().text()}; json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText); // Retrieve number of pages @@ -91,8 +92,8 @@ TEST_CASE("Retrieve pages 10 times with parallelization", "[retrievePagesParalle aApiUrl.setPageSize("16"); aApiUrl.setPage("1"); std::vector<std::string> aRequests; - TokenPool::fillTokenSource("tests/resources/credentials.json"); - std::string kTokenText{TokenPool::unusedToken().value()}; + TokenPool::feedTokenSource("tests/resources/credentials.json"); + std::string kTokenText{TokenPool::availableToken().value().text()}; json kFirstPageJson = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText); int kNumberOfPages{kFirstPageJson["pageCount"]}; @@ -124,3 +125,17 @@ TEST_CASE("Merge two card lists from two page requests", "[Merge pages]") { 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 kContentType{"cards"}; + const std::string kRegion{"eu"}; + ApiUrl aApiUrl(kContentType, kRegion); + aApiUrl.setPage(3); + TokenPool::feedTokenSource("tests/resources/credentials.json"); + json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, TokenPool::availableToken().value().text()); + const json::size_type kExpectedNumberOfCards{kApiResponse["cards"].size()}; + TokenPool::feedTokenSource("tests/resources/credentials.json"); + kApiResponse = HearthstoneApi::downloadCards(aApiUrl, TokenPool::availableToken().value()); + const json::size_type kCurrentNumberOfCards{kApiResponse["cards"].size()}; + REQUIRE(kCurrentNumberOfCards == kExpectedNumberOfCards); +} |
