Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/HttpClientMock/Matcher/Hit.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace Brainbits\FunctionalTestHelpers\HttpClientMock\Matcher;

use function is_array;
use function Safe\json_encode;

final readonly class Hit
{
private function __construct(
Expand Down Expand Up @@ -34,9 +37,10 @@ public static function matchesHeader(string $key, string $value): self
return new self('header', $key, 5, $value);
}

public static function matchesQueryParam(string $key, string $value): self
/** @param string|mixed[] $value */
public static function matchesQueryParam(string $key, string|array $value): self
{
return new self('queryParam', $key, 5, $value);
return new self('queryParam', $key, 5, is_array($value) ? json_encode($value) : $value);
}

public static function matchesRequestParam(string $key, string $value): self
Expand Down
11 changes: 8 additions & 3 deletions src/HttpClientMock/Matcher/Mismatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;

use function is_array;
use function Safe\json_encode;

use const PHP_EOL;
Expand Down Expand Up @@ -131,13 +132,17 @@ public static function mismatchingHeader(string $key, mixed $value, mixed $other
);
}

public static function mismatchingQueryParam(string $key, string $value, string $otherValue): self
/**
* @param string|mixed[] $value
* @param string|mixed[] $otherValue
*/
public static function mismatchingQueryParam(string $key, string|array $value, string|array $otherValue): self
{
return new self(
'queryParam',
$key,
$value,
$otherValue,
is_array($value) ? json_encode($value) : $value,
is_array($otherValue) ? json_encode($otherValue) : $otherValue,
);
}

Expand Down
8 changes: 6 additions & 2 deletions src/HttpClientMock/Matcher/Missing.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace Brainbits\FunctionalTestHelpers\HttpClientMock\Matcher;

use function is_array;
use function Safe\json_encode;

final readonly class Missing
{
public int $score;
Expand All @@ -22,12 +25,13 @@ public static function missingHeader(string $key, string $expected): self
);
}

public static function missingQueryParam(string $key, string $expected): self
/** @param string|mixed[] $expected */
public static function missingQueryParam(string $key, string|array $expected): self
{
return new self(
'queryParam',
$key,
$expected,
is_array($expected) ? json_encode($expected) : $expected,
);
}

Expand Down
44 changes: 38 additions & 6 deletions src/HttpClientMock/Matcher/QueryParamMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,42 @@

use Brainbits\FunctionalTestHelpers\HttpClientMock\RealRequest;

use function in_array;
use function is_array;
use function Safe\json_encode;
use function sprintf;
use function str_ends_with;
use function substr;
use function vsprintf;

final readonly class QueryParamMatcher implements Matcher
{
private string $value;
private string $key;

/** @param array<string> $placeholders */
public function __construct(private string $key, string $value, array $placeholders)
/** @var string|mixed[] */
private string|array $value;

private bool $isArray;

/**
* @param string|mixed[] $value
* @param array<string> $placeholders
*/
public function __construct(string $key, string|array $value, array $placeholders)
{
$this->value = vsprintf($value, $placeholders);
$isArray = false;
if (str_ends_with($key, '[]')) {
$key = substr($key, 0, -2);
$isArray = true;
}

if (!is_array($value)) {
$value = vsprintf($value, $placeholders);
}

$this->key = $key;
$this->value = $value;
$this->isArray = $isArray;
}

public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
Expand All @@ -28,7 +53,10 @@ public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing
$expectedValue = $this->value;
$realValue = $realRequest->getQueryParam($this->key);

if ($expectedValue !== $realValue) {
if (
(!$this->isArray && $expectedValue !== $realValue) ||
($this->isArray && !in_array($expectedValue, $realValue, true))
) {
return Mismatch::mismatchingQueryParam($this->key, $expectedValue, $realValue);
}

Expand All @@ -37,6 +65,10 @@ public function __invoke(RealRequest $realRequest): Hit|Mismatch|Missing

public function __toString(): string
{
return sprintf('request.queryParams["%s"] === "%s"', $this->key, $this->value);
return sprintf(
'request.queryParams["%s"] === "%s"',
$this->key,
is_array($this->value) ? json_encode($this->value) : $this->value,
);
}
}
9 changes: 5 additions & 4 deletions src/HttpClientMock/MockRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -187,18 +187,19 @@ public function xml(string|callable $xml): self
return $this;
}

public function queryParam(string $key, string $value, string ...$placeholders): self
/** @param string|mixed[] $value */
public function queryParam(string $key, string|array $value, string ...$placeholders): self
{
$this->matchers['queryParams'] ??= [];
$this->matchers['queryParams'][$key] = new QueryParamMatcher($key, $value, $placeholders);
$this->matchers['queryParams'][] = new QueryParamMatcher($key, $value, $placeholders);

return $this;
}

