Skip to content

Commit 5383f00

Browse files
committed
test: cover codex compatibility helpers
1 parent f68ad89 commit 5383f00

File tree

3 files changed

+179
-25
lines changed

3 files changed

+179
-25
lines changed

phpstan-baseline.neon

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -570,18 +570,6 @@ parameters:
570570
count: 1
571571
path: src/Internal/Codex/Testing/Assert.php
572572

573-
-
574-
message: '#^Call to an undefined static method PHPUnit\\Framework\\InvalidArgumentException\:\:create\(\)\.$#'
575-
identifier: staticMethod.notFound
576-
count: 2
577-
path: src/Internal/Codex/Testing/Assert.php
578-
579-
-
580-
message: '#^Call to static method factory\(\) on an unknown class PHPUnit\\Util\\InvalidArgumentHelper\.$#'
581-
identifier: class.notFound
582-
count: 2
583-
path: src/Internal/Codex/Testing/Assert.php
584-
585573
-
586574
message: '#^Method Laravie\\Codex\\Testing\\Assert\:\:assertArraySubset\(\) has parameter \$array with generic interface ArrayAccess but does not specify its types\: TKey, TValue$#'
587575
identifier: missingType.generics

src/Internal/Codex/Testing/Assert.php

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,9 @@
44

55
use ArrayAccess;
66
use PHPUnit\Framework\Assert as PHPUnit;
7-
use PHPUnit\Framework\InvalidArgumentException;
87
use PHPUnit\Runner\Version;
9-
use PHPUnit\Util\InvalidArgumentHelper;
108

