[PhpSpecToPHPUnit] Deprecate historical set, mostly for experimental in early days (#1901)

This commit is contained in:
Tomas Votruba 2022-03-03 19:51:15 +00:00 committed by GitHub
parent 320cdcd8de
commit e2cc867255
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
59 changed files with 6 additions and 3474 deletions

View File

@ -1,4 +1,4 @@
# 512 Rules Overview
# 505 Rules Overview
<br>
@ -74,8 +74,6 @@
- [Php81](#php81) (9)
- [PhpSpecToPHPUnit](#phpspectophpunit) (7)
- [PostRector](#postrector) (7)
- [Privatization](#privatization) (10)
@ -8550,225 +8548,6 @@ Refactor Spatie enum class to native Enum
<br>
## PhpSpecToPHPUnit
### AddMockPropertiesRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\Class_\AddMockPropertiesRector`](../rules/PhpSpecToPHPUnit/Rector/Class_/AddMockPropertiesRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### MockVariableToPropertyFetchRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\Variable\MockVariableToPropertyFetchRector`](../rules/PhpSpecToPHPUnit/Rector/Variable/MockVariableToPropertyFetchRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### PhpSpecClassToPHPUnitClassRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\Class_\PhpSpecClassToPHPUnitClassRector`](../rules/PhpSpecToPHPUnit/Rector/Class_/PhpSpecClassToPHPUnitClassRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### PhpSpecMethodToPHPUnitMethodRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\ClassMethod\PhpSpecMethodToPHPUnitMethodRector`](../rules/PhpSpecToPHPUnit/Rector/ClassMethod/PhpSpecMethodToPHPUnitMethodRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### PhpSpecMocksToPHPUnitMocksRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecMocksToPHPUnitMocksRector`](../rules/PhpSpecToPHPUnit/Rector/MethodCall/PhpSpecMocksToPHPUnitMocksRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### PhpSpecPromisesToPHPUnitAssertRector
Migrate PhpSpec behavior to PHPUnit test
- class: [`Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecPromisesToPHPUnitAssertRector`](../rules/PhpSpecToPHPUnit/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php)
```diff
namespace spec\SomeNamespaceForThisTest;
-use PhpSpec\ObjectBehavior;
-
class OrderSpec extends ObjectBehavior
{
- public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
+ /**
+ * @var \SomeNamespaceForThisTest\Order
+ */
+ private $order;
+ protected function setUp()
{
- $factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
+ /** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
+ $factory = $this->createMock(OrderFactory::class);
+
+ /** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
+ $shippingMethod = $this->createMock(ShippingMethod::class);
+
+ $factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
```
<br>
### RenameSpecFileToTestFileRector
Rename "*Spec.php" file to "*Test.php" file
- class: [`Rector\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector`](../rules/PhpSpecToPHPUnit/Rector/Class_/RenameSpecFileToTestFileRector.php)
```diff
-// tests/SomeSpec.php
+// tests/SomeTest.php
```
<br>
## PostRector
### ClassRenamingPostRector

View File

@ -70,7 +70,7 @@
"phpstan/phpstan-strict-rules": "^1.1",
"phpstan/phpstan-webmozart-assert": "^1.0",
"phpunit/phpunit": "^9.5",
"rector/phpstan-rules": "^0.4.20",
"rector/phpstan-rules": "^0.4.21",
"spatie/enum": "^3.12",
"symplify/coding-standard": "^10.1",
"symplify/easy-ci": "^10.1",

View File

@ -1,32 +0,0 @@
<?php
declare(strict_types=1);
use Rector\PhpSpecToPHPUnit\Rector\Class_\AddMockPropertiesRector;
use Rector\PhpSpecToPHPUnit\Rector\Class_\PhpSpecClassToPHPUnitClassRector;
use Rector\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector;
use Rector\PhpSpecToPHPUnit\Rector\ClassMethod\PhpSpecMethodToPHPUnitMethodRector;
use Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecMocksToPHPUnitMocksRector;
use Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecPromisesToPHPUnitAssertRector;
use Rector\PhpSpecToPHPUnit\Rector\Variable\MockVariableToPropertyFetchRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
# see: https://gnugat.github.io/2015/09/23/phpunit-with-phpspec.html
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
# 1. first convert mocks
$services->set(PhpSpecMocksToPHPUnitMocksRector::class);
$services->set(PhpSpecPromisesToPHPUnitAssertRector::class);
# 2. then methods
$services->set(PhpSpecMethodToPHPUnitMethodRector::class);
# 3. then the class itself
$services->set(PhpSpecClassToPHPUnitClassRector::class);
$services->set(AddMockPropertiesRector::class);
$services->set(MockVariableToPropertyFetchRector::class);
$services->set(RenameSpecFileToTestFileRector::class);
};

View File

@ -83,11 +83,6 @@ final class SetList implements SetListInterface
*/
public const PHPSPEC_40 = __DIR__ . '/../../../config/set/phpspec40.php';
/**
* @var string
*/
public const PHPSPEC_TO_PHPUNIT = __DIR__ . '/../../../config/set/phpspec-to-phpunit.php';
/**
* @var string
*/

View File

@ -7,7 +7,6 @@ includes:
- vendor/symplify/phpstan-rules/config/regex-rules.neon
- vendor/symplify/phpstan-rules/config/services-rules.neon
- vendor/symplify/phpstan-rules/config/static-rules.neon
- vendor/symplify/phpstan-rules/config/size-rules.neon
- vendor/symplify/phpstan-rules/config/string-to-constant-rules.neon
- vendor/symplify/phpstan-rules/config/symfony-rules.neon
- vendor/symplify/phpstan-rules/config/test-rules.neon
@ -84,10 +83,6 @@ parameters:
- '#Cognitive complexity for "Rector\\Php80\\NodeResolver\\SwitchExprsResolver\:\:resolve\(\)" is (.*?), keep it under 10#'
-
message: "#^Cognitive complexity for \"Rector\\\\PhpSpecToPHPUnit\\\\Rector\\\\MethodCall\\\\PhpSpecPromisesToPHPUnitAssertRector\\:\\:refactor\\(\\)\" is (.*?), keep it under 10$#"
path: rules/PhpSpecToPHPUnit/Rector/MethodCall/PhpSpecPromisesToPHPUnitAssertRector.php
-
message: '#Class cognitive complexity is \d+, keep it under \d+#'
paths:
@ -150,11 +145,6 @@ parameters:
# for config class reflection
- packages/NodeTypeResolver/DependencyInjection/PHPStanServicesFactory.php
# known values from other methods
-
message: '#Negated boolean expression is always true#'
path: rules/PhpSpecToPHPUnit/NodeFactory/AssertMethodCallFactory.php
- '#PhpParser\\Node\\Expr\\Error\|PhpParser\\Node\\Expr\\Variable given#'
- '#Method Rector\\CodeQuality\\Rector\\Foreach_\\SimplifyForeachToCoalescingRector\:\:matchReturnOrAssignNode\(\) should return PhpParser\\Node\\Expr\\Assign\|PhpParser\\Node\\Stmt\\Return_\|null but returns PhpParser\\Node\|null#'
@ -341,7 +331,6 @@ parameters:
paths:
- packages/BetterPhpDocParser/ValueObject/PhpDoc/DoctrineAnnotation/AbstractValuesAwareNode.php
- packages/PostRector/Rector/AbstractPostRector.php
- rules/PhpSpecToPHPUnit/Rector/AbstractPhpSpecToPHPUnitRector.php
- src/Rector/AbstractRector.php
-
@ -601,3 +590,7 @@ parameters:
-
path: src/PhpParser/Node/BetterNodeFinder.php
message: '#Method Rector\\Core\\PhpParser\\Node\\BetterNodeFinder\:\:findParentByTypes\(\) should return T of PhpParser\\Node\|null but returns PhpParser\\Node#'
-
message: '#Make callable type explicit#'
path: src/NodeManipulator/BinaryOpManipulator.php

View File

@ -1,11 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector\Fixture;
class SomeFileSpec
{
public function run()
{
return 1000;
}
}

View File

@ -1,37 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class RenameSpecFileToTestFileRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
// test file is moved
$isFileRemoved = $this->removedAndAddedFilesCollector->isFileRemoved($this->originalTempFileInfo);
$this->assertTrue($isFileRemoved);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture', '*.php');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,11 +0,0 @@
<?php
declare(strict_types=1);
use Rector\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(RenameSpecFileToTestFileRector::class);
};

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Blabla
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class CreateMe
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Currency
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Delivery
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Exception
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class ItIsMe
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class MockProperties
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class MockPropertiesNonLocal
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Order
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Rates
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class Result
{
}

View File

@ -1,116 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class RatesSpec extends ObjectBehavior
{
public function let(Provider $provider)
{
$provider->get()->shouldBeCalled()->willReturn(
'08.12.2017 #237
země|měna|množství|kód|kurz
Austrálie|dolar|1|AUD|16,362
Velká Británie|libra|1|GBP|29,194'
);
$this->beConstructedWith($provider);
}
public function it_is_initializable()
{
$this->shouldHaveType(Rates::class);
}
public function it_should_load_current_rates(Provider $provider)
{
$provider->get()->shouldBeCalled()->willReturn(
'08.12.2017 #237
země|měna|množství|kód|kurz
Austrálie|dolar|1|AUD|16,362
Velká Británie|libra|1|GBP|29,194'
);
$this->load()->shouldReturnRates(new ArrayCollection([
new Rate('AUD', '16.362'),
new Rate('GBP', '29.194'),
]));
}
public function getMatchers(): array
{
return [
'returnRates' => function (ArrayCollection $rates, ArrayCollection $expectedRates) {
foreach ($rates as $index => $rate) {
if ($rate->rate !== $expectedRates[$index]->rate || $rate->currency !== $expectedRates[$index]->currency) {
return false;
}
}
return true;
},
];
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class RatesTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Rates $rates;
private \PHPUnit\Framework\MockObject\MockObject|\spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Provider $provider;
protected function setUp()
{
$this->provider = $this->createMock(Provider::class);
$this->provider->expects($this->atLeastOnce())->method('get')->willReturn(
'08.12.2017 #237
země|měna|množství|kód|kurz
Austrálie|dolar|1|AUD|16,362
Velká Británie|libra|1|GBP|29,194'
);
$this->rates = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Rates($this->provider);
}
public function testInitializable()
{
$this->assertInstanceOf(Rates::class, $this->rates);
}
public function testLoadCurrentRates()
{
$this->provider->expects($this->atLeastOnce())->method('get')->willReturn(
'08.12.2017 #237
země|měna|množství|kód|kurz
Austrálie|dolar|1|AUD|16,362
Velká Británie|libra|1|GBP|29,194'
);
$matcherCallable = $this->getMatchers()['returnRates'];
$matcherCallable(new ArrayCollection([
new Rate('AUD', '16.362'),
new Rate('GBP', '29.194'),
]), $this->rates->load());
}
public function getMatchers(): array
{
return [
'returnRates' => function (ArrayCollection $rates, ArrayCollection $expectedRates) {
foreach ($rates as $index => $rate) {
if ($rate->rate !== $expectedRates[$index]->rate || $rate->currency !== $expectedRates[$index]->currency) {
return false;
}
}
return true;
},
];
}
}
?>

View File

@ -1,42 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class ExceptionSpec extends ObjectBehavior
{
public function it_should_throw_exceptions_where_rates_are_not_loaded()
{
$this->beConstructedWith('https://non-existent-rates.example.com/denni_kurz.txt');
$this->shouldThrow(RatesNotLoadedException::class)->during('get');
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class ExceptionTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Exception $exception;
protected function setUp()
{
parent::setUp();
$this->exception = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Exception();
}
public function testThrowExceptionsWhereRatesAreNotLoaded()
{
$this->exception = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Exception('https://non-existent-rates.example.com/denni_kurz.txt');
$this->expectException(RatesNotLoadedException::class);
$this->exception->get();
}
}
?>

View File

@ -1,97 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\Address;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\Cart;
class CreateMeSpec extends ObjectBehavior
{
public function let()
{
$this->beConstructedWith(5);
}
public function it_returns_id()
{
$this->id()->shouldReturn(5);
}
public function it_blows()
{
$this->shouldThrow('SomeException')->during('item', [5]);
}
public function it_should_be_called(Cart $cart)
{
$cart->price()->shouldBeCalled()->willReturn(5);
$cart->shippingAddress(Argument::type(Address::class))->shouldBeCalled();
$cart->shippingAddress(Argument::type('DateTime'))->shouldBeCalled();
$cart->shippingAddress(Argument::type('string'))->shouldBeCalled();
}
public function is_bool_check()
{
$this->hasFailed()->shouldBe(false);
$this->hasFailed()->shouldNotBe(false);
}
public function is_array_type()
{
$this->shippingAddresses()->shouldBeArray();
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\Address;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\Cart;
class CreateMeTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\CreateMe $createMe;
protected function setUp()
{
$this->createMe = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\CreateMe(5);
}
public function testReturnsId()
{
$this->assertSame(5, $this->createMe->id());
}
public function testBlows()
{
$this->expectException('SomeException');
$this->createMe->item(5);
}
public function testCalled()
{
/** @var Cart|\PHPUnit\Framework\MockObject\MockObject $cart */
$cart = $this->createMock(Cart::class);
$cart->expects($this->atLeastOnce())->method('price')->willReturn(5);
$cart->expects($this->atLeastOnce())->method('shippingAddress')->with($this->isInstanceOf(Address::class));
$cart->expects($this->atLeastOnce())->method('shippingAddress')->with($this->isInstanceOf('DateTime'));
$cart->expects($this->atLeastOnce())->method('shippingAddress')->with($this->isType('string'));
}
public function testBoolCheck()
{
$this->assertFalse($this->createMe->hasFailed());
$this->assertNotFalse($this->createMe->hasFailed());
}
public function testArrayType()
{
$this->assertIsIterable($this->createMe->shippingAddresses());
}
}
?>

View File

@ -1,352 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use Ecommerce\Cart\Cart;
use Ecommerce\Cart\Exception\NotFoundException;
use Ecommerce\Component\Factory\EntityFactory;
use Ecommerce\Pricing\Currency\DefaultCurrency;
use Ecommerce\Pricing\Currency\DummyDefaultCurrencyProvider;
use Ecommerce\Pricing\Price\CalculatedPrice;
use Ecommerce\Pricing\Price\Price;
use Ecommerce\Taxing\PriceType;
use Ramsey\Uuid\Uuid;
use PhpSpec\ObjectBehavior;
class CartSpec extends ObjectBehavior
{
public function let()
{
DefaultCurrency::setProvider(new DummyDefaultCurrencyProvider());
$this->beConstructedWith(Uuid::uuid1());
}
public function it_is_initializable()
{
$this->shouldHaveType(Cart::class);
}
public function it_should_add_new_item()
{
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 4, new Price(671, $taxRate, $currency)));
$item = $this->item($id);
$item->id()->shouldReturn($id);
$item->quantity()->shouldReturn(4);
}
public function it_should_provide_item_by_its_identifier()
{
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->item($id)->shouldBeAnInstanceOf(\Ecommerce\Cart\Contract\Item::class);
}
public function it_should_throw_an_exception_when_item_is_not_in_cart()
{
$id = Uuid::uuid1();
$this->shouldThrow(NotFoundException::class)->during('item', [$id]);
}
public function it_should_summ_up_quantities_when_adding_same_item_multiple_times()
{
PriceType::set(PriceType::WITH_VAT);
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->add(new \Ecommerce\Cart\Item($id, 'Dolor sit amet', 7, new Price(671, $taxRate, $currency)));
$item = $this->item($id);
$item->quantity()->shouldReturn(10);
}
public function it_should_remove_item()
{
PriceType::set(PriceType::WITH_VAT);
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->remove($id);
$this->shouldThrow(NotFoundException::class)->during('item', [$id]);
}
public function it_should_calculate_zero_price_when_cart_is_empty()
{
$price = $this->price();
$price->shouldBeAnInstanceOf(CalculatedPrice::class);
$price->withVat()->shouldReturn(0.0);
$price->withoutVat()->shouldReturn(0.0);
$price->vat()->shouldReturn(0.0);
}
public function it_should_calculate_total_price_of_all_items_when_not_empty()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->add(new \Ecommerce\Cart\Item(Uuid::uuid1(), 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$price = $this->price();
$price->shouldReturnAnInstanceOf(CalculatedPrice::class);
$price->withVat()->shouldReturn(2013.00);
$price->withoutVat()->shouldReturn(1663.54);
$price->vat()->shouldReturn(349.46);
}
public function it_should_contain_old_items_when_merged_with_empty_cart()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$cart = new Cart(Uuid::uuid1());
$item1 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 2, new Price(671, $taxRate, $currency));
$item2 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f80c-af76-11e8-8981-529269fb1459'), 'Dolor sit amet', 3, new Price(475, $taxRate, $currency));
$this->add($item1);
$this->add($item2);
$this->merge($cart);
$items = $this->items();
$items->shouldHaveCount(2);
$this->item($item1->key())->quantity()->shouldBe(2);
$this->item($item2->key())->quantity()->shouldBe(3);
}
public function it_should_contain_only_items_from_second_cart_when_merged_with_not_empty_cart()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$cart = new Cart(Uuid::uuid1());
$item1 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 2, new Price(671, $taxRate, $currency));
$item2 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f80c-af76-11e8-8981-529269fb1459'), 'Dolor sit amet', 3, new Price(475, $taxRate, $currency));
$item3 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 4, new Price(671, $taxRate, $currency));
$item4 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9fa0a-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 5, new Price(671, $taxRate, $currency));
$cart->add($item1);
$cart->add($item2);
$this->add($item3);
$this->add($item4);
$this->merge($cart);
$items = $this->items();
$items->shouldHaveCount(2);
$this->item($item1->key())->quantity()->shouldBe(2);
$this->item($item2->key())->quantity()->shouldBe(3);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use Ecommerce\Cart\Cart;
use Ecommerce\Cart\Exception\NotFoundException;
use Ecommerce\Component\Factory\EntityFactory;
use Ecommerce\Pricing\Currency\DefaultCurrency;
use Ecommerce\Pricing\Currency\DummyDefaultCurrencyProvider;
use Ecommerce\Pricing\Price\CalculatedPrice;
use Ecommerce\Pricing\Price\Price;
use Ecommerce\Taxing\PriceType;
use Ramsey\Uuid\Uuid;
use PhpSpec\ObjectBehavior;
class CartTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Cart $cart;
protected function setUp()
{
DefaultCurrency::setProvider(new DummyDefaultCurrencyProvider());
$this->cart = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Cart(Uuid::uuid1());
}
public function testInitializable()
{
$this->assertInstanceOf(Cart::class, $this->cart);
}
public function testAddNewItem()
{
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->cart->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 4, new Price(671, $taxRate, $currency)));
$item = $this->cart->item($id);
$this->assertSame($id, $item->id());
$this->assertSame(4, $item->quantity());
}
public function testProvideItemByItsIdentifier()
{
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->cart->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->assertInstanceOf(\Ecommerce\Cart\Contract\Item::class, $this->cart->item($id));
}
public function testThrowAnExceptionWhenItemIsNotInCart()
{
$id = Uuid::uuid1();
$this->expectException(NotFoundException::class);
$this->cart->item($id);
}
public function testSummUpQuantitiesWhenAddingSameItemMultipleTimes()
{
PriceType::set(PriceType::WITH_VAT);
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->cart->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->cart->add(new \Ecommerce\Cart\Item($id, 'Dolor sit amet', 7, new Price(671, $taxRate, $currency)));
$item = $this->cart->item($id);
$this->assertSame(10, $item->quantity());
}
public function testRemoveItem()
{
PriceType::set(PriceType::WITH_VAT);
$id = Uuid::uuid1();
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->cart->add(new \Ecommerce\Cart\Item($id, 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$this->cart->remove($id);
$this->expectException(NotFoundException::class);
$this->cart->item($id);
}
public function testCalculateZeroPriceWhenCartIsEmpty()
{
$price = $this->cart->price();
$this->assertInstanceOf(CalculatedPrice::class, $price);
$this->assertSame(0.0, $price->withVat());
$this->assertSame(0.0, $price->withoutVat());
$this->assertSame(0.0, $price->vat());
}
public function testCalculateTotalPriceOfAllItemsWhenNotEmpty()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$this->cart->add(new \Ecommerce\Cart\Item(Uuid::uuid1(), 'Lorem ipsum', 3, new Price(671, $taxRate, $currency)));
$price = $this->cart->price();
$this->assertInstanceOf(CalculatedPrice::class, $price);
$this->assertSame(2013.00, $price->withVat());
$this->assertSame(1663.54, $price->withoutVat());
$this->assertSame(349.46, $price->vat());
}
public function testContainOldItemsWhenMergedWithEmptyCart()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$cart = new Cart(Uuid::uuid1());
$item1 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 2, new Price(671, $taxRate, $currency));
$item2 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f80c-af76-11e8-8981-529269fb1459'), 'Dolor sit amet', 3, new Price(475, $taxRate, $currency));
$this->cart->add($item1);
$this->cart->add($item2);
$this->cart->merge($cart);
$items = $this->cart->items();
$this->assertCount(2, $items);
$this->assertSame(2, $this->cart->item($item1->key())->quantity());
$this->assertSame(3, $this->cart->item($item2->key())->quantity());
}
public function testContainOnlyItemsFromSecondCartWhenMergedWithNotEmptyCart()
{
PriceType::set(PriceType::WITH_VAT);
$taxRate = EntityFactory::make('tax_rate_21');
$currency = EntityFactory::make('currency_czk');
$cart = new Cart(Uuid::uuid1());
$item1 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 2, new Price(671, $taxRate, $currency));
$item2 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f80c-af76-11e8-8981-529269fb1459'), 'Dolor sit amet', 3, new Price(475, $taxRate, $currency));
$item3 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9f49c-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 4, new Price(671, $taxRate, $currency));
$item4 = new \Ecommerce\Cart\Item(Uuid::fromString('3cf9fa0a-af76-11e8-8981-529269fb1459'), 'Lorem ipsum', 5, new Price(671, $taxRate, $currency));
$cart->add($item1);
$cart->add($item2);
$this->cart->add($item3);
$this->cart->add($item4);
$this->cart->merge($cart);
$items = $this->cart->items();
$this->assertCount(2, $items);
$this->assertSame(2, $this->cart->item($item1->key())->quantity());
$this->assertSame(3, $this->cart->item($item2->key())->quantity());
}
}
?>