public function requestParam(string $key, string $value): self
{
$this->matchers['requestParams'] ??= [];
$this->matchers['requestParams'][$key] = new RequestParamMatcher($key, $value);
$this->matchers['requestParams'][] = new RequestParamMatcher($key, $value);

/*
if ((string) $this->content !== '') {
Expand All @@ -218,7 +219,7 @@ public function multipart(
string|null $content = null,
): self {
$this->matchers['multiparts'] ??= [];
$this->matchers['multiparts'][$name] = new MultipartMatcher($name, $mimetype, $filename, $content);
$this->matchers['multiparts'][] = new MultipartMatcher($name, $mimetype, $filename, $content);

return $this;
}
Expand Down
5 changes: 3 additions & 2 deletions src/HttpClientMock/RealRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ final class RealRequest
/**
* @param array<string, string> $headers
* @param mixed[] $json
* @param array<string, string> $queryParams
* @param array<string, string|mixed[]> $queryParams
* @param array<string, string> $requestParams
* @param array<string, array{name: string, filename?: string, mimetype?: string, content?: string}> $multiparts
*/
Expand Down Expand Up @@ -84,7 +84,8 @@ public function hasQueryParam(string $key): bool
return array_key_exists($key, $this->queryParams);
}

public function getQueryParam(string $key): string|null
/** @return string|mixed[]|null */
public function getQueryParam(string $key): string|array|null
{
return $this->queryParams[$key] ?? null;
}
Expand Down
39 changes: 39 additions & 0 deletions tests/HttpClientMock/Matcher/QueryParamMatcherTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,45 @@ public function testMatchQueryParamWithZeroValue(): void
self::assertMatcher('queryParam', $result);
}

public function testMatchQueryParamWithFirstArrayValue(): void
{
$matcher = new QueryParamMatcher('name[]', 'abc', []);

$realRequest = $this->createRealRequest(queryParams: ['name' => ['abc', 'def']]);

$result = $matcher($realRequest);

self::assertInstanceOf(Hit::class, $result);
self::assertScore(5, $result);
self::assertMatcher('queryParam', $result);
}

public function testMatchQueryParamWithSecondArrayValue(): void
{
$matcher = new QueryParamMatcher('name[]', 'def', []);

$realRequest = $this->createRealRequest(queryParams: ['name' => ['abc', 'def']]);

$result = $matcher($realRequest);

self::assertInstanceOf(Hit::class, $result);
self::assertScore(5, $result);
self::assertMatcher('queryParam', $result);
}

public function testMatchQueryParamWithArrayValue(): void
{
$matcher = new QueryParamMatcher('name', ['abc', 'def'], []);

$realRequest = $this->createRealRequest(queryParams: ['name' => ['abc', 'def']]);

$result = $matcher($realRequest);

self::assertInstanceOf(Hit::class, $result);
self::assertScore(5, $result);
self::assertMatcher('queryParam', $result);
}

public function testMatchQueryParamWithPlaceholder(): void
{
$matcher = new QueryParamMatcher('filter', '%s%s', ['last', 'name']);
Expand Down
19 changes: 18 additions & 1 deletion tests/HttpClientMock/MockRequestBuilderCollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,21 @@ public function setUp(): void
->queryParam('two', '2')
->willRespond(new MockResponseBuilder()),

'get_uri_array_param1' => (new MockRequestBuilder())
->name('get_uri_array_param1')
->method('GET')
->uri('/uri')
->queryParam('name[]', 'abc')
->queryParam('name[]', 'def')
->willRespond(new MockResponseBuilder()),

'get_uri_array_param2' => (new MockRequestBuilder())
->name('get_uri_array_param2')
->method('GET')
->uri('/uri')
->queryParam('test', ['123', '456'])
->willRespond(new MockResponseBuilder()),

'post_uri_json' => (new MockRequestBuilder())
->name('post_uri_json')
->method('POST')
Expand Down Expand Up @@ -127,7 +142,7 @@ public function setUp(): void
#[DataProvider('requests')]
public function testRequestMatching(string $method, string $uri, array $options, string $index): void
{
$x = ($this->collection)($method, $uri, $options);
($this->collection)($method, $uri, $options);

$expectedMockRequestBuilder = $this->builders[$index];

Expand Down Expand Up @@ -236,6 +251,8 @@ public static function requests(): array
'getUri' => ['GET', '/uri', [], 'get_uri'],
'getUriWithOneParam' => ['GET', '/uri?one=1', [], 'get_uri_param'],
'getUriWithTwoParams' => ['GET', '/uri?one=1&two=2', [], 'get_uri_params'],
'getUriWithArrayParam1' => ['GET', '/uri?name[]=abc&name[]=def', [], 'get_uri_array_param1'],
'getUriWithArrayParam2' => ['GET', '/uri?test[]=123&test[]=456', [], 'get_uri_array_param2'],
'postUri' => ['POST', '/uri', [], 'post'],
'postUriJson' => ['POST', '/uri', ['json' => ['json' => 'data']], 'post_uri_json'],
'postUriXml' => [
Expand Down
2 changes: 1 addition & 1 deletion tests/HttpClientMock/RealRequestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ trait RealRequestTrait
/**
* @param array<string, string> $headers
* @param mixed[] $json
* @param array<string, string> $queryParams
* @param array<string, string|mixed[]> $queryParams
* @param array<string, string> $requestParams
* @param array<string, array{name: string, filename?: string, mimetype?: string, content?: string}> $multiparts
*/
Expand Down
Loading