From 83b3879dfcebe5e4fce6134cb454f0494ae7a51f Mon Sep 17 00:00:00 2001 From: Marcelo Rocha Date: Tue, 15 Oct 2024 12:14:07 -0300 Subject: [PATCH] Only chek if error starts with a text to avoid issues when the last part change based on cakephp version. --- src/Constraint/ArrayOfStringStartsWith.php | 86 +++++++++++++++++++ .../AnalyseCheckLineStartsWithTrait.php | 39 +++++++++ ...ddAssociationMatchOptionsTypesRuleTest.php | 27 +++--- 3 files changed, 136 insertions(+), 16 deletions(-) create mode 100644 src/Constraint/ArrayOfStringStartsWith.php create mode 100644 src/Rule/Traits/AnalyseCheckLineStartsWithTrait.php diff --git a/src/Constraint/ArrayOfStringStartsWith.php b/src/Constraint/ArrayOfStringStartsWith.php new file mode 100644 index 0000000..68e7a9b --- /dev/null +++ b/src/Constraint/ArrayOfStringStartsWith.php @@ -0,0 +1,86 @@ + + */ + private readonly array $actual; + /** + * @var array + */ + private array $result = []; + /** + * @var array + */ + private array $notExpected = []; + + /** + * @param array $actual + */ + public function __construct(array $actual) + { + $this->actual = $actual; + } + + /** + * @return string + */ + public function toString(): string + { + return 'a list of errors'; + } + + /** + * @param mixed $other + * @return bool + */ + protected function matches(mixed $other): bool + { + $result = true; + $this->notExpected = $this->actual; + assert(is_array($other)); + foreach ($other as $key => $error) { + if (!isset($this->actual[$key])) { + $this->result[$key] = ['expected' => $error, 'type' => 'missing', 'actual' => null]; + $result = false; + continue; + } + unset($this->notExpected[$key]); + if (!str_starts_with($this->actual[$key], $error)) { + $this->result[$key] = ['expected' => $error, 'type' => 'not-equal', 'actual' => $this->actual[$key]]; + $result = false; + } + } + + return $result && empty($this->notExpected); + } + + /** + * @param mixed $other + * @return string + */ + protected function failureDescription(mixed $other): string + { + $text = "\n"; + foreach ($this->result as $item) { + if ($item['type'] === 'not-equal') { + $text .= sprintf(" -%s \n +%s \n", $item['expected'], $item['actual']); + } + if ($item['type'] === 'missing') { + $text .= sprintf(" -%s \n", $item['expected']); + } + } + + foreach ($this->notExpected as $item) { + $text .= sprintf(" \n +%s", $item); + } + + return $text; + } +} diff --git a/src/Rule/Traits/AnalyseCheckLineStartsWithTrait.php b/src/Rule/Traits/AnalyseCheckLineStartsWithTrait.php new file mode 100644 index 0000000..61a48ec --- /dev/null +++ b/src/Rule/Traits/AnalyseCheckLineStartsWithTrait.php @@ -0,0 +1,39 @@ +gatherAnalyserErrors($files); + $messageText = static function (int $line, string $message): string { + return sprintf('%02d: %s', $line, $message); + }; + $actualErrors = array_map(static function (Error $error) use ($messageText): string { + $line = $error->getLine(); + if ($line === null) { + return $messageText(-1, $error->getMessage()); + } + + return $messageText($line, $error->getMessage()); + }, $actualErrors); + + $expected = array_map(static function (array $item) use ($messageText): string { + return $messageText($item[1], $item[0]); + }, $expected); + $this->assertThat($expected, new ArrayOfStringStartsWith($actualErrors)); + } +} diff --git a/tests/TestCase/Rule/Model/AddAssociationMatchOptionsTypesRuleTest.php b/tests/TestCase/Rule/Model/AddAssociationMatchOptionsTypesRuleTest.php index 778de32..31b0fe1 100644 --- a/tests/TestCase/Rule/Model/AddAssociationMatchOptionsTypesRuleTest.php +++ b/tests/TestCase/Rule/Model/AddAssociationMatchOptionsTypesRuleTest.php @@ -3,8 +3,8 @@ namespace CakeDC\PHPStan\Test\TestCase\Rule\Model; -use Cake\Core\Configure; use CakeDC\PHPStan\Rule\Model\AddAssociationMatchOptionsTypesRule; +use CakeDC\PHPStan\Rule\Traits\AnalyseCheckLineStartsWithTrait; use PHPStan\Rules\Properties\PropertyReflectionFinder; use PHPStan\Rules\Rule; use PHPStan\Rules\RuleLevelHelper; @@ -12,6 +12,8 @@ class AddAssociationMatchOptionsTypesRuleTest extends RuleTestCase { + use AnalyseCheckLineStartsWithTrait; + /** * @return \PHPStan\Rules\Rule */ @@ -38,14 +40,7 @@ protected function getRule(): Rule */ public function testRule(): void { - $messageThrough = 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsToMany with option "through" (Cake\ORM\Table|string|null) does not accept stdClass.'; - if (version_compare(Configure::version(), '5.0.5', '<')) { - $messageThrough = 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsToMany with option "through" (Cake\ORM\Table|string) does not accept stdClass.'; - } - // first argument: path to the example file that contains some errors that should be reported by MyRule - // second argument: an array of expected errors, - // each error consists of the asserted error message, and the asserted error file line - $this->analyse([__DIR__ . '/Fake/FailingRuleItemsTable.php'], [ + $this->analyseCheckLineStartsWith([__DIR__ . '/Fake/FailingRuleItemsTable.php'], [ [ 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsTo with option "className" (string) does not accept false.', 66, @@ -67,12 +62,12 @@ public function testRule(): void 66, ], [ - 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsTo with option "bindingKey" (list|string) does not accept 10.', + 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsTo with option "bindingKey" ', 66, 'Type #1 from the union: 10 is not a list.', ], [ - 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsTo with option "foreignKey" (list|string|false) does not accept 11.', + 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsTo with option "foreignKey" ', 66, 'Type #1 from the union: 11 is not a list.', ], @@ -114,7 +109,7 @@ public function testRule(): void 'Type #1 from the union: Closure(): 10 is not a list.', ], [ - $messageThrough, + 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::belongsToMany with option "through"', 98, ], [ @@ -150,12 +145,12 @@ public function testRule(): void 120, ], [ - 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::hasOne with option "bindingKey" (list|string) does not accept 10.', + 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::hasOne with option "bindingKey" ', 120, 'Type #1 from the union: 10 is not a list.', ], [ - 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::hasOne with option "foreignKey" (list|string|false) does not accept 11.', + 'Call to CakeDC\PHPStan\Test\TestCase\Rule\Model\Fake\FailingRuleItemsTable::hasOne with option "foreignKey" ', 120, 'Type #1 from the union: 11 is not a list.', ], @@ -220,12 +215,12 @@ public function testRule(): void 148, ], [ - 'Call to Cake\ORM\AssociationCollection::load with option "bindingKey" (list|string) does not accept 10.', + 'Call to Cake\ORM\AssociationCollection::load with option "bindingKey" ', 148, 'Type #1 from the union: 10 is not a list.', ], [ - 'Call to Cake\ORM\AssociationCollection::load with option "foreignKey" (list|string|false) does not accept 11.', + 'Call to Cake\ORM\AssociationCollection::load with option "foreignKey" ', 148, 'Type #1 from the union: 11 is not a list.', ],