fix: unittests

This commit is contained in:
Sebastian Dine
2026-05-10 12:18:45 +02:00
committed by GitHub
parent 8b7d45fdac
commit 5805101d24
20 changed files with 598 additions and 139 deletions
+6
View File
@@ -7,6 +7,7 @@
#include "ccm/ports/IHttpClient.hpp"
#include <chrono>
#include <functional>
#include <memory>
#include <mutex>
@@ -23,7 +24,11 @@ namespace ccm {
// only fires one outbound request at a time anyway.
class CprHttpClient final : public IHttpClient {
public:
using GetExecutor = std::function<Result<std::string>(std::string_view)>;
explicit CprHttpClient(std::chrono::milliseconds timeout = std::chrono::milliseconds{30000});
CprHttpClient(GetExecutor executor,
std::chrono::milliseconds timeout = std::chrono::milliseconds{30000});
~CprHttpClient() override;
Result<std::string> get(std::string_view url) override;
@@ -31,6 +36,7 @@ public:
private:
std::chrono::milliseconds timeout_;
std::unique_ptr<cpr::Session> session_;
GetExecutor executor_;
std::mutex sessionMutex_;
};
+22
View File
@@ -0,0 +1,22 @@
#pragma once
#include <cctype>
#include <string>
#include <string_view>
namespace ccm {
// ASCII-only tolower for sort/filter parity with the legacy TS path:
// String.prototype.toLowerCase() on English/German/etc. card metadata behaves
// identically for this byte range.
[[nodiscard]] inline std::string asciiLower(std::string_view s) {
std::string out;
out.reserve(s.size());
for (char c : s) {
out.push_back(static_cast<char>(
std::tolower(static_cast<unsigned char>(c))));
}
return out;
}
} // namespace ccm
+30
View File
@@ -0,0 +1,30 @@
#pragma once
#include "ccm/util/Result.hpp"
#include <string>
#include <string_view>
namespace ccm {
// Shared classification for raw HTTP GET outcomes (transport vs status vs OK).
// `CprHttpClient::get` delegates here so doctest can exercise the branches
// without touching libcpr or the network stack.
[[nodiscard]] inline Result<std::string> mapHttpGetResponse(bool curlTransportError,
std::string_view curlErrorMessage,
long httpStatusCode,
std::string responseBody,
std::string_view requestUrl) {
if (curlTransportError) {
return Result<std::string>::err(std::string("HTTP error: ") +
std::string(curlErrorMessage));
}
if (httpStatusCode < 200 || httpStatusCode >= 300) {
return Result<std::string>::err(
"HTTP " + std::to_string(httpStatusCode) + " from " +
std::string(requestUrl));
}
return Result<std::string>::ok(std::move(responseBody));
}
} // namespace ccm
+33
View File
@@ -0,0 +1,33 @@
#pragma once
#include <sstream>
#include <string>
#include <string_view>
namespace ccm {
// Percent-encode all bytes that are not unreserved per RFC 3986
// (A-Z / a-z / 0-9 / - . _ ~). Needed because cpr does not encode the URL
// string passed to IHttpClient::get.
[[nodiscard]] inline std::string rfc3986PercentEncode(std::string_view in) {
std::ostringstream out;
out.fill('0');
out << std::hex << std::uppercase;
for (unsigned char c : in) {
const bool unreserved =
(c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '.' || c == '_' || c == '~';
if (unreserved) {
out << static_cast<char>(c);
} else {
out << '%';
out.width(2);
out << static_cast<unsigned int>(c);
}
}
return out.str();
}
} // namespace ccm