FileFilterIteratorTest.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. <?php
  2. declare(strict_types=1);
  3. /*
  4. * This file is part of PHP CS Fixer.
  5. *
  6. * (c) Fabien Potencier <fabien@symfony.com>
  7. * Dariusz Rumiński <dariusz.ruminski@gmail.com>
  8. *
  9. * This source file is subject to the MIT license that is bundled
  10. * with this source code in the file LICENSE.
  11. */
  12. namespace PhpCsFixer\Tests\Runner;
  13. use PhpCsFixer\Cache\CacheManagerInterface;
  14. use PhpCsFixer\Runner\Event\FileProcessed;
  15. use PhpCsFixer\Runner\FileFilterIterator;
  16. use PhpCsFixer\Tests\TestCase;
  17. use Symfony\Component\EventDispatcher\EventDispatcher;
  18. /**
  19. * @internal
  20. *
  21. * @covers \PhpCsFixer\Runner\FileFilterIterator
  22. */
  23. final class FileFilterIteratorTest extends TestCase
  24. {
  25. /**
  26. * @dataProvider provideAcceptCases
  27. */
  28. public function testAccept(int $repeat): void
  29. {
  30. $file = __FILE__;
  31. $content = file_get_contents($file);
  32. $events = [];
  33. $eventDispatcher = new EventDispatcher();
  34. $eventDispatcher->addListener(
  35. FileProcessed::NAME,
  36. static function (FileProcessed $event) use (&$events): void {
  37. $events[] = $event;
  38. }
  39. );
  40. $fileInfo = new \SplFileInfo($file);
  41. $filter = new FileFilterIterator(
  42. new \ArrayIterator(array_fill(0, $repeat, $fileInfo)),
  43. $eventDispatcher,
  44. $this->createCacheManagerDouble(true)
  45. );
  46. self::assertCount(0, $events);
  47. $files = iterator_to_array($filter);
  48. self::assertCount(1, $files);
  49. self::assertSame($fileInfo, reset($files));
  50. }
  51. /**
  52. * @return iterable<array{int}>
  53. */
  54. public static function provideAcceptCases(): iterable
  55. {
  56. yield [1];
  57. yield [2];
  58. yield [3];
  59. }
  60. public function testEmitSkipEventWhenCacheNeedFixingFalse(): void
  61. {
  62. $file = __FILE__;
  63. $content = file_get_contents($file);
  64. $events = [];
  65. $eventDispatcher = new EventDispatcher();
  66. $eventDispatcher->addListener(
  67. FileProcessed::NAME,
  68. static function (FileProcessed $event) use (&$events): void {
  69. $events[] = $event;
  70. }
  71. );
  72. $filter = new FileFilterIterator(
  73. new \ArrayIterator([new \SplFileInfo($file)]),
  74. $eventDispatcher,
  75. $this->createCacheManagerDouble(false)
  76. );
  77. self::assertCount(0, $filter);
  78. self::assertCount(1, $events);
  79. /** @var FileProcessed $event */
  80. $event = reset($events);
  81. self::assertInstanceOf(FileProcessed::class, $event);
  82. self::assertSame(FileProcessed::STATUS_SKIPPED, $event->getStatus());
  83. }
  84. public function testIgnoreEmptyFile(): void
  85. {
  86. $file = __DIR__.'/../Fixtures/empty.php';
  87. $content = file_get_contents($file);
  88. $events = [];
  89. $eventDispatcher = new EventDispatcher();
  90. $eventDispatcher->addListener(
  91. FileProcessed::NAME,
  92. static function (FileProcessed $event) use (&$events): void {
  93. $events[] = $event;
  94. }
  95. );
  96. $filter = new FileFilterIterator(
  97. new \ArrayIterator([new \SplFileInfo($file)]),
  98. $eventDispatcher,
  99. $this->createCacheManagerDouble(true)
  100. );
  101. self::assertCount(0, $filter);
  102. self::assertCount(1, $events);
  103. /** @var FileProcessed $event */
  104. $event = reset($events);
  105. self::assertInstanceOf(FileProcessed::class, $event);
  106. self::assertSame(FileProcessed::STATUS_SKIPPED, $event->getStatus());
  107. }
  108. public function testIgnore(): void
  109. {
  110. $eventDispatcher = new EventDispatcher();
  111. $eventDispatcher->addListener(
  112. FileProcessed::NAME,
  113. static function (): void {
  114. throw new \Exception('No event expected.');
  115. }
  116. );
  117. $filter = new FileFilterIterator(
  118. new \ArrayIterator([
  119. new \SplFileInfo(__DIR__),
  120. new \SplFileInfo('__INVALID__'),
  121. ]),
  122. $eventDispatcher,
  123. $this->createCacheManagerDouble(true)
  124. );
  125. self::assertCount(0, $filter);
  126. }
  127. public function testWithoutDispatcher(): void
  128. {
  129. $file = __FILE__;
  130. $content = file_get_contents($file);
  131. $filter = new FileFilterIterator(
  132. new \ArrayIterator([new \SplFileInfo($file)]),
  133. null,
  134. $this->createCacheManagerDouble(false)
  135. );
  136. self::assertCount(0, $filter);
  137. }
  138. public function testInvalidIterator(): void
  139. {
  140. $filter = new FileFilterIterator(
  141. new \ArrayIterator([__FILE__]), // @phpstan-ignore-line we want this check for contexts without static analysis
  142. null,
  143. $this->createCacheManagerDouble(true)
  144. );
  145. $this->expectException(
  146. \RuntimeException::class
  147. );
  148. $this->expectExceptionMessageMatches(
  149. '#^Expected instance of "\\\SplFileInfo", got "string"\.$#'
  150. );
  151. iterator_to_array($filter);
  152. }
  153. /**
  154. * @requires OS Linux|Darwin
  155. */
  156. public function testFileIsAcceptedAfterFilteredAsSymlink(): void
  157. {
  158. $link = __DIR__.'/../Fixtures/Test/FileFilterIteratorTest/FileFilterIteratorTest.php.link';
  159. self::assertTrue(is_link($link), 'Fixture data is no longer correct for this test.');
  160. self::assertSame(__FILE__, realpath($link), 'Fixture data is no longer correct for this test.');
  161. $file = new \SplFileInfo(__FILE__);
  162. $link = new \SplFileInfo($link);
  163. $filter = new FileFilterIterator(
  164. new \ArrayIterator([$link, $file]),
  165. null,
  166. $this->createCacheManagerDouble(true)
  167. );
  168. $files = iterator_to_array($filter);
  169. self::assertCount(1, $files);
  170. self::assertSame($file, reset($files));
  171. }
  172. private function createCacheManagerDouble(bool $needFixing): CacheManagerInterface
  173. {
  174. return new class($needFixing) implements CacheManagerInterface {
  175. private bool $needFixing;
  176. public function __construct(bool $needFixing)
  177. {
  178. $this->needFixing = $needFixing;
  179. }
  180. public function needFixing(string $file, string $fileContent): bool
  181. {
  182. return $this->needFixing;
  183. }
  184. public function setFile(string $file, string $fileContent): void
  185. {
  186. throw new \LogicException('Not implemented.');
  187. }
  188. public function setFileHash(string $file, string $hash): void
  189. {
  190. throw new \LogicException('Not implemented.');
  191. }
  192. };
  193. }
  194. }