Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#5 #6 detected property/method visibility/existence change #30

Merged
merged 5 commits into from
Apr 15, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
#6 implemented MethodVisibilityReduced comparator
  • Loading branch information
Ocramius committed Apr 15, 2018
commit d7b77a5d0d50e410b88da1fcfc5c272fb75e0a12
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<?php

declare(strict_types=1);

namespace Roave\ApiCompare\Comparator\BackwardsCompatibility\ClassBased;

use Assert\Assert;
use Roave\ApiCompare\Change;
use Roave\ApiCompare\Changes;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflection\ReflectionMethod;

final class MethodVisibilityReduced implements ClassBased
{
private const VISIBILITY_PRIVATE = 'private';

private const VISIBILITY_PROTECTED = 'protected';

private const VISIBILITY_PUBLIC = 'public';

public function compare(ReflectionClass $fromClass, ReflectionClass $toClass) : Changes
{
Assert::that($fromClass->getName())->same($toClass->getName());

$visibilitiesFrom = $this->methodVisibilities($fromClass);
$visibilitiesTo = $this->methodVisibilities($toClass);

$affectedVisibilities = array_filter(
array_combine(
array_keys(array_intersect_key($visibilitiesFrom, $visibilitiesTo)),
array_map(
function (string $visibilityFrom, string $visibilityTo) : array {
return [$visibilityFrom, $visibilityTo];
},
array_intersect_key($visibilitiesFrom, $visibilitiesTo),
array_intersect_key($visibilitiesTo, $visibilitiesFrom)
)
),
function (array $visibilities) : bool {
// Note: works because public, protected and private are (luckily) sortable
return $visibilities[0] > $visibilities[1];
}
);

return Changes::fromArray(array_values(array_map(function (string $methodName, array $visibilities) use (
$fromClass
) : Change {
return Change::changed(
sprintf(
'Method %s#%s() changed visibility from %s to %s',
$fromClass->getName(),
$fromClass->getMethod($methodName)->getName(),
$visibilities[0],
$visibilities[1]
),
true
);
}, array_keys($affectedVisibilities), $affectedVisibilities)));
}

/** @return string[] */
private function methodVisibilities(ReflectionClass $class) : array
{
$methods = $class->getMethods();

return array_combine(
array_map(function (ReflectionMethod $method) : string {
return $method->getName();
}, $methods),
array_map(function (ReflectionMethod $method) : string {
if ($method->isPublic()) {
return self::VISIBILITY_PUBLIC;
}

if ($method->isProtected()) {
return self::VISIBILITY_PROTECTED;
}

return self::VISIBILITY_PRIVATE;
}, $methods)
);
}
}
35 changes: 35 additions & 0 deletions test/asset/api/new/ClassWithMethodVisibilitiesBeingChanged.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);

namespace RoaveTestAsset;

class ClassWithMethodVisibilitiesBeingChanged
{
public function publicMaintainedPublic()
{
}
protected function publicReducedToProtected()
{
}
private function publicReducedToPrivate()
{
}
protected function protectedMaintainedProtected()
{
}
private function protectedReducedToPrivate()
{
}
public function protectedIncreasedToPublic()
{
}
private function privateMaintainedPrivate()
{
}
protected function privateIncreasedToProtected()
{
}
public function privateIncreasedToPublic()
{
}
}
35 changes: 35 additions & 0 deletions test/asset/api/old/ClassWithMethodVisibilitiesBeingChanged.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);

namespace RoaveTestAsset;

class ClassWithMethodVisibilitiesBeingChanged
{
public function publicMaintainedPublic()
{
}
public function publicReducedToProtected()
{
}
public function publicReducedToPrivate()
{
}
protected function protectedMaintainedProtected()
{
}
protected function protectedReducedToPrivate()
{
}
protected function protectedIncreasedToPublic()
{
}
private function privateMaintainedPrivate()
{
}
private function privateIncreasedToProtected()
{
}
private function privateIncreasedToPublic()
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php

declare(strict_types=1);

namespace RoaveTest\ApiCompare\Comparator\BackwardsCompatibility\ClassBased;

use PHPUnit\Framework\TestCase;
use Roave\ApiCompare\Change;
use Roave\ApiCompare\Comparator\BackwardsCompatibility\ClassBased\MethodVisibilityReduced;
use Roave\ApiCompare\Comparator\BackwardsCompatibility\ClassBased\PropertyVisibilityReduced;
use Roave\BetterReflection\BetterReflection;
use Roave\BetterReflection\Reflection\ReflectionClass;
use Roave\BetterReflection\Reflector\ClassReflector;
use Roave\BetterReflection\SourceLocator\Type\SingleFileSourceLocator;

final class MethodVisibilityReducedTest extends TestCase
{
/**
* @dataProvider classesToBeTested
*
* @param string[] $expectedMessages
*/
public function testDiffs(
ReflectionClass $fromClass,
ReflectionClass $toClass,
array $expectedMessages
) : void {
$changes = (new MethodVisibilityReduced())
->compare($fromClass, $toClass);

self::assertSame(
$expectedMessages,
array_map(function (Change $change) : string {
return $change->__toString();
}, iterator_to_array($changes))
);
}

/** @return (string[]|ReflectionClass)[][] */
public function classesToBeTested() : array
{
$locator = (new BetterReflection())->astLocator();

return [
'RoaveTestAsset\\ClassWithPropertyVisibilitiesBeingChanged' => [
(new ClassReflector(new SingleFileSourceLocator(
__DIR__ . '/../../../../asset/api/old/ClassWithMethodVisibilitiesBeingChanged.php',
$locator
)))->reflect('RoaveTestAsset\\ClassWithMethodVisibilitiesBeingChanged'),
(new ClassReflector(new SingleFileSourceLocator(
__DIR__ . '/../../../../asset/api/new/ClassWithMethodVisibilitiesBeingChanged.php',
$locator
)))->reflect('RoaveTestAsset\\ClassWithMethodVisibilitiesBeingChanged'),
[
'[BC] CHANGED: Method RoaveTestAsset\ClassWithMethodVisibilitiesBeingChanged#publicReducedToProtected() changed visibility from public to protected',
'[BC] CHANGED: Method RoaveTestAsset\ClassWithMethodVisibilitiesBeingChanged#publicReducedToPrivate() changed visibility from public to private',
'[BC] CHANGED: Method RoaveTestAsset\ClassWithMethodVisibilitiesBeingChanged#protectedReducedToPrivate() changed visibility from protected to private',
],
],
];
}
}