FinderTest.php 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  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. /**
  257. * @expectedException \InvalidArgumentException
  258. */
  259. public function testInWithNonExistentDirectory()
  260. {
  261. $finder = new Finder();
  262. $finder->in('foobar');
  263. }
  264. public function testInWithGlob()
  265. {
  266. $finder = $this->buildFinder();
  267. $finder->in([__DIR__.'/Fixtures/*/B/C/', __DIR__.'/Fixtures/*/*/B/C/'])->getIterator();
  268. $this->assertIterator($this->toAbsoluteFixtures(['A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy']), $finder);
  269. }
  270. /**
  271. * @expectedException \InvalidArgumentException
  272. */
  273. public function testInWithNonDirectoryGlob()
  274. {
  275. $finder = new Finder();
  276. $finder->in(__DIR__.'/Fixtures/A/a*');
  277. }
  278. public function testInWithGlobBrace()
  279. {
  280. if (!\defined('GLOB_BRACE')) {
  281. $this->markTestSkipped('Glob brace is not supported on this system.');
  282. }
  283. $finder = $this->buildFinder();
  284. $finder->in([__DIR__.'/Fixtures/{A,copy/A}/B/C'])->getIterator();
  285. $this->assertIterator($this->toAbsoluteFixtures(['A/B/C/abc.dat', 'copy/A/B/C/abc.dat.copy']), $finder);
  286. }
  287. /**
  288. * @expectedException \LogicException
  289. */
  290. public function testGetIteratorWithoutIn()
  291. {
  292. $finder = Finder::create();
  293. $finder->getIterator();
  294. }
  295. public function testGetIterator()
  296. {
  297. $finder = $this->buildFinder();
  298. $dirs = [];
  299. foreach ($finder->directories()->in(self::$tmpDir) as $dir) {
  300. $dirs[] = (string) $dir;
  301. }
  302. $expected = $this->toAbsolute(['foo', 'toto']);
  303. sort($dirs);
  304. sort($expected);
  305. $this->assertEquals($expected, $dirs, 'implements the \IteratorAggregate interface');
  306. $finder = $this->buildFinder();
  307. $this->assertEquals(2, iterator_count($finder->directories()->in(self::$tmpDir)), 'implements the \IteratorAggregate interface');
  308. $finder = $this->buildFinder();
  309. $a = iterator_to_array($finder->directories()->in(self::$tmpDir));
  310. $a = array_values(array_map('strval', $a));
  311. sort($a);
  312. $this->assertEquals($expected, $a, 'implements the \IteratorAggregate interface');
  313. }
  314. public function testRelativePath()
  315. {
  316. $finder = $this->buildFinder()->in(self::$tmpDir);
  317. $paths = [];
  318. foreach ($finder as $file) {
  319. $paths[] = $file->getRelativePath();
  320. }
  321. $ref = ['', '', '', '', 'foo', ''];
  322. sort($ref);
  323. sort($paths);
  324. $this->assertEquals($ref, $paths);
  325. }
  326. public function testRelativePathname()
  327. {
  328. $finder = $this->buildFinder()->in(self::$tmpDir)->sortByName();
  329. $paths = [];
  330. foreach ($finder as $file) {
  331. $paths[] = $file->getRelativePathname();
  332. }
  333. $ref = ['test.php', 'toto', 'test.py', 'foo', 'foo'.\DIRECTORY_SEPARATOR.'bar.tmp', 'foo bar'];
  334. sort($paths);
  335. sort($ref);
  336. $this->assertEquals($ref, $paths);
  337. }
  338. public function testAppendWithAFinder()
  339. {
  340. $finder = $this->buildFinder();
  341. $finder->files()->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  342. $finder1 = $this->buildFinder();
  343. $finder1->directories()->in(self::$tmpDir);
  344. $finder = $finder->append($finder1);
  345. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'toto']), $finder->getIterator());
  346. }
  347. public function testAppendWithAnArray()
  348. {
  349. $finder = $this->buildFinder();
  350. $finder->files()->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  351. $finder->append($this->toAbsolute(['foo', 'toto']));
  352. $this->assertIterator($this->toAbsolute(['foo', 'foo/bar.tmp', 'toto']), $finder->getIterator());
  353. }
  354. public function testAppendReturnsAFinder()
  355. {
  356. $this->assertInstanceOf('Symfony\\Component\\Finder\\Finder', Finder::create()->append([]));
  357. }
  358. public function testAppendDoesNotRequireIn()
  359. {
  360. $finder = $this->buildFinder();
  361. $finder->in(self::$tmpDir.\DIRECTORY_SEPARATOR.'foo');
  362. $finder1 = Finder::create()->append($finder);
  363. $this->assertIterator(iterator_to_array($finder->getIterator()), $finder1->getIterator());
  364. }
  365. public function testCountDirectories()
  366. {
  367. $directory = Finder::create()->directories()->in(self::$tmpDir);
  368. $i = 0;
  369. foreach ($directory as $dir) {
  370. ++$i;
  371. }
  372. $this->assertCount($i, $directory);
  373. }
  374. public function testCountFiles()
  375. {
  376. $files = Finder::create()->files()->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures');
  377. $i = 0;
  378. foreach ($files as $file) {
  379. ++$i;
  380. }
  381. $this->assertCount($i, $files);
  382. }
  383. /**
  384. * @expectedException \LogicException
  385. */
  386. public function testCountWithoutIn()
  387. {
  388. $finder = Finder::create()->files();
  389. \count($finder);
  390. }
  391. public function testHasResults()
  392. {
  393. $finder = $this->buildFinder();
  394. $finder->in(__DIR__);
  395. $this->assertTrue($finder->hasResults());
  396. }
  397. public function testNoResults()
  398. {
  399. $finder = $this->buildFinder();
  400. $finder->in(__DIR__)->name('DoesNotExist');
  401. $this->assertFalse($finder->hasResults());
  402. }
  403. /**
  404. * @dataProvider getContainsTestData
  405. */
  406. public function testContains($matchPatterns, $noMatchPatterns, $expected)
  407. {
  408. $finder = $this->buildFinder();
  409. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures')
  410. ->name('*.txt')->sortByName()
  411. ->contains($matchPatterns)
  412. ->notContains($noMatchPatterns);
  413. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  414. }
  415. public function testContainsOnDirectory()
  416. {
  417. $finder = $this->buildFinder();
  418. $finder->in(__DIR__)
  419. ->directories()
  420. ->name('Fixtures')
  421. ->contains('abc');
  422. $this->assertIterator([], $finder);
  423. }
  424. public function testNotContainsOnDirectory()
  425. {
  426. $finder = $this->buildFinder();
  427. $finder->in(__DIR__)
  428. ->directories()
  429. ->name('Fixtures')
  430. ->notContains('abc');
  431. $this->assertIterator([], $finder);
  432. }
  433. /**
  434. * Searching in multiple locations involves AppendIterator which does an unnecessary rewind which leaves FilterIterator
  435. * with inner FilesystemIterator in an invalid state.
  436. *
  437. * @see https://bugs.php.net/68557
  438. */
  439. public function testMultipleLocations()
  440. {
  441. $locations = [
  442. self::$tmpDir.'/',
  443. self::$tmpDir.'/toto/',
  444. ];
  445. // it is expected that there are test.py test.php in the tmpDir
  446. $finder = new Finder();
  447. $finder->in($locations)
  448. // the default flag IGNORE_DOT_FILES fixes the problem indirectly
  449. // so we set it to false for better isolation
  450. ->ignoreDotFiles(false)
  451. ->depth('< 1')->name('test.php');
  452. $this->assertCount(1, $finder);
  453. }
  454. /**
  455. * Searching in multiple locations with sub directories involves
  456. * AppendIterator which does an unnecessary rewind which leaves
  457. * FilterIterator with inner FilesystemIterator in an invalid state.
  458. *
  459. * @see https://bugs.php.net/68557
  460. */
  461. public function testMultipleLocationsWithSubDirectories()
  462. {
  463. $locations = [
  464. __DIR__.'/Fixtures/one',
  465. self::$tmpDir.\DIRECTORY_SEPARATOR.'toto',
  466. ];
  467. $finder = $this->buildFinder();
  468. $finder->in($locations)->depth('< 10')->name('*.neon');
  469. $expected = [
  470. __DIR__.'/Fixtures/one'.\DIRECTORY_SEPARATOR.'b'.\DIRECTORY_SEPARATOR.'c.neon',
  471. __DIR__.'/Fixtures/one'.\DIRECTORY_SEPARATOR.'b'.\DIRECTORY_SEPARATOR.'d.neon',
  472. ];
  473. $this->assertIterator($expected, $finder);
  474. $this->assertIteratorInForeach($expected, $finder);
  475. }
  476. /**
  477. * Iterator keys must be the file pathname.
  478. */
  479. public function testIteratorKeys()
  480. {
  481. $finder = $this->buildFinder()->in(self::$tmpDir);
  482. foreach ($finder as $key => $file) {
  483. $this->assertEquals($file->getPathname(), $key);
  484. }
  485. }
  486. public function testRegexSpecialCharsLocationWithPathRestrictionContainingStartFlag()
  487. {
  488. $finder = $this->buildFinder();
  489. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR.'r+e.gex[c]a(r)s')
  490. ->path('/^dir/');
  491. $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'];
  492. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  493. }
  494. public function getContainsTestData()
  495. {
  496. return [
  497. ['', '', []],
  498. ['foo', 'bar', []],
  499. ['', 'foobar', ['dolor.txt', 'ipsum.txt', 'lorem.txt']],
  500. ['lorem ipsum dolor sit amet', 'foobar', ['lorem.txt']],
  501. ['sit', 'bar', ['dolor.txt', 'ipsum.txt', 'lorem.txt']],
  502. ['dolor sit amet', '@^L@m', ['dolor.txt', 'ipsum.txt']],
  503. ['/^lorem ipsum dolor sit amet$/m', 'foobar', ['lorem.txt']],
  504. ['lorem', 'foobar', ['lorem.txt']],
  505. ['', 'lorem', ['dolor.txt', 'ipsum.txt']],
  506. ['ipsum dolor sit amet', '/^IPSUM/m', ['lorem.txt']],
  507. ];
  508. }
  509. public function getRegexNameTestData()
  510. {
  511. return [
  512. ['~.+\\.p.+~i'],
  513. ['~t.*s~i'],
  514. ];
  515. }
  516. /**
  517. * @dataProvider getTestPathData
  518. */
  519. public function testPath($matchPatterns, $noMatchPatterns, array $expected)
  520. {
  521. $finder = $this->buildFinder();
  522. $finder->in(__DIR__.\DIRECTORY_SEPARATOR.'Fixtures')
  523. ->path($matchPatterns)
  524. ->notPath($noMatchPatterns);
  525. $this->assertIterator($this->toAbsoluteFixtures($expected), $finder);
  526. }
  527. public function getTestPathData()
  528. {
  529. return [
  530. ['', '', []],
  531. ['/^A\/B\/C/', '/C$/',
  532. ['A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat'],
  533. ],
  534. ['/^A\/B/', 'foobar',
  535. [
  536. 'A'.\DIRECTORY_SEPARATOR.'B',
  537. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  538. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat',
  539. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  540. ],
  541. ],
  542. ['A/B/C', 'foobar',
  543. [
  544. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  545. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  546. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  547. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat.copy',
  548. ],
  549. ],
  550. ['A/B', 'foobar',
  551. [
  552. //dirs
  553. 'A'.\DIRECTORY_SEPARATOR.'B',
  554. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  555. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B',
  556. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C',
  557. //files
  558. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat',
  559. 'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat',
  560. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'ab.dat.copy',
  561. 'copy'.\DIRECTORY_SEPARATOR.'A'.\DIRECTORY_SEPARATOR.'B'.\DIRECTORY_SEPARATOR.'C'.\DIRECTORY_SEPARATOR.'abc.dat.copy',
  562. ],
  563. ],
  564. ['/^with space\//', 'foobar',
  565. [
  566. 'with space'.\DIRECTORY_SEPARATOR.'foo.txt',
  567. ],
  568. ],
  569. ];
  570. }
  571. public function testAccessDeniedException()
  572. {
  573. if ('\\' === \DIRECTORY_SEPARATOR) {
  574. $this->markTestSkipped('chmod is not supported on Windows');
  575. }
  576. $finder = $this->buildFinder();
  577. $finder->files()->in(self::$tmpDir);
  578. // make 'foo' directory non-readable
  579. $testDir = self::$tmpDir.\DIRECTORY_SEPARATOR.'foo';
  580. chmod($testDir, 0333);
  581. if (false === $couldRead = is_readable($testDir)) {
  582. try {
  583. $this->assertIterator($this->toAbsolute(['foo bar', 'test.php', 'test.py']), $finder->getIterator());
  584. $this->fail('Finder should throw an exception when opening a non-readable directory.');
  585. } catch (\Exception $e) {
  586. $expectedExceptionClass = 'Symfony\\Component\\Finder\\Exception\\AccessDeniedException';
  587. if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
  588. $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, 'PHPUnit_Framework_ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
  589. }
  590. if ($e instanceof \PHPUnit\Framework\ExpectationFailedException) {
  591. $this->fail(sprintf("Expected exception:\n%s\nGot:\n%s\nWith comparison failure:\n%s", $expectedExceptionClass, '\PHPUnit\Framework\ExpectationFailedException', $e->getComparisonFailure()->getExpectedAsString()));
  592. }
  593. $this->assertInstanceOf($expectedExceptionClass, $e);
  594. }
  595. }
  596. // restore original permissions
  597. chmod($testDir, 0777);
  598. clearstatcache(true, $testDir);
  599. if ($couldRead) {
  600. $this->markTestSkipped('could read test files while test requires unreadable');
  601. }
  602. }
  603. public function testIgnoredAccessDeniedException()
  604. {
  605. if ('\\' === \DIRECTORY_SEPARATOR) {
  606. $this->markTestSkipped('chmod is not supported on Windows');
  607. }
  608. $finder = $this->buildFinder();
  609. $finder->files()->ignoreUnreadableDirs()->in(self::$tmpDir);
  610. // make 'foo' directory non-readable
  611. $testDir = self::$tmpDir.\DIRECTORY_SEPARATOR.'foo';
  612. chmod($testDir, 0333);
  613. if (false === ($couldRead = is_readable($testDir))) {
  614. $this->assertIterator($this->toAbsolute(['foo bar', 'test.php', 'test.py']), $finder->getIterator());
  615. }
  616. // restore original permissions
  617. chmod($testDir, 0777);
  618. clearstatcache(true, $testDir);
  619. if ($couldRead) {
  620. $this->markTestSkipped('could read test files while test requires unreadable');
  621. }
  622. }
  623. protected function buildFinder()
  624. {
  625. return Finder::create();
  626. }
  627. }