Skip to content

Commit

Permalink
SpecificAssertContainsWithoutIdentityRector: add phpunit 9 compatibil…
Browse files Browse the repository at this point in the history
…ity rector

As of sebastianbergmann/phpunit#3426 assertContains() and assertNotContains() will perform strict comparisons starting with PHPUnit 9 where non-strict comparisons were performed in PHPUnit 8 and earlier; assertContainsEqual() and assertNotContainsEqual() should be used instead if needed non-strict comparison
  • Loading branch information
nightlinus committed Mar 15, 2020
1 parent 3b68551 commit e2b5ff1
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 1 deletion.
1 change: 1 addition & 0 deletions config/set/phpunit/phpunit90.yaml
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
services:
Rector\PHPUnit\Rector\Class_\TestListenerToHooksRector: null
Rector\PHPUnit\Rector\MethodCall\ExplicitPhpErrorApiRector: null
Rector\PHPUnit\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector: null
28 changes: 27 additions & 1 deletion docs/AllRectorsOverview.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# All 464 Rectors Overview
# All 465 Rectors Overview

- [Projects](#projects)
- [General](#general)
Expand Down Expand Up @@ -5677,6 +5677,32 @@ Change assertContains()/assertNotContains() method to new string and iterable al

<br>

### `SpecificAssertContainsWithoutIdentityRector`

- class: [`Rector\PHPUnit\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector`](/../master/rules/phpunit/src/Rector/MethodCall/SpecificAssertContainsWithoutIdentityRector.php)
- [test fixtures](/../master/rules/phpunit/tests/Rector/MethodCall/SpecificAssertContainsWithoutIdentityRector/Fixture)

Change assertContains()/assertNotContains() with non-strict comparison to new specific alternatives

```diff
<?php

-final class SomeTest extends \PHPUnit\Framework\TestCase
+final class SomeTest extends TestCase
{
public function test()
{
$objects = [ new \stdClass(), new \stdClass(), new \stdClass() ];
- $this->assertContains(new \stdClass(), $objects, 'message', false, false);
- $this->assertNotContains(new \stdClass(), $objects, 'message', false, false);
+ $this->assertContainsEquals(new \stdClass(), $objects, 'message');
+ $this->assertNotContainsEquals(new \stdClass(), $objects, 'message');
}
}
```

<br>

### `SpecificAssertInternalTypeRector`

- class: [`Rector\PHPUnit\Rector\MethodCall\SpecificAssertInternalTypeRector`](/../master/rules/phpunit/src/Rector/MethodCall/SpecificAssertInternalTypeRector.php)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?php

declare(strict_types=1);

namespace Rector\PHPUnit\Rector\MethodCall;

use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use PhpParser\Node\Expr\StaticCall;
use PhpParser\Node\Identifier;
use PHPStan\Type\StringType;
use Rector\Core\Rector\AbstractPHPUnitRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;

/**
* @see https://github.com/sebastianbergmann/phpunit/issues/3426
* @see \Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\SpecificAssertContainsWithoutIdentityRectorTest
*/
final class SpecificAssertContainsWithoutIdentityRector extends AbstractPHPUnitRector
{
/**
* @var string[][]
*/
private const OLD_METHODS_NAMES_TO_NEW_NAMES = [
'string' => [
'assertContains' => 'assertContainsEquals',
'assertNotContains' => 'assertNotContainsEquals',
],
];

public function getDefinition(): RectorDefinition
{
return new RectorDefinition(
'Change assertContains()/assertNotContains() with non-strict comparison to new specific alternatives',
[
new CodeSample(
<<<'PHP'
<?php
final class SomeTest extends \PHPUnit\Framework\TestCase
{
public function test()
{
$objects = [ new \stdClass(), new \stdClass(), new \stdClass() ];
$this->assertContains(new \stdClass(), $objects, 'message', false, false);
$this->assertNotContains(new \stdClass(), $objects, 'message', false, false);
}
}
PHP
,
<<<'PHP'
<?php
final class SomeTest extends TestCase
{
public function test()
{
$objects = [ new \stdClass(), new \stdClass(), new \stdClass() ];
$this->assertContainsEquals(new \stdClass(), $objects, 'message');
$this->assertNotContainsEquals(new \stdClass(), $objects, 'message');
}
}
PHP
),
]
);
}

/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class, StaticCall::class];
}

/**
* @param MethodCall|StaticCall $node
*/
public function refactor(Node $node): ?Node
{
if (! $this->isPHPUnitMethodNames($node, ['assertContains', 'assertNotContains'])) {
return null;
}

//when second argument is string: do nothing
if ($this->isStaticType($node->args[1]->value, StringType::class)) {
return null;
}

//when less then 5 arguments given: do nothing
if (! isset($node->args[4]) || $node->args[4]->value === null) {
return null;
}

//when 5th argument check identity is true: do nothing
if ($this->isValue($node->args[4]->value, true)) {
return null;
}

/* here we search for element of array without identity check and we can replace functions */
$methodName = $this->getName($node->name);

$node->name = new Identifier(self::OLD_METHODS_NAMES_TO_NEW_NAMES['string'][$methodName]);
unset($node->args[3], $node->args[4]);

return $node;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\Fixture;

use PHPUnit\Framework\TestCase;
use stdClass;

final class CheckIdentity extends TestCase
{
public function test()
{
$objects = [ new stdClass(), new stdClass(), new stdClass() ];
$this->assertContains(new stdClass(), $objects, 'message', false, true);
$this->assertNotContains(new stdClass(), $objects, 'message', false, true);
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\Fixture;

use PHPUnit\Framework\TestCase;
use stdClass;

final class SomeTest extends TestCase
{
public function test()
{
$objects = [ new stdClass(), new stdClass(), new stdClass() ];
$this->assertContains(new stdClass(), $objects, 'message', false, false);
$this->assertNotContains(new stdClass(), $objects, 'message', false, false);
}
}

?>
-----
<?php

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\Fixture;

use PHPUnit\Framework\TestCase;
use stdClass;

final class SomeTest extends TestCase
{
public function test()
{
$objects = [ new stdClass(), new stdClass(), new stdClass() ];
$this->assertContainsEquals(new stdClass(), $objects, 'message');
$this->assertNotContainsEquals(new stdClass(), $objects, 'message');
}
}

?>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\Fixture;

use PHPUnit\Framework\TestCase;
use stdClass;

final class PartialArguments extends TestCase
{
public function test()
{
$objects = [ new stdClass(), new stdClass(), new stdClass() ];
$this->assertContains(new stdClass(), $objects, 'message', false);
$this->assertNotContains(new stdClass(), $objects, 'message', false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector\Fixture;

use PHPUnit\Framework\TestCase;

final class NoChangeOnStrings extends TestCase
{
public function test()
{
$this->assertContains('foo', 'foo bar', 'message', false, false);
$this->assertNotContains('foo', 'foo bar', 'message', false, false);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace Rector\PHPUnit\Tests\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector;

use Iterator;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;

use Rector\PHPUnit\Rector\MethodCall\SpecificAssertContainsWithoutIdentityRector;

final class SpecificAssertContainsWithoutIdentityRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(string $file): void
{
$this->doTestFile($file);
}

public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}

protected function getRectorClass(): string
{
return SpecificAssertContainsWithoutIdentityRector::class;
}
}

0 comments on commit e2b5ff1

Please sign in to comment.