From bc9da46a0adade08b64f4a09915ba6d853a8507d Mon Sep 17 00:00:00 2001 From: Christian Sciberras Date: Thu, 23 Jan 2025 23:54:53 +0100 Subject: [PATCH 1/2] Update to PHPStan level 3; various fixes --- phpstan.dist.neon | 2 +- .../Gherkin/Loader/AbstractFileLoader.php | 2 +- src/Behat/Gherkin/Loader/DirectoryLoader.php | 6 ++- .../Gherkin/Loader/GherkinFileLoader.php | 8 +++- src/Behat/Gherkin/Loader/YamlFileLoader.php | 8 +++- src/Behat/Gherkin/Node/OutlineNode.php | 12 ++--- src/Behat/Gherkin/Node/TableNode.php | 10 ++--- tests/Behat/Gherkin/Filter/LineFilterTest.php | 13 +++--- .../Gherkin/Filter/LineRangeFilterTest.php | 28 ++++++------ tests/Behat/Gherkin/Filter/TagFilterTest.php | 30 ++++++------- .../Behat/Gherkin/Loader/ArrayLoaderTest.php | 44 ++++++++++--------- tests/Behat/Gherkin/Node/ExampleNodeTest.php | 42 ++++++++++++------ 12 files changed, 116 insertions(+), 89 deletions(-) diff --git a/phpstan.dist.neon b/phpstan.dist.neon index 31f6166b..749a32d9 100644 --- a/phpstan.dist.neon +++ b/phpstan.dist.neon @@ -1,5 +1,5 @@ parameters: - level: 1 + level: 3 paths: - src - tests diff --git a/src/Behat/Gherkin/Loader/AbstractFileLoader.php b/src/Behat/Gherkin/Loader/AbstractFileLoader.php index fa0d2106..ba4c7d1e 100644 --- a/src/Behat/Gherkin/Loader/AbstractFileLoader.php +++ b/src/Behat/Gherkin/Loader/AbstractFileLoader.php @@ -50,7 +50,7 @@ protected function findRelativePath($path) * * @param string $path Relative path * - * @return string + * @return false|string */ protected function findAbsolutePath($path) { diff --git a/src/Behat/Gherkin/Loader/DirectoryLoader.php b/src/Behat/Gherkin/Loader/DirectoryLoader.php index 93f1e60e..1f2ab732 100644 --- a/src/Behat/Gherkin/Loader/DirectoryLoader.php +++ b/src/Behat/Gherkin/Loader/DirectoryLoader.php @@ -44,7 +44,8 @@ public function __construct(Gherkin $gherkin) public function supports($resource) { return is_string($resource) - && is_dir($this->findAbsolutePath($resource)); + && ($path = $this->findAbsolutePath($resource)) !== false + && is_dir($path); } /** @@ -57,6 +58,9 @@ public function supports($resource) public function load($resource) { $path = $this->findAbsolutePath($resource); + if ($path === false) { + throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); + } $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS) diff --git a/src/Behat/Gherkin/Loader/GherkinFileLoader.php b/src/Behat/Gherkin/Loader/GherkinFileLoader.php index 11e0870b..68d40525 100644 --- a/src/Behat/Gherkin/Loader/GherkinFileLoader.php +++ b/src/Behat/Gherkin/Loader/GherkinFileLoader.php @@ -56,8 +56,9 @@ public function setCache(CacheInterface $cache) public function supports($resource) { return is_string($resource) - && is_file($absolute = $this->findAbsolutePath($resource)) - && pathinfo($absolute, PATHINFO_EXTENSION) === 'feature'; + && ($path = $this->findAbsolutePath($resource)) !== false + && is_file($path) + && pathinfo($path, PATHINFO_EXTENSION) === 'feature'; } /** @@ -70,6 +71,9 @@ public function supports($resource) public function load($resource) { $path = $this->findAbsolutePath($resource); + if ($path === false) { + throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); + } if ($this->cache) { if ($this->cache->isFresh($path, filemtime($path))) { diff --git a/src/Behat/Gherkin/Loader/YamlFileLoader.php b/src/Behat/Gherkin/Loader/YamlFileLoader.php index d5e8e2d0..ddfed7d2 100644 --- a/src/Behat/Gherkin/Loader/YamlFileLoader.php +++ b/src/Behat/Gherkin/Loader/YamlFileLoader.php @@ -37,8 +37,9 @@ public function __construct() public function supports($resource) { return is_string($resource) - && is_file($absolute = $this->findAbsolutePath($resource)) - && pathinfo($absolute, PATHINFO_EXTENSION) === 'yml'; + && ($path = $this->findAbsolutePath($resource)) !== false + && is_file($path) + && pathinfo($path, PATHINFO_EXTENSION) === 'yml'; } /** @@ -51,6 +52,9 @@ public function supports($resource) public function load($resource) { $path = $this->findAbsolutePath($resource); + if ($path === false) { + throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); + } $hash = Yaml::parse(file_get_contents($path)); $features = $this->loader->load($hash); diff --git a/src/Behat/Gherkin/Node/OutlineNode.php b/src/Behat/Gherkin/Node/OutlineNode.php index fe7572b9..81899050 100644 --- a/src/Behat/Gherkin/Node/OutlineNode.php +++ b/src/Behat/Gherkin/Node/OutlineNode.php @@ -30,7 +30,7 @@ class OutlineNode implements ScenarioInterface */ private $steps; /** - * @var ExampleTableNode|ExampleTableNode[] + * @var array */ private $tables; /** @@ -52,7 +52,7 @@ class OutlineNode implements ScenarioInterface * @param string|null $title * @param string[] $tags * @param StepNode[] $steps - * @param ExampleTableNode|ExampleTableNode[] $tables + * @param ExampleTableNode|array $tables * @param string $keyword * @param int $line */ @@ -69,11 +69,7 @@ public function __construct( $this->steps = $steps; $this->keyword = $keyword; $this->line = $line; - if (!is_array($tables)) { - $this->tables = [$tables]; - } else { - $this->tables = $tables; - } + $this->tables = is_array($tables) ? $tables : [$tables]; } /** @@ -197,7 +193,7 @@ public function getExamples() /** * Returns examples tables array for the outline. * - * @return ExampleTableNode[] + * @return array */ public function getExampleTables() { diff --git a/src/Behat/Gherkin/Node/TableNode.php b/src/Behat/Gherkin/Node/TableNode.php index f4df6e8f..1b038b3a 100644 --- a/src/Behat/Gherkin/Node/TableNode.php +++ b/src/Behat/Gherkin/Node/TableNode.php @@ -23,14 +23,12 @@ */ class TableNode implements ArgumentInterface, IteratorAggregate { + private array $table; + /** - * @var array - */ - private $table; - /** - * @var int + * @var array */ - private $maxLineLength = []; + private array $maxLineLength = []; /** * Initializes table. diff --git a/tests/Behat/Gherkin/Filter/LineFilterTest.php b/tests/Behat/Gherkin/Filter/LineFilterTest.php index fd7d1a1c..683469b1 100644 --- a/tests/Behat/Gherkin/Filter/LineFilterTest.php +++ b/tests/Behat/Gherkin/Filter/LineFilterTest.php @@ -18,7 +18,7 @@ class LineFilterTest extends FilterTestCase { - public function testIsFeatureMatchFilter() + public function testIsFeatureMatchFilter(): void { $feature = new FeatureNode(null, null, [], null, [], null, null, null, 1); @@ -32,7 +32,7 @@ public function testIsFeatureMatchFilter() $this->assertFalse($filter->isFeatureMatch($feature)); } - public function testIsScenarioMatchFilter() + public function testIsScenarioMatchFilter(): void { $scenario = new ScenarioNode(null, [], [], null, 2); @@ -54,7 +54,7 @@ public function testIsScenarioMatchFilter() $this->assertTrue($filter->isScenarioMatch($outline)); } - public function testFilterFeatureScenario() + public function testFilterFeatureScenario(): void { $filter = new LineFilter(2); $feature = $filter->filterFeature($this->getParsedFeature()); @@ -71,19 +71,20 @@ public function testFilterFeatureScenario() $this->assertCount(0, $scenarios = $feature->getScenarios()); } - public function testFilterFeatureOutline() + public function testFilterFeatureOutline(): void { $filter = new LineFilter(13); $feature = $filter->filterFeature($this->getParsedFeature()); - /* @var OutlineNode[] $scenarios */ $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $this->assertCount(4, $scenarios[0]->getExampleTable()->getRows()); $filter = new LineFilter(20); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $exampleTableNodes = $scenarios[0]->getExampleTables(); $this->assertCount(1, $exampleTableNodes); $this->assertCount(2, $exampleTableNodes[0]->getRows()); @@ -97,6 +98,7 @@ public function testFilterFeatureOutline() $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $exampleTableNodes = $scenarios[0]->getExampleTables(); $this->assertCount(1, $exampleTableNodes); $this->assertCount(2, $exampleTableNodes[0]->getRows()); @@ -110,6 +112,7 @@ public function testFilterFeatureOutline() $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $this->assertCount(1, $scenarios[0]->getExampleTable()->getRows()); $this->assertSame([['action', 'outcome']], $scenarios[0]->getExampleTable()->getRows()); } diff --git a/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php b/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php index ca869248..450ce46f 100644 --- a/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php +++ b/tests/Behat/Gherkin/Filter/LineRangeFilterTest.php @@ -15,10 +15,11 @@ use Behat\Gherkin\Node\FeatureNode; use Behat\Gherkin\Node\OutlineNode; use Behat\Gherkin\Node\ScenarioNode; +use PHPUnit\Framework\Attributes\DataProvider; class LineRangeFilterTest extends FilterTestCase { - public function featureLineRangeProvider() + public static function featureLineRangeProvider(): iterable { return [ ['1', '1', true], @@ -29,10 +30,8 @@ public function featureLineRangeProvider() ]; } - /** - * @dataProvider featureLineRangeProvider - */ - public function testIsFeatureMatchFilter($filterMinLine, $filterMaxLine, $expected) + #[DataProvider('featureLineRangeProvider')] + public function testIsFeatureMatchFilter(string $filterMinLine, string $filterMaxLine, bool $expected): void { $feature = new FeatureNode(null, null, [], null, [], null, null, null, 1); @@ -40,7 +39,7 @@ public function testIsFeatureMatchFilter($filterMinLine, $filterMaxLine, $expect $this->assertSame($expected, $filter->isFeatureMatch($feature)); } - public function scenarioLineRangeProvider() + public static function scenarioLineRangeProvider(): iterable { return [ ['1', '2', 1], @@ -55,10 +54,8 @@ public function scenarioLineRangeProvider() ]; } - /** - * @dataProvider scenarioLineRangeProvider - */ - public function testIsScenarioMatchFilter($filterMinLine, $filterMaxLine, $expectedNumberOfMatches) + #[DataProvider('scenarioLineRangeProvider')] + public function testIsScenarioMatchFilter(string $filterMinLine, string $filterMaxLine, int $expectedNumberOfMatches): void { $scenario = new ScenarioNode(null, [], [], null, 2); $outline = new OutlineNode(null, [], [], [new ExampleTableNode([], null)], null, 3); @@ -66,11 +63,11 @@ public function testIsScenarioMatchFilter($filterMinLine, $filterMaxLine, $expec $filter = new LineRangeFilter($filterMinLine, $filterMaxLine); $this->assertEquals( $expectedNumberOfMatches, - intval($filter->isScenarioMatch($scenario)) + intval($filter->isScenarioMatch($outline)) + (int) $filter->isScenarioMatch($scenario) + (int) $filter->isScenarioMatch($outline) ); } - public function testFilterFeatureScenario() + public function testFilterFeatureScenario(): void { $filter = new LineRangeFilter(1, 3); $feature = $filter->filterFeature($this->getParsedFeature()); @@ -87,19 +84,20 @@ public function testFilterFeatureScenario() $this->assertCount(0, $scenarios = $feature->getScenarios()); } - public function testFilterFeatureOutline() + public function testFilterFeatureOutline(): void { $filter = new LineRangeFilter(12, 14); $feature = $filter->filterFeature($this->getParsedFeature()); - /* @var OutlineNode[] $scenarios */ $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $this->assertFalse($scenarios[0]->hasExamples()); $filter = new LineRangeFilter(16, 21); $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $exampleTableNodes = $scenarios[0]->getExampleTables(); $this->assertCount(1, $exampleTableNodes); $this->assertCount(3, $exampleTableNodes[0]->getRows()); @@ -114,6 +112,7 @@ public function testFilterFeatureOutline() $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $exampleTableNodes = $scenarios[0]->getExampleTables(); $this->assertCount(2, $exampleTableNodes); @@ -137,6 +136,7 @@ public function testFilterFeatureOutline() $feature = $filter->filterFeature($this->getParsedFeature()); $this->assertCount(1, $scenarios = $feature->getScenarios()); $this->assertSame('Scenario#3', $scenarios[0]->getTitle()); + $this->assertInstanceOf(OutlineNode::class, $scenarios[0]); $exampleTableNodes = $scenarios[0]->getExampleTables(); $this->assertCount(1, $exampleTableNodes); $this->assertCount(2, $exampleTableNodes[0]->getRows()); diff --git a/tests/Behat/Gherkin/Filter/TagFilterTest.php b/tests/Behat/Gherkin/Filter/TagFilterTest.php index ad2320a9..4b66dd5b 100644 --- a/tests/Behat/Gherkin/Filter/TagFilterTest.php +++ b/tests/Behat/Gherkin/Filter/TagFilterTest.php @@ -20,7 +20,7 @@ class TagFilterTest extends TestCase { - public function testFilterFeature() + public function testFilterFeature(): void { $feature = new FeatureNode(null, null, ['wip'], null, [], null, null, null, 1); $filter = new TagFilter('@wip'); @@ -46,7 +46,7 @@ public function testFilterFeature() $this->assertSame([$matchedScenario], $filteredFeature->getScenarios()); } - public function testIsFeatureMatchFilter() + public function testIsFeatureMatchFilter(): void { $feature = new FeatureNode(null, null, [], null, [], null, null, null, 1); @@ -95,7 +95,7 @@ public function testIsFeatureMatchFilter() $this->assertTrue($filter->isFeatureMatch($feature)); } - public function testIsScenarioMatchFilter() + public function testIsScenarioMatchFilter(): void { $feature = new FeatureNode(null, null, ['feature-tag'], null, [], null, null, null, 1); $scenario = new ScenarioNode(null, [], [], null, 2); @@ -189,7 +189,7 @@ public function testIsScenarioMatchFilter() $this->assertFalse($tagFilter->isScenarioMatch($feature, $scenario), 'Tags from different examples tables'); } - public function testFilterFeatureWithTaggedExamples() + public function testFilterFeatureWithTaggedExamples(): void { $exampleTableNode1 = new ExampleTableNode([], null, ['etag1', 'etag2']); $exampleTableNode2 = new ExampleTableNode([], null, ['etag2', 'etag3']); @@ -207,13 +207,13 @@ public function testFilterFeatureWithTaggedExamples() $tagFilter = new TagFilter('@etag1'); $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode1], $scenarioInterfaces[0]->getExampleTables()); $tagFilter = new TagFilter('~@etag3'); $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode1], $scenarioInterfaces[0]->getExampleTables()); $tagFilter = new TagFilter('@wip'); @@ -224,13 +224,13 @@ public function testFilterFeatureWithTaggedExamples() $tagFilter = new TagFilter('@wip&&@etag3'); $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode2], $scenarioInterfaces[0]->getExampleTables()); $tagFilter = new TagFilter('@feature-tag&&@etag1&&@wip'); $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode1], $scenarioInterfaces[0]->getExampleTables()); $tagFilter = new TagFilter('@feature-tag&&~@etag11111&&@wip'); @@ -241,7 +241,7 @@ public function testFilterFeatureWithTaggedExamples() $tagFilter = new TagFilter('@feature-tag&&~@etag1&&@wip'); $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode2], $scenarioInterfaces[0]->getExampleTables()); $tagFilter = new TagFilter('@feature-tag&&@etag2'); @@ -272,13 +272,13 @@ public function testFilterFeatureWithTaggedExamples() $matched = $tagFilter->filterFeature($feature); $scenarioInterfaces = $matched->getScenarios(); $this->assertCount(2, $scenarioInterfaces); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[0]); $this->assertEquals([$exampleTableNode2], $scenarioInterfaces[0]->getExampleTables()); - /* @noinspection PhpUndefinedMethodInspection */ + $this->assertInstanceOf(OutlineNode::class, $scenarioInterfaces[1]); $this->assertEquals([$exampleTableNode3], $scenarioInterfaces[1]->getExampleTables()); } - public function testFilterWithWhitespaceIsDeprecated() + public function testFilterWithWhitespaceIsDeprecated(): void { $this->expectDeprecationError(); @@ -291,7 +291,7 @@ public function testFilterWithWhitespaceIsDeprecated() $this->assertEquals([$scenario], $scenarios); } - public function testTagFilterThatIsAllWhitespaceIsIgnored() + public function testTagFilterThatIsAllWhitespaceIsIgnored(): void { $feature = new FeatureNode(null, null, [], null, [], null, null, null, 1); $tagFilter = new TagFilter(''); @@ -300,7 +300,7 @@ public function testTagFilterThatIsAllWhitespaceIsIgnored() $this->assertTrue($result); } - private function expectDeprecationError() + private function expectDeprecationError(): void { set_error_handler( static function ($errno, $errstr) { @@ -309,6 +309,6 @@ static function ($errno, $errstr) { }, E_ALL ); - $this->expectException('Exception'); + $this->expectException(Exception::class); } } diff --git a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php index 229d2172..cda73f59 100644 --- a/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php +++ b/tests/Behat/Gherkin/Loader/ArrayLoaderTest.php @@ -11,19 +11,22 @@ namespace Tests\Behat\Gherkin\Loader; use Behat\Gherkin\Loader\ArrayLoader; +use Behat\Gherkin\Node\OutlineNode; +use Behat\Gherkin\Node\PyStringNode; +use Behat\Gherkin\Node\ScenarioNode; +use Behat\Gherkin\Node\TableNode; use PHPUnit\Framework\TestCase; class ArrayLoaderTest extends TestCase { - /** @var ArrayLoader */ - private $loader; + private ArrayLoader $loader; protected function setUp(): void { $this->loader = new ArrayLoader(); } - public function testSupports() + public function testSupports(): void { $this->assertFalse($this->loader->supports(__DIR__)); $this->assertFalse($this->loader->supports(__FILE__)); @@ -34,12 +37,12 @@ public function testSupports() $this->assertTrue($this->loader->supports(['feature' => []])); } - public function testLoadEmpty() + public function testLoadEmpty(): void { $this->assertEquals([], $this->loader->load(['features' => []])); } - public function testLoadFeatures() + public function testLoadFeatures(): void { $features = $this->loader->load([ 'features' => [ @@ -72,7 +75,7 @@ public function testLoadFeatures() $this->assertEquals(['some', 'tags'], $features[1]->getTags()); } - public function testLoadScenarios() + public function testLoadScenarios(): void { $features = $this->loader->load([ 'features' => [ @@ -101,23 +104,23 @@ public function testLoadScenarios() $this->assertCount(3, $scenarios); - $this->assertInstanceOf('Behat\Gherkin\Node\ScenarioNode', $scenarios[0]); + $this->assertInstanceOf(ScenarioNode::class, $scenarios[0]); $this->assertEquals('First scenario', $scenarios[0]->getTitle()); $this->assertFalse($scenarios[0]->hasTags()); $this->assertEquals(2, $scenarios[0]->getLine()); - $this->assertInstanceOf('Behat\Gherkin\Node\ScenarioNode', $scenarios[1]); + $this->assertInstanceOf(ScenarioNode::class, $scenarios[1]); $this->assertNull($scenarios[1]->getTitle()); $this->assertEquals(['second', 'scenario', 'tags'], $scenarios[1]->getTags()); $this->assertEquals(1, $scenarios[1]->getLine()); - $this->assertInstanceOf('Behat\Gherkin\Node\ScenarioNode', $scenarios[2]); + $this->assertInstanceOf(ScenarioNode::class, $scenarios[2]); $this->assertNull($scenarios[2]->getTitle()); $this->assertEquals(['third', 'scenario'], $scenarios[2]->getTags()); $this->assertEquals(3, $scenarios[2]->getLine()); } - public function testLoadOutline() + public function testLoadOutline(): void { $features = $this->loader->load([ 'features' => [ @@ -144,18 +147,18 @@ public function testLoadOutline() $this->assertCount(2, $outlines); - $this->assertInstanceOf('Behat\Gherkin\Node\OutlineNode', $outlines[0]); + $this->assertInstanceOf(OutlineNode::class, $outlines[0]); $this->assertEquals('First outline', $outlines[0]->getTitle()); $this->assertFalse($outlines[0]->hasTags()); $this->assertEquals(2, $outlines[0]->getLine()); - $this->assertInstanceOf('Behat\Gherkin\Node\OutlineNode', $outlines[1]); + $this->assertInstanceOf(OutlineNode::class, $outlines[1]); $this->assertNull($outlines[1]->getTitle()); $this->assertEquals(['second', 'outline', 'tags'], $outlines[1]->getTags()); $this->assertEquals(1, $outlines[1]->getLine()); } - public function testOutlineExamples() + public function testOutlineExamples(): void { $features = $this->loader->load([ 'features' => [ @@ -186,13 +189,14 @@ public function testOutlineExamples() $scenarios = $features[0]->getScenarios(); $scenario = $scenarios[0]; + $this->assertInstanceOf(OutlineNode::class, $scenario); $this->assertEquals( [['user' => 'ever', 'pass' => 'sdsd'], ['user' => 'anto', 'pass' => 'fdfd']], $scenario->getExampleTable()->getHash() ); } - public function testLoadBackground() + public function testLoadBackground(): void { $features = $this->loader->load([ 'features' => [ @@ -218,7 +222,7 @@ public function testLoadBackground() $this->assertEquals(2, $features[2]->getBackground()->getLine()); } - public function testLoadSteps() + public function testLoadSteps(): void { $features = $this->loader->load([ 'features' => [ @@ -298,7 +302,7 @@ public function testLoadSteps() $this->assertEquals(1, $steps[1]->getLine()); } - public function testLoadStepArguments() + public function testLoadStepArguments(): void { $features = $this->loader->load([ 'features' => [ @@ -355,7 +359,7 @@ public function testLoadStepArguments() $this->assertEquals('Gangway!', $steps[0]->getKeyword()); $this->assertEquals('Given', $steps[0]->getKeywordType()); $this->assertEquals('step with table argument', $steps[0]->getText()); - $this->assertInstanceOf('Behat\Gherkin\Node\TableNode', $arguments[0]); + $this->assertInstanceOf(TableNode::class, $arguments[0]); $this->assertEquals([['key' => 1, 'val' => 2], ['key' => 3, 'val' => 4]], $arguments[0]->getHash()); $arguments = $steps[1]->getArguments(); @@ -363,7 +367,7 @@ public function testLoadStepArguments() $this->assertEquals('Blimey!', $steps[1]->getKeyword()); $this->assertEquals('When', $steps[1]->getKeywordType()); $this->assertEquals('step with pystring argument', $steps[1]->getText()); - $this->assertInstanceOf('Behat\Gherkin\Node\PyStringNode', $arguments[0]); + $this->assertInstanceOf(PyStringNode::class, $arguments[0]); $this->assertEquals(' some text', (string) $arguments[0]); $arguments = $steps[2]->getArguments(); @@ -371,11 +375,11 @@ public function testLoadStepArguments() $this->assertEquals('Let go and haul', $steps[2]->getKeyword()); $this->assertEquals('Then', $steps[2]->getKeywordType()); $this->assertEquals('2nd step with pystring argument', $steps[2]->getText()); - $this->assertInstanceOf('Behat\Gherkin\Node\PyStringNode', $arguments[0]); + $this->assertInstanceOf(PyStringNode::class, $arguments[0]); $this->assertEquals('some text', (string) $arguments[0]); } - public function testSingleFeatureArray() + public function testSingleFeatureArray(): void { $features = $this->loader->load([ 'feature' => [ diff --git a/tests/Behat/Gherkin/Node/ExampleNodeTest.php b/tests/Behat/Gherkin/Node/ExampleNodeTest.php index d57168ce..818e271a 100644 --- a/tests/Behat/Gherkin/Node/ExampleNodeTest.php +++ b/tests/Behat/Gherkin/Node/ExampleNodeTest.php @@ -19,13 +19,13 @@ class ExampleNodeTest extends TestCase { - public function testCreateExampleSteps() + public function testCreateExampleSteps(): void { $steps = [ - $step1 = new StepNode('Gangway!', 'I am ', [], null, 'Given'), - $step2 = new StepNode('Aye!', 'my email is ', [], null, 'And'), - $step3 = new StepNode('Blimey!', 'I open homepage', [], null, 'When'), - $step4 = new StepNode('Let go and haul', 'website should recognise me', [], null, 'Then'), + new StepNode('Gangway!', 'I am ', [], null, 'Given'), + new StepNode('Aye!', 'my email is ', [], null, 'And'), + new StepNode('Blimey!', 'I open homepage', [], null, 'When'), + new StepNode('Let go and haul', 'website should recognise me', [], null, 'Then'), ]; $table = new ExampleTableNode([ @@ -68,17 +68,29 @@ public function testCreateExampleSteps() $this->assertEquals('I open homepage', $steps[2]->getText()); } - public function testCreateExampleStepsWithArguments() + public function testCreateExampleStepsWithArguments(): void { $steps = [ - $step1 = new StepNode('Gangway!', 'I am ', [], null, 'Given'), - $step2 = new StepNode('Aye!', 'my email is ', [], null, 'And'), - $step3 = new StepNode('Blimey!', 'I open:', [ - new PyStringNode(['page: '], null), - ], null, 'When'), - $step4 = new StepNode('Let go and haul', 'website should recognise me', [ - new TableNode([['page', '']]), - ], null, 'Then'), + new StepNode('Gangway!', 'I am ', [], null, 'Given'), + new StepNode('Aye!', 'my email is ', [], null, 'And'), + new StepNode( + 'Blimey!', + 'I open:', + [ + new PyStringNode(['page: '], null), + ], + null, + 'When' + ), + new StepNode( + 'Let go and haul', + 'website should recognise me', + [ + new TableNode([['page', '']]), + ], + null, + 'Then' + ), ]; $table = new ExampleTableNode([ @@ -93,9 +105,11 @@ public function testCreateExampleStepsWithArguments() $steps = $examples[0]->getSteps(); $args = $steps[2]->getArguments(); + $this->assertInstanceOf(PyStringNode::class, $args[0]); $this->assertEquals('page: homepage', $args[0]->getRaw()); $args = $steps[3]->getArguments(); + $this->assertInstanceOf(TableNode::class, $args[0]); $this->assertEquals('| page | homepage |', $args[0]->getTableAsString()); } } From ac706426284aa88a76d8bb1b3ba50fd9615b4068 Mon Sep 17 00:00:00 2001 From: Christian Sciberras Date: Mon, 3 Feb 2025 20:32:11 +0100 Subject: [PATCH 2/2] Resolve absolute path with helper --- src/Behat/Gherkin/Loader/AbstractFileLoader.php | 13 +++++++++++++ src/Behat/Gherkin/Loader/DirectoryLoader.php | 6 +----- src/Behat/Gherkin/Loader/GherkinFileLoader.php | 6 +----- src/Behat/Gherkin/Loader/YamlFileLoader.php | 5 +---- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/Behat/Gherkin/Loader/AbstractFileLoader.php b/src/Behat/Gherkin/Loader/AbstractFileLoader.php index ba4c7d1e..5ccde77d 100644 --- a/src/Behat/Gherkin/Loader/AbstractFileLoader.php +++ b/src/Behat/Gherkin/Loader/AbstractFileLoader.php @@ -69,4 +69,17 @@ protected function findAbsolutePath($path) return false; } + + /** + * @throws \RuntimeException + */ + final protected function getAbsolutePath(string $path): string + { + $resolvedPath = $this->findAbsolutePath($path); + if ($resolvedPath === false) { + throw new \RuntimeException("Unable to locate absolute path of \"$path\""); + } + + return $resolvedPath; + } } diff --git a/src/Behat/Gherkin/Loader/DirectoryLoader.php b/src/Behat/Gherkin/Loader/DirectoryLoader.php index 1f2ab732..f791b50d 100644 --- a/src/Behat/Gherkin/Loader/DirectoryLoader.php +++ b/src/Behat/Gherkin/Loader/DirectoryLoader.php @@ -57,11 +57,7 @@ public function supports($resource) */ public function load($resource) { - $path = $this->findAbsolutePath($resource); - if ($path === false) { - throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); - } - + $path = $this->getAbsolutePath($resource); $iterator = new RecursiveIteratorIterator( new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS) ); diff --git a/src/Behat/Gherkin/Loader/GherkinFileLoader.php b/src/Behat/Gherkin/Loader/GherkinFileLoader.php index 68d40525..93f3adb5 100644 --- a/src/Behat/Gherkin/Loader/GherkinFileLoader.php +++ b/src/Behat/Gherkin/Loader/GherkinFileLoader.php @@ -70,11 +70,7 @@ public function supports($resource) */ public function load($resource) { - $path = $this->findAbsolutePath($resource); - if ($path === false) { - throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); - } - + $path = $this->getAbsolutePath($resource); if ($this->cache) { if ($this->cache->isFresh($path, filemtime($path))) { $feature = $this->cache->read($path); diff --git a/src/Behat/Gherkin/Loader/YamlFileLoader.php b/src/Behat/Gherkin/Loader/YamlFileLoader.php index ddfed7d2..682b6d8f 100644 --- a/src/Behat/Gherkin/Loader/YamlFileLoader.php +++ b/src/Behat/Gherkin/Loader/YamlFileLoader.php @@ -51,10 +51,7 @@ public function supports($resource) */ public function load($resource) { - $path = $this->findAbsolutePath($resource); - if ($path === false) { - throw new \LogicException("Unable to locate absolute path of supported resource: $resource"); - } + $path = $this->getAbsolutePath($resource); $hash = Yaml::parse(file_get_contents($path)); $features = $this->loader->load($hash);