Skip to content

Commit

Permalink
Test with multiple HTTP clients
Browse files Browse the repository at this point in the history
  • Loading branch information
cs278 committed Aug 28, 2024
1 parent 0d08e66 commit 14d8999
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 22 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ jobs:
- slim/psr7:^1.7
psr18:
- symfony/http-client:^5.4
- guzzlehttp/guzzle:^7
experimental: [false]
include:
- os: ubuntu-latest
Expand Down
3 changes: 3 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,7 @@ parameters:
- vendor-bin/phpunit/vendor
excludePaths:
analyse:
- tests/ClientTest/guzzle.php
- tests/ClientTest/symfony.php
- vendor-bin/phpunit/vendor
treatPhpDocTypesAsCertain: false
62 changes: 40 additions & 22 deletions tests/ClientTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,12 @@

namespace WiderPlan\Hcaptcha;

use Composer\InstalledVersions;
use Http\Discovery\Psr17FactoryDiscovery;
use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\UsesClass;
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Psr18Client;
use Symfony\Component\HttpClient\Response\MockResponse;
use Psr\Http\Message\ResponseInterface;

#[CoversClass(Client::class)]
#[UsesClass(Result::class)]
Expand All @@ -27,10 +27,10 @@ final class ClientTest extends TestCase
{
public function testWithoutSiteKeyAndRemoteIp(): void
{
$client = $this->createClient(function (string $method, string $url, array $options) {
$client = $this->createClient(function (string $method, string $url, string $body) {
self::assertSame('POST', $method);
self::assertSame('https://api.hcaptcha.com/siteverify', $url);
self::assertSame('response=abcdef', $options['body']);
self::assertSame('response=abcdef', $body);

return $this->createResponse([]);
});
Expand All @@ -41,10 +41,10 @@ public function testWithoutSiteKeyAndRemoteIp(): void

public function testWithSiteKeyAndWithoutRemoteIp(): void
{
$client = $this->createClient(function (string $method, string $url, array $options) {
$client = $this->createClient(function (string $method, string $url, string $body) {
self::assertSame('POST', $method);
self::assertSame('https://api.hcaptcha.com/siteverify', $url);
self::assertSame('response=abcdef&sitekey=12345+67890', $options['body']);
self::assertSame('response=abcdef&sitekey=12345+67890', $body);

return $this->createResponse([]);
});
Expand All @@ -55,10 +55,10 @@ public function testWithSiteKeyAndWithoutRemoteIp(): void

public function testWithoutSiteKeyAndWithRemoteIp(): void
{
$client = $this->createClient(function (string $method, string $url, array $options) {
$client = $this->createClient(function (string $method, string $url, string $body) {
self::assertSame('POST', $method);
self::assertSame('https://api.hcaptcha.com/siteverify', $url);
self::assertSame('response=abcdef&remoteip=10.9.2.234', $options['body']);
self::assertSame('response=abcdef&remoteip=10.9.2.234', $body);

return $this->createResponse([]);
});
Expand All @@ -69,10 +69,10 @@ public function testWithoutSiteKeyAndWithRemoteIp(): void

public function testWithSiteKeyRemoteIp(): void
{
$client = $this->createClient(function (string $method, string $url, array $options) {
$client = $this->createClient(function (string $method, string $url, string $body) {
self::assertSame('POST', $method);
self::assertSame('https://api.hcaptcha.com/siteverify', $url);
self::assertSame('response=abcdef&remoteip=10.9.2.234&sitekey=112233_445566%26789', $options['body']);
self::assertSame('response=abcdef&remoteip=10.9.2.234&sitekey=112233_445566%26789', $body);

return $this->createResponse([]);
});
Expand All @@ -83,14 +83,17 @@ public function testWithSiteKeyRemoteIp(): void

public function testWithNonJsonContentType(): void
{
$client = $this->createClient(function (string $method, string $url, array $options) {
$client = $this->createClient(function (string $method, string $url, string $body) {
self::assertSame('POST', $method);
self::assertSame('https://api.hcaptcha.com/siteverify', $url);
self::assertSame('response=abcdef&remoteip=10.9.2.234&sitekey=112233_445566%26789', $options['body']);
self::assertSame('response=abcdef&remoteip=10.9.2.234&sitekey=112233_445566%26789', $body);

return new MockResponse(\json_encode(['success' => true], flags: \JSON_THROW_ON_ERROR), [
'response_headers' => ['Content-Type: application/not-json'],
]);
$body = \json_encode(['success' => true], flags: \JSON_THROW_ON_ERROR);

return Psr17FactoryDiscovery::findResponseFactory()
->createResponse(200)
->withHeader('Content-Type', 'application/not-json')
->withBody(Psr17FactoryDiscovery::findStreamFactory()->createStream($body));
});

$this->expectException(Exception\NotSupportedResponseException::class);
Expand All @@ -99,21 +102,36 @@ public function testWithNonJsonContentType(): void
$client->verify('abcdef', '112233_445566&789', '10.9.2.234');
}

/**
* @param \Closure(string, string, string): ResponseInterface $responseFactory
*/
private function createClient(\Closure $responseFactory): Client
{
$httpClient = new MockHttpClient($responseFactory);
if (InstalledVersions::isInstalled('symfony/http-client')) {
$factory = 'symfony.php';
}

if (InstalledVersions::isInstalled('guzzlehttp/guzzle')) {
$factory = 'guzzle.php';
}

if (isset($factory)) {
return (require basename(__FILE__, '.php') . '/' . $factory)('', $responseFactory);
}

return Client::create('', new Psr18Client($httpClient));
self::markTestSkipped('No supported packages installed');
}

/** @param list<ErrorCode> $errorCodes */
private function createResponse(array $errorCodes): MockResponse
private function createResponse(array $errorCodes): ResponseInterface
{
$content = ['error-codes' => $errorCodes];
$content['success'] = $errorCodes === [] ? true : false;
$body = \json_encode($content, flags: \JSON_THROW_ON_ERROR);

return new MockResponse(\json_encode($content, flags: \JSON_THROW_ON_ERROR), [
'response_headers' => ['Content-Type: application/json'],
]);
return Psr17FactoryDiscovery::findResponseFactory()
->createResponse(200)
->withHeader('Content-Type', 'application/json')
->withBody(Psr17FactoryDiscovery::findStreamFactory()->createStream($body));
}
}
37 changes: 37 additions & 0 deletions tests/ClientTest/guzzle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

/*
* This file is part of the hCaptcha API Client package.
*
* (c) Wider Plan <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace WiderPlan\Hcaptcha;

use GuzzleHttp\Client as Guzzle;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Promise\Create;
use Http\Discovery\Psr18Client;
use Psr\Http\Message\RequestInterface;

return function (string $secretKey, \Closure $responseFactory): Client {
$handler = function (RequestInterface $request) use ($responseFactory) {
$response = $responseFactory(
$request->getMethod(),
(string) $request->getUri(),
(string) $request->getBody(),
);

return Create::promiseFor($response);
};

return Client::create(
$secretKey,
new Psr18Client(new Guzzle(['handler' => HandlerStack::create($handler)])),
);
};
41 changes: 41 additions & 0 deletions tests/ClientTest/symfony.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

/*
* This file is part of the hCaptcha API Client package.
*
* (c) Wider Plan <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace WiderPlan\Hcaptcha;

use Psr\Http\Message\ResponseInterface;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Psr18Client;
use Symfony\Component\HttpClient\Response\MockResponse;

return function (string $secretKey, \Closure $responseFactory): Client {
$httpClient = new MockHttpClient(function (string $method, string $uri, array $options) use ($responseFactory) {
$response = $responseFactory($method, $uri, $options['body']);
\assert($response instanceof ResponseInterface);

$headers = [];

foreach ($response->getHeaders() as $name => $values) {
foreach ($values as $value) {
$headers[] = sprintf('%s: %s', $name, $value);
}
}

return new MockResponse((string) $response->getBody(), [
'http_code' => $response->getStatusCode(),
'response_headers' => $headers,
]);
});

return Client::create($secretKey, new Psr18Client($httpClient));
};

0 comments on commit 14d8999

Please sign in to comment.