infection / infection

PHP Mutation Testing library
https://infection.github.io
BSD 3-Clause "New" or "Revised" License
2.05k stars 160 forks source link

0.29.* PHAR version throws Fatal Error: Undefined constant when running tests with PHP-Parser 4 #1984

Open kristos80 opened 3 months ago

kristos80 commented 3 months ago
Question Answer
Infection version 0.29.0
Test Framework version PHPUnit
PHP version 8.3.8
Platform MacOS
Github Repo -

After installing from PHAR wget https://github.com/infection/infection/releases/download/0.29.0/infection.phar, when running mutation tests I get the error

Fatal error: Uncaught Error: Undefined constant PhpParser\NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN in phar:///usr/local/bin/infection/src/PhpParser/Visitor/NonMutableNodesIgnorerVisitor.php:20
Stack trace:
...
infection.json5 ```json5 { "$schema": "https://raw.githubusercontent.com/infection/infection/0.28.1/resources/schema.json", "source": { "directories": [ "src" ], }, "mutators": { "@default": true }, "logs": { "text": "infection.log" } } ```
phpunit.xml ```xml tests src/ ```
Output with issue ``` Fatal error: Uncaught Error: Undefined constant PhpParser\NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN in phar:///usr/local/bin/infection/src/PhpParser/Visitor/NonMutableNodesIgnorerVisitor.php:20 Stack trace: #0 /Users/chrisathanasiadis/Herd/kiko-source/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(200): Infected\Infection\PhpParser\Visitor\NonMutableNodesIgnorerVisitor->enterNode(Object(PhpParser\Node\Stmt\Interface_)) #1 /Users/chrisathanasiadis/Herd/kiko-source/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(114): PhpParser\NodeTraverser->traverseArray(Array) #2 /Users/chrisathanasiadis/Herd/kiko-source/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(223): PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Namespace_)) #3 /Users/chrisathanasiadis/Herd/kiko-source/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(91): PhpParser\NodeTraverser->traverseArray(Array) #4 phar:///usr/local/bin/infection/src/Mutation/FileMutationGenerator.php(33): PhpParser\NodeTraverser->traverse(Array) #5 phar:///usr/local/bin/infection/src/Mutation/MutationGenerator.php(32): Infected\Infection\Mutation\FileMutationGenerator->generate(Object(Infected\Infection\TestFramework\Coverage\ProxyTrace), false, Array, Array) #6 [internal function]: Infected\Infection\Mutation\MutationGenerator->generate(false, Array) #7 phar:///usr/local/bin/infection/src/IterableCounter.php(22): iterator_to_array(Object(Generator), false) #8 phar:///usr/local/bin/infection/src/Process/Runner/MutationTestingRunner.php(27): Infected\Infection\IterableCounter::bufferAndCountIfNeeded(Object(Generator), false) #9 phar:///usr/local/bin/infection/src/Engine.php(62): Infected\Infection\Process\Runner\MutationTestingRunner->run(Object(Generator), '') #10 phar:///usr/local/bin/infection/src/Engine.php(34): Infected\Infection\Engine->runMutationAnalysis() #11 phar:///usr/local/bin/infection/src/Command/RunCommand.php(88): Infected\Infection\Engine->execute() #12 phar:///usr/local/bin/infection/src/Command/BaseCommand.php(29): Infected\Infection\Command\RunCommand->executeCommand(Object(Infected\Infection\Console\IO)) #13 phar:///usr/local/bin/infection/vendor/symfony/console/Command/Command.php(169): Infected\Infection\Command\BaseCommand->execute(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput)) #14 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(700): Infected\Symfony\Component\Console\Command\Command->run(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput)) #15 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(231): Infected\Symfony\Component\Console\Application->doRunCommand(Object(Infected\Infection\Command\RunCommand), Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput)) #16 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(124): Infected\Symfony\Component\Console\Application->doRun(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput)) #17 phar:///usr/local/bin/infection/bin/infection(72): Infected\Symfony\Component\Console\Application->run() #18 /usr/local/bin/infection(14): require('phar:///usr/loc...') #19 {main} thrown in phar:///usr/local/bin/infection/src/PhpParser/Visitor/NonMutableNodesIgnorerVisitor.php on line 20 ```

