FinderTest.php 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Symfony\Component\Finder\Tests;
  11. use Symfony\Component\Finder\Finder;
  12. class FinderTest extends Iterator\RealIteratorTestCase
  13. {
  14. public function testCreate()
  15. {
  16. $this->assertInstanceOf('Symfony\Component\Finder\Finder', Finder::create());
  17. }
  18. public function testDirectories()
  19. {
  20. $finder = $this->buildFinder();
  21. $this->assertSame($finder, $finder->directories());
  22. $this->assertIterator($this->toAbsolute(['foo', 'toto']), $finder->in(self::$tmpDir)->getIterator());
  23. $finder = $this->buildFinder();
  24. $finder->directories();
  25. $finder->files();
  26. $finder->directories();
  27. $this->assertIterator($this->toAbsolute(['foo', 'toto']), $finder->in(self::$tmpDir)->getIterator());
  28. }
  29. public function testFiles()
  30. {
  31. $finder = $this->buildFinder();
  32. $this->assertSame($finder, $finder->files());
  33. $this->assertIterator($this->toAbsolute(['foo/bar.tmp', 'test.php', 'test.py', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  34. $finder = $this->buildFinder();
  35. $finder->files();
  36. $finder->directories();
  37. $finder->files();
  38. $this->assertIterator($this->toAbsolute(['foo/bar.tmp', 'test.php', 'test.py', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  39. }
  40. public function testRemoveTrailingSlash()
  41. {
  42. $finder = $this->buildFinder();
  43. $expected = $this->toAbsolute(['foo/bar.tmp', 'test.php', 'test.py', 'foo bar']);
  44. $in = self::$tmpDir.'//';
  45. $this->assertIterator($expected, $finder->in($in)->files()->getIterator());
  46. }
  47. public function testSymlinksNotResolved()
  48. {
  49. if ('\\' === \DIRECTORY_SEPARATOR) {
  50. $this->markTestSkipped('symlinks are not supported on Windows');
  51. }
  52. $finder = $this->buildFinder();
  53. symlink($this->toAbsolute('foo'), $this->toAbsolute('baz'));
  54. $expected = $this->toAbsolute(['baz/bar.tmp']);
  55. $in = self::$tmpDir.'/baz/';
  56. try {
  57. $this->assertIterator($expected, $finder->in($in)->files()->getIterator());
  58. unlink($this->toAbsolute('baz'));
  59. } catch (\Exception $e) {
  60. unlink($this->toAbsolute('baz'));
  61. throw $e;
  62. }
  63. }
  64. public function testBackPathNotNormalized()
  65. {
  66. $finder = $this->buildFinder();
  67. $expected = $this->toAbsolute(['foo/../foo/bar.tmp']);
  68. $in = self::$tmpDir.'/foo/../foo/';
  69. $this->assertIterator($expected, $finder->in($in)->files()->getIterator());
  70. }
  71. public function testDepth()
  72. {
  73. $finder = $this->buildFinder();
  74. $this->assertSame($finder, $finder->depth('< 1'));
  75. $this->assertIterator($this->toAbsolute(['foo', 'test.php', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  76. $finder = $this->buildFinder();
  77. $this->assertSame($finder, $finder->depth('<= 0'));
  78. $this->assertIterator($this->toAbsolute(['foo', 'test.php', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  79. $finder = $this->buildFinder();
  80. $this->assertSame($finder, $finder->depth('>= 1'));
  81. $this->assertIterator($this->toAbsolute(['foo/bar.tmp']), $finder->in(self::$tmpDir)->getIterator());
  82. $finder = $this->buildFinder();
  83. $finder->depth('< 1')->depth('>= 1');
  84. $this->assertIterator([], $finder->in(self::$tmpDir)->getIterator());
  85. }
  86. public function testName()
  87. {
  88. $finder = $this->buildFinder();
  89. $this->assertSame($finder, $finder->name('*.php'));
  90. $this->assertIterator($this->toAbsolute(['test.php']), $finder->in(self::$tmpDir)->getIterator());
  91. $finder = $this->buildFinder();
  92. $finder->name('test.ph*');
  93. $finder->name('test.py');
  94. $this->assertIterator($this->toAbsolute(['test.php', 'test.py']), $finder->in(self::$tmpDir)->getIterator());
  95. $finder = $this->buildFinder();
  96. $finder->name('~^test~i');
  97. $this->assertIterator($this->toAbsolute(['test.php', 'test.py']), $finder->in(self::$tmpDir)->getIterator());
  98. $finder = $this->buildFinder();
  99. $finder->name('~\\.php$~i');
  100. $this->assertIterator($this->toAbsolute(['test.php']), $finder->in(self::$tmpDir)->getIterator());
  101. $finder = $this->buildFinder();
  102. $finder->name('test.p{hp,y}');
  103. $this->assertIterator($this->toAbsolute(['test.php', 'test.py']), $finder->in(self::$tmpDir)->getIterator());
  104. }
  105. public function testNotName()
  106. {
  107. $finder = $this->buildFinder();
  108. $this->assertSame($finder, $finder->notName('*.php'));
  109. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  110. $finder = $this->buildFinder();
  111. $finder->notName('*.php');
  112. $finder->notName('*.py');
  113. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  114. $finder = $this->buildFinder();
  115. $finder->name('test.ph*');
  116. $finder->name('test.py');
  117. $finder->notName('*.php');
  118. $finder->notName('*.py');
  119. $this->assertIterator([], $finder->in(self::$tmpDir)->getIterator());
  120. $finder = $this->buildFinder();
  121. $finder->name('test.ph*');
  122. $finder->name('test.py');
  123. $finder->notName('*.p{hp,y}');
  124. $this->assertIterator([], $finder->in(self::$tmpDir)->getIterator());
  125. }
  126. /**
  127. * @dataProvider getRegexNameTestData
  128. */
  129. public function testRegexName($regex)
  130. {
  131. $finder = $this->buildFinder();
  132. $finder->name($regex);
  133. $this->assertIterator($this->toAbsolute(['test.py', 'test.php']), $finder->in(self::$tmpDir)->getIterator());
  134. }
  135. public function testSize()
  136. {
  137. $finder = $this->buildFinder();
  138. $this->assertSame($finder, $finder->files()->size('< 1K')->size('> 500'));
  139. $this->assertIterator($this->toAbsolute(['test.php']), $finder->in(self::$tmpDir)->getIterator());
  140. }
  141. public function testDate()
  142. {
  143. $finder = $this->buildFinder();
  144. $this->assertSame($finder, $finder->files()->date('until last month'));
  145. $this->assertIterator($this->toAbsolute(['foo/bar.tmp', 'test.php']), $finder->in(self::$tmpDir)->getIterator());
  146. }
  147. public function testExclude()
  148. {
  149. $finder = $this->buildFinder();
  150. $this->assertSame($finder, $finder->exclude('foo'));
  151. $this->assertIterator($this->toAbsolute(['test.php', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  152. }
  153. public function testIgnoreVCS()
  154. {
  155. $finder = $this->buildFinder();
  156. $this->assertSame($finder, $finder->ignoreVCS(false)->ignoreDotFiles(false));
  157. $this->assertIterator($this->toAbsolute(['.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  158. $finder = $this->buildFinder();
  159. $finder->ignoreVCS(false)->ignoreVCS(false)->ignoreDotFiles(false);
  160. $this->assertIterator($this->toAbsolute(['.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  161. $finder = $this->buildFinder();
  162. $this->assertSame($finder, $finder->ignoreVCS(true)->ignoreDotFiles(false));
  163. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  164. }
  165. public function testIgnoreVCSCanBeDisabledAfterFirstIteration()
  166. {
  167. $finder = $this->buildFinder();
  168. $finder->in(self::$tmpDir);
  169. $finder->ignoreDotFiles(false);
  170. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->getIterator());
  171. $finder->ignoreVCS(false);
  172. $this->assertIterator($this->toAbsolute(['.git', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->getIterator());
  173. }
  174. public function testIgnoreDotFiles()
  175. {
  176. $finder = $this->buildFinder();
  177. $this->assertSame($finder, $finder->ignoreDotFiles(false)->ignoreVCS(false));
  178. $this->assertIterator($this->toAbsolute(['.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  179. $finder = $this->buildFinder();
  180. $finder->ignoreDotFiles(false)->ignoreDotFiles(false)->ignoreVCS(false);
  181. $this->assertIterator($this->toAbsolute(['.git', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'toto/.git', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  182. $finder = $this->buildFinder();
  183. $this->assertSame($finder, $finder->ignoreDotFiles(true)->ignoreVCS(false));
  184. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  185. }
  186. public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration()
  187. {
  188. $finder = $this->buildFinder();
  189. $finder->in(self::$tmpDir);
  190. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar']), $finder->getIterator());
  191. $finder->ignoreDotFiles(false);
  192. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', '.bar', '.foo', '.foo/.bar', '.foo/bar', 'foo bar']), $finder->getIterator());
  193. }
  194. public function testSortByName()
  195. {
  196. $finder = $this->buildFinder();
  197. $this->assertSame($finder, $finder->sortByName());
  198. $this->assertIterator($this->toAbsolute(['foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto']), $finder->in(self::$tmpDir)->getIterator());
  199. }
  200. public function testSortByType()
  201. {
  202. $finder = $this->buildFinder();
  203. $this->assertSame($finder, $finder->sortByType());
  204. $this->assertIterator($this->toAbsolute(['foo', 'foo bar', 'toto', 'foo/bar.tmp', 'test.php', 'test.py']), $finder->in(self::$tmpDir)->getIterator());
  205. }
  206. public function testSortByAccessedTime()
  207. {
  208. $finder = $this->buildFinder();
  209. $this->assertSame($finder, $finder->sortByAccessedTime());
  210. $this->assertIterator($this->toAbsolute(['foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  211. }
  212. public function testSortByChangedTime()
  213. {
  214. $finder = $this->buildFinder();
  215. $this->assertSame($finder, $finder->sortByChangedTime());
  216. $this->assertIterator($this->toAbsolute(['toto', 'test.py', 'test.php', 'foo/bar.tmp', 'foo', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  217. }
  218. public function testSortByModifiedTime()
  219. {
  220. $finder = $this->buildFinder();
  221. $this->assertSame($finder, $finder->sortByModifiedTime());
  222. $this->assertIterator($this->toAbsolute(['foo/bar.tmp', 'test.php', 'toto', 'test.py', 'foo', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  223. }
  224. public function testSort()
  225. {
  226. $finder = $this->buildFinder();
  227. $this->assertSame($finder, $finder->sort(function (\SplFileInfo $a, \SplFileInfo $b) { return strcmp($a->getRealPath(), $b->getRealPath()); }));
  228. $this->assertIterator($this->toAbsolute(['foo', 'foo bar', 'foo/bar.tmp', 'test.php', 'test.py', 'toto']), $finder->in(self::$tmpDir)->getIterator());
  229. }
  230. public function testFilter()
  231. {
  232. $finder = $this->buildFinder();
  233. $this->assertSame($finder, $finder->filter(function (\SplFileInfo $f) { return false !== strpos($f, 'test'); }));
  234. $this->assertIterator($this->toAbsolute(['test.php', 'test.py']), $finder->in(self::$tmpDir)->getIterator());
  235. }
  236. public function testFollowLinks()
  237. {
  238. if ('\\' == \DIRECTORY_SEPARATOR) {
  239. $this->markTestSkipped('symlinks are not supported on Windows');
  240. }
  241. $finder = $this->buildFinder();
  242. $this->assertSame($finder, $finder->followLinks());
  243. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'test.php', 'test.py', 'toto', 'foo bar']), $finder->in(self::$tmpDir)->getIterator());
  244. }
  245. public function testIn()
  246. {
  247. $finder = $this->buildFinder();
  248. $iterator = $finder->files()->name('*.php')->depth('< 1')->in([self::$tmpDir, __DIR__])->getIterator();
  249. $expected = [
  250. self::$tmpDir.\DIRECTORY_SEPARATOR.'test.php',
  251. __DIR__.\DIRECTORY_SEPARATOR.'FinderTest.php',
  252. __DIR__.\DIRECTORY_SEPARATOR.'GlobTest.php',
  253. ];
  254. $this->assertIterator($expected, $iterator);
  255. }
  256. public function testInWithNonExistentDirectory()
  257. {
  258. $this->expectException('InvalidArgumentException');
  259. $finder = new Finder();
  260. $finder->in('foobar');
  261. }
  262. public function testInWithGlob()
  263. {
  264. $finder = $this->buildFinder();
  265. $finder->in([__DIR__.'/Fixtures/*/B/C/', __DIR__.'/Fixtures/*/*/B/C/'])->getIterator();
  266. $this->assertIterator($this->toAbsoluteFixtures(['A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy']), $finder);
  267. }
  268. public function testInWithNonDirectoryGlob()
  269. {
  270. $this->expectException('InvalidArgumentException');
  271. $finder = new Finder();
  272. $finder->in(__DIR__.'/Fixtures/A/a*');
  273. }
  274. public function testInWithGlobBrace()
  275. {
  276. if (!\defined('GLOB_BRACE')) {
  277. $this->markTestSkipped('Glob brace is not supported on this system.');
  278. }
  279. $finder = $this->buildFinder();
  280. $finder->in([__DIR__.'/Fixtures/{A,copy/A}/B/C'])->getIterator();
  281. $this->assertIterator($this->toAbsoluteFixtures(['A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy']), $finder);
  282. }
  283. public function testGetIteratorWithoutIn()
  284. {
  285. $this->expectException('LogicException');
  286. $finder = Finder::create();
  287. $finder->getIterator();
  288. }
  289. public function testGetIterator()
  290. {
  291. $finder = $this->buildFinder();
  292. $dirs = [];
  293. foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
  294. $dirs[] = (string) $dir;
  295. }
  296. $expected = $this->toAbsolute(['foo', 'toto']);
  297. sort($dirs);
  298. sort($expected);
  299. $this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
  300. $finder = $this->buildFinder();
  301. $this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
  302. $finder = $this->buildFinder();
  303. $a = iterator_to_array($finder->directories()->in(self::$tmpDir));
  304. $a = array_values(array_map('strval', $a));
  305. sort($a);
  306. $this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
  307. }
  308. public function testRelativePath()
  309. {
  310. $finder = $this->buildFinder()->in(self::$tmpDir);
  311. $paths = [];
  312. foreach ($finder as $file) {
  313. $paths[] = $file->getRelativePath();
  314. }
  315. $ref = ['', '', '', '', 'foo', ''];
  316. sort($ref);
  317. sort($paths);
  318. $this->assertEquals($ref, $paths);
  319. }
  320. public function testRelativePathname()
  321. {
  322. $finder = $this->buildFinder()->in(self::$tmpDir)->sortByName();
  323. $paths = [];
  324. foreach ($finder as $file) {
  325. $paths[] = $file->getRelativePathname();
  326. }
  327. $ref = ['test.php', 'toto', 'test.py', 'foo', 'foo'.\DIRECTORY_SEPARATOR.'bar.tmp', 'foo bar'];
  328. sort($paths);
  329. sort($ref);
  330. $this->assertEquals($ref, $paths);
  331. }
  332. public function testAppendWithAFinder()
  333. {
  334. $finder = $this->buildFinder();
  335. $finder->files()->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  336. $finder1 = $this->buildFinder();
  337. $finder1->directories()->in(self::$tmpDir);
  338. $finder = $finder->append($finder1);
  339. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'toto']), $finder->getIterator());
  340. }
  341. public function testAppendWithAnArray()
  342. {
  343. $finder = $this->buildFinder();
  344. $finder->files()->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  345. $finder->append($this->toAbsolute(['foo', 'toto']));
  346. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'toto']), $finder->getIterator());
  347. }
  348. public function testAppendReturnsAFinder()
  349. {
  350. $this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', Finder::create()->append([]));
  351. }
  352. public function testAppendDoesNotRequireIn()
  353. {
  354. $finder = $this->buildFinder();
  355. $finder->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  356. $finder1 = Finder::create()->append($finder);
  357. $this->assertIterator(iterator_to_array($finder->getIterator()), $finder1->getIterator());
  358. }
  359. public function testCountDirectories()
  360. {
  361. $directory = Finder::create()->directories()->in(self::$tmpDir);
  362. $i = 0;
  363. foreach ($directory as $dir) {
  364. ++$i;
  365. }
  366. $this->assertCount($i, $directory);
  367. }
  368. public function testCountFiles()
  369. {
  370. $files = Finder::create()->files()->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
  371. $i = 0;
  372. foreach ($files as $file) {
  373. ++$i;
  374. }
  375. $this->assertCount($i, $files);
  376. }
  377. public function testCountWithoutIn()
  378. {
  379. $this->expectException('LogicException');
  380. $finder = Finder::create()->files();
  381. \count($finder);
  382. }
  383. public function testHasResults()
  384. {
  385. $finder = $this->buildFinder();
  386. $finder->in(__DIR__);
  387. $this->assertTrue($finder->hasResults());
  388. }
  389. public function testNoResults()
  390. {
  391. $finder = $this->buildFinder();
  392. $finder->in(__DIR__)->name('DoesNotExist');
  393. $this->assertFalse($finder->hasResults());
  394. }
  395. /**
  396. * @dataProvider getContainsTestData
  397. */
  398. public function testContains($matchPatterns, $noMatchPatterns, $expected)
  399. {
  400. $finder = $this->buildFinder();
  401. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures')
  402. ->name('*.txt')->sortByName()
  403. ->contains($matchPatterns)
  404. ->notContains($noMatchPatterns);
  405. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  406. }
  407. public function testContainsOnDirectory()
  408. {
  409. $finder = $this->buildFinder();
  410. $finder->in(__DIR__)
  411. ->directories()
  412. ->name('Fixtures')
  413. ->contains('abc');
  414. $this->assertIterator([], $finder);
  415. }
  416. public function testNotContainsOnDirectory()
  417. {
  418. $finder = $this->buildFinder();
  419. $finder->in(__DIR__)
  420. ->directories()
  421. ->name('Fixtures')
  422. ->notContains('abc');
  423. $this->assertIterator([], $finder);
  424. }
  425. /**
  426. * Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
  427. * with inner FilesystemIterator in an invalid state.
  428. *
  429. * @see https://bugs.php.net/68557
  430. */
  431. public function testMultipleLocations()
  432. {
  433. $locations = [
  434. self::$tmpDir.'/',
  435. self::$tmpDir.'/toto/',
  436. ];
  437. // it is expected that there are test.py test.php in the tmpDir
  438. $finder = new Finder();
  439. $finder->in($locations)
  440. // the default flag IGNORE_DOT_FILES fixes the problem indirectly
  441. // so we set it to false for better isolation
  442. ->ignoreDotFiles(false)
  443. ->depth('< 1')->name('test.php');
  444. $this->assertCount(1, $finder);
  445. }
  446. /**
  447. * Searching in multiple locations with sub directories involves
  448. * AppendIterator which does an unnecessary rewind which leaves
  449. * FilterIterator with inner FilesystemIterator in an invalid state.
  450. *
  451. * @see https://bugs.php.net/68557
  452. */
  453. public function testMultipleLocationsWithSubDirectories()
  454. {
  455. $locations = [
  456. __DIR__.'/Fixtures/one',
  457. self::$tmpDir.\DIRECTORY_SEPARATOR.'toto',
  458. ];
  459. $finder = $this->buildFinder();
  460. $finder->in($locations)->depth('< 10')->name('*.neon');
  461. $expected = [
  462. __DIR__.'/Fixtures/one'.\DIRECTORY_SEPARATOR.'b'.\DIRECTORY_SEPARATOR.'c.neon',
  463. __DIR__.'/Fixtures/one'.\DIRECTORY_SEPARATOR.'b'.\DIRECTORY_SEPARATOR.'d.neon',
  464. ];
  465. $this->assertIterator($expected, $finder);
  466. $this->assertIteratorInForeach($expected, $finder);
  467. }
  468. /**
  469. * Iterator keys must be the file pathname.
  470. */
  471. public function testIteratorKeys()
  472. {
  473. $finder = $this->buildFinder()->in(self::$tmpDir);
  474. foreach ($finder as $key => $file) {
  475. $this->assertEquals($file->getPathname(), $key);
  476. }
  477. }
  478. public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag()
  479. {
  480. $finder = $this->buildFinder();
  481. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
  482. ->path('/^dir/');
  483. $expected = ['r+e.gex[c]a(r)s'.\DIRECTORY_SEPARATOR.'dir', 'r+e.gex[c]a(r)s'.\DIRECTORY_SEPARATOR.'dir'.\DIRECTORY_SEPARATOR.'bar.dat'];
  484. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  485. }
  486. public function getContainsTestData()
  487. {
  488. return [
  489. ['', '', []],
  490. ['foo', 'bar', []],
  491. ['', 'foobar', ['dolor.txt', 'ipsum.txt', 'lorem.txt']],
  492. ['lorem ipsum dolor sit amet', 'foobar', ['lorem.txt']],
  493. ['sit', 'bar', ['dolor.txt', 'ipsum.txt', 'lorem.txt']],
  494. ['dolor sit amet', '@^L@m', ['dolor.txt', 'ipsum.txt']],
  495. ['/^lorem ipsum dolor sit amet$/m', 'foobar', ['lorem.txt']],
  496. ['lorem', 'foobar', ['lorem.txt']],
  497. ['', 'lorem', ['dolor.txt', 'ipsum.txt']],
  498. ['ipsum dolor sit amet', '/^IPSUM/m', ['lorem.txt']],
  499. ];
  500. }
  501. public function getRegexNameTestData()
  502. {
  503. return [
  504. ['~.+\\.p.+~i'],
  505. ['~t.*s~i'],
  506. ];
  507. }
  508. /**
  509. * @dataProvider getTestPathData
  510. */
  511. public function testPath($matchPatterns, $noMatchPatterns, array $expected)
  512. {
  513. $finder = $this->buildFinder();
  514. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures')
  515. ->path($matchPatterns)
  516. ->notPath($noMatchPatterns);
  517. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  518. }
  519. public function getTestPathData()
  520. {
  521. return [
  522. ['', '', []],
  523. ['/^A\/B\/C/', '/C$/',
  524. ['A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat'],
  525. ],
  526. ['/^A\/B/', 'foobar',
  527. [
  528. 'A'.\DIRECTORY_SEPARATOR.'B',
  529. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  530. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat',
  531. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  532. ],
  533. ],
  534. ['A/B/C', 'foobar',
  535. [
  536. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  537. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  538. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  539. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat.copy',
  540. ],
  541. ],
  542. ['A/B', 'foobar',
  543. [
  544. //dirs
  545. 'A'.\DIRECTORY_SEPARATOR.'B',
  546. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  547. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B',
  548. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  549. //files
  550. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat',
  551. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  552. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat.copy',
  553. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat.copy',
  554. ],
  555. ],
  556. ['/^with space\//', 'foobar',
  557. [
  558. 'with space'.\DIRECTORY_SEPARATOR.'foo.txt',
  559. ],
  560. ],
  561. ];
  562. }
  563. public function testAccessDeniedException()
  564. {
  565. if ('\\' === \DIRECTORY_SEPARATOR) {
  566. $this->markTestSkipped('chmod is not supported on Windows');
  567. }
  568. $finder = $this->buildFinder();
  569. $finder->files()->in(self::$tmpDir);
  570. // make 'foo' directory non-readable
  571. $testDir = self::$tmpDir.\DIRECTORY_SEPARATOR.'foo';
  572. chmod($testDir, 0333);
  573. if (false === $couldRead = is_readable($testDir)) {
  574. try {
  575. $this->assertIterator($this->toAbsolute(['foo bar', 'test.php', 'test.py']), $finder->getIterator());
  576. $this->fail('Finder should throw an exception when opening a non-readable directory.');
  577. } catch (\Exception $e) {
  578. $expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException';
  579. if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) {
  580. $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit\Framework\ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
  581. }
  582. $this->assertInstanceOf($expectedExceptionClass, $e);
  583. }
  584. }
  585. // restore original permissions
  586. chmod($testDir, 0777);
  587. clearstatcache(true, $testDir);
  588. if ($couldRead) {
  589. $this->markTestSkipped('could read test files while test requires unreadable');
  590. }
  591. }
  592. public function testIgnoredAccessDeniedException()
  593. {
  594. if ('\\' === \DIRECTORY_SEPARATOR) {
  595. $this->markTestSkipped('chmod is not supported on Windows');
  596. }
  597. $finder = $this->buildFinder();
  598. $finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
  599. // make 'foo' directory non-readable
  600. $testDir = self::$tmpDir.\DIRECTORY_SEPARATOR.'foo';
  601. chmod($testDir, 0333);
  602. if (false === ($couldRead = is_readable($testDir))) {
  603. $this->assertIterator($this->toAbsolute(['foo bar', 'test.php', 'test.py']), $finder->getIterator());
  604. }
  605. // restore original permissions
  606. chmod($testDir, 0777);
  607. clearstatcache(true, $testDir);
  608. if ($couldRead) {
  609. $this->markTestSkipped('could read test files while test requires unreadable');
  610. }
  611. }
  612. protected function buildFinder()
  613. {
  614. return Finder::create();
  615. }
  616. }