Browse Source

DX: remove Prophecy (#7509)

Kuba Werłos 1 year ago
parent
commit
f87756dca9

+ 1 - 8
.github/composite-actions/install-composer-deps/action.yml

@@ -44,13 +44,6 @@ runs:
           Composer-${{ runner.os }}-${{ env.COMPOSER_CACHE_PHP }}-
           Composer-${{ runner.os }}-
 
-    - name: Auto-add ignore-platform-req
-      uses: actions/github-script@v7
-      id: resolve-ignore-platform-req
-      with:
-        script: 'return ${{ env.PHP_VERSION_ID }} >= 80400 ? "--ignore-platform-req=php+" : ""'
-        result-encoding: string
-
     - name: Install dependencies
       uses: nick-invision/retry@v2
       with:
@@ -59,7 +52,7 @@ runs:
         retry_wait_seconds: 30
         # `--no-scripts` to avoid side-effects (e.g. installing dev-tools for all jobs on CI level),
         # all executed scripts should be explicit and run only when needed.
-        command: composer update --optimize-autoloader --no-interaction --no-progress --no-scripts ${{ inputs.flags }} ${{ steps.resolve-ignore-platform-req.outputs.result }}
+        command: composer update --optimize-autoloader --no-interaction --no-progress --no-scripts ${{ inputs.flags }}
 
     - name: Show versions of packages
       shell: bash

+ 0 - 2
composer.json

@@ -46,8 +46,6 @@
         "php-cs-fixer/accessible-object": "^1.1",
         "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.4",
         "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.4",
-        "phpspec/prophecy": "^1.18",
-        "phpspec/prophecy-phpunit": "^2.0",
         "phpunit/phpunit": "^9.6",
         "symfony/phpunit-bridge": "^6.3.8 || ^7.0",
         "symfony/yaml": "^5.4 || ^6.0 || ^7.0"

+ 1 - 1
tests/AutoReview/ProjectCodeTest.php

@@ -381,7 +381,7 @@ final class ProjectCodeTest extends TestCase
         );
         $strings = array_unique($strings);
 
-        $message = sprintf('Class %s must not use PHPUnit\'s mock,, it shall use ->prophesize() instead.', $testClassName);
+        $message = sprintf('Class %s must not use PHPUnit\'s mock, it shall use anonymous class instead.', $testClassName);
         self::assertNotContains('getMockBuilder', $strings, $message);
         self::assertNotContains('createMock', $strings, $message);
         self::assertNotContains('createMockForIntersectionOfInterfaces', $strings, $message);

+ 228 - 230
tests/Cache/FileCacheManagerTest.php

@@ -14,13 +14,14 @@ declare(strict_types=1);
 
 namespace PhpCsFixer\Tests\Cache;
 
+use PhpCsFixer\AccessibleObject\AccessibleObject;
 use PhpCsFixer\Cache\CacheInterface;
 use PhpCsFixer\Cache\CacheManagerInterface;
+use PhpCsFixer\Cache\DirectoryInterface;
 use PhpCsFixer\Cache\FileCacheManager;
 use PhpCsFixer\Cache\FileHandlerInterface;
 use PhpCsFixer\Cache\SignatureInterface;
 use PhpCsFixer\Tests\TestCase;
