Skip to content

Conversation

@carlos-granados
Copy link
Contributor

@carlos-granados carlos-granados commented Dec 3, 2024

We should be increasing our Psalm level. Moving to error level 6 produces more than 100 errors, so, to make this more manageable, we can introduce the level 6 rules in small batches. This PR introduces one of these rules with the corresponding needed changes

</MethodSignatureMismatch>

<InvalidArgument>
<errorLevel type="error"/>
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By adding this, we ask Psalm to apply this rule and report any errors found

<InvalidArgument>
<errorLevel type="error"/>
<errorLevel type="suppress">
<file name="src/Behat/Testwork/EventDispatcher/TestworkEventDispatcher.php" />
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two files need to be excluded because they produce false positives due to the code that is needed to keep the bc compatibility for all Symfony versions

$message = $this->translator->trans('snippet_context_choice', array('%count%' => $suiteName), 'output');
$choices = array_values(array_merge(array('None'), $contextClasses));
$default = 1;
$default = '1';
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$default needs to be a string

* @param string $class
*/
public function __construct($message, $class)
public function __construct(string $message, string $class)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc-block was wrong, I changed it to use php types


$result = $newResult;
$definitions[] = $newResult->getMatchedDefinition();
$matchedDefinition = $newResult->getMatchedDefinition();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getMatchDefinition() can return null, we need to check this and only add to the list of definitions if its not null

$this->exampleSetupPrinter->printSetup($formatter, $event->getSetup());
$this->examplePrinter->printHeader($formatter, $event->getFeature(), $this->example);

$this->example = $event->getScenario();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to make sure that the ScenarioNode returned by getScenario() is an ExampleNode

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The structure of the way the event listeners is registered is somewhat complex, but I think the assumption is that events only reach this listener if we're in the course of running an Outline and therefore the scenario should be an ExampleNode?

If so, getting an unexpected type of ScenarioNode here would suggest either there's a problem with our event binding, or with our assumptions about how the nodes / events are structured.

In which case it might be better / safer to throw an exception (and hopefully fail CI) rather than silently not print anything? This would be the intentional version of the current behaviour where it will hit a TypeError.

$totalCount = 0;
} else {
$totalCount = array_sum($stats);
$totalCount = (int) array_sum($stats);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$totalCount needs to be an int

$style = $this->resultConverter->convertResultCodeToString($resultCode);
$hook = $callResult->getCall()->getCallee();
$path = $hook->getPath();
$hookName = (string)$hook;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We make the conversion to string explicit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$hookName = (string)$hook;
$hookName = (string) $hook;

To ensure code style consistency :)

* Returns counters for different scenario result codes.
*
* @return array[]
* @return int[]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doc-block was wrong

}

private function bcAwareDispatch(object $event, $eventName)
private function bcAwareDispatch(?object $event, $eventName)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$event can be null

use Behat\Testwork\Event\Event;
use Behat\Testwork\Output\Formatter;
use Behat\Testwork\Output\Node\EventListener\EventListener;
use phpDocumentor\Reflection\DocBlock\Tags\Example;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this use statement looks wrong.

* Returns counters for different scenario result codes.
*
* @return array[]
* @return int[]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest documenting this as array<TestResults::*, int> to be more precise about the array keys.

$style = $this->resultConverter->convertResultCodeToString($resultCode);
$hook = $callResult->getCall()->getCallee();
$path = $hook->getPath();
$hookName = (string)$hook;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$hookName = (string)$hook;
$hookName = (string) $hook;

To ensure code style consistency :)

$style = $this->resultConverter->convertResultCodeToString($resultCode);
$hook = $callResult->getCall()->getCallee();
$path = $hook->getPath();
$hookName = (string)$hook;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$hookName = (string)$hook;
$hookName = (string) $hook;

Same here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated, thanks!!

Copy link
Contributor

@acoulton acoulton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good work @carlos-granados just a question about how best to handle unexpected types

$this->exampleSetupPrinter->printSetup($formatter, $event->getSetup());
$this->examplePrinter->printHeader($formatter, $event->getFeature(), $this->example);

$this->example = $event->getScenario();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The structure of the way the event listeners is registered is somewhat complex, but I think the assumption is that events only reach this listener if we're in the course of running an Outline and therefore the scenario should be an ExampleNode?

If so, getting an unexpected type of ScenarioNode here would suggest either there's a problem with our event binding, or with our assumptions about how the nodes / events are structured.

In which case it might be better / safer to throw an exception (and hopefully fail CI) rather than silently not print anything? This would be the intentional version of the current behaviour where it will hit a TypeError.

Comment on lines 219 to 221
if ($example instanceof ExampleNode) {
$this->exampleRowPrinter->printExampleRow($formatter, $this->outline, $example, $this->stepAfterTestedEvents);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same observation as the other Outline-related listener above, I think perhaps we should throw?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the code to use assertions, which is what PHPStan recommends for this kind of type narrowing. What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That looks like a good solution to me

Copy link
Contributor

@acoulton acoulton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great, thanks @carlos-granados

@acoulton acoulton merged commit 91c9e0d into Behat:master Dec 9, 2024
17 checks passed
@carlos-granados carlos-granados deleted the psalm-level-6-1 branch December 9, 2024 10:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants