summaryrefslogtreecommitdiff
path: root/battleNetApi
diff options
context:
space:
mode:
Diffstat (limited to 'battleNetApi')
-rw-r--r--battleNetApi/CMakeLists.txt13
-rw-r--r--battleNetApi/include/hearthstoneTokenBuilder.hpp32
-rw-r--r--battleNetApi/include/token.hpp8
-rw-r--r--battleNetApi/src/hearthstoneTokenBuilder.cpp86
-rw-r--r--battleNetApi/src/token.cpp16
-rw-r--r--battleNetApi/tests/CMakeLists.txt43
-rw-r--r--battleNetApi/tests/src/tests.cpp144
-rw-r--r--battleNetApi/tests/src/tokenTests.cpp20
-rw-r--r--battleNetApi/tests/tests.cpp149
9 files changed, 280 insertions, 231 deletions
diff --git a/battleNetApi/CMakeLists.txt b/battleNetApi/CMakeLists.txt
index e662d13..6999d57 100644
--- a/battleNetApi/CMakeLists.txt
+++ b/battleNetApi/CMakeLists.txt
@@ -22,21 +22,8 @@ set(SRC
${PROJECT_SOURCE_DIR}/src/apiUrl.cpp
${PROJECT_SOURCE_DIR}/src/main.cpp
)
-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/tests.cpp
-)
-
find_package(Catch2 3 REQUIRED)
find_package(nlohmann_json 3.12.0 REQUIRED)
-add_executable(tests ${SRC_TESTS})
-target_include_directories(tests PRIVATE ${INCLUDE_DIR})
-target_link_libraries(tests PRIVATE Catch2::Catch2WithMain curl)
-
add_executable(downloadCards ${SRC})
target_include_directories(downloadCards PRIVATE ${INCLUDE_DIR})
target_link_libraries(downloadCards PRIVATE curl)
diff --git a/battleNetApi/include/hearthstoneTokenBuilder.hpp b/battleNetApi/include/hearthstoneTokenBuilder.hpp
index 488aff4..e946fe8 100644
--- a/battleNetApi/include/hearthstoneTokenBuilder.hpp
+++ b/battleNetApi/include/hearthstoneTokenBuilder.hpp
@@ -14,30 +14,40 @@ class HearthstoneTokenBuilder : TokenBuilder {
private:
std::shared_ptr<Token> mCurrentToken;
bool mUpdateSourceFile{false};
- std::vector<std::string> mJsonPaths;
+ std::vector<std::string> _credentialJsonPaths;
+ [[nodiscard]]
bool isUpdateSourceFileAllowed() const;
- const bool hasExpired(json iToken) const;
- static size_t curlCallbackStringOutput(void *iPtr, size_t iSize,
- size_t iNmemb,
+ [[nodiscard]]
+ const bool hasExpired(json iTokenJson) const;
+ static size_t curlCallbackStringOutput(void *iPtr, size_t iSize, size_t iNmemb,
std::string *iUserData);
+ [[nodiscard]]
std::chrono::seconds getCurrentTime() const;
- std::pair<std::string, std::uint64_t> getTokenWithApi() const;
+ [[nodiscard]]
+ std::pair<std::string, std::uint64_t>
+ getTokenWithApi(const std::string &iAgentJsonFilePath) const;
+ [[nodiscard]]
std::string getTokenFromLocalFile() const;
- void writeTokenToLocalFile(
- const std::pair<std::string, std::uint64_t> &iToken) const;
+ void writeTokenToLocalFile(const std::pair<std::string, std::uint64_t> &iToken) const;
public:
HearthstoneTokenBuilder(const std::span<std::string> &iJsonPaths);
- HearthstoneTokenBuilder(const std::string &iJsonPath);
- HearthstoneTokenBuilder &addJsonPath(const std::string &iJsonPath);
- HearthstoneTokenBuilder &addJsonPaths(const std::string &iJsonPath);
+ template <typename... CredentialJsonPaths>
+ HearthstoneTokenBuilder(CredentialJsonPaths... iCredentialJsonPaths) {
+ (_credentialJsonPaths.push_back(iCredentialJsonPaths), ...);
+ }
+ template <typename... CredentialJsonPaths>
+ HearthstoneTokenBuilder &addCredentialJsonFiles(CredentialJsonPaths... iCredentialJsonPaths) {
+ (_credentialJsonPaths.push_back(iCredentialJsonPaths), ...);
+ }
HearthstoneTokenBuilder &allowUpdateSourceFile();
/**
* @return Create an access token to perform API requests.
- * First, the cache files are checked.
+ * First, the cache files are checked. (Which ones?)
* A new token is computed if the token lifetimes expired,
* or if there is no token at all.
*/
HearthstoneTokenBuilder &buildToken() override;
+ [[nodiscard]]
std::shared_ptr<Token> getToken() override;
};
diff --git a/battleNetApi/include/token.hpp b/battleNetApi/include/token.hpp
index cc909a8..8b9f95e 100644
--- a/battleNetApi/include/token.hpp
+++ b/battleNetApi/include/token.hpp
@@ -1,13 +1,17 @@
#pragma once
+#include <chrono>
#include <string>
class Token {
public:
- explicit Token(const std::string &iTokenText);
+ explicit Token(const std::string &iTokenText, const std::chrono::seconds &iExpirationTime);
std::string text() const;
void setText(const std::string &iTokenText);
+ void setExpirationTime(const std::chrono::seconds &iExpirationTime);
+ bool isExpired();
private:
- std::string mTokenText; //!< Token value
+ std::string _tokenText;
+ std::chrono::seconds _expirationTime;
};
diff --git a/battleNetApi/src/hearthstoneTokenBuilder.cpp b/battleNetApi/src/hearthstoneTokenBuilder.cpp
index 8403f46..9509aa6 100644
--- a/battleNetApi/src/hearthstoneTokenBuilder.cpp
+++ b/battleNetApi/src/hearthstoneTokenBuilder.cpp
@@ -1,29 +1,20 @@
+#include <algorithm>
#include <curl/curl.h>
+#include <fstream>
#include <hearthstoneTokenBuilder.hpp>
#include <iostream>
#include <memory>
-HearthstoneTokenBuilder::HearthstoneTokenBuilder(const std::string &iJsonPath) {
- mJsonPaths.push_back(iJsonPath);
-}
-HearthstoneTokenBuilder::HearthstoneTokenBuilder(
- const std::span<std::string> &iJsonPaths) {
- mJsonPaths.append_range(iJsonPaths);
-}
-HearthstoneTokenBuilder &
-HearthstoneTokenBuilder::addJsonPath(const std::string &iJsonPath) {
- mJsonPaths.push_back(iJsonPath);
- return *this;
-}
-HearthstoneTokenBuilder &
-HearthstoneTokenBuilder::addJsonPaths(const std::string &iJsonPath) {
- mJsonPaths.push_back(iJsonPath);
- return *this;
+HearthstoneTokenBuilder::HearthstoneTokenBuilder(const std::span<std::string> &iJsonPaths) {
+ _credentialJsonPaths.append_range(iJsonPaths);
}
HearthstoneTokenBuilder &HearthstoneTokenBuilder::buildToken() {
+ std::ranges::find_if(_credentialJsonPaths,
+ [](const std::string &iCredentialJsonPath) { return true; });
if (hasExpired()) {
- const std::pair<std::string, std::uint64_t> kTokenContent{
- getTokenWithApi()};
+ if (isUpdateSourceFileAllowed()) {
+ }
+ const std::pair<std::string, std::uint64_t> kTokenContent{getTokenWithApi()};
writeTokenToLocalFile(kTokenContent);
}
// return getTokenFromLocalFile();
@@ -35,38 +26,31 @@ HearthstoneTokenBuilder &HearthstoneTokenBuilder::buildToken() {
// mCurrentToken = std::make_unique<Token>(...);
return *this;
}
-std::shared_ptr<Token> HearthstoneTokenBuilder::getToken() {
- return mCurrentToken;
-}
+std::shared_ptr<Token> HearthstoneTokenBuilder::getToken() { return mCurrentToken; }
HearthstoneTokenBuilder &HearthstoneTokenBuilder::allowUpdateSourceFile() {
mUpdateSourceFile = true;
return *this;
}
-bool HearthstoneTokenBuilder::isUpdateSourceFileAllowed() const {
- return mUpdateSourceFile;
-}
+bool HearthstoneTokenBuilder::isUpdateSourceFileAllowed() const { return mUpdateSourceFile; }
-const bool HearthstoneTokenBuilder::hasExpired(json iCredentials) const {
- if (not iCredentials.contains("Token") or
- not iCredentials["Token"].contains("ExpirationTime") or
- not iCredentials["Token"].contains("Content")) {
+const bool HearthstoneTokenBuilder::hasExpired(json iTokenJson) const {
+ if (not iTokenJson.contains("Token") or not iTokenJson["Token"].contains("ExpirationTime") or
+ not iTokenJson["Token"].contains("Content")) {
return true;
}
- if (iCredentials["Token"]["Content"].dump().length() <
- kTOKEN_CONTENT_MIN_LENGTH) {
+ if (iTokenJson["Token"]["Content"].dump().length() < kTOKEN_CONTENT_MIN_LENGTH) {
return true;
}
- const std::uint64_t kExpirationTime{
- iCredentials["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())
- .count())};
+ 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())
+ .count())};
return kCurrentTime >= kExpirationTime;
}
-size_t HearthstoneTokenBuilder::curlCallbackStringOutput(
- void *iPtr, size_t iSize, size_t iNmemb, std::string *iUserData) {
+size_t HearthstoneTokenBuilder::curlCallbackStringOutput(void *iPtr, size_t iSize, size_t iNmemb,
+ std::string *iUserData) {
size_t newLength{iSize * iNmemb};
try {
iUserData->append(static_cast<char *>(iPtr), newLength);
@@ -83,11 +67,10 @@ std::chrono::seconds HearthstoneTokenBuilder::getCurrentTime() const {
}
std::pair<std::string, std::uint64_t>
-HearthstoneTokenBuilder::getTokenWithApi() const {
- std::ifstream aCredentialsFile{mFilePath};
- json aCredentials = json::parse(aCredentialsFile);
- if (not aCredentials.contains("Agent") or
- not aCredentials["Agent"].contains("Username") or
+HearthstoneTokenBuilder::getTokenWithApi(const std::string &iAgentJsonFilePath) const {
+ std::ifstream aAgentJsonFile{iAgentJsonFilePath};
+ json aCredentials = json::parse(aAgentJsonFile);
+ if (not aCredentials.contains("Agent") or not aCredentials["Agent"].contains("Username") or
not aCredentials["Agent"].contains("Password")) {
std::cerr << "Please define Agent/Username and Agent/Password in the "
"JSON credentials file\n";
@@ -101,18 +84,15 @@ HearthstoneTokenBuilder::getTokenWithApi() const {
curl_easy_setopt(aCurl, CURLOPT_URL, "https://oauth.battle.net/token");
curl_easy_setopt(aCurl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(aCurl, CURLOPT_SSL_VERIFYHOST, 0L);
- curl_easy_setopt(aCurl, CURLOPT_WRITEFUNCTION,
- curlCallbackStringOutput);
+ curl_easy_setopt(aCurl, CURLOPT_WRITEFUNCTION, curlCallbackStringOutput);
curl_easy_setopt(aCurl, CURLOPT_WRITEDATA, &aTokenInfo);
- curl_easy_setopt(
- aCurl, CURLOPT_USERPWD,
- std::format("{}:{}", kAgentUsername, kAgentPassword).data());
- curl_easy_setopt(aCurl, CURLOPT_POSTFIELDS,
- "grant_type=client_credentials");
+ curl_easy_setopt(aCurl, CURLOPT_USERPWD,
+ std::format("{}:{}", kAgentUsername, kAgentPassword).data());
+ curl_easy_setopt(aCurl, CURLOPT_POSTFIELDS, "grant_type=client_credentials");
CURLcode result_code{curl_easy_perform(aCurl)};
curl_easy_cleanup(aCurl);
if (result_code != CURLE_OK) {
- std::cerr << "ERROR: token request failed" << std::endl;
+ std::cerr << "ERROR: token request failed\n";
std::exit(EXIT_FAILURE);
}
}
@@ -131,8 +111,8 @@ void HearthstoneTokenBuilder::writeTokenToLocalFile(
json aCredentialsFile = json::parse(aTokenFileInput);
aCredentialsFile["Token"]["Content"] = iToken.first;
aCredentialsFile["Token"]["ExpirationTime"] =
- std::chrono::duration_cast<std::chrono::seconds>(
- getCurrentTime() + std::chrono::seconds(iToken.second))
+ std::chrono::duration_cast<std::chrono::seconds>(getCurrentTime() +
+ std::chrono::seconds(iToken.second))
.count();
std::ofstream aTokenFileOutput{mFilePath};
diff --git a/battleNetApi/src/token.cpp b/battleNetApi/src/token.cpp
index b312cc1..6fcef1a 100644
--- a/battleNetApi/src/token.cpp
+++ b/battleNetApi/src/token.cpp
@@ -1,7 +1,17 @@
#include "token.hpp"
-Token::Token(const std::string &iTokenText) : mTokenText{iTokenText} {}
+Token::Token(const std::string &iTokenText, const std::chrono::seconds &iExpirationTime)
+ : _tokenText{iTokenText}, _expirationTime{iExpirationTime} {}
-std::string Token::text() const { return mTokenText; }
+std::string Token::text() const { return _tokenText; }
-void Token::setText(const std::string &iTokenText) { mTokenText = iTokenText; }
+void Token::setText(const std::string &iTokenText) { _tokenText = iTokenText; }
+
+void Token::setExpirationTime(const std::chrono::seconds &iExpirationTime) {
+ _expirationTime = iExpirationTime;
+}
+
+bool Token::isExpired() {
+ return _expirationTime <= std::chrono::duration_cast<std::chrono::seconds>(
+ std::chrono::steady_clock::now().time_since_epoch());
+}
diff --git a/battleNetApi/tests/CMakeLists.txt b/battleNetApi/tests/CMakeLists.txt
new file mode 100644
index 0000000..6918fb5
--- /dev/null
+++ b/battleNetApi/tests/CMakeLists.txt
@@ -0,0 +1,43 @@
+cmake_minimum_required(VERSION 3.15)
+
+get_filename_component(FNAME ${CMAKE_SOURCE_DIR} NAME)
+set(ProjectName ${FNAME})
+
+project(${ProjectName} LANGUAGES CXX)
+
+set(CMAKE_COMPILE_COMMANDS ON)
+set(CMAKE_CXX_STANDARD 23)
+set(CXX_STANDARD_REQUIRED ON)
+set(CMAKE_BUILD_TYPE Debug)
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall")
+set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
+add_definitions(-DSOURCE_DIR_PATH="${CMAKE_SOURCE_DIR}")
+find_package(Catch2 3 REQUIRED)
+find_package(nlohmann_json 3.12.0 REQUIRED)
+execute_process(
+ COMMAND "git" "rev-parse" "--show-toplevel"
+ OUTPUT_VARIABLE GIT_REPOSITORY_FOLDER_PATH
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+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(INCLUDE_TOKEN_DIR ${BATTLE_NET_API_DIR}/include)
+set(SRC_TOKEN_TESTS
+ ${BATTLE_NET_API_DIR}/src/token.cpp
+ ${BATTLE_NET_API_DIR}/tests/src/tokenTests.cpp
+)
+add_executable(tokenTests ${SRC_TOKEN_TESTS})
+target_include_directories(tokenTests PRIVATE ${INCLUDE_TOKEN_DIR})
+target_link_libraries(tokenTests PRIVATE Catch2::Catch2WithMain curl)
diff --git a/battleNetApi/tests/src/tests.cpp b/battleNetApi/tests/src/tests.cpp
new file mode 100644
index 0000000..d3c09c7
--- /dev/null
+++ b/battleNetApi/tests/src/tests.cpp
@@ -0,0 +1,144 @@
+#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.push_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.push_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
new file mode 100644
index 0000000..89e4039
--- /dev/null
+++ b/battleNetApi/tests/src/tokenTests.cpp
@@ -0,0 +1,20 @@
+#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 <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, std::chrono::seconds(0));
+ const std::string aTokenContent{aToken.text()};
+ const std::string::size_type aTokenSize{aTokenContent.size()};
+ REQUIRE(aTokenSize >= 30);
+ REQUIRE(aTokenSize <= 40);
+}
diff --git a/battleNetApi/tests/tests.cpp b/battleNetApi/tests/tests.cpp
deleted file mode 100644
index 10c6f23..0000000
--- a/battleNetApi/tests/tests.cpp
+++ /dev/null
@@ -1,149 +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 kCredentialsFile{"tests/resources/credentials.json"};
- Token aToken(kCredentialsFile);
- const std::string kTokenContent{aToken.text()};
- const std::string::size_type kTokenSize{kTokenContent.size()};
- REQUIRE(kTokenSize >= 30);
- REQUIRE(kTokenSize <= 40);
-}
-
-TEST_CASE("Retrieve number of cards", "[countCards]") {
- const std::string kCredentialsFile{};
- const std::string kContentType{"cards"};
- const std::string kRegion{"eu"};
- ApiUrl aApiUrl(kContentType, kRegion);
- aApiUrl.setLocale("fr_FR");
- aApiUrl.setGameMode("constructed");
- aApiUrl.setPageSize("1");
- TokenPool::feedTokenSource("tests/resources/credentials.json");
- const json kResponse = HearthstoneApi::makeApiRequest(
- aApiUrl, TokenPool::build().value().text());
- REQUIRE(kResponse.size() > 0);
- REQUIRE(kResponse.contains("pageCount"));
- std::uint64_t kNumberOfCards{kResponse["pageCount"]};
- std::uint64_t kExpectedNumberOfCards{6178};
- REQUIRE(kNumberOfCards == kExpectedNumberOfCards);
-}
-
-TEST_CASE("Retrieve page once", "[retrievePageOnce]") {
- const std::string kCredentialsFile{"tests/resources/credentials.json"};
- Token aToken(kCredentialsFile);
- const std::string kContentType{"cards"};
- const std::string kRegion{"eu"};
- ApiUrl aApiUrl(kContentType, kRegion);
- aApiUrl.setLocale("fr_FR");
- aApiUrl.setGameMode("constructed");
- aApiUrl.setPageSize("16");
- TokenPool::feedTokenSource("tests/resources/credentials.json");
- const json kApiResponse = HearthstoneApi::makeApiRequest(
- aApiUrl, TokenPool::build().value().text());
- REQUIRE(kApiResponse["cards"].size() == 16);
-}
-
-TEST_CASE("Retrieve pages 10 times without parallelization",
- "[retrievePagesNoParallel]") {
- const std::string kCredentialsFile{"tests/resources/credentials.json"};
- Token aToken(kCredentialsFile);
- const std::string kContentType{"cards"};
- const std::string kRegion{"eu"};
- ApiUrl aApiUrl(kContentType, kRegion);
- aApiUrl.setLocale("fr_FR");
- aApiUrl.setGameMode("constructed");
- aApiUrl.setPageSize("16");
- aApiUrl.setPage("1");
- TokenPool::feedTokenSource("tests/resources/credentials.json");
- std::string kTokenText{TokenPool::build().value().text()};
- json kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText);
-
- // Retrieve number of pages
- const int kNumberOfRetrievals{10};
- const int kNumberOfPages{kApiResponse["pageCount"]};
- REQUIRE(kNumberOfPages >= kNumberOfRetrievals);
- for (int i{1}; i < kNumberOfRetrievals; ++i) {
- REQUIRE(kApiResponse["cards"].size() == 16);
- aApiUrl.setPage(std::to_string(i + 1));
- kApiResponse = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText);
- }
- REQUIRE(kApiResponse["cards"].size() >= 1);
- REQUIRE(kApiResponse["cards"].size() <= 16);
-}
-
-TEST_CASE("Retrieve pages 10 times with parallelization",
- "[retrievePagesParallel]") {
- const std::string kCredentialsFile{"tests/resources/credentials.json"};
- Token aToken(kCredentialsFile);
- const std::string kContentType{"cards"};
- const std::string kRegion{"eu"};
- ApiUrl aApiUrl(kContentType, kRegion);
- 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 kTokenText{TokenPool::build().value().text()};
- json kFirstPageJson = HearthstoneApi::makeApiRequest(aApiUrl, kTokenText);
-
- int kNumberOfPages{kFirstPageJson["pageCount"]};
- const int kNumberOfRetrievals{10};
- REQUIRE(kNumberOfPages >= kNumberOfRetrievals);
- for (int i{1}; i < kNumberOfRetrievals; ++i) {
- aApiUrl.setPage(std::to_string(i + 1));
- aRequests.push_back(aApiUrl.text());
- }
- std::vector<json> kApiResponses =
- HearthstoneApi::makeApiRequest(aRequests, kTokenText);
- kApiResponses.emplace(kApiResponses.begin(), kFirstPageJson);
- REQUIRE(kApiResponses.size() == kNumberOfRetrievals);
- for (const json &kApiResponse : kApiResponses) {
- REQUIRE(kApiResponse["cards"].size() == 16);
- }
-}
-
-TEST_CASE("Merge two card lists from two page requests", "[Merge pages]") {
- std::ifstream aFirstPage{"tests/resources/page_merge_00.json"};
- json kFirstPage = json::parse(aFirstPage);
- std::ifstream aSecondPage{"tests/resources/page_merge_01.json"};
- const json kSecondPage = json::parse(aSecondPage);
-
- json::reference aMergedCards = kFirstPage["cards"];
- for (auto &card : kSecondPage["cards"]) {
- aMergedCards.push_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 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::build().value().text());
- const json::size_type kExpectedNumberOfCards{kApiResponse["cards"].size()};
- TokenPool::feedTokenSource("tests/resources/credentials.json");
- kApiResponse =
- HearthstoneApi::downloadCards(aApiUrl, TokenPool::build().value());
- const json::size_type kCurrentNumberOfCards{kApiResponse["cards"].size()};
- REQUIRE(kCurrentNumberOfCards == kExpectedNumberOfCards);
-}