Skip to content

Commit

Permalink
Fix mocking classes with new initializers in method and attribute p…
Browse files Browse the repository at this point in the history
…arams on PHP 8.1 (#1301)

Signed-off-by: Nathanael Esayeas <nathanael.esayeas@protonmail.com>
  • Loading branch information
ghostwriter committed Jul 18, 2023
2 parents 9677b3b + 638b2b9 commit 5a4410e
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 15 deletions.
1 change: 1 addition & 0 deletions composer.json
Expand Up @@ -51,6 +51,7 @@
},
"autoload-dev": {
"psr-4": {
"Fixture\\": "tests/Fixture/",
"test\\": "tests/"
},
"files": [
Expand Down
24 changes: 12 additions & 12 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions psalm-baseline.xml
Expand Up @@ -1575,6 +1575,7 @@
<code><![CDATA[$method->getParameters()]]></code>
<code><![CDATA[$overrides[$class_name][$method->getName()]]]></code>
<code><![CDATA[$overrides[strtolower($class->getName())][$method->getName()]]]></code>
<code><![CDATA[$param->__toString()]]></code>
</MixedArgument>
<MixedArgumentTypeCoercion>
<code>$param</code>
Expand Down
Expand Up @@ -70,8 +70,20 @@ protected function renderParams(Method $method, $config)

if (is_object($defaultValue)) {
$prefix = get_class($defaultValue);
if ($isPhp81 && enum_exists($prefix)) {
$prefix = var_export($defaultValue, true);
if ($isPhp81) {
if (enum_exists($prefix)) {
$prefix = var_export($defaultValue, true);
} elseif (
!$param->isDefaultValueConstant() &&
// "Parameter #1 [ <optional> F\Q\CN $a = new \F\Q\CN(param1, param2: 2) ]
preg_match(
'#<optional>\s.*?\s=\snew\s(.*?)\s]$#',
$param->__toString(),
$matches
) === 1
) {
$prefix = 'new ' . $matches[1];
}
}
} else {
$prefix = var_export($defaultValue, true);
Expand Down Expand Up @@ -158,7 +170,7 @@ private function renderMethodBody($method, $config)

$body .= "\$ret = {$invoke}(__FUNCTION__, \$argv);\n";

if (! in_array($method->getReturnType(), ['never','void'], true)) {
if (! in_array($method->getReturnType(), ['never', 'void'], true)) {
$body .= "return \$ret;\n";
}

Expand Down
18 changes: 18 additions & 0 deletions tests/Fixture/PHP81/A.php
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

class A
{
public function __construct(
private int $x = 1
) {
}

public function test(): int
{
return $this->x;
}
}
18 changes: 18 additions & 0 deletions tests/Fixture/PHP81/B.php
@@ -0,0 +1,18 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

class B
{
public function __construct(
private int $x
) {
}

public function test(): int
{
return $this->x;
}
}
19 changes: 19 additions & 0 deletions tests/Fixture/PHP81/C.php
@@ -0,0 +1,19 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

class C
{
public function __construct(
private int $x = 1,
private B $b = new B(1)
) {
}

public function test(): int
{
return $this->x + $this->b->test();
}
}
13 changes: 13 additions & 0 deletions tests/Fixture/PHP81/HandlerClass.php
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

class HandlerClass
{
public function doStuff(MockClass $mockClass): string
{
return $mockClass->test('test');
}
}
29 changes: 29 additions & 0 deletions tests/Fixture/PHP81/MockClass.php
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

use DateTime;

class MockClass
{
public function __construct(
public A $a = new A(),
protected B $b = new B(1),
private C $c = new C(b: new B(1), x: 2),
public DateTime $dateTime = new DateTime(),
) {
}

public function test(
string $msg,
#[SomeAttribute(param: new A())]
A $a = new A(),
B $b = new B(1),
C $c = new C(x: 2),
DateTime $dateTime = new DateTime(),
): string {
return $msg . ' - ' . $a->test() . ' - ' . $b->test() . ' - ' . $c->test() . ' - ' . $dateTime->format('Y-m-d');
}
}
14 changes: 14 additions & 0 deletions tests/Fixture/PHP81/SomeAttribute.php
@@ -0,0 +1,14 @@
<?php

declare(strict_types=1);

namespace Fixture\PHP81;

#[\Attribute(\Attribute::TARGET_PARAMETER)]
class SomeAttribute
{
public function __construct(
public object $param = new stdClass()
) {
}
}
26 changes: 26 additions & 0 deletions tests/Unit/PHP81/Php81LanguageFeaturesTest.php
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

namespace test\Unit\PHP81;

use Fixture\PHP81\HandlerClass;
use Fixture\PHP81\MockClass;
use Mockery\Adapter\Phpunit\MockeryTestCase;

/**
* @requires PHP 8.1.0-dev
*/
class Php81LanguageFeaturesTest extends MockeryTestCase
{
public function testNewInitializerExpression()
{
$class = mock(MockClass::class)
->expects('test')
->with('test')
->andReturn('it works')
->getMock();

self::assertSame('it works', (new HandlerClass())->doStuff($class));
}
}

0 comments on commit 5a4410e

Please sign in to comment.