Skip to content

Commit 83e7219

Browse files
authored
Merge pull request #5 from xepozz/fix-fallback-arguments
Pass arguments to the fallback
2 parents a045b08 + 2a898b9 commit 83e7219

File tree

10 files changed

+115
-27
lines changed

10 files changed

+115
-27
lines changed

.github/workflows/phpunit.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ jobs:
3232
run: composer install
3333

3434
- name: Run tests with code coverage.
35-
run: php -ddisable_functions=time vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always
35+
run: composer test
3636

3737
- name: Upload coverage to Codecov.
3838
if: matrix.os == 'ubuntu-latest'

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@
2424
}
2525
},
2626
"scripts": {
27-
"test": "php -ddisable_functions=time vendor/bin/phpunit"
27+
"test": "php -ddisable_functions=time,header,headers_sent vendor/bin/phpunit"
2828
}
2929
}

src/Mocker.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,23 +103,33 @@ private function normalizeMocks(array $mocks): array
103103

104104
private function generateFunction(mixed $groupedMocks): string
105105
{
106+
$stubs = require __DIR__ . '/stubs.php';
106107
$innerOutputs = [];
107108
foreach ($groupedMocks as $functionName => $_) {
108-
$function = "fn() => \\$functionName(...\$arguments)";
109+
$signatureArguments = $stubs[$functionName]['signatureArguments'] ?? '...$arguments';
110+
if (isset($stubs[$functionName]['arguments'])) {
111+
$arrayArguments = sprintf('[%s]', $stubs[$functionName]['arguments']);
112+
$unpackedArguments = $stubs[$functionName]['arguments'];
113+
} else {
114+
$arrayArguments = '$arguments';
115+
$unpackedArguments = '...$arguments';
116+
}
117+
118+
$function = "fn($signatureArguments) => \\$functionName($unpackedArguments)";
109119
if ($_[0]['function'] !== false) {
110120
$function = is_string($_[0]['function'])
111121
? $_[0]['function']
112122
: VarDumper::create($_[0]['function'])->export(false);
113123
}
114124

115125
$string = <<<PHP
116-
function $functionName(...\$arguments)
126+
function $functionName($signatureArguments)
117127
{
118-
\$position = MockerState::saveTrace(__NAMESPACE__, "$functionName", \$arguments);
119-
if (MockerState::checkCondition(__NAMESPACE__, "$functionName", \$arguments)) {
120-
\$result = MockerState::getResult(__NAMESPACE__, "$functionName", \$arguments);
128+
\$position = MockerState::saveTrace(__NAMESPACE__, "$functionName", $unpackedArguments);
129+
if (MockerState::checkCondition(__NAMESPACE__, "$functionName", $arrayArguments)) {
130+
\$result = MockerState::getResult(__NAMESPACE__, "$functionName", $unpackedArguments);
121131
} else {
122-
\$result = MockerState::getDefaultResult(__NAMESPACE__, "$functionName", $function);
132+
\$result = MockerState::getDefaultResult(__NAMESPACE__, "$functionName", $function, $unpackedArguments);
123133
}
124134
125135
return MockerState::saveTraceResult(__NAMESPACE__, "$functionName", \$position, \$result);

src/MockerState.php

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ final class MockerState
1414
public static function addCondition(
1515
string $namespace,
1616
string $functionName,
17-
array $arguments,
17+
array|string $arguments,
1818
mixed $result,
1919
bool $default = false
2020
): void {
@@ -39,7 +39,7 @@ public static function addCondition(
3939
public static function checkCondition(
4040
string $namespace,
4141
string $functionName,
42-
array $expectedArguments,
42+
array|string $expectedArguments,
4343
): bool {
4444
$mocks = self::$state[$namespace][$functionName] ?? [];
4545

@@ -51,10 +51,10 @@ public static function checkCondition(
5151
return false;
5252
}
5353

54-
private static function compareArguments(array $arguments, array $expectedArguments): bool
54+
private static function compareArguments(array $arguments, array|string $expectedArguments): bool
5555
{
5656
return $arguments['arguments'] === $expectedArguments
57-
|| array_values($arguments['arguments']) === $expectedArguments;
57+
|| (is_array($arguments['arguments']) && array_values($arguments['arguments']) === $expectedArguments);
5858
}
5959

6060
private static function replaceResult(
@@ -75,13 +75,13 @@ private static function replaceResult(
7575
public static function getResult(
7676
string $namespace,
7777
string $functionName,
78-
array $expectedArguments,
78+
&...$expectedArguments,
7979
): mixed {
8080
$mocks = self::$state[$namespace][$functionName] ?? [];
8181

8282
foreach ($mocks as $mock) {
8383
if (self::compareArguments($mock, $expectedArguments)) {
84-
return $mock['result'];
84+
return is_callable($mock['result']) ? $mock['result'](...$expectedArguments) : $mock['result'];
8585
}
8686
}
8787
return false;
@@ -91,12 +91,13 @@ public static function getDefaultResult(
9191
string $namespace,
9292
string $functionName,
9393
callable $fallback,
94+
&...$arguments,
9495
): mixed {
9596
if (isset(self::$defaults[$namespace][$functionName])) {
9697
return self::$defaults[$namespace][$functionName];
9798
}
9899

99-
return $fallback();
100+
return $fallback(...$arguments);
100101
}
101102

102103
public static function saveState(): void
@@ -113,11 +114,11 @@ public static function resetState(): void
113114
public static function saveTrace(
114115
string $namespace,
115116
string $functionName,
116-
array $arguments
117+
&...$arguments
117118
): int {
118119
$position = count(self::$traces[$namespace][$functionName] ?? []);
119120
self::$traces[$namespace][$functionName][$position] = [
120-
'arguments' => $arguments,
121+
'arguments' => &$arguments,
121122
'trace' => debug_backtrace(),
122123
];
123124

src/stubs.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
return [
4+
'headers_sent' => [
5+
'signature' => 'headers_sent(&$filename, &$line): bool',
6+
'signatureArguments' => '&$filename, &$line',
7+
'arguments' => '$filename, $line',
8+
],
9+
'time' => [
10+
'signature' => 'time(): int',
11+
'signatureArguments' => '',
12+
'arguments' => '',
13+
],
14+
];

tests/Integration/HeaderTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Xepozz\InternalMocker\Tests\Integration;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Xepozz\InternalMocker\MockerState;
9+
10+
final class HeaderTest extends TestCase
11+
{
12+
public function testRun()
13+
{
14+
header('Content-Type: application/json');
15+
16+
$trace = MockerState::getTraces(
17+
'',
18+
'header',
19+
);
20+
21+
$this->assertEquals(['Content-Type: application/json'], $trace[0]['arguments']);
22+
}
23+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Xepozz\InternalMocker\Tests\Integration;
6+
7+
use PHPUnit\Framework\TestCase;
8+
use Xepozz\InternalMocker\MockerState;
9+
10+
final class HeadersSentTest extends TestCase
11+
{
12+
public function testCheckReferences()
13+
{
14+
MockerState::addCondition(
15+
'',
16+
'headers_sent',
17+
[null, null],
18+
fn (&$file, &$line) => $file = $line = 123,
19+
);
20+
headers_sent($file, $line);
21+
22+
$trace = MockerState::getTraces(
23+
'',
24+
'headers_sent',
25+
);
26+
27+
$this->assertEquals(123, $file);
28+
$this->assertEquals(123, $line);
29+
$this->assertEquals([123, 123], $trace[0]['arguments']);
30+
}
31+
}

tests/Integration/TraceTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ public function testBacktrace(): void
6767

6868
$this->assertEquals(['test'], $traces[0]['arguments']);
6969
$this->assertEquals('saveTrace', $traces[0]['trace'][0]['function']);
70-
$this->assertEquals(120, $traces[0]['trace'][0]['line']);
70+
$this->assertEquals(144, $traces[0]['trace'][0]['line']);
7171
$this->assertEquals(
7272
[
7373
__NAMESPACE__,
7474
'serialize',
75-
['test'],
75+
'test',
7676
],
7777
$traces[0]['trace'][0]['args'],
7878
);

tests/MockerExtension.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,15 @@ public static function load(): void
7474
'name' => 'time',
7575
'function' => fn () => `date +%s`,
7676
],
77+
[
78+
'namespace' => '',
79+
'name' => 'header',
80+
'function' => fn (string $value) => true,
81+
],
82+
[
83+
'namespace' => '',
84+
'name' => 'headers_sent',
85+
],
7786
];
7887

7988
$mocker = new Mocker();

tests/MockerTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,13 @@ public function generateProvider()
4747
namespace Xepozz\InternalMocker\Tests\Integration {
4848
use Xepozz\InternalMocker\MockerState;
4949
50-
function time(...\$arguments)
50+
function time()
5151
{
52-
\$position = MockerState::saveTrace(__NAMESPACE__, "time", \$arguments);
53-
if (MockerState::checkCondition(__NAMESPACE__, "time", \$arguments)) {
54-
\$result = MockerState::getResult(__NAMESPACE__, "time", \$arguments);
52+
\$position = MockerState::saveTrace(__NAMESPACE__, "time", );
53+
if (MockerState::checkCondition(__NAMESPACE__, "time", [])) {
54+
\$result = MockerState::getResult(__NAMESPACE__, "time", );
5555
} else {
56-
\$result = MockerState::getDefaultResult(__NAMESPACE__, "time", fn() => \\time(...\$arguments));
56+
\$result = MockerState::getDefaultResult(__NAMESPACE__, "time", fn() => \\time(), );
5757
}
5858
5959
return MockerState::saveTraceResult(__NAMESPACE__, "time", \$position, \$result);
@@ -108,11 +108,11 @@ function time(...\$arguments)
108108
109109
function str_contains(...\$arguments)
110110
{
111-
\$position = MockerState::saveTrace(__NAMESPACE__, "str_contains", \$arguments);
111+
\$position = MockerState::saveTrace(__NAMESPACE__, "str_contains", ...\$arguments);
112112
if (MockerState::checkCondition(__NAMESPACE__, "str_contains", \$arguments)) {
113-
\$result = MockerState::getResult(__NAMESPACE__, "str_contains", \$arguments);
113+
\$result = MockerState::getResult(__NAMESPACE__, "str_contains", ...\$arguments);
114114
} else {
115-
\$result = MockerState::getDefaultResult(__NAMESPACE__, "str_contains", fn() => \\str_contains(...\$arguments));
115+
\$result = MockerState::getDefaultResult(__NAMESPACE__, "str_contains", fn(...\$arguments) => \\str_contains(...\$arguments), ...\$arguments);
116116
}
117117
118118
return MockerState::saveTraceResult(__NAMESPACE__, "str_contains", \$position, \$result);

0 commit comments

Comments
 (0)