-use Prophecy\Argument;
 
 /**
  * @author Andreas Möller <am@localheinz.com>
@@ -47,131 +48,65 @@ final class FileCacheManagerTest extends TestCase
 
     public function testCreatesCacheIfHandlerReturnedNoCache(): void
     {
-        $signature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->shouldBeCalled()->willReturn(null);
-        $handlerProphecy->write(Argument::that(static fn (CacheInterface $cache): bool => $cache->getSignature() === $signature))->shouldBeCalled();
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
+        $signature = $this->createSignatureDouble(false);
+        $handler = $this->createFileHandlerDouble(null);
 
+        $manager = new FileCacheManager($handler, $signature);
         unset($manager);
+
+        self::assertSame(1, AccessibleObject::create($handler)->writeCallCount);
     }
 
     public function testCreatesCacheIfCachedSignatureIsDifferent(): void
     {
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->shouldBeCalled()->willReturn(false);
-        $signature = $signatureProphecy->reveal();
-
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->shouldBeCalled()->willReturn($cachedSignature);
-        $cache = $cacheProphecy->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->shouldBeCalled()->willReturn($cache);
-        $handlerProphecy->write(Argument::that(static fn (CacheInterface $cache): bool => $cache->getSignature() === $signature))->shouldBeCalled();
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
+        $cachedSignature = $this->createSignatureDouble(false);
+        $signature = $this->createSignatureDouble(false);
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache);
 
+        $manager = new FileCacheManager($handler, $signature);
         unset($manager);
+
+        self::assertSame(1, AccessibleObject::create($handler)->writeCallCount);
     }
 
     public function testUsesCacheIfCachedSignatureIsEqualAndNoFileWasUpdated(): void
     {
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
-
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->shouldBeCalled()->willReturn($cachedSignature);
-        $cache = $cacheProphecy->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->shouldBeCalled()->willReturn($cache);
-        $handlerProphecy->write(Argument::is($cache))->shouldNotBeCalled();
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache);
 
+        $manager = new FileCacheManager($handler, $signature);
         unset($manager);
+
+        self::assertSame(0, AccessibleObject::create($handler)->writeCallCount);
     }
 
     public function testNeedFixingReturnsTrueIfCacheHasNoHash(): void
     {
-        $file = 'hello.php';
-        $fileContent = '<?php echo "Hello!"';
-
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
-
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($file))->willReturn(false);
-        $cache = $cacheProphecy->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache, $this->getFile());
 
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($this->getFile());
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
+        $manager = new FileCacheManager($handler, $signature);
 
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
-
-        self::assertTrue($manager->needFixing($file, $fileContent));
+        self::assertTrue($manager->needFixing('hello.php', '<?php echo "Hello!"'));
     }
 
     public function testNeedFixingReturnsTrueIfCachedHashIsDifferent(): void
     {
         $file = 'hello.php';
-        $fileContent = '<?php echo "Hello!"';
-        $previousFileContent = '<?php echo "Hello, world!"';
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
+        $cache = $this->createCacheDouble($cachedSignature, [$file => md5('<?php echo "Hello, old world!";')]);
+        $handler = $this->createFileHandlerDouble($cache, $this->getFile());
 
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $manager = new FileCacheManager($handler, $signature);
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($file))->willReturn(true);
-        $cacheProphecy->get(Argument::is($file))->willReturn(md5($previousFileContent));
-        $cache = $cacheProphecy->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($this->getFile());
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
-
-        self::assertTrue($manager->needFixing($file, $fileContent));
+        self::assertTrue($manager->needFixing($file, '<?php echo "Hello, new world!";'));
     }
 
     public function testNeedFixingReturnsFalseIfCachedHashIsIdentical(): void
@@ -179,28 +114,12 @@ final class FileCacheManagerTest extends TestCase
         $file = 'hello.php';
         $fileContent = '<?php echo "Hello!"';
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
+        $cache = $this->createCacheDouble($cachedSignature, [$file => md5($fileContent)]);
+        $handler = $this->createFileHandlerDouble($cache, $this->getFile());
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($file))->willReturn(true);
-        $cacheProphecy->get(Argument::is($file))->willReturn(md5($fileContent));
-        $cache = $cacheProphecy->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($this->getFile());
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
+        $manager = new FileCacheManager($handler, $signature);
 
         self::assertFalse($manager->needFixing($file, $fileContent));
     }
@@ -210,37 +129,17 @@ final class FileCacheManagerTest extends TestCase
         $cacheFile = $this->getFile();
         $file = '/foo/bar/baz/src/hello.php';
         $relativePathToFile = 'src/hello.php';
-        $fileContent = '<?php echo "Hello!"';
 
-        $directoryProphecy = $this->prophesize(\PhpCsFixer\Cache\DirectoryInterface::class);
-        $directoryProphecy->getRelativePathTo(Argument::is($file))->willReturn($relativePathToFile);
+        $directory = $this->createDirectoryDouble($relativePathToFile);
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
+        $cache = $this->createCacheDouble($cachedSignature, [$relativePathToFile => md5('<?php echo "Old!"')]);
+        $handler = $this->createFileHandlerDouble($cache, $this->getFile());
 
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $manager = new FileCacheManager($handler, $signature, false, $directory);
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($relativePathToFile))->willReturn(true);
-        $cacheProphecy->has(Argument::is($relativePathToFile))->willReturn(0);
-        $cache = $cacheProphecy->reveal();
-
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($cacheFile);
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature,
-            false,
-            $directoryProphecy->reveal()
-        );
-
-        self::assertTrue($manager->needFixing($file, $fileContent));
+        self::assertTrue($manager->needFixing($file, '<?php echo "New!"'));
     }
 
     public function testSetFileSetsHashOfFileContent(): void
@@ -249,29 +148,22 @@ final class FileCacheManagerTest extends TestCase
         $file = 'hello.php';
         $fileContent = '<?php echo "Hello!"';
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache, $cacheFile);
 
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $manager = new FileCacheManager($handler, $signature);
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->set(Argument::is($file), Argument::is(md5($fileContent)))->shouldBeCalled();
-        $cache = $cacheProphecy->reveal();
+        self::assertFalse($cache->has($file));
 
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($cacheFile);
-        $handlerProphecy->write(Argument::is($cache))->shouldBeCalled();
-        $handler = $handlerProphecy->reveal();
+        $manager->setFile($file, $fileContent);
 
-        $manager = new FileCacheManager(
-            $handler,
-            $signature
-        );
+        unset($manager);
 
-        $manager->setFile($file, $fileContent);
+        self::assertTrue($cache->has($file));
+        self::assertSame(md5($fileContent), $cache->get($file));
+        self::assertSame(1, AccessibleObject::create($handler)->writeCallCount);
     }
 
     public function testSetFileSetsHashOfFileContentDuringDryRunIfCacheHasNoHash(): void
@@ -281,31 +173,20 @@ final class FileCacheManagerTest extends TestCase
         $file = 'hello.php';
         $fileContent = '<?php echo "Hello!"';
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($file))->willReturn(false);
-        $cacheProphecy->set(Argument::is($file), Argument::is(md5($fileContent)))->shouldBeCalled();
-        $cache = $cacheProphecy->reveal();
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache, $cacheFile);
 
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($cacheFile);
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
+        self::assertFalse($cache->has($file));
 
-        $manager = new FileCacheManager(
-            $handler,
-            $signature,
-            $isDryRun
-        );
+        $manager = new FileCacheManager($handler, $signature, $isDryRun);
 
         $manager->setFile($file, $fileContent);
+
+        self::assertTrue($cache->has($file));
+        self::assertSame(md5($fileContent), $cache->get($file));
     }
 
     public function testSetFileClearsHashDuringDryRunIfCachedHashIsDifferent(): void
@@ -316,32 +197,17 @@ final class FileCacheManagerTest extends TestCase
         $fileContent = '<?php echo "Hello!"';
         $previousFileContent = '<?php echo "Hello, world!"';
 
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
 
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->has(Argument::is($file))->willReturn(true);
-        $cacheProphecy->get(Argument::is($file))->willReturn(md5($previousFileContent));
-        $cacheProphecy->clear(Argument::is($file))->shouldBeCalled();
-        $cache = $cacheProphecy->reveal();
+        $cache = $this->createCacheDouble($cachedSignature, [$file => md5($previousFileContent)]);
+        $handler = $this->createFileHandlerDouble($cache, $cacheFile);
 
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($cacheFile);
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
-
-        $manager = new FileCacheManager(
-            $handler,
-            $signature,
-            $isDryRun
-        );
+        $manager = new FileCacheManager($handler, $signature, $isDryRun);
 
         $manager->setFile($file, $fileContent);
+
+        self::assertFalse($cache->has($file));
     }
 
     public function testSetFileUsesRelativePathToFile(): void
@@ -351,38 +217,170 @@ final class FileCacheManagerTest extends TestCase
         $relativePathToFile = 'src/hello.php';
         $fileContent = '<?php echo "Hello!"';
 
-        $directoryProphecy = $this->prophesize(\PhpCsFixer\Cache\DirectoryInterface::class);
-        $directoryProphecy->getRelativePathTo(Argument::is($file))->willReturn($relativePathToFile);
-
-        $cachedSignature = $this->prophesize(SignatureInterface::class)->reveal();
-
-        $signatureProphecy = $this->prophesize(SignatureInterface::class);
-        $signatureProphecy->equals(Argument::is($cachedSignature))->willReturn(true);
-        $signature = $signatureProphecy->reveal();
-
-        $cacheProphecy = $this->prophesize(CacheInterface::class);
-        $cacheProphecy->getSignature()->willReturn($cachedSignature);
-        $cacheProphecy->set(Argument::is($relativePathToFile), Argument::is(md5($fileContent)))->shouldBeCalled();
-        $cache = $cacheProphecy->reveal();
+        $directory = $this->createDirectoryDouble($relativePathToFile);
+        $cachedSignature = $this->createSignatureDouble(true);
+        $signature = $this->createSignatureDouble(true);
 
-        $handlerProphecy = $this->prophesize(FileHandlerInterface::class);
-        $handlerProphecy->read()->willReturn($cache);
-        $handlerProphecy->getFile()->willReturn($cacheFile);
-        $handlerProphecy->write(Argument::is($cache));
-        $handler = $handlerProphecy->reveal();
+        $cache = $this->createCacheDouble($cachedSignature);
+        $handler = $this->createFileHandlerDouble($cache, $cacheFile);
 
-        $manager = new FileCacheManager(
-            $handler,
-            $signature,
-            false,
-            $directoryProphecy->reveal()
-        );
+        $manager = new FileCacheManager($handler, $signature, false, $directory);
 
         $manager->setFile($file, $fileContent);
+
+        self::assertTrue($cache->has($relativePathToFile));
+        self::assertSame(md5($fileContent), $cache->get($relativePathToFile));
     }
 
     private function getFile(): string
     {
         return __DIR__.'/../Fixtures/.php_cs.empty-cache';
     }
+
+    private function createDirectoryDouble(string $relativePathToFile): DirectoryInterface
+    {
+        return new class($relativePathToFile) implements DirectoryInterface {
+            private string $relativePathToFile;
+
+            public function __construct(string $relativePathToFile)
+            {
+                $this->relativePathToFile = $relativePathToFile;
+            }
+
+            public function getRelativePathTo(string $file): string
+            {
+                return $this->relativePathToFile;
+            }
+        };
+    }
+
+    private function createSignatureDouble(bool $isEqual): SignatureInterface
+    {
+        return new class($isEqual) implements SignatureInterface {
+            private bool $isEqual;
+
+            public function __construct(bool $isEqual)
+            {
+                $this->isEqual = $isEqual;
+            }
+
+            public function getPhpVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getFixerVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getIndent(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getLineEnding(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getRules(): array
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function equals(SignatureInterface $signature): bool
+            {
+                return $this->isEqual;
+            }
+        };
+    }
+
+    /**
+     * @param array<string, string> $fileMap
+     */
+    private function createCacheDouble(SignatureInterface $signature, array $fileMap = []): CacheInterface
+    {
+        return new class($signature, $fileMap) implements CacheInterface {
+            private SignatureInterface $signature;
+
+            /** @var array<string, string> */
+            private array $fileMap;
+
+            /**
+             * @param array<string, string> $fileMap
+             */
+            public function __construct(SignatureInterface $signature, array $fileMap)
+            {
+                $this->signature = $signature;
+                $this->fileMap = $fileMap;
+            }
+
+            public function getSignature(): SignatureInterface
+            {
+                return $this->signature;
+            }
+
+            public function has(string $file): bool
+            {
+                return isset($this->fileMap[$file]);
+            }
+
+            public function get(string $file): ?string
+            {
+                return $this->fileMap[$file];
+            }
+
+            public function set(string $file, string $hash): void
+            {
+                $this->fileMap[$file] = $hash;
+            }
+
+            public function clear(string $file): void
+            {
+                unset($this->fileMap[$file]);
+            }
+
+            public function toJson(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
+    }
+
+    private function createFileHandlerDouble(?CacheInterface $cache, ?string $file = null, ?string $signature = null): FileHandlerInterface
+    {
+        return new class($cache, $file, $signature) implements FileHandlerInterface {
+            private ?CacheInterface $cache;
+            private ?string $file;
+            private ?string $signature;
+            private int $writeCallCount = 0;
+
+            public function __construct(?CacheInterface $cache, ?string $file, ?string $signature)
+            {
+                $this->cache = $cache;
+                $this->file = $file;
+                $this->signature = $signature;
+            }
+
+            public function getFile(): string
+            {
+                return $this->file;
+            }
+
+            public function read(): ?CacheInterface
+            {
+                return $this->cache;
+            }
+
+            public function write(CacheInterface $cache): void
+            {
+                ++$this->writeCallCount;
+
+                if (null !== $this->signature) {
+                    TestCase::assertSame($this->signature, $cache->getSignature());
+                }
+            }
+        };
+    }
 }

+ 123 - 71
tests/Console/Command/DescribeCommandTest.php

@@ -36,7 +36,6 @@ use PhpCsFixer\Tests\Fixtures\DescribeCommand\DescribeFixtureFixer;
 use PhpCsFixer\Tests\TestCase;
 use PhpCsFixer\Tokenizer\Token;
 use PhpCsFixer\Tokenizer\Tokens;
-use Prophecy\Argument;
 use Symfony\Component\Console\Output\OutputInterface;
 use Symfony\Component\Console\Tester\CommandTester;
 
@@ -339,17 +338,45 @@ $/s',
 
     public function testFixerClassNameIsExposedWhenVerbose(): void
     {
-        $fixerName = uniqid('Foo/bar_');
+        $fixer = new class() implements FixerInterface {
+            public function isCandidate(Tokens $tokens): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function isRisky(): bool
+            {
+                return true;
+            }
+
+            public function fix(\SplFileInfo $file, Tokens $tokens): void
+            {
+                throw new \LogicException('Not implemented.');
+            }
 
-        $fixer = $this->prophesize(FixerInterface::class);
-        $fixer->getName()->willReturn($fixerName);
-        $fixer->getPriority()->willReturn(0);
-        $fixer->isRisky()->willReturn(true);
-        $fixer->getDefinition()->willReturn(new FixerDefinition('Fixes stuff.', []));
-        $mock = $fixer->reveal();
+            public function getDefinition(): FixerDefinition
+            {
+                return new FixerDefinition('Fixes stuff.', []);
+            }
+
+            public function getName(): string
+            {
+                return 'Foo/bar_baz';
+            }
+
+            public function getPriority(): int
+            {
+                return 0;
+            }
+
+            public function supports(\SplFileInfo $file): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
 
         $fixerFactory = new FixerFactory();
-        $fixerFactory->registerFixer($mock, true);
+        $fixerFactory->registerFixer($fixer, true);
 
         $application = new Application();
         $application->add(new DescribeCommand($fixerFactory));
@@ -360,14 +387,14 @@ $/s',
         $commandTester->execute(
             [
                 'command' => $command->getName(),
-                'name' => $fixerName,
+                'name' => 'Foo/bar_baz',
             ],
             [
                 'verbosity' => OutputInterface::VERBOSITY_VERBOSE,
             ]
         );
 
-        self::assertStringContainsString(\get_class($mock), $commandTester->getDisplay(true));
+        self::assertStringContainsString(str_replace("\0", '\\', \get_class($fixer)), $commandTester->getDisplay(true));
     }
 
     public function testCommandDescribesCustomFixer(): void
@@ -457,71 +484,96 @@ Fixing examples:
         };
     }
 