If I downgrade to 0.28.1 everything works as expected.

Thanks for this wonderful piece of code once again :)

rubenrubiob commented 3 months ago

I just got the same issue with Infection 0.29.5 in two different projects. With 0.28.1 it works fine on both projects.

Fatal error: Uncaught Error: Undefined constant PhpParser\NodeVisitor::DONT_TRAVERSE_CURRENT_AND_CHILDREN in phar:///usr/local/bin/infection/src/PhpParser/Visitor/NonMutableNodesIgnorerVisitor.php:20
Stack trace:
#0 /app/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(200): Infected\Infection\PhpParser\Visitor\NonMutableNodesIgnorerVisitor->enterNode(Object(PhpParser\Node\Stmt\Interface_))
#1 /app/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(114): PhpParser\NodeTraverser->traverseArray(Array)
#2 /app/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(223): PhpParser\NodeTraverser->traverseNode(Object(PhpParser\Node\Stmt\Namespace_))
#3 /app/vendor/nikic/php-parser/lib/PhpParser/NodeTraverser.php(91): PhpParser\NodeTraverser->traverseArray(Array)
#4 phar:///usr/local/bin/infection/src/Mutation/FileMutationGenerator.php(33): PhpParser\NodeTraverser->traverse(Array)
#5 phar:///usr/local/bin/infection/src/Mutation/MutationGenerator.php(32): Infected\Infection\Mutation\FileMutationGenerator->generate(Object(Infected\Infection\TestFramework\Coverage\ProxyTrace), false, Array, Array)
#6 [internal function]: Infected\Infection\Mutation\MutationGenerator->generate(false, Array)
#7 phar:///usr/local/bin/infection/src/IterableCounter.php(22): iterator_to_array(Object(Generator), false)
#8 phar:///usr/local/bin/infection/src/Process/Runner/MutationTestingRunner.php(27): Infected\Infection\IterableCounter::bufferAndCountIfNeeded(Object(Generator), false)
#9 phar:///usr/local/bin/infection/src/Engine.php(62): Infected\Infection\Process\Runner\MutationTestingRunner->run(Object(Generator), '')
#10 phar:///usr/local/bin/infection/src/Engine.php(34): Infected\Infection\Engine->runMutationAnalysis()
#11 phar:///usr/local/bin/infection/src/Command/RunCommand.php(87): Infected\Infection\Engine->execute()
#12 phar:///usr/local/bin/infection/src/Command/BaseCommand.php(29): Infected\Infection\Command\RunCommand->executeCommand(Object(Infected\Infection\Console\IO))
#13 phar:///usr/local/bin/infection/vendor/symfony/console/Command/Command.php(169): Infected\Infection\Command\BaseCommand->execute(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#14 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(700): Infected\Symfony\Component\Console\Command\Command->run(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#15 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(231): Infected\Symfony\Component\Console\Application->doRunCommand(Object(Infected\Infection\Command\RunCommand), Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#16 phar:///usr/local/bin/infection/vendor/symfony/console/Application.php(124): Infected\Symfony\Component\Console\Application->doRun(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#17 phar:///usr/local/bin/infection/bin/infection(72): Infected\Symfony\Component\Console\Application->run()
#18 /usr/local/bin/infection(14): require('phar:///usr/loc...')
#19 {main}
  thrown in phar:///usr/local/bin/infection/src/PhpParser/Visitor/NonMutableNodesIgnorerVisitor.php on line 20
maks-rafalko commented 3 months ago

Hello!

Probably related to https://github.com/infection/infection/pull/1968/files.

The first guess is that Infection uses PHP-Parser 5 while your project uses PHP-Parser 4. Could you please confirm?

If so, please use Infection with a compatible version of PHP-Parser. Unfortunately, we can not prefix this lib in PHAR

https://github.com/infection/infection/blob/a663d6cecee222e9b33f11608073c134eb5e6916/scoper.inc.php#L43-L46

kristos80 commented 3 months ago

Hi @maks-rafalko , I was about to write this. That the problem occurs when using a package that needs a version older or equal to PHP-Parser 4. In my case is roave/backward-compatibility-check.

Yes, I am afraid there's no easy solution for that.

