From 9af313a59faae2b2ca2757e39466c369ac06100e Mon Sep 17 00:00:00 2001 From: Sander Muller Date: Mon, 31 Aug 2026 17:13:04 +0200 Subject: [PATCH 1/2] Set Option::SOURCE parameter from the resolved paths AbstractRectorTestCase sets it, a real run never does, so code reading the parameter works under the test harness and is empty in production. Excluded from the cache invalidation hash: the paths change per invocation, so hashing them would drop the cache whenever the target changes. --- src/Configuration/ConfigurationFactory.php | 16 ++-- .../Parameter/SimpleParameterProvider.php | 1 + .../ConfigurationFactoryTest.php | 80 +++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) diff --git a/src/Configuration/ConfigurationFactory.php b/src/Configuration/ConfigurationFactory.php index 4f81642eb0b..56c656f85c7 100644 --- a/src/Configuration/ConfigurationFactory.php +++ b/src/Configuration/ConfigurationFactory.php @@ -168,15 +168,19 @@ private function resolvePaths(InputInterface $input): array if ($commandLinePaths !== []) { // mark the run as narrowed, so unused skip reporting can be disabled to avoid false positives SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, true); - $this->setFilesWithoutExtensionParameter($commandLinePaths); - return $commandLinePaths; + $paths = $commandLinePaths; + } else { + // fallback to parameter + $paths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); } - // fallback to parameter - $configPaths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); - $this->setFilesWithoutExtensionParameter($configPaths); + $this->setFilesWithoutExtensionParameter($paths); + + // extensions read the processed paths from here; without this only the test harness + // sets it, so the parameter is empty in a real run + SimpleParameterProvider::setParameter(Option::SOURCE, $paths); - return $configPaths; + return $paths; } /** diff --git a/src/Configuration/Parameter/SimpleParameterProvider.php b/src/Configuration/Parameter/SimpleParameterProvider.php index 5f0be8a24b5..4548b61296d 100644 --- a/src/Configuration/Parameter/SimpleParameterProvider.php +++ b/src/Configuration/Parameter/SimpleParameterProvider.php @@ -21,6 +21,7 @@ final class SimpleParameterProvider * @var array */ private const array CACHE_IGNORED_PARAMETER_NAMES = [ + Option::SOURCE, Option::PARALLEL, Option::PARALLEL_JOB_SIZE, Option::PARALLEL_MAX_NUMBER_OF_PROCESSES, diff --git a/tests/Configuration/ConfigurationFactoryTest.php b/tests/Configuration/ConfigurationFactoryTest.php index 9602940f0a2..ea7b344a77a 100644 --- a/tests/Configuration/ConfigurationFactoryTest.php +++ b/tests/Configuration/ConfigurationFactoryTest.php @@ -5,8 +5,13 @@ namespace Rector\Tests\Configuration; use Rector\Configuration\ConfigurationFactory; +use Rector\Configuration\Option; +use Rector\Configuration\Parameter\SimpleParameterProvider; +use Rector\Console\ProcessConfigureDecorator; use Rector\FileSystem\FilesFinder; use Rector\Testing\PHPUnit\AbstractLazyTestCase; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Input\ArrayInput; final class ConfigurationFactoryTest extends AbstractLazyTestCase { @@ -42,4 +47,79 @@ public function test(): void realpath($thirdFilePath), ); } + + public function testPublishesCommandLinePathsAsSourceParameter(): void + { + $originalPaths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); + $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); + $originalIsRunNarrowed = SimpleParameterProvider::provideBoolParameter(Option::IS_RUN_NARROWED, false); + + try { + SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); + + $this->make(ConfigurationFactory::class) + ->createFromInput($this->createInput([__DIR__ . '/Source'])); + + $this->assertSame( + [__DIR__ . '/Source'], + SimpleParameterProvider::provideArrayParameter(Option::SOURCE) + ); + } finally { + SimpleParameterProvider::setParameter(Option::PATHS, $originalPaths); + SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); + SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, $originalIsRunNarrowed); + } + } + + public function testPublishesConfiguredPathsAsSourceParameterWhenNoneGivenOnTheCommandLine(): void + { + $originalPaths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); + $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); + + try { + SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); + + $this->make(ConfigurationFactory::class) + ->createFromInput($this->createInput([])); + + $this->assertSame( + [__DIR__ . '/config'], + SimpleParameterProvider::provideArrayParameter(Option::SOURCE) + ); + } finally { + SimpleParameterProvider::setParameter(Option::PATHS, $originalPaths); + SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); + } + } + + public function testSourceParameterIsOutsideTheCacheInvalidationHash(): void + { + // The processed paths change per invocation. Were they hashed, running Rector on a + // single file and then on the whole project would drop the cache each time. + $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); + + try { + SimpleParameterProvider::setParameter(Option::SOURCE, ['src']); + $hashForOnePath = SimpleParameterProvider::hashForCacheInvalidation(); + + SimpleParameterProvider::setParameter(Option::SOURCE, ['tests', 'src/Some/Other.php']); + + $this->assertSame($hashForOnePath, SimpleParameterProvider::hashForCacheInvalidation()); + } finally { + SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); + } + } + + /** + * @param string[] $paths + */ + private function createInput(array $paths): ArrayInput + { + $command = new Command('process'); + ProcessConfigureDecorator::decorate($command); + + return new ArrayInput([ + Option::SOURCE => $paths, + ], $command->getDefinition()); + } } From 5d9fd2cd2877a3daf8a38a96b9a34cc078ea5be6 Mon Sep 17 00:00:00 2001 From: Sander Muller Date: Mon, 31 Aug 2026 20:38:59 +0200 Subject: [PATCH 2/2] Drop try/finally from the tests Set the parameters and assert, as UnusedSkipResolverTest does. --- .../ConfigurationFactoryTest.php | 68 ++++++------------- 1 file changed, 22 insertions(+), 46 deletions(-) diff --git a/tests/Configuration/ConfigurationFactoryTest.php b/tests/Configuration/ConfigurationFactoryTest.php index ea7b344a77a..0085c8c8ac2 100644 --- a/tests/Configuration/ConfigurationFactoryTest.php +++ b/tests/Configuration/ConfigurationFactoryTest.php @@ -50,64 +50,40 @@ public function test(): void public function testPublishesCommandLinePathsAsSourceParameter(): void { - $originalPaths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); - $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); - $originalIsRunNarrowed = SimpleParameterProvider::provideBoolParameter(Option::IS_RUN_NARROWED, false); - - try { - SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); - - $this->make(ConfigurationFactory::class) - ->createFromInput($this->createInput([__DIR__ . '/Source'])); - - $this->assertSame( - [__DIR__ . '/Source'], - SimpleParameterProvider::provideArrayParameter(Option::SOURCE) - ); - } finally { - SimpleParameterProvider::setParameter(Option::PATHS, $originalPaths); - SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); - SimpleParameterProvider::setParameter(Option::IS_RUN_NARROWED, $originalIsRunNarrowed); - } + SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); + + $this->make(ConfigurationFactory::class) + ->createFromInput($this->createInput([__DIR__ . '/Source'])); + + $this->assertSame( + [__DIR__ . '/Source'], + SimpleParameterProvider::provideArrayParameter(Option::SOURCE) + ); } public function testPublishesConfiguredPathsAsSourceParameterWhenNoneGivenOnTheCommandLine(): void { - $originalPaths = SimpleParameterProvider::provideArrayParameter(Option::PATHS); - $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); - - try { - SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); - - $this->make(ConfigurationFactory::class) - ->createFromInput($this->createInput([])); - - $this->assertSame( - [__DIR__ . '/config'], - SimpleParameterProvider::provideArrayParameter(Option::SOURCE) - ); - } finally { - SimpleParameterProvider::setParameter(Option::PATHS, $originalPaths); - SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); - } + SimpleParameterProvider::setParameter(Option::PATHS, [__DIR__ . '/config']); + + $this->make(ConfigurationFactory::class) + ->createFromInput($this->createInput([])); + + $this->assertSame( + [__DIR__ . '/config'], + SimpleParameterProvider::provideArrayParameter(Option::SOURCE) + ); } public function testSourceParameterIsOutsideTheCacheInvalidationHash(): void { // The processed paths change per invocation. Were they hashed, running Rector on a // single file and then on the whole project would drop the cache each time. - $originalSource = SimpleParameterProvider::provideArrayParameter(Option::SOURCE); - - try { - SimpleParameterProvider::setParameter(Option::SOURCE, ['src']); - $hashForOnePath = SimpleParameterProvider::hashForCacheInvalidation(); + SimpleParameterProvider::setParameter(Option::SOURCE, ['src']); + $hashForOnePath = SimpleParameterProvider::hashForCacheInvalidation(); - SimpleParameterProvider::setParameter(Option::SOURCE, ['tests', 'src/Some/Other.php']); + SimpleParameterProvider::setParameter(Option::SOURCE, ['tests', 'src/Some/Other.php']); - $this->assertSame($hashForOnePath, SimpleParameterProvider::hashForCacheInvalidation()); - } finally { - SimpleParameterProvider::setParameter(Option::SOURCE, $originalSource); - } + $this->assertSame($hashForOnePath, SimpleParameterProvider::hashForCacheInvalidation()); } /**