Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PHP8] Add broken tests with complex types #503

Merged
merged 3 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions tests/Fixtures/project/src/Application/ClassWithComplexTypes.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<?php
declare(strict_types = 1);

namespace Go\Tests\TestProject\Application;

use Closure;
use Countable;
use Exception;
use Iterator;

class ClassWithComplexTypes
{
public function publicMethodWithUnionTypeReturn(Exception|Closure $value): Exception|Closure
{
return $value;
}

public function publicMethodWithIntersectionTypeReturn(Exception&Countable $value): Exception&Countable
{
return $value;
}

public function publicMethodWithDNFTypeReturn(Iterator|(Exception&Countable) $value): Iterator|(Exception&Countable)
{
return $value;
}
}
6 changes: 6 additions & 0 deletions tests/Fixtures/project/src/Aspect/WeavingAspect.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,10 @@ public function afterPublicMethodInTheInterface()
{
echo 'It does not intercept methods in the interface';
}

#[Pointcut\After("within(Go\Tests\TestProject\Application\ClassWithComplexTypes) && execution(public **->*(*))")]
public function afterComplexTypeMethods(): void
{
echo 'It intercepts methods with complex types';
}
}
21 changes: 16 additions & 5 deletions tests/Go/Functional/ClassWeavingTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
namespace Go\Functional;

use Go\Tests\TestProject\Application\AbstractBar;
use Go\Tests\TestProject\Application\ClassWithComplexTypes;
use Go\Tests\TestProject\Application\FinalClass;
use Go\Tests\TestProject\Application\FooInterface;
use Go\Tests\TestProject\Application\Main;

