* 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\ConfigurationException\InvalidFixerConfigurationException; use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer; use PhpCsFixer\Tests\Test\AbstractFixerTestCase; use PhpCsFixer\Utils; use PHPUnit\Framework\TestCase; /** * @author Filippo Tessarotto * * @internal * * @covers \PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer * * @extends AbstractFixerTestCase<\PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer> * * @phpstan-import-type _AutogeneratedInputConfiguration from \PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer */ final class PhpUnitTestCaseStaticMethodCallsFixerTest extends AbstractFixerTestCase { public function testFixerContainsAllPhpunitStaticMethodsInItsList(): void { $assertionRefClass = new \ReflectionClass(TestCase::class); $updatedStaticMethodsList = $assertionRefClass->getMethods(\ReflectionMethod::IS_PUBLIC); $staticMethods = (new \ReflectionClass(PhpUnitTestCaseStaticMethodCallsFixer::class))->getConstant('STATIC_METHODS'); $missingMethods = []; foreach ($updatedStaticMethodsList as $method) { if ($method->isStatic() && !isset($staticMethods[$method->name])) { $missingMethods[] = $method->name; } } self::assertSame([], $missingMethods, \sprintf( 'The following static methods from "%s" are missing from "%s::$staticMethods": %s', TestCase::class, PhpUnitTestCaseStaticMethodCallsFixer::class, // `Utils::naturalLanguageJoin` does not accept empty array, so let's use it only if there's an actual difference. [] === $missingMethods ? '' : Utils::naturalLanguageJoin($missingMethods) )); } public function testWrongConfigTypeForMethodsKey(): void { $this->expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessage('[php_unit_test_case_static_method_calls] Invalid configuration: The option "methods" with value array is expected to be of type "string[]", but one of the elements is of type "int".'); $this->fixer->configure(['methods' => [123 => 1]]); // @phpstan-ignore-line } public function testWrongConfigTypeForMethodsValue(): void { $this->expectException(InvalidFixerConfigurationException::class); $this->expectExceptionMessage('[php_unit_test_case_static_method_calls] Invalid configuration: The option "methods" with value array is expected to be of type "string[]", but one of the elements is of type "int".'); $this->fixer->configure(['methods' => ['assertSame' => 123]]); // @phpstan-ignore-line } /** * @param _AutogeneratedInputConfiguration $config * * @dataProvider provideFixCases */ public function testFix(string $expected, ?string $input = null, array $config = []): void { $this->fixer->configure($config); $this->doTest($expected, $input); } public static function provideFixCases(): iterable { yield [ <<<'EOF' assertSame(1, 2); $this->markTestIncomplete('foo'); $this->fail('foo'); } } EOF, ]; yield [ <<<'EOF' createMock(MyInterface::class); $mock ->expects(static::once()) ->method('run') ->with( static::identicalTo(1), static::stringContains('foo') ) ->will(static::onConsecutiveCalls( static::returnSelf(), static::throwException(new \Exception()) )) ; } } EOF, <<<'EOF' createMock(MyInterface::class); $mock ->expects($this->once()) ->method('run') ->with( $this->identicalTo(1), $this->stringContains('foo') ) ->will($this->onConsecutiveCalls( $this->returnSelf(), $this->throwException(new \Exception()) )) ; } } EOF, ]; yield [ <<<'EOF' markTestIncomplete('foo'); /* $this->fail('foo'); */ } } EOF, <<<'EOF' assertSame (1, 2); // $this->markTestIncomplete('foo'); /* $this->fail('foo'); */ } } EOF, ]; yield [ <<<'EOF' assertSame(1, 2); $this->markTestIncomplete('foo'); $this->fail('foo'); $lambda = function () { $this->assertSame(1, 23); self::assertSame(1, 23); static::assertSame(1, 23); }; } } EOF, <<<'EOF' assertSame(1, 2); self::markTestIncomplete('foo'); static::fail('foo'); $lambda = function () { $this->assertSame(1, 23); self::assertSame(1, 23); static::assertSame(1, 23); }; } } EOF, ['call_type' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_THIS], ]; yield [ <<<'EOF' assertSame(1, 2); self::markTestIncomplete('foo'); static::fail('foo'); } } EOF, ['call_type' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_SELF], ]; yield [ <<<'EOF' assertSame(1, 2); $this->assertSame(1, 2); static::setUpBeforeClass(); static::setUpBeforeClass(); $otherTest->setUpBeforeClass(); OtherTest::setUpBeforeClass(); } } EOF, <<<'EOF' assertSame(1, 2); static::setUpBeforeClass(); $this->setUpBeforeClass(); $otherTest->setUpBeforeClass(); OtherTest::setUpBeforeClass(); } } EOF, [ 'call_type' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_THIS, 'methods' => ['setUpBeforeClass' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_STATIC], ], ]; yield [ <<<'EOF' assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); $lambda = function () { $this->assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); }; } public function bar() { $lambda = static function () { $this->assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); }; $myProphecy->setCount(0)->will(function () { $this->getCount()->willReturn(0); }); } static public function baz() { $this->assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); $lambda = function () { $this->assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); }; } static final protected function xyz() { static::assertSame(1, 2); } } EOF, null, [ 'call_type' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_THIS, ], ]; yield [ <<<'EOF' assertSame(1, 2); $this->assertSame(1, 2); $this->assertSame(1, 2); } public function bar() { $lambdaOne = static function () { $this->assertSame(1, 21); self::assertSame(1, 21); static::assertSame(1, 21); }; $lambdaTwo = function () { $this->assertSame(1, 21); self::assertSame(1, 21); static::assertSame(1, 21); }; } public function baz2() { $this->assertSame(1, 22); $this->assertSame(1, 22); $this->assertSame(1, 22); $this->assertSame(1, 23); } } EOF, <<<'EOF' assertSame(1, 2); self::assertSame(1, 2); static::assertSame(1, 2); } public function bar() { $lambdaOne = static function () { $this->assertSame(1, 21); self::assertSame(1, 21); static::assertSame(1, 21); }; $lambdaTwo = function () { $this->assertSame(1, 21); self::assertSame(1, 21); static::assertSame(1, 21); }; } public function baz2() { $this->assertSame(1, 22); self::assertSame(1, 22); static::assertSame(1, 22); STATIC::assertSame(1, 23); } } EOF, [ 'call_type' => PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_THIS, ], ]; yield 'do not change class property and method signature' => [ <<<'EOF' assertSame = 42; } public function assertSame($foo, $bar){} } EOF, ]; yield 'do not change when only case is different' => [ <<<'EOF' [ <<<'EOF' PhpUnitTestCaseStaticMethodCallsFixer::CALL_TYPE_THIS, ], ]; yield 'handle $this with double colon following' => [ 'doTest( 'assertSame(1, 2); } }; } }', 'assertSame(1, 2); $foo = new class() { public function assertSame($a, $b) { $this->assertSame(1, 2); } }; } }' ); } /** * @dataProvider provideFix81Cases * * @requires PHP 8.1 */ public function testFix81(string $expected, ?string $input = null): void { $this->doTest($expected, $input); } /** * @return iterable */ public static function provideFix81Cases(): iterable { yield [ '