Skip to content

Commit

Permalink
Merge pull request #5 from xepozz/fix-fallback-arguments
Browse files Browse the repository at this point in the history
Pass arguments to the fallback
  • Loading branch information
xepozz committed Feb 24, 2024
2 parents a045b08 + 2a898b9 commit 83e7219
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 27 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/phpunit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ jobs:
run: composer install

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

- name: Upload coverage to Codecov.
if: matrix.os == 'ubuntu-latest'
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,6 @@
}
},
"scripts": {
"test": "php -ddisable_functions=time vendor/bin/phpunit"
"test": "php -ddisable_functions=time,header,headers_sent vendor/bin/phpunit"
}
}
22 changes: 16 additions & 6 deletions src/Mocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -103,23 +103,33 @@ private function normalizeMocks(array $mocks): array

private function generateFunction(mixed $groupedMocks): string
{
$stubs = require __DIR__ . '/stubs.php';
$innerOutputs = [];
foreach ($groupedMocks as $functionName => $_) {
$function = "fn() => \\$functionName(...\$arguments)";
$signatureArguments = $stubs[$functionName]['signatureArguments'] ?? '...$arguments';
if (isset($stubs[$functionName]['arguments'])) {
$arrayArguments = sprintf('[%s]', $stubs[$functionName]['arguments']);
$unpackedArguments = $stubs[$functionName]['arguments'];
} else {
$arrayArguments = '$arguments';
$unpackedArguments = '...$arguments';
}

$function = "fn($signatureArguments) => \\$functionName($unpackedArguments)";
if ($_[0]['function'] !== false) {
$function = is_string($_[0]['function'])
? $_[0]['function']
: VarDumper::create($_[0]['function'])->export(false);
}

$string = <<<PHP
function $functionName(...\$arguments)
function $functionName($signatureArguments)
{
\$position = MockerState::saveTrace(__NAMESPACE__, "$functionName", \$arguments);
if (MockerState::checkCondition(__NAMESPACE__, "$functionName", \$arguments)) {
\$result = MockerState::getResult(__NAMESPACE__, "$functionName", \$arguments);
\$position = MockerState::saveTrace(__NAMESPACE__, "$functionName", $unpackedArguments);
if (MockerState::checkCondition(__NAMESPACE__, "$functionName", $arrayArguments)) {
\$result = MockerState::getResult(__NAMESPACE__, "$functionName", $unpackedArguments);
} else {
\$result = MockerState::getDefaultResult(__NAMESPACE__, "$functionName", $function);
\$result = MockerState::getDefaultResult(__NAMESPACE__, "$functionName", $function, $unpackedArguments);
}
return MockerState::saveTraceResult(__NAMESPACE__, "$functionName", \$position, \$result);
Expand Down
19 changes: 10 additions & 9 deletions src/MockerState.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ final class MockerState
public static function addCondition(
string $namespace,
string $functionName,
array $arguments,
array|string $arguments,
mixed $result,
bool $default = false
): void {
Expand All @@ -39,7 +39,7 @@ public static function addCondition(
public static function checkCondition(
string $namespace,
string $functionName,
array $expectedArguments,
array|string $expectedArguments,
): bool {
$mocks = self::$state[$namespace][$functionName] ?? [];

Expand All @@ -51,10 +51,10 @@ public static function checkCondition(
return false;
}

private static function compareArguments(array $arguments, array $expectedArguments): bool
private static function compareArguments(array $arguments, array|string $expectedArguments): bool
{
return $arguments['arguments'] === $expectedArguments
|| array_values($arguments['arguments']) === $expectedArguments;
|| (is_array($arguments['arguments']) && array_values($arguments['arguments']) === $expectedArguments);
}

private static function replaceResult(
Expand All @@ -75,13 +75,13 @@ private static function replaceResult(
public static function getResult(
string $namespace,
string $functionName,
array $expectedArguments,
&...$expectedArguments,
): mixed {
$mocks = self::$state[$namespace][$functionName] ?? [];

foreach ($mocks as $mock) {
if (self::compareArguments($mock, $expectedArguments)) {
return $mock['result'];
return is_callable($mock['result']) ? $mock['result'](...$expectedArguments) : $mock['result'];
}
}
return false;
Expand All @@ -91,12 +91,13 @@ public static function getDefaultResult(
string $namespace,
string $functionName,
callable $fallback,
&...$arguments,
): mixed {
if (isset(self::$defaults[$namespace][$functionName])) {
return self::$defaults[$namespace][$functionName];
}

return $fallback();
return $fallback(...$arguments);
}

public static function saveState(): void
Expand All @@ -113,11 +114,11 @@ public static function resetState(): void
public static function saveTrace(
string $namespace,
string $functionName,
array $arguments
&...$arguments
): int {
$position = count(self::$traces[$namespace][$functionName] ?? []);
self::$traces[$namespace][$functionName][$position] = [
'arguments' => $arguments,
'arguments' => &$arguments,
'trace' => debug_backtrace(),
];

Expand Down
14 changes: 14 additions & 0 deletions src/stubs.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

return [
'headers_sent' => [
'signature' => 'headers_sent(&$filename, &$line): bool',
'signatureArguments' => '&$filename, &$line',
'arguments' => '$filename, $line',
],
'time' => [
'signature' => 'time(): int',
'signatureArguments' => '',
'arguments' => '',
],
];
23 changes: 23 additions & 0 deletions tests/Integration/HeaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Xepozz\InternalMocker\Tests\Integration;

use PHPUnit\Framework\TestCase;
use Xepozz\InternalMocker\MockerState;

final class HeaderTest extends TestCase
{
public function testRun()
{
header('Content-Type: application/json');

$trace = MockerState::getTraces(
'',
'header',
);

$this->assertEquals(['Content-Type: application/json'], $trace[0]['arguments']);
}
}
31 changes: 31 additions & 0 deletions tests/Integration/HeadersSentTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Xepozz\InternalMocker\Tests\Integration;

use PHPUnit\Framework\TestCase;
use Xepozz\InternalMocker\MockerState;

final class HeadersSentTest extends TestCase
{
public function testCheckReferences()
{
MockerState::addCondition(
'',
'headers_sent',
[null, null],
fn (&$file, &$line) => $file = $line = 123,
);
headers_sent($file, $line);

$trace = MockerState::getTraces(
'',
'headers_sent',
);

$this->assertEquals(123, $file);
$this->assertEquals(123, $line);
$this->assertEquals([123, 123], $trace[0]['arguments']);
}
}
4 changes: 2 additions & 2 deletions tests/Integration/TraceTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ public function testBacktrace(): void

$this->assertEquals(['test'], $traces[0]['arguments']);
$this->assertEquals('saveTrace', $traces[0]['trace'][0]['function']);
$this->assertEquals(120, $traces[0]['trace'][0]['line']);
$this->assertEquals(144, $traces[0]['trace'][0]['line']);
$this->assertEquals(
[
__NAMESPACE__,
'serialize',
['test'],
'test',
],
$traces[0]['trace'][0]['args'],
);
Expand Down
9 changes: 9 additions & 0 deletions tests/MockerExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,15 @@ public static function load(): void
'name' => 'time',
'function' => fn () => `date +%s`,
],
[
'namespace' => '',
'name' => 'header',
'function' => fn (string $value) => true,
],
[
'namespace' => '',
'name' => 'headers_sent',
],
];

$mocker = new Mocker();
Expand Down
16 changes: 8 additions & 8 deletions tests/MockerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,13 @@ public function generateProvider()
namespace Xepozz\InternalMocker\Tests\Integration {
use Xepozz\InternalMocker\MockerState;
function time(...\$arguments)
function time()
{
\$position = MockerState::saveTrace(__NAMESPACE__, "time", \$arguments);
if (MockerState::checkCondition(__NAMESPACE__, "time", \$arguments)) {
\$result = MockerState::getResult(__NAMESPACE__, "time", \$arguments);
\$position = MockerState::saveTrace(__NAMESPACE__, "time", );
if (MockerState::checkCondition(__NAMESPACE__, "time", [])) {
\$result = MockerState::getResult(__NAMESPACE__, "time", );
} else {
\$result = MockerState::getDefaultResult(__NAMESPACE__, "time", fn() => \\time(...\$arguments));
\$result = MockerState::getDefaultResult(__NAMESPACE__, "time", fn() => \\time(), );
}
return MockerState::saveTraceResult(__NAMESPACE__, "time", \$position, \$result);
Expand Down Expand Up @@ -108,11 +108,11 @@ function time(...\$arguments)
function str_contains(...\$arguments)
{
\$position = MockerState::saveTrace(__NAMESPACE__, "str_contains", \$arguments);
\$position = MockerState::saveTrace(__NAMESPACE__, "str_contains", ...\$arguments);
if (MockerState::checkCondition(__NAMESPACE__, "str_contains", \$arguments)) {
\$result = MockerState::getResult(__NAMESPACE__, "str_contains", \$arguments);
\$result = MockerState::getResult(__NAMESPACE__, "str_contains", ...\$arguments);
} else {
\$result = MockerState::getDefaultResult(__NAMESPACE__, "str_contains", fn() => \\str_contains(...\$arguments));
\$result = MockerState::getDefaultResult(__NAMESPACE__, "str_contains", fn(...\$arguments) => \\str_contains(...\$arguments), ...\$arguments);
}
return MockerState::saveTraceResult(__NAMESPACE__, "str_contains", \$position, \$result);
Expand Down

0 comments on commit 83e7219

Please sign in to comment.