-
-
Notifications
You must be signed in to change notification settings - Fork 154
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
Fix the issue with anonymous classes inside arrays #1745
Conversation
We can see where it happens in the stack trace:
|
This is where we initialize the range: infection/src/TestFramework/Coverage/LineRangeCalculator.php Lines 47 to 56 in c770354
It looks like |
There's something very confusing because if infection/src/Mutator/NodeMutationGenerator.php Lines 177 to 180 in 8042277
I don't think I have the mental capacity to understand this right now. |
It is interesting that if I restructure the fixture like so, the error goes away: --- a/tests/e2e/Github1735/src/SourceClass.php
+++ b/tests/e2e/Github1735/src/SourceClass.php
@@ -6,13 +6,15 @@ class SourceClass
{
public function hello(): array
{
+ $class = new class() {
+ public function foo(): bool
+ {
+ return true;
+ }
+ };
+
$var = [
- 'class' => new class() {
- public function foo(): bool
- {
- return true;
- }
- },
+ 'class' => $class,
];
return $var; |
… node to detect start/end lines of the method in an anonymous class instead of using outermost array start/end lines Example: ```php [1] $var = [ [2] 'class' => new class() { [3] public function foo(): bool [4] { [5] return true; [6] } [7] }, [8] ]; ``` Here, start line must be 3, end line 6. Previously it was 1 and 8 correspondingly
Thank you @Slamdunk for reporting the issue and creating a reproducer, this helps so much. Thanks @sanmai for the valuable feedback, helped me quicker understand the issue. So, the bug in because of line
this is because here infection/src/Mutator/NodeMutationGenerator.php Lines 177 to 180 in 8042277
we use original node, but here infection/src/TestFramework/Coverage/LineRangeCalculator.php Lines 47 to 56 in c770354
we use "outermost array node", wich is completely separate node for which That being said, the update I pushed is just to use original node ( The reported bug is fixed. HOWEVER, I still think Infection can't (or is not able to currently) working with anonymous classes properly, even if this particular test passes. Why? This is how the XML coverage report look like: <?xml version="1.0"?>
<phpunit xmlns="https://schema.phpunit.de/coverage/1.0">
<file name="SourceClass.php" path="/">
<totals>
<lines total="21" comments="0" code="21" executable="4" executed="4" percent="100.00"/>
<methods count="1" tested="1" percent="100.00"/>
<functions count="0" tested="0" percent="0"/>
<classes count="1" tested="1" percent="100.00"/>
<traits count="0" tested="0" percent="0"/>
</totals>
<class name="Github1735\SourceClass" start="5" executable="4" executed="4" crap="1">
<namespace name="Github1735"/>
<method name="hello" signature="hello(): array" start="7" end="19" crap="1" executable="4" executed="4" coverage="100"/>
</class>
<coverage>
<line nr="9">
<covered by="Github1735\Test\SourceClassTest::test_hello"/>
</line>
<line nr="10">
<covered by="Github1735\Test\SourceClassTest::test_hello"/>
</line>
<line nr="13">
<covered by="Github1735\Test\SourceClassTest::test_hello"/>
</line>
<line nr="18">
<covered by="Github1735\Test\SourceClassTest::test_hello"/>
</line>
</coverage>
<source>
<line no="1">
<token name="T_OPEN_TAG"><?php</token>
</line>
<line no="2"/>
<line no="3">
<token name="T_NAMESPACE">namespace</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">Github1735</token>
<token name="T_SEMICOLON">;</token>
</line>
<line no="4"/>
<line no="5">
<token name="T_CLASS">class</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">SourceClass</token>
</line>
<line no="6">
<token name="T_OPEN_CURLY">{</token>
</line>
<line no="7">
<token name="T_WHITESPACE"> </token>
<token name="T_PUBLIC">public</token>
<token name="T_WHITESPACE"> </token>
<token name="T_FUNCTION">function</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">hello</token>
<token name="T_OPEN_BRACKET">(</token>
<token name="T_CLOSE_BRACKET">)</token>
<token name="T_COLON">:</token>
<token name="T_WHITESPACE"> </token>
<token name="T_ARRAY">array</token>
</line>
<line no="8">
<token name="T_WHITESPACE"> </token>
<token name="T_OPEN_CURLY">{</token>
</line>
<line no="9">
<token name="T_WHITESPACE"> </token>
<token name="T_VARIABLE">$var</token>
<token name="T_WHITESPACE"> </token>
<token name="T_EQUAL">=</token>
<token name="T_WHITESPACE"> </token>
<token name="T_OPEN_SQUARE">[</token>
</line>
<line no="10">
<token name="T_WHITESPACE"> </token>
<token name="T_CONSTANT_ENCAPSED_STRING">'class'</token>
<token name="T_WHITESPACE"> </token>
<token name="T_DOUBLE_ARROW">=></token>
<token name="T_WHITESPACE"> </token>
<token name="T_NEW">new</token>
<token name="T_WHITESPACE"> </token>
<token name="T_CLASS">class</token>
<token name="T_OPEN_BRACKET">(</token>
<token name="T_CLOSE_BRACKET">)</token>
<token name="T_WHITESPACE"> </token>
<token name="T_OPEN_CURLY">{</token>
</line>
<line no="11">
<token name="T_WHITESPACE"> </token>
<token name="T_PUBLIC">public</token>
<token name="T_WHITESPACE"> </token>
<token name="T_FUNCTION">function</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">foo</token>
<token name="T_OPEN_BRACKET">(</token>
<token name="T_CLOSE_BRACKET">)</token>
<token name="T_COLON">:</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">bool</token>
</line>
<line no="12">
<token name="T_WHITESPACE"> </token>
<token name="T_OPEN_CURLY">{</token>
</line>
<line no="13">
<token name="T_WHITESPACE"> </token>
<token name="T_RETURN">return</token>
<token name="T_WHITESPACE"> </token>
<token name="T_STRING">true</token>
<token name="T_SEMICOLON">;</token>
</line>
<line no="14">
<token name="T_WHITESPACE"> </token>
<token name="T_CLOSE_CURLY">}</token>
</line>
<line no="15">
<token name="T_WHITESPACE"> </token>
<token name="T_CLOSE_CURLY">}</token>
<token name="T_COMMA">,</token>
</line>
<line no="16">
<token name="T_WHITESPACE"> </token>
<token name="T_CLOSE_SQUARE">]</token>
<token name="T_SEMICOLON">;</token>
</line>
<line no="17"/>
<line no="18">
<token name="T_WHITESPACE"> </token>
<token name="T_RETURN">return</token>
<token name="T_WHITESPACE"> </token>
<token name="T_VARIABLE">$var</token>
<token name="T_SEMICOLON">;</token>
</line>
<line no="19">
<token name="T_WHITESPACE"> </token>
<token name="T_CLOSE_CURLY">}</token>
</line>
<line no="20">
<token name="T_CLOSE_CURLY">}</token>
</line>
<line no="21"/>
</source>
</file>
</phpunit> Look at this piece: <class name="Github1735\SourceClass" start="5" executable="4" executed="4" crap="1">
<namespace name="Github1735"/>
<method name="hello" signature="hello(): array" start="7" end="19" crap="1" executable="4" executed="4" coverage="100"/>
</class> Only 1 method (
class SourceClass
{
public function hello(): array
{
$var = [
'class' => new class() {
public function foo(): bool
{
return true;
}
},
];
return $var;
}
} What it breaks is that Infection incorrectly determines that the test that covers public function test_hello()
{
$sourceClass = new SourceClass();
- self::assertTrue($sourceClass->hello()['class']->foo());
+ self::assertIsArray($sourceClass->hello());
} In this case, In practice, this leads to a bug with With the change above to the test, if I run
then I still get 2 mutations, one of them is escaped. However, What to do with this? I don't know, because PHPUnit doesn't provide a coverage data Infection needs to build I think we should leave it as is for now, as I don't see a proper solution but at the same time mutating methods of anonymous classes located in other methods of real classes still sounds good and helpful. |
|
||
return new NodeLineRangeData($node->getStartLine(), $endLine); | ||
return new NodeLineRangeData($outerMostArrayNode->getStartLine(), $outerMostArrayNode->getEndLine()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I first started a fix a week ago, I came to a conclusion similar to this, but all other tests were failing.
Glad to see I was in the right path. Still, the Generator
thing makes debugging so painful 😩
Putting iterator_to_array
everywhere has been tedious, I'd like to have a magic php settings to turn every Generator
into an array immediately for debug purposes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still, the Generator thing makes debugging to painful weary
Same feelings here. I had to debug them a while ago and they just blew my mind, it's very hard. Though I didn't do any investigation on how to improve this process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It isn't that generators are at the fault but the structure we have here isn't friendly to generator-style programming. When you call one thing that calls another, and yet another, creating an implicit generator chain, it gets really convoluted. Much better to make explicit generators and chain them like we do in MutationTestingRunner
.
Thank you for your help :) |
This PR shows #1735 in action: https://github.com/infection/infection/actions/runs/3272547451/jobs/5383690401#step:13:265
Despite been related to
PublicVisibility
(andProtectedVisibility
as well), I have not been able to get the error in a Unit Test within\Infection\Tests\Mutator\FunctionSignature\PublicVisibilityTest
.I'd like to fix this and propose it here, but I'm stuck: I have no clue where to start, can you help me please with some hits?
Quick command to get the error locally:
(cd tests/e2e/Github1735/ && php ../../../bin/infection -v)
Fixes #1735