View File

@ -1,39 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class BlablaSpec extends ObjectBehavior
{
public function it_is_me(SomeType $someType)
{
$assignMe = $someType->getWrappedObject();
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class BlablaTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Blabla $blabla;
protected function setUp()
{
parent::setUp();
$this->blabla = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Blabla();
}
public function testMe()
{
/** @var SomeType|\PHPUnit\Framework\MockObject\MockObject $someType */
$someType = $this->createMock(SomeType::class);
$assignMe = $someType;
}
}
?>

View File

@ -1,103 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use JsonApiBundle\Paging\PageLinksGenerator;
use JsonApiBundle\Paging\Paginator;
use Neomerx\JsonApi\Document\Link;
use PhpSpec\ObjectBehavior;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Class PageLinksGeneratorSpec
*/
class PageLinksGeneratorSpec extends ObjectBehavior
{
public function it_is_initializable()
{
$this->shouldHaveType(PageLinksGenerator::class);
}
public function let(Router $router)
{
$this->beConstructedWith($router);
}
public function it_should_return_only_self_link_when_no_results(Router $router)
{
$paginator = new Paginator(
10,
0,
1,
0,
'route_name'
);
$router->generate($paginator->getRouteName(), [], UrlGeneratorInterface::ABSOLUTE_URL)
->shouldBeCalled()->willReturn('http://api.foo.loc/bar/1.0.0/');
$expectations = [
'self' => new Link('http://api.foo.loc/bar/1.0.0/'),
'first' => null,
'prev' => null,
'next' => null,
'last' => null,
];
$this->generateLinks($paginator)->shouldBeLike($expectations);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use JsonApiBundle\Paging\PageLinksGenerator;
use JsonApiBundle\Paging\Paginator;
use Neomerx\JsonApi\Document\Link;
use PhpSpec\ObjectBehavior;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
/**
* Class PageLinksGeneratorSpec
*/
class PageLinksGeneratorTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\PageLinksGenerator $pageLinksGenerator;
private \PHPUnit\Framework\MockObject\MockObject|\Symfony\Bundle\FrameworkBundle\Routing\Router $router;
public function testInitializable()
{
$this->assertInstanceOf(PageLinksGenerator::class, $this->pageLinksGenerator);
}
protected function setUp()
{
$this->router = $this->createMock(Router::class);
$this->pageLinksGenerator = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\PageLinksGenerator($this->router);
}
public function testReturnOnlySelfLinkWhenNoResults()
{
$paginator = new Paginator(
10,
0,
1,
0,
'route_name'
);
$this->router->expects($this->atLeastOnce())
->method('generate')->with($this->equalTo($paginator->getRouteName()))->willReturn('http://api.foo.loc/bar/1.0.0/');
$expectations = [
'self' => new Link('http://api.foo.loc/bar/1.0.0/'),
'first' => null,
'prev' => null,
'next' => null,
'last' => null,
];
$this->pageLinksGenerator->generateLinks($paginator)->shouldBeLike($expectations);
}
}
?>

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
final class KeepMethod
{
}

View File

@ -1,52 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class CurrencySpec extends ObjectBehavior
{
public function let(CurrencyData $data)
{
$data->code = 'CZK';
$this->beConstructedThrough('create', [$data]);
}
public function it_should_not_be_constructed_without_code(CurrencyData $data)
{
$data->code = '';
$this->beConstructedThrough('create', [$data]);
$this->shouldThrow(ValidationException::class)->duringInstantiation();
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class CurrencyTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Currency $currency;
private \PHPUnit\Framework\MockObject\MockObject|\spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\CurrencyData $data;
protected function setUp()
{
$this->data = $this->createMock(CurrencyData::class);
$this->data->code = 'CZK';
$this->currency = \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Currency::create($this->data);
}
public function testNotBeConstructedWithoutCode()
{
$this->data->code = '';
$this->expectException(ValidationException::class);
$this->currency = \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Currency::create($this->data);
}
}
?>

View File

@ -1,46 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class KeepMethodSpec extends ObjectBehavior
{
public function let()
{
$this->beConstructedWith(5);
$result = $this->getSomeNumbers();
}
private function getSomeNumbers()
{
return [1, 2, 3];
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class KeepMethodTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\KeepMethod $keepMethod;
protected function setUp()
{
$this->keepMethod = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\KeepMethod(5);
$result = $this->getSomeNumbers();
}
private function getSomeNumbers()
{
return [1, 2, 3];
}
}
?>

View File

@ -1,44 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\DeliveryFactory;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\ShippingMethod;
class DeliverySpec extends ObjectBehavior
{
public function let(DeliveryFactory $factory, ShippingMethod $shippingMethod)
{
$factory->createShippingMethodFor(5)
->shouldBeCalled()
->willReturn($shippingMethod);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\DeliveryFactory;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\ShippingMethod;
class DeliveryTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Delivery $delivery;
protected function setUp()
{
/** @var DeliveryFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
$factory = $this->createMock(DeliveryFactory::class);
/** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
$shippingMethod = $this->createMock(ShippingMethod::class);
$factory->expects($this->atLeastOnce())
->method('createShippingMethodFor')->with($this->equalTo(5))
->willReturn($shippingMethod);
}
}
?>

View File

@ -1,48 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\OrderFactory;
class MockPropertiesSpec extends ObjectBehavior
{
public function let(OrderFactory $factory)
{
$this->beConstructedWith($factory);
}
public function let_it_go(OrderFactory $factory)
{
$factory->someMethod()->shouldBeCalled();
$this->run();
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\OrderFactory;
class MockPropertiesTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\MockProperties $mockProperties;
private \PHPUnit\Framework\MockObject\MockObject|\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\OrderFactory $factory;
protected function setUp()
{
$this->factory = $this->createMock(OrderFactory::class);
$this->mockProperties = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\MockProperties($this->factory);
}
public function testLetItGo()
{
$this->factory->expects($this->atLeastOnce())->method('someMethod');
$this->mockProperties->run();
}
}
?>

View File

@ -1,64 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\AnotherMock;
class MockPropertiesNonLocalSpec extends ObjectBehavior
{
public function let(OrderFactory $factory)
{
$this->beConstructedWith($factory);
}
public function let_it_go(AnotherMock $anotherMock)
{
$anotherMock->setName('Nummy');
$this->addAnotherMock($anotherMock);
}
public function let_it_go_again(AnotherMock $anotherMock)
{
$anotherMock->setName('Nummy2');
$this->addAnotherMock($anotherMock);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source\AnotherMock;
class MockPropertiesNonLocalTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\MockPropertiesNonLocal $mockPropertiesNonLocal;
protected function setUp()
{
/** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
$factory = $this->createMock(OrderFactory::class);
$this->mockPropertiesNonLocal = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\MockPropertiesNonLocal($factory);
}
public function testLetItGo()
{
/** @var AnotherMock|\PHPUnit\Framework\MockObject\MockObject $anotherMock */
$anotherMock = $this->createMock(AnotherMock::class);
$anotherMock->setName('Nummy');
$this->mockPropertiesNonLocal->addAnotherMock($anotherMock);
}
public function testLetItGoAgain()
{
/** @var AnotherMock|\PHPUnit\Framework\MockObject\MockObject $anotherMock */
$anotherMock = $this->createMock(AnotherMock::class);
$anotherMock->setName('Nummy2');
$this->mockPropertiesNonLocal->addAnotherMock($anotherMock);
}
}
?>

View File

@ -1,38 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class OrderSpec extends ObjectBehavior
{
public function let(OrderFactory $factory, ShippingMethod $shippingMethod)
{
$factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
$factory->anotherMethod(25)->shouldBeCalled()->willReturn($shippingMethod);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class OrderTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Order $order;
protected function setUp()
{
/** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
$factory = $this->createMock(OrderFactory::class);
/** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
$shippingMethod = $this->createMock(ShippingMethod::class);
$factory->expects($this->atLeastOnce())->method('createShippingMethodFor')->willReturn($shippingMethod);
$factory->expects($this->atLeastOnce())->method('anotherMethod')->with($this->equalTo(25))->willReturn($shippingMethod);
}
}
?>

View File

@ -1,35 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\ItIsMe;
use PhpSpec\ObjectBehavior;
class ItIsMeSpec extends ObjectBehavior
{
public function it_is_me()
{
$this->shouldHaveType(ItIsMe::class);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\ItIsMe;
use PhpSpec\ObjectBehavior;
class ItIsMeTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\ItIsMe $itIsMe;
protected function setUp()
{
parent::setUp();
$this->itIsMe = new \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\ItIsMe();
}
}
?>

View File

@ -1,46 +0,0 @@
<?php
namespace spec\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class ResultSpec extends ObjectBehavior
{
public function it_is_initializable()
{
$this->beConstructedThrough('success');
$this->shouldHaveType(Result::class);
}
public function it_should_succeed()
{
$this->beConstructedThrough('fail');
$this->hasFailed()->shouldReturn(false);
}
}
?>
-----
<?php
namespace Tests\Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture;
use PhpSpec\ObjectBehavior;
class ResultTest extends \PHPUnit\Framework\TestCase
{
private \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Result $result;
public function testInitializable()
{
$this->result = \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Result::success();
$this->assertInstanceOf(Result::class, $this->result);
}
public function testSucceed()
{
$this->result = \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Fixture\Result::fail();
$this->assertFalse($this->result->hasFailed());
}
}
?>

View File

@ -1,34 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector;
use Iterator;
use Rector\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\EasyTesting\DataProvider\StaticFixtureFinder;
use Symplify\SmartFileSystem\SmartFileInfo;
final class PhpSpecToPHPUnitRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
/**
* @return Iterator<SmartFileInfo>
*/
public function provideData(): Iterator
{
return StaticFixtureFinder::yieldDirectory(__DIR__ . '/Fixture');
}
public function provideConfigFilePath(): string
{
return __DIR__ . '/config/configured_rule.php';
}
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class Address
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class AnotherMock
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class Cart
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class DeliveryFactory
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class OrderFactory
{
}

View File

@ -1,10 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\Source;
final class ShippingMethod
{
}

View File

@ -1,21 +0,0 @@
<?php
declare(strict_types=1);
use Rector\PhpSpecToPHPUnit\Rector\Class_\AddMockPropertiesRector;
use Rector\PhpSpecToPHPUnit\Rector\Class_\PhpSpecClassToPHPUnitClassRector;
use Rector\PhpSpecToPHPUnit\Rector\ClassMethod\PhpSpecMethodToPHPUnitMethodRector;
use Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecMocksToPHPUnitMocksRector;
use Rector\PhpSpecToPHPUnit\Rector\MethodCall\PhpSpecPromisesToPHPUnitAssertRector;
use Rector\PhpSpecToPHPUnit\Rector\Variable\MockVariableToPropertyFetchRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$services = $containerConfigurator->services();
$services->set(PhpSpecMocksToPHPUnitMocksRector::class);
$services->set(PhpSpecPromisesToPHPUnitAssertRector::class);
$services->set(PhpSpecMethodToPHPUnitMethodRector::class);
$services->set(PhpSpecClassToPHPUnitClassRector::class);
$services->set(AddMockPropertiesRector::class);
$services->set(MockVariableToPropertyFetchRector::class);
};

View File

@ -1,49 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
final class LetManipulator
{
public function __construct(
private readonly BetterNodeFinder $betterNodeFinder,
private readonly NodeNameResolver $nodeNameResolver
) {
}
public function isLetNeededInClass(Class_ $class): bool
{
foreach ($class->getMethods() as $classMethod) {
// new test
if ($this->nodeNameResolver->isName($classMethod, 'test*')) {
continue;
}
$hasBeConstructedThrough = (bool) $this->betterNodeFinder->find(
(array) $classMethod->stmts,
function (Node $node): bool {
if (! $node instanceof MethodCall) {
return false;
}
return $this->nodeNameResolver->isName($node->name, 'beConstructedThrough');
}
);
if ($hasBeConstructedThrough) {
continue;
}
return true;
}
return false;
}
}

View File

@ -1,52 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Return_;
final class MatchersManipulator
{
/**
* @return string[]
*/
public function resolveMatcherNamesFromClass(Class_ $class): array
{
$classMethod = $class->getMethod('getMatchers');
if (! $classMethod instanceof ClassMethod) {
return [];
}
if (! isset($classMethod->stmts[0])) {
return [];
}
if (! $classMethod->stmts[0] instanceof Return_) {
return [];
}
/** @var Return_ $return */
$return = $classMethod->stmts[0];
if (! $return->expr instanceof Array_) {
return [];
}
$keys = [];
foreach ($return->expr->items as $arrayItem) {
if ($arrayItem === null) {
continue;
}
if ($arrayItem->key instanceof String_) {
$keys[] = $arrayItem->key->value;
}
}
return $keys;
}
}

View File

@ -1,138 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Naming;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Name\FullyQualified;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassLike;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Namespace_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\Core\Util\StaticRectorStrings;
use Rector\NodeNameResolver\NodeNameResolver;
use Symplify\PackageBuilder\Strings\StringFormatConverter;
final class PhpSpecRenaming
{
/**
* @var string
*/
private const SPEC = 'Spec';
public function __construct(
private readonly NodeNameResolver $nodeNameResolver,
private readonly StringFormatConverter $stringFormatConverter,
private readonly BetterNodeFinder $betterNodeFinder
) {
}
public function renameMethod(ClassMethod $classMethod): void
{
if ($classMethod->isPrivate()) {
return;
}
$classMethodName = $this->nodeNameResolver->getName($classMethod);
$classMethodName = $this->removeNamePrefixes($classMethodName);
// from PhpSpec to PHPUnit method naming convention
$classMethodName = $this->stringFormatConverter->underscoreAndHyphenToCamelCase($classMethodName);
// add "test", so PHPUnit runs the method
if (! \str_starts_with($classMethodName, 'test')) {
$classMethodName = 'test' . ucfirst($classMethodName);
}
$classMethod->name = new Identifier($classMethodName);
}
public function renameExtends(Class_ $class): void
{
$class->extends = new FullyQualified('PHPUnit\Framework\TestCase');
}
public function renameNamespace(Class_ $class): void
{
$namespace = $this->betterNodeFinder->findParentType($class, Namespace_::class);
if (! $namespace instanceof Namespace_) {
return;
}
$namespaceName = $this->nodeNameResolver->getName($namespace);
if ($namespaceName === null) {
return;
}
$newNamespaceName = StaticRectorStrings::removePrefixes($namespaceName, ['spec\\']);
$namespace->name = new Name('Tests\\' . $newNamespaceName);
}
public function renameClass(Class_ $class): void
{
$classShortName = $this->nodeNameResolver->getShortName($class);
// anonymous class?
if ($classShortName === '') {
throw new ShouldNotHappenException();
}
// 2. change class name
$newClassName = StaticRectorStrings::removeSuffixes($classShortName, [self::SPEC]);
$newTestClassName = $newClassName . 'Test';
$class->name = new Identifier($newTestClassName);
}
public function resolveObjectPropertyName(Class_ $class): string
{
// anonymous class?
if ($class->name === null) {
throw new ShouldNotHappenException();
}
$shortClassName = $this->nodeNameResolver->getShortName($class);
$bareClassName = StaticRectorStrings::removeSuffixes($shortClassName, [self::SPEC, 'Test']);
return lcfirst($bareClassName);
}
public function resolveTestedClass(Node $node): string
{
if ($node instanceof ClassLike) {
$className = (string) $this->nodeNameResolver->getName($node);
} else {
$classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
if (! $classLike instanceof ClassLike) {
throw new ShouldNotHappenException();
}
$className = (string) $this->nodeNameResolver->getName($classLike);
}
$newClassName = StaticRectorStrings::removePrefixes($className, ['spec\\']);
return StaticRectorStrings::removeSuffixes($newClassName, [self::SPEC]);
}
private function removeNamePrefixes(string $name): string
{
$originalName = $name;
$name = StaticRectorStrings::removePrefixes(
$name,
['it_should_have_', 'it_should_be', 'it_should_', 'it_is_', 'it_', 'is_']
);
if ($name === '') {
return $originalName;
}
return $name;
}
}

View File

@ -1,86 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
final class AssertMethodCallFactory
{
private bool $isBoolAssert = false;
public function __construct(
private readonly NodeFactory $nodeFactory,
private readonly NodeNameResolver $nodeNameResolver,
private readonly ValueResolver $valueResolver
) {
}
public function createAssertMethod(
string $name,
Expr $value,
?Expr $expected,
PropertyFetch $testedObjectPropertyFetch
): MethodCall {
$this->isBoolAssert = false;
// special case with bool!
if ($expected instanceof Expr) {
$name = $this->resolveBoolMethodName($name, $expected);
}
$assetMethodCall = $this->nodeFactory->createMethodCall('this', $name);
if (! $this->isBoolAssert && $expected instanceof Expr) {
$assetMethodCall->args[] = new Arg($this->thisToTestedObjectPropertyFetch(
$expected,
$testedObjectPropertyFetch
));
}
$assetMethodCall->args[] = new Arg($this->thisToTestedObjectPropertyFetch($value, $testedObjectPropertyFetch));
return $assetMethodCall;
}
private function resolveBoolMethodName(string $name, Expr $expr): string
{
if (! $this->valueResolver->isTrueOrFalse($expr)) {
return $name;
}
$isFalse = $this->valueResolver->isFalse($expr);
if ($name === 'assertSame') {
$this->isBoolAssert = true;
return $isFalse ? 'assertFalse' : 'assertTrue';
}
if ($name === 'assertNotSame') {
$this->isBoolAssert = true;
return $isFalse ? 'assertNotFalse' : 'assertNotTrue';
}
return $name;
}
private function thisToTestedObjectPropertyFetch(Expr $expr, PropertyFetch $propertyFetch): Expr
{
if (! $expr instanceof Variable) {
return $expr;
}
if (! $this->nodeNameResolver->isName($expr, 'this')) {
return $expr;
}
return $propertyFetch;
}
}

View File

@ -1,82 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\ArrayItem;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Name\FullyQualified;
use Rector\Core\PhpParser\Node\NodeFactory;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\NodeNameResolver\NodeNameResolver;
final class BeConstructedWithAssignFactory
{
public function __construct(
private readonly NodeNameResolver $nodeNameResolver,
private readonly ValueResolver $valueResolver,
private readonly NodeFactory $nodeFactory
) {
}
public function create(MethodCall $methodCall, string $testedClass, PropertyFetch $propertyFetch): ?Assign
{
if ($this->nodeNameResolver->isName($methodCall->name, 'beConstructedWith')) {
$new = new New_(new FullyQualified($testedClass));
$new->args = $methodCall->args;
return new Assign($propertyFetch, $new);
}
if ($this->nodeNameResolver->isName($methodCall->name, 'beConstructedThrough')) {
if (! isset($methodCall->args[0])) {
return null;
}
if (! $methodCall->args[0] instanceof Arg) {
return null;
}
$methodName = $this->valueResolver->getValue($methodCall->args[0]->value);
$staticCall = $this->nodeFactory->createStaticCall($testedClass, $methodName);
$this->moveConstructorArguments($methodCall, $staticCall);
return new Assign($propertyFetch, $staticCall);
}
return null;
}
private function moveConstructorArguments(MethodCall $methodCall, StaticCall $staticCall): void
{
if (! isset($methodCall->args[1])) {
return;
}
if (! $methodCall->args[1] instanceof Arg) {
return;
}
if (! $methodCall->args[1]->value instanceof Array_) {
return;
}
/** @var Array_ $array */
$array = $methodCall->args[1]->value;
foreach ($array->items as $arrayItem) {
if (! $arrayItem instanceof ArrayItem) {
continue;
}
$staticCall->args[] = new Arg($arrayItem->value);
}
}
}

View File

@ -1,55 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\NodeFactory;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Array_;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Identifier;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\Value\ValueResolver;
use Rector\PostRector\Collector\NodesToAddCollector;
final class DuringMethodCallFactory
{
public function __construct(
private readonly ValueResolver $valueResolver,
private readonly NodesToAddCollector $nodesToAddCollector
) {
}
public function create(MethodCall $methodCall, PropertyFetch $propertyFetch): MethodCall
{
if (! isset($methodCall->args[0])) {
throw new ShouldNotHappenException();
}
if (! $methodCall->args[0] instanceof Arg) {
throw new ShouldNotHappenException();
}
$name = $this->valueResolver->getValue($methodCall->args[0]->value);
$thisObjectPropertyMethodCall = new MethodCall($propertyFetch, $name);
if (isset($methodCall->args[1]) && $methodCall->args[1] instanceof Arg && $methodCall->args[1]->value instanceof Array_) {
/** @var Array_ $array */
$array = $methodCall->args[1]->value;
if (isset($array->items[0])) {
$thisObjectPropertyMethodCall->args[] = new Arg($array->items[0]->value);
}
}
/** @var MethodCall $parentMethodCall */
$parentMethodCall = $methodCall->var;
$parentMethodCall->name = new Identifier('expectException');
// add $this->object->someCall($withArgs)
$this->nodesToAddCollector->addNodeAfterNode($thisObjectPropertyMethodCall, $methodCall);
return $parentMethodCall;
}
}

View File

@ -1,36 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\PhpParser\AstResolver;
use Rector\Core\ValueObject\MethodName;
use Rector\Testing\PHPUnit\StaticPHPUnitEnvironment;
/**
* Decorate setUp() and tearDown() with "void" when local TestClass class uses them
*/
final class PHPUnitTypeDeclarationDecorator
{
public function __construct(
private readonly AstResolver $astResolver
) {
}
public function decorate(ClassMethod $classMethod): void
{
// skip test run
if (StaticPHPUnitEnvironment::isPHPUnitRun()) {
return;
}
$setUpClassMethod = $this->astResolver->resolveClassMethod('PHPUnit\Framework\TestCase', MethodName::SET_UP);
if (! $setUpClassMethod instanceof ClassMethod) {
return;
}
$classMethod->returnType = $setUpClassMethod->returnType;
}
}

View File

@ -1,122 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit;
use PhpParser\Node;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Param;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\PhpParser\Node\BetterNodeFinder;
use Rector\NodeNameResolver\NodeNameResolver;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Symplify\Astral\NodeTraverser\SimpleCallableNodeTraverser;
final class PhpSpecMockCollector
{
/**
* @var mixed[]
*/
private array $mocks = [];
/**
* @var mixed[]
*/
private array $mocksWithsTypes = [];
/**
* @var mixed[]
*/
private array $propertyMocksByClass = [];
public function __construct(
private readonly SimpleCallableNodeTraverser $simpleCallableNodeTraverser,
private readonly NodeNameResolver $nodeNameResolver,
private readonly BetterNodeFinder $betterNodeFinder,
) {
}
/**
* @return mixed[]
*/
public function resolveClassMocksFromParam(Class_ $class): array
{
$className = (string) $this->nodeNameResolver->getName($class);
if (isset($this->mocks[$className]) && $this->mocks[$className] !== []) {
return $this->mocks[$className];
}
$this->simpleCallableNodeTraverser->traverseNodesWithCallable($class, function (Node $node) use ($class) {
if (! $node instanceof ClassMethod) {
return null;
}
if (! $node->isPublic()) {
return null;
}
foreach ($node->params as $param) {
$this->addMockFromParam($class, $param);
}
return null;
});
// set default value if none was found
if (! isset($this->mocks[$className])) {
$this->mocks[$className] = [];
}
return $this->mocks[$className];
}
public function isVariableMockInProperty(Class_ $class, Variable $variable): bool
{
$variableName = $this->nodeNameResolver->getName($variable);
$className = (string) $this->nodeNameResolver->getName($class);
return in_array($variableName, $this->propertyMocksByClass[$className] ?? [], true);
}
public function getTypeForClassAndVariable(Class_ $class, string $variable): string
{
$className = (string) $this->nodeNameResolver->getName($class);
if (! isset($this->mocksWithsTypes[$className][$variable])) {
throw new ShouldNotHappenException();
}
return $this->mocksWithsTypes[$className][$variable];
}
public function addPropertyMock(string $class, string $property): void
{
$this->propertyMocksByClass[$class][] = $property;
}
private function addMockFromParam(Class_ $class, Param $param): void
{
$variable = $this->nodeNameResolver->getName($param->var);
$className = (string) $this->nodeNameResolver->getName($class);
$classMethod = $this->betterNodeFinder->findParentType($param, ClassMethod::class);
if (! $classMethod instanceof ClassMethod) {
throw new ShouldNotHappenException();
}
$methodName = $this->nodeNameResolver->getName($classMethod);
$this->mocks[$className][$variable][] = $methodName;
if ($param->type === null) {
throw new ShouldNotHappenException();
}
$paramType = (string) ($param->type ?? $param->type->getAttribute(AttributeKey::ORIGINAL_NAME));
$this->mocksWithsTypes[$className][$variable] = $paramType;
}
}

View File

@ -1,76 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector;
use PhpParser\Node;
use PhpParser\Node\Stmt\ClassLike;
use PHPStan\Type\ObjectType;
use Rector\Core\Rector\AbstractRector;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @changelog https://gnugat.github.io/2015/09/23/phpunit-with-phpspec.html
* @changelog http://www.phpspec.net/en/stable/cookbook/construction.html
*/
abstract class AbstractPhpSpecToPHPUnitRector extends AbstractRector
{
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition('Migrate PhpSpec behavior to PHPUnit test', [
new CodeSample(
<<<'CODE_SAMPLE'
namespace spec\SomeNamespaceForThisTest;
use PhpSpec\ObjectBehavior;
class OrderSpec extends ObjectBehavior
{
public function let(OrderFactory $factory, ShippingMethod $shippingMethod): void
{
$factory->createShippingMethodFor(Argument::any())->shouldBeCalled()->willReturn($shippingMethod);
}
}
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
namespace spec\SomeNamespaceForThisTest;
class OrderSpec extends ObjectBehavior
{
/**
* @var \SomeNamespaceForThisTest\Order
*/
private $order;
protected function setUp()
{
/** @var OrderFactory|\PHPUnit\Framework\MockObject\MockObject $factory */
$factory = $this->createMock(OrderFactory::class);
/** @var ShippingMethod|\PHPUnit\Framework\MockObject\MockObject $shippingMethod */
$shippingMethod = $this->createMock(ShippingMethod::class);
$factory->expects($this->once())->method('createShippingMethodFor')->willReturn($shippingMethod);
}
}
CODE_SAMPLE
),
]);
}
protected function isInPhpSpecBehavior(Node $node): bool
{
if ($node instanceof ClassLike) {
return $this->isObjectType($node, new ObjectType('PhpSpec\ObjectBehavior'));
}
$classLike = $this->betterNodeFinder->findParentType($node, ClassLike::class);
if (! $classLike instanceof ClassLike) {
return false;
}
return $this->isInPhpSpecBehavior($classLike);
}
}

View File

@ -1,89 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\ClassMethod;
use PhpParser\Node;
use PhpParser\Node\Identifier;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\ValueObject\MethodName;
use Rector\PhpSpecToPHPUnit\Naming\PhpSpecRenaming;
use Rector\PhpSpecToPHPUnit\PHPUnitTypeDeclarationDecorator;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
use Rector\Privatization\NodeManipulator\VisibilityManipulator;
/**
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class PhpSpecMethodToPHPUnitMethodRector extends AbstractPhpSpecToPHPUnitRector
{
public function __construct(
private readonly PHPUnitTypeDeclarationDecorator $phpUnitTypeDeclarationDecorator,
private readonly PhpSpecRenaming $phpSpecRenaming,
private readonly VisibilityManipulator $visibilityManipulator,
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class];
}
/**
* @param ClassMethod $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInPhpSpecBehavior($node)) {
return null;
}
if ($this->isName($node, 'letGo')) {
$node->name = new Identifier(MethodName::TEAR_DOWN);
$this->visibilityManipulator->makeProtected($node);
$this->phpUnitTypeDeclarationDecorator->decorate($node);
} elseif ($this->isName($node, 'let')) {
$node->name = new Identifier(MethodName::SET_UP);
$this->visibilityManipulator->makeProtected($node);
$this->phpUnitTypeDeclarationDecorator->decorate($node);
} elseif ($node->isPublic()) {
$this->processTestMethod($node);
} else {
return null;
}
return $node;
}
private function processTestMethod(ClassMethod $classMethod): void
{
// special case, @see https://johannespichler.com/writing-custom-phpspec-matchers/
if ($this->isName($classMethod, 'getMatchers')) {
return;
}
// change name to phpunit test case format
$this->phpSpecRenaming->renameMethod($classMethod);
// reorder instantiation + expected exception
$previousStmt = null;
foreach ((array) $classMethod->stmts as $key => $stmt) {
$printedStmtContent = $this->print($stmt);
if (\str_contains($printedStmtContent, 'duringInstantiation') && $previousStmt instanceof Stmt) {
$printedPreviousStmt = $this->print($previousStmt);
if (\str_contains($printedPreviousStmt, 'beConstructedThrough')) {
$classMethod->stmts[$key - 1] = $stmt;
$classMethod->stmts[$key] = $previousStmt;
}
}
$previousStmt = $stmt;
}
}
}

View File

@ -1,74 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use PHPStan\Type\ObjectType;
use PHPStan\Type\UnionType;
use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\PhpSpecToPHPUnit\PhpSpecMockCollector;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
/**
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class AddMockPropertiesRector extends AbstractPhpSpecToPHPUnitRector
{
public function __construct(
private readonly ClassInsertManipulator $classInsertManipulator,
private readonly PhpSpecMockCollector $phpSpecMockCollector
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInPhpSpecBehavior($node)) {
return null;
}
$classMocks = $this->phpSpecMockCollector->resolveClassMocksFromParam($node);
$className = $this->getName($node);
if (! is_string($className)) {
return null;
}
foreach ($classMocks as $name => $methods) {
if ((is_countable($methods) ? count($methods) : 0) <= 1) {
continue;
}
// non-ctor used mocks are probably local only
if (! in_array('let', $methods, true)) {
continue;
}
$this->phpSpecMockCollector->addPropertyMock($className, $name);
$variableType = $this->phpSpecMockCollector->getTypeForClassAndVariable($node, $name);
$unionType = new UnionType([
new ObjectType($variableType),
new ObjectType('PHPUnit\Framework\MockObject\MockObject'),
]);
$this->classInsertManipulator->addPropertyToClass($node, $name, $unionType);
}
return null;
}
}

View File

@ -1,162 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\Class_;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\New_;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Name;
use PhpParser\Node\Stmt;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use PHPStan\Type\ObjectType;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\NodeManipulator\ClassInsertManipulator;
use Rector\PhpSpecToPHPUnit\LetManipulator;
use Rector\PhpSpecToPHPUnit\Naming\PhpSpecRenaming;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
use Rector\PHPStanStaticTypeMapper\Enum\TypeKind;
use Rector\PHPUnit\NodeFactory\SetUpClassMethodFactory;
/**
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class PhpSpecClassToPHPUnitClassRector extends AbstractPhpSpecToPHPUnitRector
{
public function __construct(
private readonly ClassInsertManipulator $classInsertManipulator,
private readonly LetManipulator $letManipulator,
private readonly PhpSpecRenaming $phpSpecRenaming,
private readonly SetUpClassMethodFactory $setUpClassMethodFactory
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInPhpSpecBehavior($node)) {
return null;
}
// 1. change namespace name to PHPUnit-like
$this->phpSpecRenaming->renameNamespace($node);
$propertyName = $this->phpSpecRenaming->resolveObjectPropertyName($node);
$this->phpSpecRenaming->renameClass($node);
$this->phpSpecRenaming->renameExtends($node);
$testedClass = $this->phpSpecRenaming->resolveTestedClass($node);
$testedObjectType = new ObjectType($testedClass);
$this->classInsertManipulator->addPropertyToClass($node, $propertyName, $testedObjectType);
$classMethod = $node->getMethod('let');
// add let if missing
if (! $classMethod instanceof ClassMethod) {
if (! $this->letManipulator->isLetNeededInClass($node)) {
return null;
}
$letClassMethod = $this->createLetClassMethod($propertyName, $testedObjectType);
$this->classInsertManipulator->addAsFirstMethod($node, $letClassMethod);
}
return $this->removeSelfTypeMethod($node, $testedObjectType);
}
private function createLetClassMethod(string $propertyName, ObjectType $testedObjectType): ClassMethod
{
$propertyFetch = new PropertyFetch(new Variable('this'), $propertyName);
$testedObjectType = $this->staticTypeMapper->mapPHPStanTypeToPhpParserNode(
$testedObjectType,
TypeKind::RETURN()
);
if (! $testedObjectType instanceof Name) {
throw new ShouldNotHappenException();
}
$new = new New_($testedObjectType);
$assign = new Assign($propertyFetch, $new);
return $this->setUpClassMethodFactory->createSetUpMethod([$assign]);
}
/**
* This is already checked on construction of object
*/
private function removeSelfTypeMethod(Class_ $class, ObjectType $testedObjectType): Class_
{
foreach ($class->getMethods() as $classMethod) {
$classMethodStmts = (array) $classMethod->stmts;
if (count($classMethodStmts) !== 1) {
continue;
}
$innerClassMethodStmt = $this->resolveFirstNonExpressionStmt($classMethodStmts);
if (! $innerClassMethodStmt instanceof MethodCall) {
continue;
}
if (! $this->isName($innerClassMethodStmt->name, 'shouldHaveType')) {
continue;
}
if (! isset($innerClassMethodStmt->args[0])) {
continue;
}
if (! $innerClassMethodStmt->args[0] instanceof Arg) {
continue;
}
// not the tested type
if (! $this->valueResolver->isValue(
$innerClassMethodStmt->args[0]->value,
$testedObjectType->getClassName()
)) {
continue;
}
// remove it
$this->removeNodeFromStatements($class, $classMethod);
}
return $class;
}
/**
* @param Stmt[] $stmts
*/
private function resolveFirstNonExpressionStmt(array $stmts): ?Node
{
if (! isset($stmts[0])) {
return null;
}
$firstStmt = $stmts[0];
if ($firstStmt instanceof Expression) {
return $firstStmt->expr;
}
return $firstStmt;
}
}

View File

@ -1,87 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\Class_;
use Nette\Utils\Strings;
use PhpParser\Node;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\Util\StringUtils;
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition;
/**
* @changelog https://gnugat.github.io/2015/09/23/phpunit-with-phpspec.html
*
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Class_\RenameSpecFileToTestFileRector\RenameSpecFileToTestFileRectorTest
*/
final class RenameSpecFileToTestFileRector extends AbstractRector
{
/**
* @var string
* @see https://regex101.com/r/r1VkPt/1
*/
private const SPEC_REGEX = '#\/spec\/#';
/**
* @var string
* @see https://regex101.com/r/WD4U43/1
*/
private const SPEC_SUFFIX_REGEX = '#Spec\.php$#';
public function getRuleDefinition(): RuleDefinition
{
return new RuleDefinition(
'Rename "*Spec.php" file to "*Test.php" file',
[
new CodeSample(
<<<'CODE_SAMPLE'
// tests/SomeSpec.php
CODE_SAMPLE
,
<<<'CODE_SAMPLE'
// tests/SomeTest.php
CODE_SAMPLE
),
]
);
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Class_::class];
}
/**
* @param Class_ $node
*/
public function refactor(Node $node): ?Node
{
$smartFileInfo = $this->file->getSmartFileInfo();
$oldPathname = $smartFileInfo->getPathname();
// ends with Spec.php
if (! StringUtils::isMatch($oldPathname, self::SPEC_SUFFIX_REGEX)) {
return null;
}
$newPathName = $this->createPathName($oldPathname);
$this->removedAndAddedFilesCollector->addMovedFile($this->file, $newPathName);
return null;
}
private function createPathName(string $oldRealPath): string
{
// suffix
$newRealPath = Strings::replace($oldRealPath, self::SPEC_SUFFIX_REGEX, 'Test.php');
// directory
return Strings::replace($newRealPath, self::SPEC_REGEX, '/tests/');
}
}

View File

@ -1,251 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\MethodCall;
use PhpParser\Comment\Doc;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\ClassConstFetch;
use PhpParser\Node\Expr\Error;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Name;
use PhpParser\Node\Param;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use PhpParser\Node\Stmt\ClassMethod;
use PhpParser\Node\Stmt\Expression;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\Core\Php\TypeAnalyzer;
use Rector\NodeTypeResolver\Node\AttributeKey;
use Rector\PhpSpecToPHPUnit\PhpSpecMockCollector;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
/**
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class PhpSpecMocksToPHPUnitMocksRector extends AbstractPhpSpecToPHPUnitRector
{
public function __construct(
private readonly PhpSpecMockCollector $phpSpecMockCollector,
private readonly TypeAnalyzer $typeAnalyzer
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [ClassMethod::class, MethodCall::class];
}
/**
* @param ClassMethod|MethodCall $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isInPhpSpecBehavior($node)) {
return null;
}
if ($node instanceof ClassMethod) {
// public = tests, protected = internal, private = own (no framework magic)
if ($node->isPrivate()) {
return null;
}
$this->processMethodParamsToMocks($node);
return $node;
}
return $this->processMethodCall($node);
}
private function processMethodParamsToMocks(ClassMethod $classMethod): void
{
// remove params and turn them to instances
$assigns = [];
foreach ($classMethod->params as $param) {
if (! $param->type instanceof Name) {
throw new ShouldNotHappenException();
}
$createMockCall = $this->createCreateMockCall($param, $param->type);
if ($createMockCall !== null) {
$assigns[] = $createMockCall;
}
}
// remove all params
$classMethod->params = [];
$classMethod->stmts = array_merge($assigns, (array) $classMethod->stmts);
}
private function processMethodCall(MethodCall $methodCall): ?MethodCall
{
if (! $this->isName($methodCall->name, 'shouldBeCalled')) {
return null;
}
if (! $methodCall->var instanceof MethodCall) {
throw new ShouldNotHappenException();
}
$mockMethodName = $this->getName($methodCall->var->name);
if ($mockMethodName === null) {
throw new ShouldNotHappenException();
}
$arg = $methodCall->var->args[0] ?? null;
$expectedArg = $arg instanceof Arg ? $arg->value : null;
$methodCall->var->name = new Identifier('expects');
$thisOnceMethodCall = $this->nodeFactory->createLocalMethodCall('atLeastOnce');
$methodCall->var->args = [new Arg($thisOnceMethodCall)];
$methodCall->name = new Identifier('method');
$methodCall->args = [new Arg(new String_($mockMethodName))];
if ($expectedArg !== null) {
return $this->appendWithMethodCall($methodCall, $expectedArg);
}
return $methodCall;
}
/**
* Variable or property fetch, based on number of present params in whole class
*/
private function createCreateMockCall(Param $param, Name $name): ?Expression
{
$class = $this->betterNodeFinder->findParentType($param, Class_::class);
if (! $class instanceof Class_) {
return null;
}
$classMocks = $this->phpSpecMockCollector->resolveClassMocksFromParam($class);
$variable = $this->getName($param->var);
$classMethod = $this->betterNodeFinder->findParentType($param, ClassMethod::class);
if (! $classMethod instanceof ClassMethod) {
throw new ShouldNotHappenException();
}
$methodName = $this->nodeNameResolver->getName($classMethod);
$methodsWithWThisMock = $classMocks[$variable];
if ($param->var instanceof Error) {
return null;
}
// single use: "$mock = $this->createMock()"
if (! $this->phpSpecMockCollector->isVariableMockInProperty($class, $param->var)) {
return $this->createNewMockVariableAssign($param, $name);
}
$reversedMethodsWithThisMock = array_flip($methodsWithWThisMock);
// first use of many: "$this->mock = $this->createMock()"
if ($reversedMethodsWithThisMock[$methodName] === 0) {
return $this->createPropertyFetchMockVariableAssign($param, $name);
}
return null;
}
private function appendWithMethodCall(MethodCall $methodCall, Expr $expr): MethodCall
{
$withMethodCall = new MethodCall($methodCall, 'with');
if ($expr instanceof StaticCall) {
if ($this->isName($expr->class, '*Argument')) {
if ($this->isName($expr->name, 'any')) {
// no added value having this method
return $methodCall;
}
if ($this->isName($expr->name, 'type')) {
$expr = $this->createIsTypeOrIsInstanceOf($expr);
}
}
} else {
$newExpr = $this->nodeFactory->createLocalMethodCall('equalTo');
$newExpr->args = [new Arg($expr)];
$expr = $newExpr;
}
$withMethodCall->args = [new Arg($expr)];
return $withMethodCall;
}
private function createNewMockVariableAssign(Param $param, Name $name): Expression
{
$methodCall = $this->nodeFactory->createLocalMethodCall('createMock');
$methodCall->args[] = new Arg(new ClassConstFetch($name, 'class'));
$assign = new Assign($param->var, $methodCall);
$assignExpression = new Expression($assign);
// add @var doc comment
$varDoc = $this->createMockVarDoc($param, $name);
$assignExpression->setDocComment(new Doc($varDoc));
return $assignExpression;
}
private function createPropertyFetchMockVariableAssign(Param $param, Name $name): Expression
{
$variable = $this->getName($param->var);
if ($variable === null) {
throw new ShouldNotHappenException();
}
$propertyFetch = new PropertyFetch(new Variable('this'), $variable);
$methodCall = $this->nodeFactory->createLocalMethodCall('createMock');
$methodCall->args[] = new Arg(new ClassConstFetch($name, 'class'));
$assign = new Assign($propertyFetch, $methodCall);
return new Expression($assign);
}
private function createIsTypeOrIsInstanceOf(StaticCall $staticCall): MethodCall
{
$args = $staticCall->args;
$type = $this->valueResolver->getValue($args[0]->value);
$name = $this->typeAnalyzer->isPhpReservedType($type) ? 'isType' : 'isInstanceOf';
return $this->nodeFactory->createLocalMethodCall($name, $args);
}
private function createMockVarDoc(Param $param, Name $name): string
{
$paramType = (string) $name->getAttribute(AttributeKey::ORIGINAL_NAME, $name);
$variableName = $this->getName($param->var);
if ($variableName === null) {
throw new ShouldNotHappenException();
}
return sprintf(
'/** @var %s|\%s $%s */',
$paramType,
'PHPUnit\Framework\MockObject\MockObject',
$variableName
);
}
}

View File

@ -1,300 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Arg;
use PhpParser\Node\Expr\ArrayDimFetch;
use PhpParser\Node\Expr\Assign;
use PhpParser\Node\Expr\Clone_;
use PhpParser\Node\Expr\FuncCall;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Identifier;
use PhpParser\Node\Scalar\String_;
use PhpParser\Node\Stmt\Class_;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\PhpSpecToPHPUnit\MatchersManipulator;
use Rector\PhpSpecToPHPUnit\Naming\PhpSpecRenaming;
use Rector\PhpSpecToPHPUnit\NodeFactory\AssertMethodCallFactory;
use Rector\PhpSpecToPHPUnit\NodeFactory\BeConstructedWithAssignFactory;
use Rector\PhpSpecToPHPUnit\NodeFactory\DuringMethodCallFactory;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
/**
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class PhpSpecPromisesToPHPUnitAssertRector extends AbstractPhpSpecToPHPUnitRector
{
/**
* @changelog https://github.com/phpspec/phpspec/blob/master/src/PhpSpec/Wrapper/Subject.php
*
* @changelog https://phpunit.readthedocs.io/en/8.0/assertions.html
* @var array<string, string[]>
*/
private const NEW_METHOD_TO_OLD_METHODS = [
'assertInstanceOf' => ['shouldBeAnInstanceOf', 'shouldHaveType', 'shouldReturnAnInstanceOf'],
'assertSame' => ['shouldBe', 'shouldReturn'],
'assertNotSame' => ['shouldNotBe', 'shouldNotReturn'],
'assertCount' => ['shouldHaveCount'],
'assertEquals' => ['shouldBeEqualTo', 'shouldEqual'],
'assertNotEquals' => ['shouldNotBeEqualTo'],
'assertContains' => ['shouldContain'],
'assertNotContains' => ['shouldNotContain'],
// types
'assertIsIterable' => ['shouldBeArray'],
'assertIsNotIterable' => ['shouldNotBeArray'],
'assertIsString' => ['shouldBeString'],
'assertIsNotString' => ['shouldNotBeString'],
'assertIsBool' => ['shouldBeBool', 'shouldBeBoolean'],
'assertIsNotBool' => ['shouldNotBeBool', 'shouldNotBeBoolean'],
'assertIsCallable' => ['shouldBeCallable'],
'assertIsNotCallable' => ['shouldNotBeCallable'],
'assertIsFloat' => ['shouldBeDouble', 'shouldBeFloat'],
'assertIsNotFloat' => ['shouldNotBeDouble', 'shouldNotBeFloat'],
'assertIsInt' => ['shouldBeInt', 'shouldBeInteger'],
'assertIsNotInt' => ['shouldNotBeInt', 'shouldNotBeInteger'],
'assertIsNull' => ['shouldBeNull'],
'assertIsNotNull' => ['shouldNotBeNull'],
'assertIsNumeric' => ['shouldBeNumeric'],
'assertIsNotNumeric' => ['shouldNotBeNumeric'],
'assertIsObject' => ['shouldBeObject'],
'assertIsNotObject' => ['shouldNotBeObject'],
'assertIsResource' => ['shouldBeResource'],
'assertIsNotResource' => ['shouldNotBeResource'],
'assertIsScalar' => ['shouldBeScalar'],
'assertIsNotScalar' => ['shouldNotBeScalar'],
'assertNan' => ['shouldBeNan'],
'assertFinite' => ['shouldBeFinite', 'shouldNotBeFinite'],
'assertInfinite' => ['shouldBeInfinite', 'shouldNotBeInfinite'],
];
/**
* @var string
*/
private const THIS = 'this';
private ?string $testedClass = null;
private bool $isPrepared = false;
/**
* @var string[]
*/
private array $matchersKeys = [];
private ?PropertyFetch $testedObjectPropertyFetch = null;
public function __construct(
private readonly MatchersManipulator $matchersManipulator,
private readonly PhpSpecRenaming $phpSpecRenaming,
private readonly AssertMethodCallFactory $assertMethodCallFactory,
private readonly BeConstructedWithAssignFactory $beConstructedWithAssignFactory,
private readonly DuringMethodCallFactory $duringMethodCallFactory
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
$this->isPrepared = false;
$this->matchersKeys = [];
if (! $this->isInPhpSpecBehavior($node)) {
return null;
}
if ($this->isName($node->name, 'getWrappedObject')) {
return $node->var;
}
if ($this->isName($node->name, 'during')) {
return $this->duringMethodCallFactory->create($node, $this->getTestedObjectPropertyFetch());
}
if ($this->isName($node->name, 'duringInstantiation')) {
return $this->processDuringInstantiation($node);
}
// skip reserved names
if ($this->isNames($node->name, ['getMatchers', 'expectException', 'assert*'])) {
return null;
}
$this->prepareMethodCall($node);
if ($this->isName($node->name, 'beConstructed*')) {
return $this->beConstructedWithAssignFactory->create(
$node,
$this->getTestedClass(),
$this->getTestedObjectPropertyFetch()
);
}
$this->processMatchersKeys($node);
$args = $node->args;
foreach (self::NEW_METHOD_TO_OLD_METHODS as $newMethod => $oldMethods) {
if (! $this->isNames($node->name, $oldMethods)) {
continue;
}
return $this->assertMethodCallFactory->createAssertMethod(
$newMethod,
$node->var,
$args[0]->value ?? null,
$this->getTestedObjectPropertyFetch()
);
}
if ($this->shouldSkip($node)) {
return null;
}
if ($this->isName($node->name, 'clone')) {
return new Clone_($this->getTestedObjectPropertyFetch());
}
$methodName = $this->getName($node->name);
if ($methodName === null) {
return null;
}
/** @var Class_ $classLike */
$classLike = $this->betterNodeFinder->findParentType($node, Class_::class);
$classMethod = $classLike->getMethod($methodName);
// it's a method call, skip
if ($classMethod !== null) {
return null;
}
// direct PHPUnit method calls, no need to call on property
if (in_array($methodName, ['atLeastOnce', 'equalTo', 'isInstanceOf', 'isType'], true)) {
return $node;
}
$node->var = $this->getTestedObjectPropertyFetch();
return $node;
}
private function processDuringInstantiation(MethodCall $methodCall): MethodCall
{
/** @var MethodCall $parentMethodCall */
$parentMethodCall = $methodCall->var;
$parentMethodCall->name = new Identifier('expectException');
return $parentMethodCall;
}
private function prepareMethodCall(MethodCall $methodCall): void
{
if ($this->isPrepared) {
return;
}
$class = $this->betterNodeFinder->findParentType($methodCall, Class_::class);
if (! $class instanceof Class_) {
return;
}
$className = $this->getName($class);
if (! is_string($className)) {
return;
}
$this->matchersKeys = $this->matchersManipulator->resolveMatcherNamesFromClass($class);
$this->testedClass = $this->phpSpecRenaming->resolveTestedClass($class);
$this->testedObjectPropertyFetch = $this->createTestedObjectPropertyFetch($class);
$this->isPrepared = true;
}
private function getTestedObjectPropertyFetch(): PropertyFetch
{
if ($this->testedObjectPropertyFetch === null) {
throw new ShouldNotHappenException();
}
return $this->testedObjectPropertyFetch;
}
private function getTestedClass(): string
{
if ($this->testedClass === null) {
throw new ShouldNotHappenException();
}
return $this->testedClass;
}
/**
* @changelog https://johannespichler.com/writing-custom-phpspec-matchers/
*/
private function processMatchersKeys(MethodCall $methodCall): void
{
foreach ($this->matchersKeys as $matcherKey) {
if (! $this->isName($methodCall->name, 'should' . ucfirst($matcherKey))) {
continue;
}
if (! $methodCall->var instanceof MethodCall) {
continue;
}
// 1. assign callable to variable
$thisGetMatchers = $this->nodeFactory->createMethodCall(self::THIS, 'getMatchers');
$arrayDimFetch = new ArrayDimFetch($thisGetMatchers, new String_($matcherKey));
$matcherCallableVariable = new Variable('matcherCallable');
$assign = new Assign($matcherCallableVariable, $arrayDimFetch);
// 2. call it on result
$funcCall = new FuncCall($matcherCallableVariable);
$funcCall->args = $methodCall->args;
$methodCall->name = $methodCall->var->name;
$methodCall->var = $this->getTestedObjectPropertyFetch();
$methodCall->args = [];
$funcCall->args[] = new Arg($methodCall);
$this->nodesToAddCollector->addNodesAfterNode([$assign, $funcCall], $methodCall);
$this->removeNode($methodCall);
return;
}
}
private function shouldSkip(MethodCall $methodCall): bool
{
if (! $methodCall->var instanceof Variable) {
return true;
}
if (! $this->nodeNameResolver->isName($methodCall->var, self::THIS)) {
return true;
}
// skip "createMock" method
return $this->isName($methodCall->name, 'createMock');
}
private function createTestedObjectPropertyFetch(Class_ $class): PropertyFetch
{
$propertyName = $this->phpSpecRenaming->resolveObjectPropertyName($class);
return new PropertyFetch(new Variable(self::THIS), $propertyName);
}
}

View File

@ -1,59 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\PhpSpecToPHPUnit\Rector\Variable;
use PhpParser\Node;
use PhpParser\Node\Expr\PropertyFetch;
use PhpParser\Node\Expr\Variable;
use PhpParser\Node\Stmt\Class_;
use Rector\PhpSpecToPHPUnit\PhpSpecMockCollector;
use Rector\PhpSpecToPHPUnit\Rector\AbstractPhpSpecToPHPUnitRector;
/**
* $mock->call()
*
* $this->mock->call()
*
* @see \Rector\Tests\PhpSpecToPHPUnit\Rector\Variable\PhpSpecToPHPUnitRector\PhpSpecToPHPUnitRectorTest
*/
final class MockVariableToPropertyFetchRector extends AbstractPhpSpecToPHPUnitRector
{
public function __construct(
private readonly PhpSpecMockCollector $phpSpecMockCollector
) {
}
/**
* @return array<class-string<Node>>
*/
public function getNodeTypes(): array
{
return [Variable::class];
}
/**
* @param Variable $node
*/
public function refactor(Node $node): ?Node
{
$class = $this->betterNodeFinder->findParentType($node, Class_::class);
if (! $class instanceof Class_) {
return null;
}
if (! $this->isInPhpSpecBehavior($class)) {
return null;
}
if (! $this->phpSpecMockCollector->isVariableMockInProperty($class, $node)) {
return null;
}
/** @var string $variableName */
$variableName = $this->getName($node);
return new PropertyFetch(new Variable('this'), $variableName);
}
}

View File

@ -1,69 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Php;
use Nette\Utils\Strings;
use Rector\Core\ValueObject\PhpVersionFeature;
final class TypeAnalyzer
{
/**
* @var string[]
*/
private const EXTRA_TYPES = ['object'];
/**
* @var string
* @see https://regex101.com/r/57HGpC/1
*/
private const SQUARE_BRACKET_REGEX = '#(\[\])+$#';
/**
* @var string[]
*/
private array $phpSupportedTypes = [
'string',
'bool',
'int',
'null',
'array',
'false',
'true',
'mixed',
'iterable',
'float',
'self',
'parent',
'callable',
'void',
];
public function __construct(PhpVersionProvider $phpVersionProvider)
{
if ($phpVersionProvider->isAtLeastPhpVersion(PhpVersionFeature::OBJECT_TYPE)) {
$this->phpSupportedTypes[] = 'object';
}
}
public function isPhpReservedType(string $type): bool
{
$types = explode('|', $type);
$reservedTypes = array_merge($this->phpSupportedTypes, self::EXTRA_TYPES);
foreach ($types as $type) {
$type = strtolower($type);
// remove [] from arrays
$type = Strings::replace($type, self::SQUARE_BRACKET_REGEX, '');
if (in_array($type, $reservedTypes, true)) {
return true;
}
}
return false;
}
}