From 3b41071980672945546b7438a8a0ce551858ba87 Mon Sep 17 00:00:00 2001 From: Paul Vogel Date: Thu, 15 Oct 2026 11:41:52 +0200 Subject: [PATCH 1/2] add ClientTestCase.php as base class for unit tests --- tests/Unit/Client/ClientTestCase.php | 113 +++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 tests/Unit/Client/ClientTestCase.php diff --git a/tests/Unit/Client/ClientTestCase.php b/tests/Unit/Client/ClientTestCase.php new file mode 100644 index 0000000..0ab7ebf --- /dev/null +++ b/tests/Unit/Client/ClientTestCase.php @@ -0,0 +1,113 @@ + + */ + protected array $requests = []; + + public function setUp(): void + { + $this->requests = []; + } + + /** + * Create a client that answers every request with one of the given responses, in order, + * and records all requests in {@see $requests}. + * + * The client gets its own configuration, because the default configuration is shared by all clients. + * @param Response[] $responses + * @return CurseForgeAPIClient + */ + protected function createClient(array $responses = []): CurseForgeAPIClient + { + $stack = HandlerStack::create(new MockHandler($responses)); + $stack->push(Middleware::history($this->requests)); + return new CurseForgeAPIClient(static::API_TOKEN, new Configuration(), new Client(['handler' => $stack])); + } + + /** + * Get a request recorded by the history middleware + * @param int $index + * @return RequestInterface + */ + protected function getRequest(int $index = 0): RequestInterface + { + $this->assertArrayHasKey($index, $this->requests, "Request " . $index . " was not sent"); + return $this->requests[$index]['request']; + } + + /** + * Get the query parameters of a recorded request + * @param int $index + * @return array + */ + protected function getQuery(int $index = 0): array + { + $query = []; + foreach (explode("&", $this->getRequest($index)->getUri()->getQuery()) as $pair) { + if ($pair === "") { + continue; + } + [$key, $value] = array_map("urldecode", explode("=", $pair, 2) + [1 => ""]); + if (array_key_exists($key, $query)) { + $query[$key] = [...(array)$query[$key], $value]; + } else { + $query[$key] = $value; + } + } + return $query; + } + + /** + * Assert that a recorded request is a GET request to the given path that contains the given query parameters + * @param string $path e.g. /v1/games/432 + * @param array $query expected query parameters, other parameters are ignored + * @param int $index + * @return void + */ + protected function assertGetRequest(string $path, array $query = [], int $index = 0): void + { + $request = $this->getRequest($index); + $this->assertSame("GET", $request->getMethod()); + $this->assertSame($path, $request->getUri()->getPath()); + + $actualQuery = $this->getQuery($index); + foreach ($query as $key => $value) { + $this->assertArrayHasKey($key, $actualQuery, "Query parameter " . $key . " is missing"); + $this->assertSame($value, $actualQuery[$key], "Query parameter " . $key . " has the wrong value"); + } + } + + /** + * Assert the number of requests that were sent + * @param int $count + * @return void + */ + protected function assertRequestCount(int $count): void + { + $this->assertCount($count, $this->requests); + } +} From 298bac46d1f3a14ebdcf6d363809ec474ec8556c Mon Sep 17 00:00:00 2001 From: Paul Vogel Date: Thu, 15 Oct 2026 11:42:06 +0200 Subject: [PATCH 2/2] add CurseForgeAPIClientTest.php for basic unit tests --- tests/Unit/Client/CurseForgeAPIClientTest.php | 82 +++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 tests/Unit/Client/CurseForgeAPIClientTest.php diff --git a/tests/Unit/Client/CurseForgeAPIClientTest.php b/tests/Unit/Client/CurseForgeAPIClientTest.php new file mode 100644 index 0000000..5451ed1 --- /dev/null +++ b/tests/Unit/Client/CurseForgeAPIClientTest.php @@ -0,0 +1,82 @@ +createClient([new Response(200, [], '{"data": {"id": 432}}')]); + + $client->getGame(432); + + $this->assertGetRequest("/v1/games/432"); + $this->assertSame(static::API_TOKEN, $this->getRequest()->getHeaderLine("x-api-key")); + } + + /** + * @throws ApiException + */ + public function testSetApiTokenReplacesApiToken(): void + { + $client = $this->createClient([new Response(200, [], '{"data": {"id": 432}}')]); + + $this->assertSame($client, $client->setApiToken("other-api-token")); + $client->getGame(432); + + $this->assertSame("other-api-token", $this->getRequest()->getHeaderLine("x-api-key")); + } + + /** + * @throws ApiException + */ + public function testSetApiTokenToNullRemovesApiToken(): void + { + $client = $this->createClient([new Response(200, [], '{"data": {"id": 432}}')]); + + $client->setApiToken(null); + $client->getGame(432); + + $this->assertFalse($this->getRequest()->hasHeader("x-api-key")); + } + + /** + * @throws ApiException + */ + public function testSetUserAgentIsSentWithRequests(): void + { + $client = $this->createClient([new Response(200, [], '{"data": {"id": 432}}')]); + + $this->assertSame($client, $client->setUserAgent("test-agent/1.0")); + $client->getGame(432); + + $this->assertSame("test-agent/1.0", $this->getRequest()->getHeaderLine("User-Agent")); + } + + /** + * @throws ApiException + */ + public function testSetHttpClientReplacesHttpClient(): void + { + $client = $this->createClient(); + $history = []; + $stack = HandlerStack::create(new MockHandler([new Response(200, [], '{"data": {"id": 432}}')])); + $stack->push(Middleware::history($history)); + + $this->assertSame($client, $client->setHttpClient(new Client(['handler' => $stack]))); + $client->getGame(432); + + $this->assertCount(1, $history); + $this->assertRequestCount(0); + } +}