11-
if (class_exists(Version::class) && (int) Version::series()[0] >= 8) {
9+
if (class_exists(Version::class) && version_compare(Version::series(), '8.0', '>=')) {
1210
/**
1311
* @internal this class is not meant to be used or overwritten outside the framework itself
1412
*/
@@ -23,19 +21,11 @@ abstract class Assert extends PHPUnit
2321
public static function assertArraySubset($subset, $array, bool $checkForIdentity = false, string $msg = ''): void
2422
{
2523
if (! (\is_array($subset) || $subset instanceof ArrayAccess)) {
26-
if (class_exists(InvalidArgumentException::class)) {
27-
throw InvalidArgumentException::create(1, 'array or ArrayAccess');
28-
} else {
29-
throw InvalidArgumentHelper::factory(1, 'array or ArrayAccess');
30-
}
24+
throw new \InvalidArgumentException('Argument #1 must be of type array or ArrayAccess');
3125
}
3226

3327
if (! (\is_array($array) || $array instanceof ArrayAccess)) {
34-
if (class_exists(InvalidArgumentException::class)) {
35-
throw InvalidArgumentException::create(2, 'array or ArrayAccess');
36-
} else {
37-
throw InvalidArgumentHelper::factory(2, 'array or ArrayAccess');
38-
}
28+
throw new \InvalidArgumentException('Argument #2 must be of type array or ArrayAccess');
3929
}
4030

4131
$constraint = new ArraySubset($subset, $checkForIdentity);

tests/CodexCoverageTest.php

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
<?php
2+
3+
use Http\Client\Common\HttpMethodsClient;
4+
use Laravie\Codex\Common\Discovery as CommonDiscovery;
5+
use Laravie\Codex\Concerns\Passport;
6+
use Laravie\Codex\Concerns\Request\Json;
7+
use Laravie\Codex\Contracts\Response as ResponseContract;
8+
use Laravie\Codex\Testing\Assert as CodexAssert;
9+
use Laravie\Codex\Testing\Faker;
10+
11+
final class TestDiscovery extends CommonDiscovery
12+
{
13+
public static int $makeCalls = 0;
14+
15+
public static ?HttpMethodsClient $nextClient = null;
16+
17+
public static function make(): HttpMethodsClient
18+
{
19+
self::$makeCalls++;
20+
21+
return self::$nextClient ?? Faker::create()->http();
22+
}
23+
}
24+
25+
it('adds the json content type header before sending requests', function (): void {
26+
$response = Mockery::mock(ResponseContract::class);
27+
28+
$request = new class($response)
29+
{
30+
use Json;
31+
32+
public array $sent = [];
33+
34+
public function __construct(private ResponseContract $response) {}
35+
36+
public function sendJsonRequest(string $method, $path, array $headers = [], $body = []): ResponseContract
37+
{
38+
return $this->sendJson($method, $path, $headers, $body);
39+
}
40+
41+
protected function send(string $method, $path, array $headers = [], $body = []): ResponseContract
42+
{
43+
$this->sent = compact('method', 'path', 'headers', 'body');
44+
45+
return $this->response;
46+
}
47+
};
48+
49+
$result = $request->sendJsonRequest('POST', '/bills', ['Accept' => 'application/json'], ['name' => 'Test']);
50+
51+
expect($result)->toBe($response);
52+
expect($request->sent)->toBe([
53+
'method' => 'POST',
54+
'path' => '/bills',
55+
'headers' => [
56+
'Accept' => 'application/json',
57+
'Content-Type' => 'application/json',
58+
],
59+
'body' => ['name' => 'Test'],
60+
]);
61+
});
62+
63+
it('stores passport credentials fluently', function (): void {
64+
$passport = new class
65+
{
66+
use Passport;
67+
};
68+
69+
expect($passport->getClientId())->toBeNull();
70+
expect($passport->getClientSecret())->toBeNull();
71+
expect($passport->getAccessToken())->toBeNull();
72+
73+
$result = $passport
74+
->setClientId('client-id')
75+
->setClientSecret('client-secret')
76+
->setAccessToken('access-token');
77+
78+
expect($result)->toBe($passport);
79+
expect($passport->getClientId())->toBe('client-id');
80+
expect($passport->getClientSecret())->toBe('client-secret');
81+
expect($passport->getAccessToken())->toBe('access-token');
82+
});
83+
84+
it('caches refreshed and overridden discovery clients', function (): void {
85+
$first = Faker::create()->http();
86+
$second = Faker::create()->http();
87+
$override = Faker::create()->http();
88+
89+
TestDiscovery::flush();
90+
TestDiscovery::$makeCalls = 0;
91+
TestDiscovery::$nextClient = $first;
92+
93+
expect(TestDiscovery::client())->toBe($first);
94+
expect(TestDiscovery::client())->toBe($first);
95+
expect(TestDiscovery::$makeCalls)->toBe(1);
96+
97+
TestDiscovery::$nextClient = $second;
98+
99+
expect(TestDiscovery::refreshClient())->toBe($second);
100+
expect(TestDiscovery::$makeCalls)->toBe(2);
101+
102+
expect(TestDiscovery::override($override))->toBe($override);
103+
expect(TestDiscovery::client())->toBe($override);
104+
105+
TestDiscovery::flush();
106+
TestDiscovery::$nextClient = null;
107+
});
108+
109+
it('asserts array subsets for arrays and array access values', function (): void {
110+
CodexAssert::assertArraySubset(['foo' => 'bar'], ['foo' => 'bar', 'baz' => 'qux']);
111+
CodexAssert::assertArraySubset(['foo' => 'bar'], new \ArrayObject(['foo' => 'bar', 'baz' => 'qux']));
112+
113+
expect(true)->toBeTrue();
114+
});
115+
116+
it('rejects invalid values when asserting array subsets', function (): void {
117+
try {
118+
CodexAssert::assertArraySubset('invalid', []);
119+
$this->fail('Expected invalid subset assertion to throw.');
120+
} catch (\InvalidArgumentException $e) {
121+
expect($e->getMessage())->toContain('array or ArrayAccess');
122+
}
123+
124+
try {
125+
CodexAssert::assertArraySubset([], 'invalid');
126+
$this->fail('Expected invalid array assertion to throw.');
127+
} catch (\InvalidArgumentException $e) {
128+
expect($e->getMessage())->toContain('array or ArrayAccess');
129+
}
130+
});
131+
132+
it('filters request bodies and preserves endpoint queries', function (): void {
133+
$this->apiVersion = 'v5';
134+
135+
$faker = $this->expectRequest(
136+
'POST',
137+
'payments?foo=bar',
138+
['Accept' => 'application/json', 'X-Test' => '1'],
139+
['amount' => 200, 'description' => 'Example']
140+
)->shouldResponseWithJson(200, '{}');
141+
142+
$request = new class extends \Billplz\Request
143+
{
144+
public function __construct()
145+
{
146+
parent::__construct();
147+
148+
$this->version = 'v5';
149+
}
150+
151+
public function createPayment(array $payload): \Laravie\Codex\Contracts\Response
152+
{
153+
return $this->send(
154+
'POST',
155+
self::to('/payments', [], ['foo' => 'bar']),
156+
$this->mergeApiHeaders(['X-Test' => '1']),
157+
$this->mergeApiBody($payload)
158+
);
159+
}
160+
161+
protected function getApiHeaders(): array
162+
{
163+
return ['Accept' => 'application/json'];
164+
}
165+
166+
protected function getApiBody(): array
167+
{
168+
return ['amount' => \Money\Money::MYR(200)];
169+
}
170+
};
171+
172+
$request->setClient($this->makeClient($faker));
173+
174+
expect($request->hasFilterable())->toBeTrue();
175+
expect($request->createPayment(['description' => 'Example']))->toBeInstanceOf(\Billplz\Response::class);
176+
});

0 commit comments

Comments
 (0)