-    private function getDefaultMockedFixer(): FixerInterface
+    private function createFixerDouble(): FixerInterface
     {
-        $fixer = $this->prophesize();
-        $fixer->willImplement(ConfigurableFixerInterface::class);
-        $fixer->willImplement(DeprecatedFixerInterface::class);
-
-        $fixer->getName()->willReturn('Foo/bar');
-        $fixer->getPriority()->willReturn(0);
-        $fixer->isRisky()->willReturn(true);
-        $fixer->getSuccessorsNames()->willReturn(['Foo/baz']);
-
-        $functionNames = ['foo', 'test'];
-
-        $fixer->getConfigurationDefinition()->willReturn(new FixerConfigurationResolver([
-            (new AliasedFixerOptionBuilder(new FixerOptionBuilder('functions', 'List of `function` names to fix.'), 'funcs'))
-                ->setAllowedTypes(['array'])
-                ->setAllowedValues([new AllowedValueSubset($functionNames)])
-                ->setDefault($functionNames)
-                ->getOption(),
-            (new FixerOptionBuilder('deprecated_option', 'A deprecated option.'))
-                ->setAllowedTypes(['bool'])
-                ->setDefault(false)
-                ->setDeprecationMessage('Use option `functions` instead.')
-                ->getOption(),
-        ]));
-
-        $fixer->getDefinition()->willReturn(new FixerDefinition(
-            'Fixes stuff.',
-            [
-                new CodeSample(
-                    "<?php echo 'bad stuff and bad thing';\n"
-                ),
-                new CodeSample(
-                    "<?php echo 'bad stuff and bad thing';\n",
-                    ['functions' => ['foo', 'bar']]
-                ),
-            ],
-            'Replaces bad stuff with good stuff.',
-            'Can break stuff.'
-        ));
-
-        $things = false;
-        $fixer->configure([])->will(static function () use (&$things): void {
-            $things = false;
-        });
-        $fixer->configure(['functions' => ['foo', 'bar']])->will(static function () use (&$things): void {
-            $things = true;
-        });
-
-        $fixer->fix(
-            Argument::type(\SplFileInfo::class),
-            Argument::type(Tokens::class)
-        )->will(static function (array $arguments) use (&$things): void {
-            $arguments[1][3] = new Token([
-                $arguments[1][3]->getId(),
-                $things ? '\'good stuff and good thing\'' : '\'good stuff and bad thing\'',
-            ]);
-        });
-
-        return $fixer->reveal();
+        return new class() implements ConfigurableFixerInterface, DeprecatedFixerInterface {
+            /** @var array<mixed> */
+            private array $configuration;
+
+            public function configure(array $configuration): void
+            {
+                $this->configuration = $configuration;
+            }
+
+            public function getConfigurationDefinition(): FixerConfigurationResolver
+            {
+                $functionNames = ['foo', 'test'];
+
+                return new FixerConfigurationResolver([
+                    (new AliasedFixerOptionBuilder(new FixerOptionBuilder('functions', 'List of `function` names to fix.'), 'funcs'))
+                        ->setAllowedTypes(['array'])
+                        ->setAllowedValues([new AllowedValueSubset($functionNames)])
+                        ->setDefault($functionNames)
+                        ->getOption(),
+                    (new FixerOptionBuilder('deprecated_option', 'A deprecated option.'))
+                        ->setAllowedTypes(['bool'])
+                        ->setDefault(false)
+                        ->setDeprecationMessage('Use option `functions` instead.')
+                        ->getOption(),
+                ]);
+            }
+
+            public function getSuccessorsNames(): array
+            {
+                return ['Foo/baz'];
+            }
+
+            public function isCandidate(Tokens $tokens): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function isRisky(): bool
+            {
+                return true;
+            }
+
+            public function fix(\SplFileInfo $file, Tokens $tokens): void
+            {
+                $tokens[3] = new Token([
+                    $tokens[3]->getId(),
+                    [] !== $this->configuration ? '\'good stuff and good thing\'' : '\'good stuff and bad thing\'',
+                ]);
+            }
+
+            public function getDefinition(): FixerDefinition
+            {
+                return new FixerDefinition(
+                    'Fixes stuff.',
+                    [
+                        new CodeSample(
+                            "<?php echo 'bad stuff and bad thing';\n"
+                        ),
+                        new CodeSample(
+                            "<?php echo 'bad stuff and bad thing';\n",
+                            ['functions' => ['foo', 'bar']]
+                        ),
+                    ],
+                    'Replaces bad stuff with good stuff.',
+                    'Can break stuff.'
+                );
+            }
+
+            public function getName(): string
+            {
+                return 'Foo/bar';
+            }
+
+            public function getPriority(): int
+            {
+                return 0;
+            }
+
+            public function supports(\SplFileInfo $file): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
     }
 
     private function execute(string $name, bool $decorated, ?FixerInterface $fixer = null): CommandTester
     {
-        $fixer ??= $this->getDefaultMockedFixer();
+        $fixer ??= $this->createFixerDouble();
 
         $fixerClassName = \get_class($fixer);
         $isBuiltIn = str_starts_with($fixerClassName, 'PhpCsFixer') && !str_contains($fixerClassName, '@anon');

+ 130 - 62
tests/Console/Command/SelfUpdateCommandTest.php

@@ -20,10 +20,12 @@ use org\bovigo\vfs\vfsStreamException;
 use org\bovigo\vfs\vfsStreamWrapper;
 use PhpCsFixer\Console\Application;
 use PhpCsFixer\Console\Command\SelfUpdateCommand;
+use PhpCsFixer\Console\SelfUpdate\GithubClientInterface;
 use PhpCsFixer\Console\SelfUpdate\NewVersionChecker;
+use PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface;
+use PhpCsFixer\PharCheckerInterface;
 use PhpCsFixer\Tests\TestCase;
 use PhpCsFixer\ToolInfoInterface;
-use Prophecy\Argument;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Tester\CommandTester;
 
@@ -70,9 +72,9 @@ final class SelfUpdateCommandTest extends TestCase
     public function testCommandName(string $name): void
     {
         $command = new SelfUpdateCommand(
-            $this->prophesize(\PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface::class)->reveal(),
-            $this->createToolInfo(),
-            $this->prophesize(\PhpCsFixer\PharCheckerInterface::class)->reveal()
+            $this->createNewVersionCheckerDouble(),
+            $this->createToolInfoDouble(),
+            $this->createPharCheckerDouble(),
         );
 
         $application = new Application();
@@ -101,28 +103,12 @@ final class SelfUpdateCommandTest extends TestCase
         string $expectedFileContents,
         string $expectedDisplay
     ): void {
-        $versionChecker = $this->prophesize(\PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface::class);
-
-        $versionChecker->getLatestVersion()->willReturn($latestVersion);
-
-        $versionChecker
-            ->getLatestVersionOfMajor(self::getCurrentMajorVersion())
-            ->willReturn($latestMinorVersion)
-        ;
-
-        $actualVersionCheck = new NewVersionChecker(
-            $this->prophesize(\PhpCsFixer\Console\SelfUpdate\GithubClientInterface::class)->reveal()
-        );
-
-        $versionChecker
-            ->compareVersions(Argument::type('string'), Argument::type('string'))
-            ->will(static fn (array $arguments): int => $actualVersionCheck->compareVersions($arguments[0], $arguments[1]))
-        ;
+        $versionChecker = $this->createNewVersionCheckerDouble($latestVersion, $latestMinorVersion);
 
         $command = new SelfUpdateCommand(
-            $versionChecker->reveal(),
-            $this->createToolInfo(),
-            $this->prophesize(\PhpCsFixer\PharCheckerInterface::class)->reveal()
+            $versionChecker,
+            $this->createToolInfoDouble(),
+            $this->createPharCheckerDouble(),
         );
 
         $commandTester = $this->execute($command, $input, $decorated);
@@ -271,38 +257,22 @@ final class SelfUpdateCommandTest extends TestCase
      * @dataProvider provideExecuteWhenNotAbleToGetLatestVersionsCases
      */
     public function testExecuteWhenNotAbleToGetLatestVersions(
-        bool $latestVersionSuccess,
+        bool $latestMajorVersionSuccess,
         bool $latestMinorVersionSuccess,
         array $input,
         bool $decorated
     ): void {
-        $versionChecker = $this->prophesize(\PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface::class);
-
-        $newMajorVersion = self::getNewMajorReleaseVersion();
-        $versionChecker->getLatestVersion()->will(static function () use ($latestVersionSuccess, $newMajorVersion): string {
-            if ($latestVersionSuccess) {
-                return $newMajorVersion;
-            }
-
-            throw new \RuntimeException('Foo.');
-        });
-
-        $newMinorVersion = self::getNewMinorReleaseVersion();
-        $versionChecker
-            ->getLatestVersionOfMajor(self::getCurrentMajorVersion())
-            ->will(static function () use ($latestMinorVersionSuccess, $newMinorVersion): string {
-                if ($latestMinorVersionSuccess) {
-                    return $newMinorVersion;
-                }
-
-                throw new \RuntimeException('Foo.');
-            })
-        ;
+        $versionChecker = $this->createNewVersionCheckerDouble(
+            self::getNewMajorReleaseVersion(),
+            self::getNewMinorReleaseVersion(),
+            $latestMajorVersionSuccess,
+            $latestMinorVersionSuccess,
+        );
 
         $command = new SelfUpdateCommand(
-            $versionChecker->reveal(),
-            $this->createToolInfo(),
-            $this->prophesize(\PhpCsFixer\PharCheckerInterface::class)->reveal()
+            $versionChecker,
+            $this->createToolInfoDouble(),
+            $this->createPharCheckerDouble(),
         );
 
         $commandTester = $this->execute($command, $input, $decorated);
@@ -361,9 +331,9 @@ final class SelfUpdateCommandTest extends TestCase
     public function testExecuteWhenNotInstalledAsPhar(array $input, bool $decorated): void
     {
         $command = new SelfUpdateCommand(
-            $this->prophesize(\PhpCsFixer\Console\SelfUpdate\NewVersionCheckerInterface::class)->reveal(),
-            $this->createToolInfo(false),
-            $this->prophesize(\PhpCsFixer\PharCheckerInterface::class)->reveal()
+            $this->createNewVersionCheckerDouble(),
+            $this->createToolInfoDouble(false),
+            $this->createPharCheckerDouble(),
         );
 
         $commandTester = $this->execute($command, $input, $decorated);
@@ -424,18 +394,48 @@ final class SelfUpdateCommandTest extends TestCase
         );
     }
 
-    private function createToolInfo(bool $isInstalledAsPhar = true): ToolInfoInterface
+    private function createToolInfoDouble(bool $isInstalledAsPhar = true): ToolInfoInterface
     {
-        $root = $this->root;
+        return new class($this->root, $isInstalledAsPhar) implements ToolInfoInterface {
+            private vfsStreamDirectory $directory;
+            private bool $isInstalledAsPhar;
+
+            public function __construct(vfsStreamDirectory $directory, bool $isInstalledAsPhar)
+            {
+                $this->directory = $directory;
+                $this->isInstalledAsPhar = $isInstalledAsPhar;
+            }
+
+            public function getComposerInstallationDetails(): array
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getComposerVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function isInstalledAsPhar(): bool
+            {
+                return $this->isInstalledAsPhar;
+            }
 
-        $toolInfo = $this->prophesize(ToolInfoInterface::class);
-        $toolInfo->isInstalledAsPhar()->willReturn($isInstalledAsPhar);
-        $toolInfo
-            ->getPharDownloadUri(Argument::type('string'))
-            ->will(static fn (array $arguments): string => "{$root->url()}/{$arguments[0]}.phar")
-        ;
+            public function isInstalledByComposer(): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
 
-        return $toolInfo->reveal();
+            public function getPharDownloadUri(string $version): string
+            {
+                return sprintf('%s/%s.phar', $this->directory->url(), $version);
+            }
+        };
     }
 
     private function getToolPath(): string
@@ -462,4 +462,72 @@ final class SelfUpdateCommandTest extends TestCase
     {
         return self::getNewMajorVersion().'.0.0';
     }
+
+    private function createNewVersionCheckerDouble(
+        string $latestVersion = Application::VERSION,
+        ?string $latestMinorVersion = Application::VERSION,
+        bool $latestMajorVersionSuccess = true,
+        bool $latestMinorVersionSuccess = true
+    ): NewVersionCheckerInterface {
+        return new class($latestVersion, $latestMinorVersion, $latestMajorVersionSuccess, $latestMinorVersionSuccess) implements NewVersionCheckerInterface {
+            private string $latestVersion;
+            private ?string $latestMinorVersion;
+            private bool $latestMajorVersionSuccess;
+            private bool $latestMinorVersionSuccess;
+
+            public function __construct(
+                string $latestVersion,
+                ?string $latestMinorVersion,
+                bool $latestMajorVersionSuccess = true,
+                bool $latestMinorVersionSuccess = true
+            ) {
+                $this->latestVersion = $latestVersion;
+                $this->latestMinorVersion = $latestMinorVersion;
+                $this->latestMajorVersionSuccess = $latestMajorVersionSuccess;
+                $this->latestMinorVersionSuccess = $latestMinorVersionSuccess;
+            }
+
+            public function getLatestVersion(): string
+            {
+                if ($this->latestMajorVersionSuccess) {
+                    return $this->latestVersion;
+                }
+
+                throw new \RuntimeException('Foo.');
+            }
+
+            public function getLatestVersionOfMajor(int $majorVersion): ?string
+            {
+                TestCase::assertSame((int) preg_replace('/^v?(\d+).*$/', '$1', Application::VERSION), $majorVersion);
+
+                if ($this->latestMinorVersionSuccess) {
+                    return $this->latestMinorVersion;
+                }
+
+                throw new \RuntimeException('Foo.');
+            }
+
+            public function compareVersions(string $versionA, string $versionB): int
+            {
+                return (new NewVersionChecker(
+                    new class() implements GithubClientInterface {
+                        public function getTags(): array
+                        {
+                            throw new \LogicException('Not implemented.');
+                        }
+                    }
+                ))->compareVersions($versionA, $versionB);
+            }
+        };
+    }
+
+    private function createPharCheckerDouble(): PharCheckerInterface
+    {
+        return new class() implements PharCheckerInterface {
+            public function checkFileValidity(string $filename): ?string
+            {
+                return null;
+            }
+        };
+    }
 }

+ 19 - 4
tests/Console/Report/FixReport/ReporterFactoryTest.php

@@ -16,6 +16,7 @@ namespace PhpCsFixer\Tests\Console\Report\FixReport;
 
 use PhpCsFixer\Console\Report\FixReport\ReporterFactory;
 use PhpCsFixer\Console\Report\FixReport\ReporterInterface;
+use PhpCsFixer\Console\Report\FixReport\ReportSummary;
 use PhpCsFixer\Tests\TestCase;
 
 /**
@@ -109,9 +110,23 @@ final class ReporterFactoryTest extends TestCase
 
     private function createReporterDouble(string $format): ReporterInterface
     {
-        $reporter = $this->prophesize(ReporterInterface::class);
-        $reporter->getFormat()->willReturn($format);
-
-        return $reporter->reveal();
+        return new class($format) implements ReporterInterface {
+            private string $format;
+
+            public function __construct(string $format)
+            {
+                $this->format = $format;
+            }
+
+            public function getFormat(): string
+            {
+                return $this->format;
+            }
+
+            public function generate(ReportSummary $reportSummary): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
     }
 }

+ 19 - 4
tests/Console/Report/ListSetsReport/ReporterFactoryTest.php

@@ -16,6 +16,7 @@ namespace PhpCsFixer\Tests\Console\Report\ListSetsReport;
 
 use PhpCsFixer\Console\Report\ListSetsReport\ReporterFactory;
 use PhpCsFixer\Console\Report\ListSetsReport\ReporterInterface;
+use PhpCsFixer\Console\Report\ListSetsReport\ReportSummary;
 use PhpCsFixer\Tests\TestCase;
 
 /**
@@ -110,9 +111,23 @@ final class ReporterFactoryTest extends TestCase
 
     private function createReporterDouble(string $format): ReporterInterface
     {
-        $reporter = $this->prophesize(ReporterInterface::class);
-        $reporter->getFormat()->willReturn($format);
-
-        return $reporter->reveal();
+        return new class($format) implements ReporterInterface {
+            private string $format;
+
+            public function __construct(string $format)
+            {
+                $this->format = $format;
+            }
+
+            public function getFormat(): string
+            {
+                return $this->format;
+            }
+
+            public function generate(ReportSummary $reportSummary): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
     }
 }

+ 286 - 285
tests/Console/SelfUpdate/NewVersionCheckerTest.php

@@ -101,290 +101,291 @@ final class NewVersionCheckerTest extends TestCase
 
     private function createGithubClientStub(): GithubClientInterface
     {
-        $githubClient = $this->prophesize(GithubClientInterface::class);
-
-        $githubClient->getTags()->willReturn([
-            [
-                'name' => 'v3.0.0-RC',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v3.0.0-RC',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v3.0.0-RC',
-                'commit' => [
-                    'sha' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-                ],
-            ],
-            [
-                'name' => 'v2.4.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.4.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.4.1',
-                'commit' => [
-                    'sha' => 'b4983586c8e7b1f99ec05dd1e75c8b673315da70',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/b4983586c8e7b1f99ec05dd1e75c8b673315da70',
-                ],
-            ],
-            [
-                'name' => 'v2.4.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.4.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.4.0',
-                'commit' => [
-                    'sha' => '63661f3add3609e90e4ab8115113e189ae547bb4',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/63661f3add3609e90e4ab8115113e189ae547bb4',
-                ],
-            ],
-            [
-                'name' => 'v2.3.3',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.3',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.3',
-                'commit' => [
-                    'sha' => 'cd1e6c47cd692c2deb8f160bb80b8feb3b265d29',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/cd1e6c47cd692c2deb8f160bb80b8feb3b265d29',
-                ],
-            ],
-            [
-                'name' => 'v2.3.2',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.2',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.2',
-                'commit' => [
-                    'sha' => '597745f744bcce1aed59dfd1bb4603de2a06cda9',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/597745f744bcce1aed59dfd1bb4603de2a06cda9',
-                ],
-            ],
-            [
-                'name' => 'v2.3.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.1',
-                'commit' => [
-                    'sha' => 'd5257f7433bb490299c4f300d95598fd911a8ab0',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d5257f7433bb490299c4f300d95598fd911a8ab0',
-                ],
-            ],
-            [
-                'name' => 'v2.3.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.0',
-                'commit' => [
-                    'sha' => 'ab8c61329ddd896e287a84c7663d06cf1bed3907',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/ab8c61329ddd896e287a84c7663d06cf1bed3907',
-                ],
-            ],
-            [
-                'name' => 'v2.2.6',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.6',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.6',
-                'commit' => [
-                    'sha' => 'c1cc52c242f17c4d52d9601159631da488fac7a4',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c1cc52c242f17c4d52d9601159631da488fac7a4',
-                ],
-            ],
-            [
-                'name' => 'v2.2.5',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.5',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.5',
-                'commit' => [
-                    'sha' => '27c2cd9d4abd2178b5b585fa2c3cca656d377c69',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/27c2cd9d4abd2178b5b585fa2c3cca656d377c69',
-                ],
-            ],
-            [
-                'name' => 'v2.2.4',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.4',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.4',
-                'commit' => [
-                    'sha' => '5191e01d0fa0f579eb709350306cd11ad6427ca6',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/5191e01d0fa0f579eb709350306cd11ad6427ca6',
-                ],
-            ],
-            [
-                'name' => 'v2.2.3',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.3',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.3',
-                'commit' => [
-                    'sha' => '8f33cf3da0da94b67b9cd696b2b9dda81c928f72',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/8f33cf3da0da94b67b9cd696b2b9dda81c928f72',
-                ],
-            ],
-            [
-                'name' => 'v2.2.2',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.2',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.2',
-                'commit' => [
-                    'sha' => '362d7bd3df3521966ae0fc82bb67c000c5f25059',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/362d7bd3df3521966ae0fc82bb67c000c5f25059',
-                ],
-            ],
-            [
-                'name' => 'v2.2.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.1',
-                'commit' => [
-                    'sha' => 'aff95e090fdaf57c20d32d7728b090f2015bfcef',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/aff95e090fdaf57c20d32d7728b090f2015bfcef',
-                ],
-            ],
-            [
-                'name' => 'v2.2.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.0',
-                'commit' => [
-                    'sha' => 'd6f17423412d33df6b69c9aaf12037b91703533b',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d6f17423412d33df6b69c9aaf12037b91703533b',
-                ],
-            ],
-            [
-                'name' => 'v2.1.3',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.3',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.3',
-                'commit' => [
-                    'sha' => 'd30ca69f8bed931b5c630407f0a98306e33c2c39',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d30ca69f8bed931b5c630407f0a98306e33c2c39',
-                ],
-            ],
-            [
-                'name' => 'v2.1.2',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.2',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.2',
-                'commit' => [
-                    'sha' => 'c7de769d7b44f2c9de68e1f678b65efd8126f60b',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c7de769d7b44f2c9de68e1f678b65efd8126f60b',
-                ],
-            ],
-            [
-                'name' => 'v2.1.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.1',
-                'commit' => [
-                    'sha' => 'e0e33ce4eaf59ba77ead9ce45256692aa29ecb38',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/e0e33ce4eaf59ba77ead9ce45256692aa29ecb38',
-                ],
-            ],
-            [
-                'name' => 'v2.1.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.0',
-                'commit' => [
-                    'sha' => '2c69f4d424f85062fe40f7689797d6d32c76b711',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/2c69f4d424f85062fe40f7689797d6d32c76b711',
-                ],
-            ],
-            [
-                'name' => 'v2.0.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.1',
-                'commit' => [
-                    'sha' => '863ad254da1e44904c8bf8fbcc9f5624834fc71a',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/863ad254da1e44904c8bf8fbcc9f5624834fc71a',
-                ],
-            ],
-            [
-                'name' => 'v2.0.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0',
-                'commit' => [
-                    'sha' => 'f3baf72eb2f58bf275b372540f5b47d25aed910f',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/f3baf72eb2f58bf275b372540f5b47d25aed910f',
-                ],
-            ],
-            [
-                'name' => 'v2.0.0-beta',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-beta',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-beta',
-                'commit' => [
-                    'sha' => '962b2c537063b670aca2d6f3fb839d2c103def38',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/962b2c537063b670aca2d6f3fb839d2c103def38',
-                ],
-            ],
-            [
-                'name' => 'v2.0.0-alpha',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-alpha',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-alpha',
-                'commit' => [
-                    'sha' => 'd0d76b434728fcf522270b67b454ed7e84e850ed',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d0d76b434728fcf522270b67b454ed7e84e850ed',
-                ],
-            ],
-            [
-                'name' => 'v2.0.0-RC',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-RC',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-RC',
-                'commit' => [
-                    'sha' => 'f88ef17f44fa442e1dd98deb7da0d943be9c8fa8',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/f88ef17f44fa442e1dd98deb7da0d943be9c8fa8',
-                ],
-            ],
-            [
-                'name' => 'v1.14.0-beta',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.14.0-beta',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.14.0-beta',
-                'commit' => [
-                    'sha' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
-                ],
-            ],
-            [
-                'name' => 'v1.13.2',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.2',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.2',
-                'commit' => [
-                    'sha' => '106313aa0d501782260e48ac04a1c671b5d418ea',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/106313aa0d501782260e48ac04a1c671b5d418ea',
-                ],
-            ],
-            [
-                'name' => 'v1.13.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.1',
-                'commit' => [
-                    'sha' => '0ea4f7ed06ca55da1d8fc45da26ff87f261c4088',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/0ea4f7ed06ca55da1d8fc45da26ff87f261c4088',
-                ],
-            ],
-            [
-                'name' => 'v1.13.0',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.0',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.0',
-                'commit' => [
-                    'sha' => 'ac04a510bed5407e91664f8a37b9d58072d96768',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/ac04a510bed5407e91664f8a37b9d58072d96768',
-                ],
-            ],
-            [
-                'name' => 'v1.12.4',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.4',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.4',
-                'commit' => [
-                    'sha' => 'c5a9d66dd27f02a3ffba4ec451ce27702604cdc8',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c5a9d66dd27f02a3ffba4ec451ce27702604cdc8',
-                ],
-            ],
-            [
-                'name' => 'v1.12.3',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.3',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.3',
-                'commit' => [
-                    'sha' => '78a820c16d13f593303511461eefa939502fb2de',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/78a820c16d13f593303511461eefa939502fb2de',
-                ],
-            ],
-            [
-                'name' => 'v1.12.2',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.2',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.2',
-                'commit' => [
-                    'sha' => 'baa7112bef3b86c65fcfaae9a7a50436e3902b41',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/baa7112bef3b86c65fcfaae9a7a50436e3902b41',
-                ],
-            ],
-            [
-                'name' => 'v1.12.1',
-                'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.1',
-                'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.1',
-                'commit' => [
-                    'sha' => 'd33ee60f3d3e6152888b7f3a385f49e5c43bf1bf',
-                    'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf',
-                ],
-            ],
-        ]);
-
-        return $githubClient->reveal();
+        return new class() implements GithubClientInterface {
+            public function getTags(): array
+            {
+                return [
+                    [
+                        'name' => 'v3.0.0-RC',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v3.0.0-RC',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v3.0.0-RC',
+                        'commit' => [
+                            'sha' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.4.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.4.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.4.1',
+                        'commit' => [
+                            'sha' => 'b4983586c8e7b1f99ec05dd1e75c8b673315da70',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/b4983586c8e7b1f99ec05dd1e75c8b673315da70',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.4.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.4.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.4.0',
+                        'commit' => [
+                            'sha' => '63661f3add3609e90e4ab8115113e189ae547bb4',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/63661f3add3609e90e4ab8115113e189ae547bb4',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.3.3',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.3',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.3',
+                        'commit' => [
+                            'sha' => 'cd1e6c47cd692c2deb8f160bb80b8feb3b265d29',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/cd1e6c47cd692c2deb8f160bb80b8feb3b265d29',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.3.2',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.2',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.2',
+                        'commit' => [
+                            'sha' => '597745f744bcce1aed59dfd1bb4603de2a06cda9',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/597745f744bcce1aed59dfd1bb4603de2a06cda9',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.3.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.1',
+                        'commit' => [
+                            'sha' => 'd5257f7433bb490299c4f300d95598fd911a8ab0',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d5257f7433bb490299c4f300d95598fd911a8ab0',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.3.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.3.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.3.0',
+                        'commit' => [
+                            'sha' => 'ab8c61329ddd896e287a84c7663d06cf1bed3907',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/ab8c61329ddd896e287a84c7663d06cf1bed3907',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.6',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.6',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.6',
+                        'commit' => [
+                            'sha' => 'c1cc52c242f17c4d52d9601159631da488fac7a4',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c1cc52c242f17c4d52d9601159631da488fac7a4',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.5',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.5',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.5',
+                        'commit' => [
+                            'sha' => '27c2cd9d4abd2178b5b585fa2c3cca656d377c69',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/27c2cd9d4abd2178b5b585fa2c3cca656d377c69',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.4',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.4',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.4',
+                        'commit' => [
+                            'sha' => '5191e01d0fa0f579eb709350306cd11ad6427ca6',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/5191e01d0fa0f579eb709350306cd11ad6427ca6',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.3',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.3',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.3',
+                        'commit' => [
+                            'sha' => '8f33cf3da0da94b67b9cd696b2b9dda81c928f72',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/8f33cf3da0da94b67b9cd696b2b9dda81c928f72',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.2',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.2',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.2',
+                        'commit' => [
+                            'sha' => '362d7bd3df3521966ae0fc82bb67c000c5f25059',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/362d7bd3df3521966ae0fc82bb67c000c5f25059',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.1',
+                        'commit' => [
+                            'sha' => 'aff95e090fdaf57c20d32d7728b090f2015bfcef',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/aff95e090fdaf57c20d32d7728b090f2015bfcef',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.2.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.2.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.2.0',
+                        'commit' => [
+                            'sha' => 'd6f17423412d33df6b69c9aaf12037b91703533b',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d6f17423412d33df6b69c9aaf12037b91703533b',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.1.3',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.3',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.3',
+                        'commit' => [
+                            'sha' => 'd30ca69f8bed931b5c630407f0a98306e33c2c39',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d30ca69f8bed931b5c630407f0a98306e33c2c39',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.1.2',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.2',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.2',
+                        'commit' => [
+                            'sha' => 'c7de769d7b44f2c9de68e1f678b65efd8126f60b',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c7de769d7b44f2c9de68e1f678b65efd8126f60b',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.1.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.1',
+                        'commit' => [
+                            'sha' => 'e0e33ce4eaf59ba77ead9ce45256692aa29ecb38',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/e0e33ce4eaf59ba77ead9ce45256692aa29ecb38',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.1.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.1.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.1.0',
+                        'commit' => [
+                            'sha' => '2c69f4d424f85062fe40f7689797d6d32c76b711',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/2c69f4d424f85062fe40f7689797d6d32c76b711',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.0.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.1',
+                        'commit' => [
+                            'sha' => '863ad254da1e44904c8bf8fbcc9f5624834fc71a',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/863ad254da1e44904c8bf8fbcc9f5624834fc71a',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.0.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0',
+                        'commit' => [
+                            'sha' => 'f3baf72eb2f58bf275b372540f5b47d25aed910f',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/f3baf72eb2f58bf275b372540f5b47d25aed910f',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.0.0-beta',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-beta',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-beta',
+                        'commit' => [
+                            'sha' => '962b2c537063b670aca2d6f3fb839d2c103def38',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/962b2c537063b670aca2d6f3fb839d2c103def38',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.0.0-alpha',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-alpha',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-alpha',
+                        'commit' => [
+                            'sha' => 'd0d76b434728fcf522270b67b454ed7e84e850ed',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d0d76b434728fcf522270b67b454ed7e84e850ed',
+                        ],
+                    ],
+                    [
+                        'name' => 'v2.0.0-RC',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v2.0.0-RC',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v2.0.0-RC',
+                        'commit' => [
+                            'sha' => 'f88ef17f44fa442e1dd98deb7da0d943be9c8fa8',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/f88ef17f44fa442e1dd98deb7da0d943be9c8fa8',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.14.0-beta',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.14.0-beta',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.14.0-beta',
+                        'commit' => [
+                            'sha' => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.13.2',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.2',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.2',
+                        'commit' => [
+                            'sha' => '106313aa0d501782260e48ac04a1c671b5d418ea',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/106313aa0d501782260e48ac04a1c671b5d418ea',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.13.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.1',
+                        'commit' => [
+                            'sha' => '0ea4f7ed06ca55da1d8fc45da26ff87f261c4088',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/0ea4f7ed06ca55da1d8fc45da26ff87f261c4088',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.13.0',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.13.0',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.13.0',
+                        'commit' => [
+                            'sha' => 'ac04a510bed5407e91664f8a37b9d58072d96768',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/ac04a510bed5407e91664f8a37b9d58072d96768',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.12.4',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.4',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.4',
+                        'commit' => [
+                            'sha' => 'c5a9d66dd27f02a3ffba4ec451ce27702604cdc8',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/c5a9d66dd27f02a3ffba4ec451ce27702604cdc8',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.12.3',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.3',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.3',
+                        'commit' => [
+                            'sha' => '78a820c16d13f593303511461eefa939502fb2de',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/78a820c16d13f593303511461eefa939502fb2de',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.12.2',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.2',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.2',
+                        'commit' => [
+                            'sha' => 'baa7112bef3b86c65fcfaae9a7a50436e3902b41',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/baa7112bef3b86c65fcfaae9a7a50436e3902b41',
+                        ],
+                    ],
+                    [
+                        'name' => 'v1.12.1',
+                        'zipball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/v1.12.1',
+                        'tarball_url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/tarball/v1.12.1',
+                        'commit' => [
+                            'sha' => 'd33ee60f3d3e6152888b7f3a385f49e5c43bf1bf',
+                            'url' => 'https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/commits/d33ee60f3d3e6152888b7f3a385f49e5c43bf1bf',
+                        ],
+                    ],
+                ];
+            }
+        };
     }
 }

+ 62 - 15
tests/Console/WarningsDetectorTest.php

@@ -16,6 +16,7 @@ namespace PhpCsFixer\Tests\Console;
 
 use PhpCsFixer\Console\WarningsDetector;
 use PhpCsFixer\Tests\TestCase;
+use PhpCsFixer\ToolInfoInterface;
 
 /**
  * @author ntzm
@@ -28,10 +29,9 @@ final class WarningsDetectorTest extends TestCase
 {
     public function testDetectOldVendorNotInstalledByComposer(): void
     {
-        $toolInfo = $this->prophesize(\PhpCsFixer\ToolInfoInterface::class);
-        $toolInfo->isInstalledByComposer()->willReturn(false);
+        $toolInfo = $this->createToolInfoDouble(false, 'not-installed-by-composer');
 
-        $warningsDetector = new WarningsDetector($toolInfo->reveal());
+        $warningsDetector = new WarningsDetector($toolInfo);
         $warningsDetector->detectOldVendor();
 
         self::assertSame([], $warningsDetector->getWarnings());
@@ -39,13 +39,9 @@ final class WarningsDetectorTest extends TestCase
 
     public function testDetectOldVendorNotLegacyPackage(): void
     {
-        $toolInfo = $this->prophesize(\PhpCsFixer\ToolInfoInterface::class);
-        $toolInfo->isInstalledByComposer()->willReturn(false);
-        $toolInfo->getComposerInstallationDetails()->willReturn([
-            'name' => 'friendsofphp/php-cs-fixer',
-        ]);
+        $toolInfo = $this->createToolInfoDouble(false, 'friendsofphp/php-cs-fixer');
 
-        $warningsDetector = new WarningsDetector($toolInfo->reveal());
+        $warningsDetector = new WarningsDetector($toolInfo);
         $warningsDetector->detectOldVendor();
 
         self::assertSame([], $warningsDetector->getWarnings());
@@ -53,13 +49,9 @@ final class WarningsDetectorTest extends TestCase
 
     public function testDetectOldVendorLegacyPackage(): void
     {
-        $toolInfo = $this->prophesize(\PhpCsFixer\ToolInfoInterface::class);
-        $toolInfo->isInstalledByComposer()->willReturn(true);
-        $toolInfo->getComposerInstallationDetails()->willReturn([
-            'name' => 'fabpot/php-cs-fixer',
-        ]);
+        $toolInfo = $this->createToolInfoDouble(true, 'fabpot/php-cs-fixer');
 
-        $warningsDetector = new WarningsDetector($toolInfo->reveal());
+        $warningsDetector = new WarningsDetector($toolInfo);
         $warningsDetector->detectOldVendor();
 
         self::assertSame([
@@ -67,4 +59,59 @@ final class WarningsDetectorTest extends TestCase
             'If you need help while solving warnings, ask at https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/discussions/, we will help you!',
         ], $warningsDetector->getWarnings());
     }
+
+    private function createToolInfoDouble(bool $isInstalledByComposer, string $packageName): ToolInfoInterface
+    {
+        $composerInstallationDetails = [
+            'name' => $packageName,
+            'version' => '1.0.0',
+            'dist' => [],
+        ];
+
+        return new class($isInstalledByComposer, $composerInstallationDetails) implements ToolInfoInterface {
+            private bool $isInstalledByComposer;
+
+            /** @var array{name: string, version: string, dist: array{reference?: string}} */
+            private array $composerInstallationDetails;
+
+            /**
+             * @param array{name: string, version: string, dist: array{reference?: string}} $composerInstallationDetails
+             */
+            public function __construct(bool $isInstalledByComposer, array $composerInstallationDetails)
+            {
+                $this->isInstalledByComposer = $isInstalledByComposer;
+                $this->composerInstallationDetails = $composerInstallationDetails;
+            }
+
+            public function getComposerInstallationDetails(): array
+            {
+                return $this->composerInstallationDetails;
+            }
+
+            public function getComposerVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function getVersion(): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function isInstalledAsPhar(): bool
+            {
+                throw new \LogicException('Not implemented.');
+            }
+
+            public function isInstalledByComposer(): bool
+            {
+                return $this->isInstalledByComposer;
+            }
+
+            public function getPharDownloadUri(string $version): string
+            {
+                throw new \LogicException('Not implemented.');
+            }
+        };
+    }
 }

Some files were not shown because too many files changed in this diff