class ClassWeavingTest extends BaseFunctionalTestCase
{
public function testPropertyWeaving()
public function testPropertyWeaving(): void
{
// it weaves Main class public and protected properties
$this->assertPropertyWoven(Main::class, 'publicClassProperty', 'Go\\Tests\\TestProject\\Aspect\\PropertyInterceptAspect->interceptClassProperty');
Expand All @@ -32,7 +33,7 @@ public function testPropertyWeaving()
/**
* test for https://github.com/goaop/framework/issues/335
*/
public function testItDoesNotWeaveAbstractMethods()
public function testItDoesNotWeaveAbstractMethods(): void
{
// it weaves Main class
$this->assertClassIsWoven(Main::class);
Expand All @@ -46,13 +47,13 @@ public function testItDoesNotWeaveAbstractMethods()
$this->assertClassIsNotWoven(AbstractBar::class);
}

public function testClassInitializationWeaving()
public function testClassInitializationWeaving(): void
{
$this->assertClassInitializationWoven(Main::class, 'Go\\Tests\\TestProject\\Aspect\\InitializationAspect->beforeInstanceInitialization');
$this->assertClassStaticInitializationWoven(Main::class, 'Go\\Tests\\TestProject\\Aspect\\InitializationAspect->afterClassStaticInitialization');
}

public function testItWeavesFinalClasses()
public function testItWeavesFinalClasses(): void
{
// it weaves FinalClass class
$this->assertClassIsWoven(FinalClass::class);
Expand All @@ -70,8 +71,18 @@ public function testItWeavesFinalClasses()
$this->assertMethodNotWoven(FinalClass::class, 'someFinalParentMethod');
}

public function testItDoesNotWeaveInterfaces()
public function testItDoesNotWeaveInterfaces(): void
{
$this->assertClassIsNotWoven(FooInterface::class);
}

public function testItDoesWeaveMethodWithComplexTypes(): void
{
// it weaves ClassWithComplexTypes class
$this->assertClassIsWoven(ClassWithComplexTypes::class);

$this->assertMethodWoven(ClassWithComplexTypes::class, 'publicMethodWithUnionTypeReturn');
$this->assertMethodWoven(ClassWithComplexTypes::class, 'publicMethodWithIntersectionTypeReturn');
$this->assertMethodWoven(ClassWithComplexTypes::class, 'publicMethodWithDNFTypeReturn');
}
}
66 changes: 42 additions & 24 deletions tests/Go/Instrument/Transformer/SelfValueTransformerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

use Go\Core\AspectContainer;
use Go\Core\AspectKernel;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

Expand Down Expand Up @@ -43,15 +44,7 @@ public function setUp(): void
*/
protected function getKernelMock(array $options): AspectKernel
{
$mock = $this->getMockForAbstractClass(
AspectKernel::class,
[],
'',
false,
true,
true,
['getOptions', 'getContainer']
);
$mock = $this->createMock(AspectKernel::class);
$mock
->method('getOptions')
->willReturn($options);
Expand All @@ -63,23 +56,48 @@ protected function getKernelMock(array $options): AspectKernel
return $mock;
}

public function testTransformerReplacesAllSelfPlaces(): void
{
$testFile = fopen(__DIR__ . '/_files/file-with-self.php', 'rb');
$content = stream_get_contents($testFile);
$metadata = new StreamMetaData($testFile, $content);
$this->transformer->transform($metadata);
$expected = file_get_contents(__DIR__ . '/_files/file-with-self-transformed.php');
$this->assertSame($expected, (string) $metadata->source);
#[DataProvider("filesDataProvider")]
public function testTransformerProcessFiles(
string $sourceFileWithContent,
string $fileWithExpectedContent,
): void {
try {
$sourceFile = fopen($sourceFileWithContent, 'rb');
$sourceContent = stream_get_contents($sourceFile);
$sourceMetadata = new StreamMetaData($sourceFile, $sourceContent);
$this->transformer->transform($sourceMetadata);

$expected = file_get_contents($fileWithExpectedContent);
$this->assertSame($expected, $sourceMetadata->source);

} finally {
if (isset($sourceFile) && is_resource($sourceFile)) {
fclose($sourceFile);
}
}
}

public function testTransformerReplacesAllSelfPlacesWithoutNamespace(): void
public static function filesDataProvider(): \Generator
{
$testFile = fopen(__DIR__ . '/_files/file-with-self-no-namespace.php', 'rb');
$content = stream_get_contents($testFile);
$metadata = new StreamMetaData($testFile, $content);
$this->transformer->transform($metadata);
$expected = file_get_contents(__DIR__ . '/_files/file-with-self-no-namespace-transformed.php');
$this->assertSame($expected, (string) $metadata->source);
yield 'file-with-self.php' => [
__DIR__ . '/_files/file-with-self.php',
__DIR__ . '/_files/file-with-self-transformed.php'
];
yield 'file-with-self-no-namespace.php' => [
__DIR__ . '/_files/file-with-self-no-namespace.php',
__DIR__ . '/_files/file-with-self-no-namespace-transformed.php'
];
yield 'php80-file.php' => [
__DIR__ . '/_files/php80-file.php',
__DIR__ . '/_files/php80-file-transformed.php'
lisachenko marked this conversation as resolved.
Show resolved Hide resolved
];
yield 'php81-file.php' => [
__DIR__ . '/_files/php81-file.php',
__DIR__ . '/_files/php81-file-transformed.php'
lisachenko marked this conversation as resolved.
Show resolved Hide resolved
];
yield 'php82-file.php' => [
__DIR__ . '/_files/php82-file.php',
__DIR__ . '/_files/php82-file-transformed.php'
lisachenko marked this conversation as resolved.
Show resolved Hide resolved
];
}
}
131 changes: 131 additions & 0 deletions tests/Go/Instrument/Transformer/_files/php80-file.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
<?php
/**
* Parser Reflection API
*
* @copyright Copyright 2016, Lisachenko Alexander <[email protected]>
*
* This source file is subject to the license that is bundled
* with this source code in the file LICENSE.
*/
declare(strict_types=1);

namespace Go\ParserReflection\Stub;

use Attribute;
use Go\ParserReflection\{ReflectionMethod, ReflectionProperty as P};

class ClassWithPhp80Features
{
public function acceptsStringArrayDefaultToNull(array|string $iterable = null) : array {}
}

/**
* @see https://php.watch/versions/8.0/named-parameters
*/
class ClassWithPHP80NamedCall
{
public static function foo(string $key1 = '', string $key2 = ''): string
{
return $key1 . ':' . $key2;
}

public static function namedCall(): array
{
return [
'key1' => self::foo(key1: 'bar'),
'key2' => self::foo(key2: 'baz'),
'keys' => self::foo(key1: 'A', key2: 'B'),
'reverseKeys' => self::foo(key2: 'A', key1: 'B'),
'unpack' => self::foo(...['key1' => 'C', 'key2' => 'D']),
];
}
}

/**
* @see https://php.watch/versions/8.0/attributes
*/
#[Attribute(Attribute::TARGET_ALL | Attribute::IS_REPEATABLE)]
readonly class ClassPHP80Attribute
{
private string $value;

public function __construct(string $value)
{
$this->value = $value;
}

public function getValue(): string
{
return $this->value;
}
}

/**
* @see https://php.watch/versions/8.0/attributes
*/
#[ClassPHP80Attribute('class')]
class ClassPHP80WithAttribute
{
#[ClassPHP80Attribute('first')]
#[ClassPHP80Attribute('second')]
public const PUBLIC_CONST = 1;

#[ClassPHP80Attribute('property')]
private string $privateProperty = 'foo';

#[ClassPHP80Attribute('method')]
public function bar(#[ClassPHP80Attribute('parameter')] $parameter)
{}
}

/**
* @see https://php.watch/versions/8.0/constructor-property-promotion
*/
class ClassPHP80WithPropertyPromotion
{
public function __construct(
private string $privateStringValue,
private $privateNonTypedValue,
protected int $protectedIntValue = 42,
public array $publicArrayValue = [M_PI, M_E],
) {}
}

/**
* @see https://php.watch/versions/8.0/union-types
*/
class ClassWithPHP80UnionTypes
{
public string|int|float|bool $scalarValue;

public array|object|null $complexValueOrNull = null;

/**
* Special case, internally iterable should be replaced with Traversable|array
*/
public iterable|object $iterableOrObject;

public static function returnsUnionType(): object|array|null {}

public static function acceptsUnionType(\stdClass|\Traversable|array $iterable): void {}
}

/**
* @see https://php.watch/versions/8.0/mixed-type
*/
class ClassWithPHP80MixedType
{
public mixed $someMixedPublicProperty;

public static function returnsMixed(): mixed {}

public static function acceptsMixed(mixed $value): void {}
}

/**
* @see https://php.watch/versions/8.0/static-return-type
*/
class ClassWithPHP80StaticReturnType
{
public static function create(): static {}
}
Loading
Loading