rubenrubiob commented 3 months ago

Hello @maks-rafalko ! The same in my case: I have version 4.17 of nikic/php-parser:

composer why nikic/php-parser
vimeo/psalm 5.24.0 requires  nikic/php-parser (^4.16)
vimeo/psalm 5.24.0 conflicts nikic/php-parser (4.17.0)

It looks I will have to downgrade in the meanwhile.

Thank you for your fast answer.

maks-rafalko commented 3 months ago

@theofidry is it possible to somehow tell Box to validate nikic/php-parser version in "requirements checker"? Or do you think there is anything we can do to make it more clear for the end user, saying that there is a conflict in php-parser versions?

theofidry commented 3 months ago

@maks-rafalko I have an idea but I need to try it out

theofidry commented 3 months ago

I don't think there is a good way to do this.

PHP-Scoper exposes its isolated finder: Isolated\Symfony\Component\Finder\Finder, but:

So the best way I think is for us to check the PHP-Parser version loaded, either the user's version is loaded first and we can crash gracefully, or it's the other way around and we can't do anything.

I'm not sure how the autoloading happens, I'm trying to find out in #1985

alfredbez commented 2 months ago

Just for the record: We see the same issue in our project. Here it's not reporting an undefined constant, but a method:

Infection - PHP Mutation Testing Framework version 0.29.0

PHP Fatal error:  Uncaught Error: Call to undefined method PhpParser\ParserFactory::createForHostVersion() in phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php:185
Stack trace:
#0 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(616): Infected\Infection\Container::Infected\Infection\{closure}(Object(Infected\Infection\Container))
#1 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(340): Infected\Infection\Container->get('PhpParser\\Parse...')
#2 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(185): Infected\Infection\Container->getParser()
#3 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(616): Infected\Infection\Container::Infected\Infection\{closure}(Object(Infected\Infection\Container))
#4 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(344): Infected\Infection\Container->get('Infected\\Infect...')
#5 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(204): Infected\Infection\Container->getFileParser()
#6 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(616): Infected\Infection\Container::Infected\Infection\{closure}(Object(Infected\Infection\Container))
#7 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(472): Infected\Infection\Container->get('Infected\\Infect...')
#8 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(216): Infected\Infection\Container->getFileMutationGenerator()
#9 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(616): Infected\Infection\Container::Infected\Infection\{closure}(Object(Infected\Infection\Container))
#10 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php(512): Infected\Infection\Container->get('Infected\\Infect...')
#11 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Command/RunCommand.php(87): Infected\Infection\Container->getMutationGenerator()
#12 phar:///Users/username/projects/project-one/.tools/infection/infection/src/Command/BaseCommand.php(29): Infected\Infection\Command\RunCommand->executeCommand(Object(Infected\Infection\Console\IO))
#13 phar:///Users/username/projects/project-one/.tools/infection/infection/vendor/symfony/console/Command/Command.php(169): Infected\Infection\Command\BaseCommand->execute(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#14 phar:///Users/username/projects/project-one/.tools/infection/infection/vendor/symfony/console/Application.php(700): Infected\Symfony\Component\Console\Command\Command->run(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#15 phar:///Users/username/projects/project-one/.tools/infection/infection/vendor/symfony/console/Application.php(231): Infected\Symfony\Component\Console\Application->doRunCommand(Object(Infected\Infection\Command\RunCommand), Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#16 phar:///Users/username/projects/project-one/.tools/infection/infection/vendor/symfony/console/Application.php(124): Infected\Symfony\Component\Console\Application->doRun(Object(Infected\Symfony\Component\Console\Input\ArgvInput), Object(Infected\Symfony\Component\Console\Output\ConsoleOutput))
#17 phar:///Users/username/projects/project-one/.tools/infection/infection/bin/infection(72): Infected\Symfony\Component\Console\Application->run()
#18 /Users/username/projects/project-one/.tools/infection/infection(14): require('phar:///Users/b...')
#19 {main}
  thrown in phar:///Users/username/projects/project-one/.tools/infection/infection/src/Container.php on line 185

We downgraded to 0.28.1, which works fine. I just wanted to post this if someone is searching in GitHub issues for some part of the stack trace.