mirror of
https://github.com/rectorphp/rector.git
synced 2024-05-28 23:10:51 +00:00
Migrate at to with consecutive and will return on consecutive calls (#5822)
This commit is contained in:
parent
d14630e1d2
commit
dc94477d54
|
@ -72,7 +72,7 @@
|
|||
|
||||
- [PHPOffice](#phpoffice) (14)
|
||||
|
||||
- [PHPUnit](#phpunit) (38)
|
||||
- [PHPUnit](#phpunit) (39)
|
||||
|
||||
- [PSR4](#psr4) (2)
|
||||
|
||||
|
@ -9181,6 +9181,21 @@ Turns getMock*() methods to `createMock()`
|
|||
|
||||
<br>
|
||||
|
||||
### MigrateAtToConsecutiveExpectationRector
|
||||
|
||||
Migrates deprecated `$this->expects($this->at(n))` expectations to `withConsecutive` and `willReturnOnConsecutiveCalls`
|
||||
|
||||
- class: [`Rector\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector`](../rules/PHPUnit/Rector/ClassMethod/MigrateAtToConsecutiveExpectationsRector.php)
|
||||
|
||||
```diff
|
||||
$mock = $this->createMock(Foo::class);
|
||||
-$mock->expects($this->at(0))->with('0')->method('someMethod')->willReturn('1');
|
||||
-$mock->expects($this->at(1))->with('1')->method('someMethod')->willReturn('2');
|
||||
+$mock->method('someMethod')->withConsecutive(['0'], ['1'])->willReturnOnConsecutiveCalls('1', '2');
|
||||
```
|
||||
|
||||
<br>
|
||||
|
||||
### RemoveDataProviderTestPrefixRector
|
||||
|
||||
Data provider methods cannot start with "test" prefix
|
||||
|
@ -15068,7 +15083,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
->call('configure', [[
|
||||
MergeInterfacesRector::OLD_TO_NEW_INTERFACES => [
|
||||
'SomeOldInterface' => 'SomeInterface',
|
||||
|
||||
|
||||
], ]]);
|
||||
};
|
||||
```
|
||||
|
@ -15139,7 +15154,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
->call('configure', [[
|
||||
MethodCallToPropertyFetchRector::METHOD_CALL_TO_PROPERTY_FETCHES => [
|
||||
'someMethod' => 'someProperty',
|
||||
|
||||
|
||||
], ]]);
|
||||
};
|
||||
```
|
||||
|
@ -15178,7 +15193,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
->call('configure', [[
|
||||
MethodCallToReturnRector::METHOD_CALL_WRAPS => [
|
||||
'SomeClass' => ['deny'],
|
||||
|
||||
|
||||
], ]]);
|
||||
};
|
||||
```
|
||||
|
@ -15470,7 +15485,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
->call('configure', [[
|
||||
ParentClassToTraitsRector::PARENT_CLASS_TO_TRAITS => [
|
||||
'Nette\Object' => ['Nette\SmartObject'],
|
||||
|
||||
|
||||
], ]]);
|
||||
};
|
||||
```
|
||||
|
@ -15942,7 +15957,7 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
->call('configure', [[
|
||||
ToStringToMethodCallRector::METHOD_NAMES_BY_TYPE => [
|
||||
'SomeObject' => 'getPath',
|
||||
|
||||
|
||||
], ]]);
|
||||
};
|
||||
```
|
||||
|
@ -16671,8 +16686,8 @@ return static function (ContainerConfigurator $containerConfigurator): void {
|
|||
ChangePropertyVisibilityRector::PROPERTY_TO_VISIBILITY_BY_CLASS => [
|
||||
'FrameworkClass' => [
|
||||
'someProperty' => 2,
|
||||
|
||||
|
||||
|
||||
|
||||
], ], ]]);
|
||||
};
|
||||
```
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class DifferentReturnValues extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
$reference = '2';
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->method('someMethod')
|
||||
->willReturnReference($reference);
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->method('someMethod')
|
||||
->willReturnMap(['foo' => 'bar']);
|
||||
$mock
|
||||
->expects($this->at(3))
|
||||
->method('someMethod')
|
||||
->willReturnArgument(1);
|
||||
$mock
|
||||
->expects($this->at(4))
|
||||
->method('someMethod')
|
||||
->willReturnCallback(static function () {
|
||||
return null;
|
||||
});
|
||||
$mock
|
||||
->expects($this->at(5))
|
||||
->method('someMethod')
|
||||
->willReturnSelf();
|
||||
$mock
|
||||
->expects($this->at(6))
|
||||
->method('someMethod')
|
||||
->willThrowException(new \Exception());
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class DifferentReturnValues extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$reference = '2';
|
||||
$mock->method('someMethod')->willReturnOnConsecutiveCalls('1', new \PHPUnit\Framework\MockObject\Stub\ReturnReference($reference), $this->returnValueMap(['foo' => 'bar']), $this->returnArgument(1), $this->returnCallback(static function () {
|
||||
return null;
|
||||
}), $this->returnSelf(), $this->throwException(new \Exception()));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class ExpectsNonAtIsSkipped extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->exactly(1))
|
||||
->method('someMethod');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,65 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class HandleMultipleVariables extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with('0')
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with('1')
|
||||
->method('someMethod')
|
||||
->willReturn('2');
|
||||
|
||||
$mock2 = $this->createMock(Foo::class);
|
||||
$mock2
|
||||
->expects($this->at(0))
|
||||
->with('0')
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
$mock2
|
||||
->expects($this->at(1))
|
||||
->with('1')
|
||||
->method('someMethod')
|
||||
->willReturn('2');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class HandleMultipleVariables extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive(['0'], ['1'])->willReturnOnConsecutiveCalls('1', '2');
|
||||
|
||||
$mock2 = $this->createMock(Foo::class);
|
||||
$mock2->method('someMethod')->withConsecutive(['0'], ['1'])->willReturnOnConsecutiveCalls('1', '2');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class MissingWithIsReplacedByEmptyArrayIfNoReturnExpectation extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with('0')
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->with('2')
|
||||
->method('someMethod');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class MissingWithIsReplacedByEmptyArrayIfNoReturnExpectation extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive(['0'], [], ['2']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class MissingWithIsReplacedByEmptyArrayIfNoReturnExpectation2 extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with('1')
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->with('2')
|
||||
->method('someMethod');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class MissingWithIsReplacedByEmptyArrayIfNoReturnExpectation2 extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive([], ['1'], ['2']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class Mixed extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with(0)
|
||||
->method('someMethod')
|
||||
->willReturn('0');
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with(1)
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class Mixed extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive([0], [1])->willReturnOnConsecutiveCalls('0', '1');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class Mixed2 extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->exactly(2))
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with(0)
|
||||
->method('someMethod')
|
||||
->willReturn('0');
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with(1)
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class Mixed2 extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->exactly(2))
|
||||
->method('someMethod');
|
||||
$mock->method('someMethod')->withConsecutive([0], [1])->willReturnOnConsecutiveCalls('0', '1');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
public function someOtherMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class SkipDifferentMethodExpectations extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with('1')
|
||||
->method('someOtherMethod');
|
||||
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->with('2')
|
||||
->method('someMethod')
|
||||
->willReturn('3');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
public function someOtherMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class SkipMissingReturnExpectation extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->method('someMethod');
|
||||
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->method('someMethod')
|
||||
->willReturn('3');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class SkipMissingWithIfReturnExpectationsExist extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with('0')
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->with('2')
|
||||
->method('someMethod')
|
||||
->willReturn('3');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,48 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WillCallbacksAreKept extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->method('someMethod')
|
||||
->will($this->throwException(new \Exception()));
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->method('someMethod')
|
||||
->will($this->returnValue('1'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WillCallbacksAreKept extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->willReturnOnConsecutiveCalls($this->throwException(new \Exception()), $this->returnValue('1'));
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WillReturnOnly extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->method('someMethod')
|
||||
->willReturn('0');
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->method('someMethod')
|
||||
->willReturn('1');
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->method('someMethod')
|
||||
->willReturn('2');
|
||||
$mock
|
||||
->expects($this->at(3))
|
||||
->method('someMethod')
|
||||
->willReturn(null);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WillReturnOnly extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->willReturnOnConsecutiveCalls('0', '1', '2', null);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WithMultipleArguments extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with('0', '1')
|
||||
->method('someMethod');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WithMultipleArguments extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive(['0', '1']);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,56 @@
|
|||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WithOnly extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock
|
||||
->expects($this->at(0))
|
||||
->with('0')
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(1))
|
||||
->with('1')
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(2))
|
||||
->with('2')
|
||||
->method('someMethod');
|
||||
$mock
|
||||
->expects($this->at(3))
|
||||
->with(null)
|
||||
->method('someMethod');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
-----
|
||||
<?php
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\Fixture;
|
||||
|
||||
class Foo
|
||||
{
|
||||
public function someMethod()
|
||||
{
|
||||
}
|
||||
}
|
||||
final class WithOnly extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function test(): void
|
||||
{
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive(['0'], ['1'], ['2'], [null]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector;
|
||||
|
||||
use Iterator;
|
||||
use Rector\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector;
|
||||
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
|
||||
use Symplify\SmartFileSystem\SmartFileInfo;
|
||||
|
||||
final class MigrateAtToConsecutiveExpectationsRectorTest extends AbstractRectorTestCase
|
||||
{
|
||||
/**
|
||||
* @dataProvider provideData()
|
||||
*/
|
||||
public function test(SmartFileInfo $fileInfo): void
|
||||
{
|
||||
$this->doTestFileInfo($fileInfo);
|
||||
}
|
||||
|
||||
public function provideData(): Iterator
|
||||
{
|
||||
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
|
||||
}
|
||||
|
||||
protected function getRectorClass(): string
|
||||
{
|
||||
return MigrateAtToConsecutiveExpectationsRector::class;
|
||||
}
|
||||
}
|
158
rules/PHPUnit/NodeAnalyzer/ExpectationAnalyzer.php
Normal file
158
rules/PHPUnit/NodeAnalyzer/ExpectationAnalyzer.php
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\NodeAnalyzer;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\PHPUnit\NodeFactory\ConsecutiveAssertionFactory;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMock;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMockCollection;
|
||||
|
||||
final class ExpectationAnalyzer
|
||||
{
|
||||
private const PROCESSABLE_WILL_STATEMENTS = [
|
||||
'will',
|
||||
'willReturn',
|
||||
'willReturnReference',
|
||||
'willReturnMap',
|
||||
'willReturnArgument',
|
||||
'willReturnCallback',
|
||||
'willReturnSelf',
|
||||
'willThrowException',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var TestsNodeAnalyzer
|
||||
*/
|
||||
private $testsNodeAnalyzer;
|
||||
|
||||
/**
|
||||
* @var ConsecutiveAssertionFactory
|
||||
*/
|
||||
private $consecutiveAssertionFactory;
|
||||
|
||||
public function __construct(TestsNodeAnalyzer $testsNodeAnalyzer, ConsecutiveAssertionFactory $consecutiveAssertionFactory)
|
||||
{
|
||||
$this->testsNodeAnalyzer = $testsNodeAnalyzer;
|
||||
$this->consecutiveAssertionFactory = $consecutiveAssertionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Expression[] $stmts
|
||||
*/
|
||||
public function getExpectationsFromExpressions(array $stmts): ExpectationMockCollection
|
||||
{
|
||||
$expectationMockCollection = new ExpectationMockCollection();
|
||||
foreach ($stmts as $stmt) {
|
||||
/** @var MethodCall $expr */
|
||||
$expr = $stmt->expr;
|
||||
$method = $this->getMethod($expr);
|
||||
if (!$this->testsNodeAnalyzer->isPHPUnitMethodName($method, 'method')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
/** @var MethodCall $expects */
|
||||
$expects = $this->getExpects($method->var, $method);
|
||||
if (!$this->isValidExpectsCall($expects)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$expectsArg = $expects->args[0];
|
||||
/** @var MethodCall $expectsValue */
|
||||
$expectsValue = $expectsArg->value;
|
||||
if (!$this->isValidAtCall($expectsValue)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$atArg = $expectsValue->args[0];
|
||||
$atValue = $atArg->value;
|
||||
if ($atValue instanceof LNumber && $expects->var instanceof Variable) {
|
||||
$expectationMockCollection->add(
|
||||
new ExpectationMock(
|
||||
$expects->var,
|
||||
$method->args,
|
||||
$atValue->value,
|
||||
$this->getWill($expr),
|
||||
$this->getWithArgs($method->var),
|
||||
$stmt
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $expectationMockCollection;
|
||||
}
|
||||
|
||||
private function getMethod(MethodCall $expr): MethodCall
|
||||
{
|
||||
if ($this->testsNodeAnalyzer->isPHPUnitMethodNames($expr, self::PROCESSABLE_WILL_STATEMENTS) && $expr->var instanceof MethodCall) {
|
||||
return $expr->var;
|
||||
}
|
||||
|
||||
return $expr;
|
||||
}
|
||||
|
||||
private function getWill(MethodCall $expr): ?Expr
|
||||
{
|
||||
if (!$this->testsNodeAnalyzer->isPHPUnitMethodNames($expr, self::PROCESSABLE_WILL_STATEMENTS)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->consecutiveAssertionFactory->createWillReturn($expr);
|
||||
}
|
||||
|
||||
private function getExpects(Expr $maybeWith, MethodCall $method): Expr
|
||||
{
|
||||
if ($this->testsNodeAnalyzer->isPHPUnitMethodName($maybeWith, 'with') && $maybeWith instanceof MethodCall) {
|
||||
return $maybeWith->var;
|
||||
}
|
||||
|
||||
return $method->var;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, Expr|null>
|
||||
*/
|
||||
private function getWithArgs(Expr $maybeWith): array
|
||||
{
|
||||
if ($this->testsNodeAnalyzer->isPHPUnitMethodName($maybeWith, 'with') && $maybeWith instanceof MethodCall) {
|
||||
return array_map(static function (Arg $arg) {
|
||||
return $arg->value;
|
||||
}, $maybeWith->args);
|
||||
}
|
||||
|
||||
return [null];
|
||||
}
|
||||
|
||||
public function isValidExpectsCall(MethodCall $expr): bool
|
||||
{
|
||||
if (!$this->testsNodeAnalyzer->isPHPUnitMethodName($expr, 'expects')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($expr->args) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isValidAtCall(MethodCall $expr): bool
|
||||
{
|
||||
if (!$this->testsNodeAnalyzer->isPHPUnitMethodName($expr, 'at')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count($expr->args) !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
197
rules/PHPUnit/NodeFactory/ConsecutiveAssertionFactory.php
Normal file
197
rules/PHPUnit/NodeFactory/ConsecutiveAssertionFactory.php
Normal file
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Rector\PHPUnit\NodeFactory;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\ArrayItem;
|
||||
use PhpParser\Node\Expr\ConstFetch;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Name\FullyQualified;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMock;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMockCollection;
|
||||
|
||||
final class ConsecutiveAssertionFactory
|
||||
{
|
||||
private const REPLACE_WILL_MAP = [
|
||||
'willReturnMap' => 'returnValueMap',
|
||||
'willReturnArgument' => 'returnArgument',
|
||||
'willReturnCallback' => 'returnCallback',
|
||||
'willThrowException' => 'throwException',
|
||||
];
|
||||
|
||||
public function createAssertionFromExpectationMockCollection(ExpectationMockCollection $expectationMockCollection): MethodCall
|
||||
{
|
||||
$expectationMocks = $expectationMockCollection->getExpectationMocks();
|
||||
|
||||
$var = $expectationMocks[0]->getExpectationVariable();
|
||||
$methodArguments = $expectationMocks[0]->getMethodArguments();
|
||||
|
||||
$expectationMocks = $this->sortExpectationMocksByIndex($expectationMocks);
|
||||
|
||||
if (!$expectationMockCollection->hasReturnValues()) {
|
||||
return $this->createWithConsecutive(
|
||||
$this->createMethod(
|
||||
$var,
|
||||
$methodArguments
|
||||
),
|
||||
$this->createWithArgs($expectationMocks)
|
||||
);
|
||||
}
|
||||
|
||||
if ($expectationMockCollection->hasWithValues()) {
|
||||
return $this->createWillReturnOnConsecutiveCalls(
|
||||
$this->createWithConsecutive(
|
||||
$this->createMethod(
|
||||
$var,
|
||||
$methodArguments
|
||||
),
|
||||
$this->createWithArgs($expectationMocks)
|
||||
),
|
||||
$this->createReturnArgs($expectationMocks)
|
||||
);
|
||||
}
|
||||
|
||||
return $this->createWillReturnOnConsecutiveCalls(
|
||||
$this->createMethod(
|
||||
$var,
|
||||
$methodArguments
|
||||
),
|
||||
$this->createReturnArgs($expectationMocks)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExpectationMock[] $expectationMocks
|
||||
* @return Arg[]
|
||||
*/
|
||||
private function createReturnArgs(array $expectationMocks): array
|
||||
{
|
||||
return array_map(static function (ExpectationMock $expectationMock) {
|
||||
return new Arg($expectationMock->getReturn() ?: new ConstFetch(new Name('null')));
|
||||
}, $expectationMocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExpectationMock[] $expectationMocks
|
||||
* @return Arg[]
|
||||
*/
|
||||
private function createWithArgs(array $expectationMocks): array
|
||||
{
|
||||
return array_map(static function (ExpectationMock $expectationMock) {
|
||||
$arrayItems = array_map(static function (?Expr $expr) {
|
||||
return new ArrayItem($expr ?: new ConstFetch(new Name('null')));
|
||||
}, $expectationMock->getWithArguments());
|
||||
return new Arg(
|
||||
new Expr\Array_(
|
||||
$arrayItems
|
||||
)
|
||||
);
|
||||
}, $expectationMocks);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*/
|
||||
public function createWillReturnOnConsecutiveCalls(Expr $expr, array $args): MethodCall
|
||||
{
|
||||
return $this->createMethodCall($expr, 'willReturnOnConsecutiveCalls', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*/
|
||||
public function createMethod(Expr $expr, array $args): MethodCall
|
||||
{
|
||||
return $this->createMethodCall($expr, 'method', $args);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*/
|
||||
public function createWithConsecutive(Expr $expr, array $args): MethodCall
|
||||
{
|
||||
return $this->createMethodCall($expr, 'withConsecutive', $args);
|
||||
}
|
||||
|
||||
public function createWillReturn(MethodCall $methodCall): Expr
|
||||
{
|
||||
if (!$methodCall->name instanceof Identifier) {
|
||||
return $methodCall;
|
||||
}
|
||||
|
||||
$methodCallName = $methodCall->name->name;
|
||||
if ($methodCallName === 'will') {
|
||||
return $methodCall->args[0]->value;
|
||||
}
|
||||
|
||||
if ($methodCallName === 'willReturnSelf') {
|
||||
return $this->createWillReturnSelf();
|
||||
}
|
||||
|
||||
if ($methodCallName === 'willReturnReference') {
|
||||
return $this->createWillReturnReference($methodCall);
|
||||
}
|
||||
|
||||
if (array_key_exists($methodCallName, self::REPLACE_WILL_MAP)) {
|
||||
return $this->createMappedWillReturn($methodCallName, $methodCall);
|
||||
}
|
||||
|
||||
return $methodCall->args[0]->value;
|
||||
}
|
||||
|
||||
private function createWillReturnSelf(): MethodCall
|
||||
{
|
||||
return $this->createMethodCall(
|
||||
new Variable('this'),
|
||||
'returnSelf',
|
||||
[]
|
||||
);
|
||||
}
|
||||
|
||||
private function createWillReturnReference(MethodCall $methodCall): Expr\New_
|
||||
{
|
||||
return new Expr\New_(
|
||||
new FullyQualified('PHPUnit\Framework\MockObject\Stub\ReturnReference'),
|
||||
[new Arg($methodCall->args[0]->value)]
|
||||
);
|
||||
}
|
||||
|
||||
private function createMappedWillReturn(string $methodCallName, MethodCall $methodCall): MethodCall
|
||||
{
|
||||
return $this->createMethodCall(
|
||||
new Variable('this'),
|
||||
self::REPLACE_WILL_MAP[$methodCallName],
|
||||
[new Arg($methodCall->args[0]->value)]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Arg[] $args
|
||||
*/
|
||||
private function createMethodCall(Expr $expr, string $name, array $args): MethodCall
|
||||
{
|
||||
return new MethodCall(
|
||||
$expr,
|
||||
new Identifier($name),
|
||||
$args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ExpectationMock[] $expectationMocks
|
||||
* @return ExpectationMock[]
|
||||
*/
|
||||
private function sortExpectationMocksByIndex(array $expectationMocks): array
|
||||
{
|
||||
usort($expectationMocks, static function (ExpectationMock $expectationMockA, ExpectationMock $expectationMockB) {
|
||||
return $expectationMockA->getIndex() > $expectationMockB->getIndex() ? 1 : -1;
|
||||
});
|
||||
return $expectationMocks;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Rector\PHPUnit\Rector\ClassMethod;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr\MethodCall;
|
||||
use PhpParser\Node\Stmt;
|
||||
use PhpParser\Node\Stmt\ClassMethod;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
use Rector\Core\Rector\AbstractRector;
|
||||
use Rector\PHPUnit\NodeAnalyzer\ExpectationAnalyzer;
|
||||
use Rector\PHPUnit\NodeAnalyzer\TestsNodeAnalyzer;
|
||||
use Rector\PHPUnit\NodeFactory\ConsecutiveAssertionFactory;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMock;
|
||||
use Rector\PHPUnit\ValueObject\ExpectationMockCollection;
|
||||
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
|
||||
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
|
||||
|
||||
/**
|
||||
* @see \Rector\Tests\PHPUnit\Rector\ClassMethod\MigrateAtToConsecutiveExpectationsRector\MigrateAtToConsecutiveExpectationsRectorTest
|
||||
*/
|
||||
final class MigrateAtToConsecutiveExpectationsRector extends AbstractRector
|
||||
{
|
||||
/**
|
||||
* @var ConsecutiveAssertionFactory
|
||||
*/
|
||||
private $consecutiveAssertionFactory;
|
||||
|
||||
/**
|
||||
* @var TestsNodeAnalyzer
|
||||
*/
|
||||
private $testsNodeAnalyzer;
|
||||
|
||||
/**
|
||||
* @var ExpectationAnalyzer
|
||||
*/
|
||||
private $expectationAnalyzer;
|
||||
|
||||
public function __construct(
|
||||
ConsecutiveAssertionFactory $consecutiveAssertionFactory,
|
||||
TestsNodeAnalyzer $testsNodeAnalyzer,
|
||||
ExpectationAnalyzer $expectationAnalyzer
|
||||
)
|
||||
{
|
||||
$this->consecutiveAssertionFactory = $consecutiveAssertionFactory;
|
||||
$this->testsNodeAnalyzer = $testsNodeAnalyzer;
|
||||
$this->expectationAnalyzer = $expectationAnalyzer;
|
||||
}
|
||||
|
||||
public function getRuleDefinition(): RuleDefinition
|
||||
{
|
||||
return new RuleDefinition(
|
||||
'Migrates deprecated $this->at to $this->withConsecutive and $this->willReturnOnConsecutiveCalls',
|
||||
[
|
||||
new CodeSample(
|
||||
<<<'CODE_SAMPLE'
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->expects($this->at(0))->with('0')->method('someMethod')->willReturn('1');
|
||||
$mock->expects($this->at(1))->with('1')->method('someMethod')->willReturn('2');
|
||||
CODE_SAMPLE,
|
||||
<<<'CODE_SAMPLE'
|
||||
$mock = $this->createMock(Foo::class);
|
||||
$mock->method('someMethod')->withConsecutive(['0'], ['1'])->willReturnOnConsecutiveCalls('1', '2');
|
||||
CODE_SAMPLE
|
||||
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<class-string<Node>>
|
||||
*/
|
||||
public function getNodeTypes(): array
|
||||
{
|
||||
return [ClassMethod::class];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ClassMethod $node
|
||||
*/
|
||||
public function refactor(Node $node): ?Node
|
||||
{
|
||||
$stmts = $node->stmts;
|
||||
if ($stmts === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$expressions = array_filter($stmts, function (Stmt $expr) {
|
||||
return $expr instanceof Expression && $expr->expr instanceof MethodCall;
|
||||
});
|
||||
|
||||
$expectationMockCollection = $this->expectationAnalyzer->getExpectationsFromExpressions($expressions);
|
||||
|
||||
if (!$expectationMockCollection->hasExpectationMocks()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$expectationCollections = $this->groupExpectationCollectionsByVariableName($expectationMockCollection);
|
||||
foreach ($expectationCollections as $expectationCollection) {
|
||||
$this->replaceExpectationNodes($expectationCollection);
|
||||
}
|
||||
|
||||
return $node;
|
||||
}
|
||||
|
||||
private function buildNewExpectation(ExpectationMockCollection $expectationMockCollection): MethodCall
|
||||
{
|
||||
$expectationMockCollection = $this->fillMissingAtIndexes($expectationMockCollection);
|
||||
return $this->consecutiveAssertionFactory->createAssertionFromExpectationMockCollection($expectationMockCollection);
|
||||
}
|
||||
|
||||
private function fillMissingAtIndexes(ExpectationMockCollection $expectationMockCollection): ExpectationMockCollection
|
||||
{
|
||||
$var = $expectationMockCollection->getExpectationMocks()[0]->getExpectationVariable();
|
||||
|
||||
// 0,1,2,3,4
|
||||
// min = 0 ; max = 4 ; count = 5
|
||||
// OK
|
||||
|
||||
// 1,2,3,4
|
||||
// min = 1 ; max = 4 ; count = 4
|
||||
// ADD 0
|
||||
|
||||
// OR
|
||||
|
||||
// 3
|
||||
// min = 3; max = 3 ; count = 1
|
||||
// 0,1,2
|
||||
if ($expectationMockCollection->getLowestAtIndex() !== 0) {
|
||||
for ($i = 0; $i < $expectationMockCollection->getLowestAtIndex(); ++$i) {
|
||||
$expectationMockCollection->add(
|
||||
new ExpectationMock($var, [], $i, null, [], null)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 0,1,2,4
|
||||
// min = 0 ; max = 4 ; count = 4
|
||||
// ADD 3
|
||||
if ($expectationMockCollection->isMissingAtIndexBetweenHighestAndLowest()) {
|
||||
$existingIndexes = array_column($expectationMockCollection->getExpectationMocks(), 'index');
|
||||
for ($i = 1; $i < $expectationMockCollection->getHighestAtIndex(); ++$i) {
|
||||
if (!in_array($i, $existingIndexes, true)) {
|
||||
$expectationMockCollection->add(
|
||||
new ExpectationMock($var, [], $i, null, [], null)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $expectationMockCollection;
|
||||
}
|
||||
|
||||
private function replaceExpectationNodes(ExpectationMockCollection $expectationMockCollection): void
|
||||
{
|
||||
if ($this->shouldSkipReplacement($expectationMockCollection)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$endLines = array_map(static function (ExpectationMock $expectationMock) {
|
||||
$originalExpression = $expectationMock->originalExpression();
|
||||
return $originalExpression === null ? 0 : $originalExpression->getEndLine();
|
||||
}, $expectationMockCollection->getExpectationMocks());
|
||||
$max = max($endLines);
|
||||
|
||||
foreach ($expectationMockCollection->getExpectationMocks() as $expectationMock) {
|
||||
$originalExpression = $expectationMock->originalExpression();
|
||||
if ($originalExpression === null) {
|
||||
continue;
|
||||
}
|
||||
if ($max > $originalExpression->getEndLine()) {
|
||||
$this->removeNode($originalExpression);
|
||||
} else {
|
||||
$originalExpression->expr = $this->buildNewExpectation($expectationMockCollection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function shouldSkipReplacement(ExpectationMockCollection $expectationMockCollection): bool
|
||||
{
|
||||
if (!$expectationMockCollection->hasReturnValues()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!$expectationMockCollection->isExpectedMethodAlwaysTheSame()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($expectationMockCollection->hasMissingAtIndexes()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($expectationMockCollection->hasMissingReturnValues()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ExpectationMockCollection[]
|
||||
*/
|
||||
private function groupExpectationCollectionsByVariableName(ExpectationMockCollection $expectationMockCollection): array
|
||||
{
|
||||
$groupedByVariable = [];
|
||||
foreach ($expectationMockCollection->getExpectationMocks() as $expectationMock) {
|
||||
$variable = $expectationMock->getExpectationVariable();
|
||||
if (!is_string($variable->name)) {
|
||||
continue;
|
||||
}
|
||||
if (!isset($groupedByVariable[$variable->name])) {
|
||||
$groupedByVariable[$variable->name] = new ExpectationMockCollection();
|
||||
}
|
||||
$groupedByVariable[$variable->name]->add($expectationMock);
|
||||
}
|
||||
|
||||
return array_values($groupedByVariable);
|
||||
}
|
||||
}
|
94
rules/PHPUnit/ValueObject/ExpectationMock.php
Normal file
94
rules/PHPUnit/ValueObject/ExpectationMock.php
Normal file
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Rector\PHPUnit\ValueObject;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\Node\Stmt\Expression;
|
||||
|
||||
final class ExpectationMock
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Variable
|
||||
*/
|
||||
private $expectationVariable;
|
||||
|
||||
/**
|
||||
* @var Arg[]
|
||||
*/
|
||||
private $methodArguments;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $index;
|
||||
|
||||
/**
|
||||
* @var ?Expr
|
||||
*/
|
||||
private $return;
|
||||
|
||||
/**
|
||||
* @var array<int, null|Expr>
|
||||
*/
|
||||
private $withArguments;
|
||||
|
||||
/**
|
||||
* @var Expression|null
|
||||
*/
|
||||
private $originalExpression;
|
||||
|
||||
/**
|
||||
* @param Arg[] $methodArguments
|
||||
* @param array<int, null|Expr> $withArguments
|
||||
*/
|
||||
public function __construct(Variable $expectationVariable, array $methodArguments, int $index, ?Expr $return, array $withArguments, ?Expression $originalExpression)
|
||||
{
|
||||
$this->expectationVariable = $expectationVariable;
|
||||
$this->methodArguments = $methodArguments;
|
||||
$this->index = $index;
|
||||
$this->return = $return;
|
||||
$this->withArguments = $withArguments;
|
||||
$this->originalExpression = $originalExpression;
|
||||
}
|
||||
|
||||
public function getExpectationVariable(): Variable
|
||||
{
|
||||
return $this->expectationVariable;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Arg[]
|
||||
*/
|
||||
public function getMethodArguments(): array
|
||||
{
|
||||
return $this->methodArguments;
|
||||
}
|
||||
|
||||
public function getIndex(): int
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
|
||||
public function getReturn(): ?Expr
|
||||
{
|
||||
return $this->return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, null|Expr>
|
||||
*/
|
||||
public function getWithArguments(): array
|
||||
{
|
||||
return $this->withArguments;
|
||||
}
|
||||
|
||||
public function originalExpression(): ?Expression
|
||||
{
|
||||
return $this->originalExpression;
|
||||
}
|
||||
}
|
132
rules/PHPUnit/ValueObject/ExpectationMockCollection.php
Normal file
132
rules/PHPUnit/ValueObject/ExpectationMockCollection.php
Normal file
|
@ -0,0 +1,132 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
|
||||
namespace Rector\PHPUnit\ValueObject;
|
||||
|
||||
use PhpParser\Node\Scalar\String_;
|
||||
|
||||
final class ExpectationMockCollection
|
||||
{
|
||||
/**
|
||||
* @var ExpectationMock[]
|
||||
*/
|
||||
private $expectationMocks = [];
|
||||
|
||||
/**
|
||||
* @return ExpectationMock[]
|
||||
*/
|
||||
public function getExpectationMocks(): array
|
||||
{
|
||||
return $this->expectationMocks;
|
||||
}
|
||||
|
||||
public function hasExpectationMocks(): bool
|
||||
{
|
||||
return count($this->expectationMocks) > 0;
|
||||
}
|
||||
|
||||
public function add(ExpectationMock $expectationMock): void
|
||||
{
|
||||
$this->expectationMocks[] = $expectationMock;
|
||||
}
|
||||
|
||||
public function getHighestAtIndex(): int
|
||||
{
|
||||
if (!$this->hasExpectationMocks()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$indexes = array_map(static function (ExpectationMock $expectationMock) {
|
||||
return $expectationMock->getIndex();
|
||||
}, $this->getExpectationMocks());
|
||||
return max($indexes) ?: 0;
|
||||
}
|
||||
|
||||
public function getLowestAtIndex(): int
|
||||
{
|
||||
if (!$this->hasExpectationMocks()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
$indexes = array_map(static function (ExpectationMock $expectationMock) {
|
||||
return $expectationMock->getIndex();
|
||||
}, $this->getExpectationMocks());
|
||||
return min($indexes) ?: 0;
|
||||
}
|
||||
|
||||
public function isMissingAtIndexBetweenHighestAndLowest(): bool
|
||||
{
|
||||
$highestAtIndex = $this->getHighestAtIndex();
|
||||
$lowestAtIndex = $this->getLowestAtIndex();
|
||||
return ($highestAtIndex - $lowestAtIndex + 1) !== count($this->getExpectationMocks());
|
||||
}
|
||||
|
||||
public function hasMissingAtIndexes(): bool
|
||||
{
|
||||
if ($this->getLowestAtIndex() !== 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isMissingAtIndexBetweenHighestAndLowest()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasWithValues(): bool
|
||||
{
|
||||
foreach ($this->getExpectationMocks() as $expectationMock) {
|
||||
if (
|
||||
count($expectationMock->getWithArguments()) > 1
|
||||
|| (
|
||||
count($expectationMock->getWithArguments()) === 1
|
||||
&& $expectationMock->getWithArguments()[0] !== null
|
||||
)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasReturnValues(): bool
|
||||
{
|
||||
foreach ($this->getExpectationMocks() as $expectationMock) {
|
||||
if ($expectationMock->getReturn() !== null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function hasMissingReturnValues(): bool
|
||||
{
|
||||
foreach ($this->getExpectationMocks() as $expectationMock) {
|
||||
if ($expectationMock->getReturn() === null) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isExpectedMethodAlwaysTheSame(): bool
|
||||
{
|
||||
$previousMethod = '';
|
||||
foreach ($this->getExpectationMocks() as $expectationMock) {
|
||||
$methodArgument = $expectationMock->getMethodArguments()[0];
|
||||
if (null !== $methodArgument && $methodArgument->value instanceof String_) {
|
||||
if ($previousMethod === '') {
|
||||
$previousMethod = $methodArgument->value->value;
|
||||
}
|
||||
if ($previousMethod !== $methodArgument->value->value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user