* Dariusz Rumiński * * This source file is subject to the MIT license that is bundled * with this source code in the file LICENSE. */ namespace PhpCsFixer\Tests\Fixer\PhpUnit; use PhpCsFixer\Tests\Test\AbstractFixerTestCase; /** * @internal * * @covers \PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer * * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer> * * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\PhpUnit\PhpUnitAttributesFixer */ final class PhpUnitAttributesFixerTest extends AbstractFixerTestCase { /** * @requires PHP 8.0 * * @dataProvider provideFixCases * * @param _AutogeneratedInputConfiguration $configuration */ public function testFix(string $expected, ?string $input = null, array $configuration = []): void { $this->fixer->configure($configuration); $this->doTest($expected, $input); } /** * @return iterable */ public static function provideFixCases(): iterable { yield 'do not fix with wrong values' => [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [<<<'PHP' [ <<<'PHP' [ <<<'PHP' in operator' => [ <<<'PHP' = 8.1')] public function testFoo() { self::assertTrue(true); } } PHP, <<<'PHP' = 8.1 */ public function testFoo() { self::assertTrue(true); } } PHP, ]; yield 'fix with trailing spaces' => self::createCase( ['class'], '#[CoversClass(Foo::class)]', '@covers Foo ', ); $byte224 = \chr(224); yield 'fix with non-alphanumeric characters' => [ << self::createCase( ['method'], '#[After]', '@after', ); yield 'handle AfterClass' => self::createCase( ['method'], '#[AfterClass]', '@afterClass', ); yield 'handle BackupGlobals enabled' => self::createCase( ['class', 'method'], '#[BackupGlobals(true)]', '@backupGlobals enabled', ); yield 'handle BackupGlobals disabled' => self::createCase( ['class', 'method'], '#[BackupGlobals(false)]', '@backupGlobals disabled', ); yield 'handle BackupGlobals no' => self::createCase( ['class', 'method'], '#[BackupGlobals(false)]', '@backupGlobals no', ); yield 'handle BackupStaticProperties enabled' => self::createCase( ['class', 'method'], '#[BackupStaticProperties(true)]', '@backupStaticAttributes enabled', ); yield 'handle BackupStaticProperties disabled' => self::createCase( ['class', 'method'], '#[BackupStaticProperties(false)]', '@backupStaticAttributes disabled', ); yield 'handle Before' => self::createCase( ['method'], '#[Before]', '@before', ); yield 'handle BeforeClass' => self::createCase( ['method'], '#[BeforeClass]', '@beforeClass', ); yield 'handle CoversClass' => self::createCase( ['class'], '#[CoversClass(\VendorName\ClassName::class)]', '@covers \VendorName\ClassName', ); yield 'handle CoversFunction' => self::createCase( ['class'], "#[CoversFunction('functionName')]", '@covers ::functionName', ); yield 'handle CoversNothing' => self::createCase( ['class', 'method'], '#[CoversNothing]', '@coversNothing', ); yield 'handle DataProvider' => self::createCase( ['method'], "#[DataProvider('provideFooCases')]", '@dataProvider provideFooCases', ); yield 'handle DataProviderExternal' => self::createCase( ['method'], "#[DataProviderExternal(BarTest::class, 'provideFooCases')]", '@dataProvider BarTest::provideFooCases', ); yield 'handle Depends' => self::createCase( ['method'], "#[Depends('methodName')]", '@depends methodName', ); yield 'handle DependsExternal' => self::createCase( ['method'], "#[DependsExternal(ClassName::class, 'methodName')]", '@depends ClassName::methodName', ); yield 'handle DependsExternalUsingDeepClone' => self::createCase( ['method'], "#[DependsExternalUsingDeepClone(ClassName::class, 'methodName')]", '@depends clone ClassName::methodName', ); yield 'handle DependsExternalUsingShallowClone' => self::createCase( ['method'], "#[DependsExternalUsingShallowClone(ClassName::class, 'methodName')]", '@depends shallowClone ClassName::methodName', ); yield 'handle DependsOnClass' => self::createCase( ['method'], '#[DependsOnClass(ClassName::class)]', '@depends ClassName::class', ); yield 'handle DependsOnClassUsingDeepClone' => self::createCase( ['method'], '#[DependsOnClassUsingDeepClone(ClassName::class)]', '@depends clone ClassName::class', ); yield 'handle DependsOnClassUsingShallowClone' => self::createCase( ['method'], '#[DependsOnClassUsingShallowClone(ClassName::class)]', '@depends shallowClone ClassName::class', ); yield 'handle DependsUsingDeepClone' => self::createCase( ['method'], "#[DependsUsingDeepClone('methodName')]", '@depends clone methodName', ); yield 'handle DependsUsingShallowClone' => self::createCase( ['method'], "#[DependsUsingShallowClone('methodName')]", '@depends shallowClone methodName', ); yield 'handle DoesNotPerformAssertions' => self::createCase( ['class', 'method'], '#[DoesNotPerformAssertions]', '@doesNotPerformAssertions', ); yield 'handle Group' => self::createCase( ['class', 'method'], "#[Group('groupName')]", '@group groupName', ); yield 'handle Large' => self::createCase( ['class'], '#[Large]', '@large', ); yield 'handle Medium' => self::createCase( ['class'], '#[Medium]', '@medium', ); yield 'handle PostCondition' => self::createCase( ['method'], '#[PostCondition]', '@postCondition', ); yield 'handle PreCondition' => self::createCase( ['method'], '#[PreCondition]', '@preCondition', ); yield 'handle PreserveGlobalState enabled' => self::createCase( ['class', 'method'], '#[PreserveGlobalState(true)]', '@preserveGlobalState enabled', ); yield 'handle PreserveGlobalState disabled' => self::createCase( ['class', 'method'], '#[PreserveGlobalState(false)]', '@preserveGlobalState disabled', ); yield 'handle RequiresFunction' => self::createCase( ['class', 'method'], "#[RequiresFunction('imap_open')]", '@requires function imap_open', ); yield 'handle RequiresMethod' => self::createCase( ['class', 'method'], "#[RequiresMethod(ReflectionMethod::class, 'setAccessible')]", '@requires function ReflectionMethod::setAccessible', ); yield 'handle RequiresOperatingSystem' => self::createCase( ['class', 'method'], "#[RequiresOperatingSystem('Linux')]", '@requires OS Linux', ); yield 'handle RequiresOperatingSystemFamily' => self::createCase( ['class', 'method'], "#[RequiresOperatingSystemFamily('Windows')]", '@requires OSFAMILY Windows', ); yield 'handle RequiresPhp' => self::createCase( ['class', 'method'], "#[RequiresPhp('8.1.20')]", '@requires PHP 8.1.20', ); yield 'handle RequiresPhpExtension' => self::createCase( ['class', 'method'], "#[RequiresPhpExtension('mysqli', '>= 8.3.0')]", '@requires extension mysqli >= 8.3.0', ); yield 'handle RequiresPhpunit' => self::createCase( ['class', 'method'], "#[RequiresPhpunit('^10.1.0')]", '@requires PHPUnit ^10.1.0', ); yield 'handle RequiresSetting' => self::createCase( ['class', 'method'], "#[RequiresSetting('date.timezone', 'Europe/London')]", '@requires setting date.timezone Europe/London', ); yield 'handle RunInSeparateProcess' => self::createCase( ['method'], '#[RunInSeparateProcess]', '@runInSeparateProcess', ); yield 'handle RunTestsInSeparateProcesses' => self::createCase( ['class'], '#[RunTestsInSeparateProcesses]', '@runTestsInSeparateProcesses', ); yield 'handle Small' => self::createCase( ['class'], '#[Small]', '@small', ); yield 'handle Test' => self::createCase( ['method'], '#[Test]', '@test', ); yield 'handle TestDox' => self::createCase( ['class', 'method'], "#[TestDox('Hello world!')]", '@testDox Hello world!', ); yield 'handle Ticket' => self::createCase( ['class', 'method'], "#[Ticket('ABC-123')]", '@ticket ABC-123', ); yield 'handle UsesClass' => self::createCase( ['class'], '#[UsesClass(ClassName::class)]', '@uses ClassName', ); yield 'handle UsesFunction' => self::createCase( ['class'], "#[UsesFunction('functionName')]", '@uses ::functionName', ); yield 'handle TestWith' => [ <<<'PHP' [ <<<'PHP' [ <<<'PHP' true, ], ]; } /** * @param non-empty-list<'class'|'method'> $scopes * * @return array{string, string} */ private static function createCase(array $scopes, string $expectedAttribute, string $inputAnnotation): array { $expectedAttribute = str_replace('#[', '#[\PHPUnit\Framework\Attributes\\', $expectedAttribute); return [ \sprintf( <<<'PHP'