Skip to content

Commit

Permalink
Add PHP 8.1 compatibility; Add basic PHPCS (#3)
Browse files Browse the repository at this point in the history
* Add PHP 8.1 compatibility; Add basic PHPCS

* Bring back PHP 7.4 compatibility
  • Loading branch information
Menelion authored Jan 31, 2024
1 parent 6bed9b6 commit 895e0a7
Show file tree
Hide file tree
Showing 10 changed files with 120 additions and 75 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ atlassian-ide-plugin.xml
composer.lock
build/
phpunit.xml
.phpunit.result.cache
11 changes: 8 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
{
"name": "lstrojny/phpunit-function-mocker",
"description": "Allows mocking otherwise untestable PHP functions through the use of namespaces",
"description": "Allows mocking otherwise untestable PHP functions through the use of namespaces. PHP 8.1 compatible fork of the eponymous library by Lars Strojny",
"license": "MIT",
"require": {
"php": "~7.1"
"php": "^7.4 || ^8.0 || ^8.1"
},
"require-dev": {
"phpunit/phpunit": "~7"
"phpunit/phpunit": "~9",
"squizlabs/php_codesniffer": "~3"
},
"authors": [
{
"name": "Lars Strojny",
"email": "[email protected]"
},
{
"name": "Andre Polykanine",
"email": "[email protected]"
}
],
"autoload": {
Expand Down
10 changes: 10 additions & 0 deletions phpcs.xml.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<?xml version="1.0"?>
<ruleset>
<exclude-pattern>*/.git/*</exclude-pattern>
<exclude-pattern>*/vendor/*</exclude-pattern>
<include-pattern>*/src/*</include-pattern>
<include-pattern>*/tests/*</include-pattern>
<rule ref="PSR2">
<exclude name="Squiz.Functions.MultiLineFunctionDeclaration"/>
</rule>
</ruleset>
26 changes: 14 additions & 12 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
<phpunit
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
backupGlobals="false"
convertErrorsToExceptions="true"
convertWarningsToExceptions="true"
convertNoticesToExceptions="true"
bootstrap="vendor/autoload.php"
verbose="true"
colors="true">

<testsuites>
<testsuite name="PHPUnit_Extension_FunctionMockerTest">
<directory>./tests/</directory>
</testsuite>
</testsuites>

<logging>
<log type="junit" target="build/logs/junit.xml"/>
</logging>
colors="true"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<coverage/>
<testsuites>
<testsuite name="PHPUnit_Extension_FunctionMockerTest">
<directory>./tests/</directory>
</testsuite>
</testsuites>
<logging>
<junit outputFile="build/logs/junit.xml"/>
</logging>
</phpunit>
29 changes: 14 additions & 15 deletions src/PHPUnit/Extension/FunctionMocker.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,22 +9,19 @@

class FunctionMocker
{
/** @var TestCase */
private $testCase;
private TestCase $testCase;
private string $namespace;

/** @var string */
private $namespace;
/** @var string[] */
private array $functions = [];

/** @var array */
private $functions = array();
/** @var string[] */
private array $constants = [];

/** @var array */
private $constants = [];
/** @var string[] */
private static $mockedFunctions = [];

/** @var array */
private static $mockedFunctions = array();

private function __construct(TestCase $testCase, $namespace)
private function __construct(TestCase $testCase, string $namespace)
{
$this->testCase = $testCase;
$this->namespace = trim($namespace, '\\');
Expand All @@ -35,7 +32,7 @@ private function __construct(TestCase $testCase, $namespace)
*
* Example: PHP global namespace function setcookie() needs to be overridden in order to test
* if a cookie gets set. When setcookie() is called from inside a class in the namespace
* \Foo\Bar the mock setcookie() created here will be used instead to the real function.
* \Foo\Bar the mock setcookie() created here will be used instead of the real function.
*/
public static function start(TestCase $testCase, string $namespace): self
{
Expand All @@ -58,6 +55,7 @@ public function mockFunction(string $function): self
return $this;
}

/** @param mixed $value */
public function mockConstant(string $constant, $value): self
{
$this->constants[trim($constant)] = $value;
Expand All @@ -68,7 +66,7 @@ public function mockConstant(string $constant, $value): self
public function getMock(): MockObject
{
$mock = $this->testCase->getMockBuilder('stdClass')
->setMethods($this->functions)
->addMethods($this->functions)
->setMockClassName('PHPUnit_Extension_FunctionMocker_' . bin2hex(random_bytes(16)))
->getMock();

Expand All @@ -78,6 +76,7 @@ public function getMock(): MockObject

foreach ($this->functions as $function) {
$fqFunction = $this->namespace . '\\' . $function;

if (in_array($fqFunction, static::$mockedFunctions, true)) {
continue;
}
Expand All @@ -87,7 +86,7 @@ public function getMock(): MockObject
}

if (!isset($GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'])) {
$GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'] = array();
$GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'] = [];
}

$GLOBALS['__PHPUNIT_EXTENSION_FUNCTIONMOCKER'][$this->namespace] = $mock;
Expand Down
16 changes: 11 additions & 5 deletions src/PHPUnit/Extension/FunctionMocker/CodeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,22 @@ public static function defineFunction(string $namespace, string $function): void
eval($code);
}

public static function generateConstant($namespace, $constant, $value)
/** @param mixed $value */
public static function generateConstant(string $namespace, string $constant, $value): string
{
$template = <<<'EOS'
namespace {namespace}
{
if (!defined(__NAMESPACE__ . '\\{constant}')) {
define(__NAMESPACE__ . '\\{constant}', {value});
} elseif ({constant} !== {value}) {
throw new \RuntimeException(sprintf('Cannot redeclare constant "{constant}" in namespace "%s". Already defined as "%s"', __NAMESPACE__, {value}));
throw new \RuntimeException(
sprintf(
'Cannot redeclare constant "{constant}" in namespace "%s". Already defined as "%s"',
__NAMESPACE__,
{value}
)
);
}
}
EOS;
Expand All @@ -60,15 +67,14 @@ public static function defineConstant(string $namespace, string $name, string $v
eval(self::generateConstant($namespace, $name, $value));
}

/** @param string[] $parameters */
private static function renderTemplate(string $template, array $parameters): string
{
return strtr(
$template,
array_combine(
array_map(
function (string $key): string {
return '{' . $key . '}';
},
fn(string $key): string => '{' . $key . '}',
array_keys($parameters)
),
array_values($parameters)
Expand Down
3 changes: 2 additions & 1 deletion tests/PHPUnitTests/Extension/Fixtures/TestClass.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

class TestClass
{
/** @return string|int */
public static function invokeGlobalFunction()
{
return strpos('ffoo', 'o');
}

public static function getGlobalConstant()
public static function getGlobalConstant(): string
{
return CNT;
}
Expand Down
23 changes: 19 additions & 4 deletions tests/PHPUnitTests/Extension/FunctionMocker/CodeGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

class CodeGeneratorTest extends TestCase
{
public function testGenerateFunctionMock()
public function testGenerateFunctionMock(): void
{
$code = CodeGenerator::generateFunction('Test\Namespace', 'strlen');

Expand All @@ -23,10 +23,11 @@ function strlen(...$args)
}
}
EOS;

self::assertSame($expected, $code);
}

public function testGenerateStringConstantMock()
public function testGenerateStringConstantMock(): void
{
$code = CodeGenerator::generateConstant('Test\Namespace', 'CONSTANT', 'value');

Expand All @@ -36,10 +37,17 @@ public function testGenerateStringConstantMock()
if (!defined(__NAMESPACE__ . '\\CONSTANT')) {
define(__NAMESPACE__ . '\\CONSTANT', 'value');
} elseif (CONSTANT !== 'value') {
throw new \RuntimeException(sprintf('Cannot redeclare constant "CONSTANT" in namespace "%s". Already defined as "%s"', __NAMESPACE__, 'value'));
throw new \RuntimeException(
sprintf(
'Cannot redeclare constant "CONSTANT" in namespace "%s". Already defined as "%s"',
__NAMESPACE__,
'value'
)
);
}
}
EOS;

self::assertSame($expected, $code);
}

Expand All @@ -53,10 +61,17 @@ public function testGenerateIntegerConstantMock(): void
if (!defined(__NAMESPACE__ . '\\CONSTANT')) {
define(__NAMESPACE__ . '\\CONSTANT', 123);
} elseif (CONSTANT !== 123) {
throw new \RuntimeException(sprintf('Cannot redeclare constant "CONSTANT" in namespace "%s". Already defined as "%s"', __NAMESPACE__, 123));
throw new \RuntimeException(
sprintf(
'Cannot redeclare constant "CONSTANT" in namespace "%s". Already defined as "%s"',
__NAMESPACE__,
123
)
);
}
}
EOS;

self::assertSame($expected, $code);
}
}
Loading

0 comments on commit 895e0a7

Please sign in to comment.