/application/vendor/symfony/filesystem/Tests/FilesystemTest.php

https://gitlab.com/MineYourMind/BoNeMEAL · PHP · 1148 lines · 760 code · 296 blank · 92 comment · 8 complexity · 1b67d400ac985f2c27ba7597e7b85d2b MD5 · raw file

  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\Filesystem\Tests;
  11. /**
  12. * Test class for Filesystem.
  13. */
  14. class FilesystemTest extends FilesystemTestCase
  15. {
  16. public function testCopyCreatesNewFile()
  17. {
  18. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  19. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  20. file_put_contents($sourceFilePath, 'SOURCE FILE');
  21. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  22. $this->assertFileExists($targetFilePath);
  23. $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
  24. }
  25. /**
  26. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  27. */
  28. public function testCopyFails()
  29. {
  30. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  31. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  32. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  33. }
  34. /**
  35. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  36. */
  37. public function testCopyUnreadableFileFails()
  38. {
  39. // skip test on Windows; PHP can't easily set file as unreadable on Windows
  40. if ('\\' === DIRECTORY_SEPARATOR) {
  41. $this->markTestSkipped('This test cannot run on Windows.');
  42. }
  43. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  44. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  45. file_put_contents($sourceFilePath, 'SOURCE FILE');
  46. // make sure target cannot be read
  47. $this->filesystem->chmod($sourceFilePath, 0222);
  48. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  49. }
  50. public function testCopyOverridesExistingFileIfModified()
  51. {
  52. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  53. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  54. file_put_contents($sourceFilePath, 'SOURCE FILE');
  55. file_put_contents($targetFilePath, 'TARGET FILE');
  56. touch($targetFilePath, time() - 1000);
  57. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  58. $this->assertFileExists($targetFilePath);
  59. $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
  60. }
  61. public function testCopyDoesNotOverrideExistingFileByDefault()
  62. {
  63. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  64. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  65. file_put_contents($sourceFilePath, 'SOURCE FILE');
  66. file_put_contents($targetFilePath, 'TARGET FILE');
  67. // make sure both files have the same modification time
  68. $modificationTime = time() - 1000;
  69. touch($sourceFilePath, $modificationTime);
  70. touch($targetFilePath, $modificationTime);
  71. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  72. $this->assertFileExists($targetFilePath);
  73. $this->assertEquals('TARGET FILE', file_get_contents($targetFilePath));
  74. }
  75. public function testCopyOverridesExistingFileIfForced()
  76. {
  77. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  78. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  79. file_put_contents($sourceFilePath, 'SOURCE FILE');
  80. file_put_contents($targetFilePath, 'TARGET FILE');
  81. // make sure both files have the same modification time
  82. $modificationTime = time() - 1000;
  83. touch($sourceFilePath, $modificationTime);
  84. touch($targetFilePath, $modificationTime);
  85. $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
  86. $this->assertFileExists($targetFilePath);
  87. $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
  88. }
  89. /**
  90. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  91. */
  92. public function testCopyWithOverrideWithReadOnlyTargetFails()
  93. {
  94. // skip test on Windows; PHP can't easily set file as unwritable on Windows
  95. if ('\\' === DIRECTORY_SEPARATOR) {
  96. $this->markTestSkipped('This test cannot run on Windows.');
  97. }
  98. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  99. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  100. file_put_contents($sourceFilePath, 'SOURCE FILE');
  101. file_put_contents($targetFilePath, 'TARGET FILE');
  102. // make sure both files have the same modification time
  103. $modificationTime = time() - 1000;
  104. touch($sourceFilePath, $modificationTime);
  105. touch($targetFilePath, $modificationTime);
  106. // make sure target is read-only
  107. $this->filesystem->chmod($targetFilePath, 0444);
  108. $this->filesystem->copy($sourceFilePath, $targetFilePath, true);
  109. }
  110. public function testCopyCreatesTargetDirectoryIfItDoesNotExist()
  111. {
  112. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  113. $targetFileDirectory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
  114. $targetFilePath = $targetFileDirectory.DIRECTORY_SEPARATOR.'copy_target_file';
  115. file_put_contents($sourceFilePath, 'SOURCE FILE');
  116. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  117. $this->assertTrue(is_dir($targetFileDirectory));
  118. $this->assertFileExists($targetFilePath);
  119. $this->assertEquals('SOURCE FILE', file_get_contents($targetFilePath));
  120. }
  121. public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToNotCopy()
  122. {
  123. $sourceFilePath = 'http://symfony.com/images/common/logo/logo_symfony_header.png';
  124. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  125. file_put_contents($targetFilePath, 'TARGET FILE');
  126. $this->filesystem->copy($sourceFilePath, $targetFilePath, false);
  127. $this->assertFileExists($targetFilePath);
  128. $this->assertEquals(file_get_contents($sourceFilePath), file_get_contents($targetFilePath));
  129. }
  130. public function testMkdirCreatesDirectoriesRecursively()
  131. {
  132. $directory = $this->workspace
  133. .DIRECTORY_SEPARATOR.'directory'
  134. .DIRECTORY_SEPARATOR.'sub_directory';
  135. $this->filesystem->mkdir($directory);
  136. $this->assertTrue(is_dir($directory));
  137. }
  138. public function testMkdirCreatesDirectoriesFromArray()
  139. {
  140. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  141. $directories = array(
  142. $basePath.'1', $basePath.'2', $basePath.'3',
  143. );
  144. $this->filesystem->mkdir($directories);
  145. $this->assertTrue(is_dir($basePath.'1'));
  146. $this->assertTrue(is_dir($basePath.'2'));
  147. $this->assertTrue(is_dir($basePath.'3'));
  148. }
  149. public function testMkdirCreatesDirectoriesFromTraversableObject()
  150. {
  151. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  152. $directories = new \ArrayObject(array(
  153. $basePath.'1', $basePath.'2', $basePath.'3',
  154. ));
  155. $this->filesystem->mkdir($directories);
  156. $this->assertTrue(is_dir($basePath.'1'));
  157. $this->assertTrue(is_dir($basePath.'2'));
  158. $this->assertTrue(is_dir($basePath.'3'));
  159. }
  160. /**
  161. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  162. */
  163. public function testMkdirCreatesDirectoriesFails()
  164. {
  165. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  166. $dir = $basePath.'2';
  167. file_put_contents($dir, '');
  168. $this->filesystem->mkdir($dir);
  169. }
  170. public function testTouchCreatesEmptyFile()
  171. {
  172. $file = $this->workspace.DIRECTORY_SEPARATOR.'1';
  173. $this->filesystem->touch($file);
  174. $this->assertFileExists($file);
  175. }
  176. /**
  177. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  178. */
  179. public function testTouchFails()
  180. {
  181. $file = $this->workspace.DIRECTORY_SEPARATOR.'1'.DIRECTORY_SEPARATOR.'2';
  182. $this->filesystem->touch($file);
  183. }
  184. public function testTouchCreatesEmptyFilesFromArray()
  185. {
  186. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  187. $files = array(
  188. $basePath.'1', $basePath.'2', $basePath.'3',
  189. );
  190. $this->filesystem->touch($files);
  191. $this->assertFileExists($basePath.'1');
  192. $this->assertFileExists($basePath.'2');
  193. $this->assertFileExists($basePath.'3');
  194. }
  195. public function testTouchCreatesEmptyFilesFromTraversableObject()
  196. {
  197. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  198. $files = new \ArrayObject(array(
  199. $basePath.'1', $basePath.'2', $basePath.'3',
  200. ));
  201. $this->filesystem->touch($files);
  202. $this->assertFileExists($basePath.'1');
  203. $this->assertFileExists($basePath.'2');
  204. $this->assertFileExists($basePath.'3');
  205. }
  206. public function testRemoveCleansFilesAndDirectoriesIteratively()
  207. {
  208. $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
  209. mkdir($basePath);
  210. mkdir($basePath.'dir');
  211. touch($basePath.'file');
  212. $this->filesystem->remove($basePath);
  213. $this->assertTrue(!is_dir($basePath));
  214. }
  215. public function testRemoveCleansArrayOfFilesAndDirectories()
  216. {
  217. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  218. mkdir($basePath.'dir');
  219. touch($basePath.'file');
  220. $files = array(
  221. $basePath.'dir', $basePath.'file',
  222. );
  223. $this->filesystem->remove($files);
  224. $this->assertTrue(!is_dir($basePath.'dir'));
  225. $this->assertTrue(!is_file($basePath.'file'));
  226. }
  227. public function testRemoveCleansTraversableObjectOfFilesAndDirectories()
  228. {
  229. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  230. mkdir($basePath.'dir');
  231. touch($basePath.'file');
  232. $files = new \ArrayObject(array(
  233. $basePath.'dir', $basePath.'file',
  234. ));
  235. $this->filesystem->remove($files);
  236. $this->assertTrue(!is_dir($basePath.'dir'));
  237. $this->assertTrue(!is_file($basePath.'file'));
  238. }
  239. public function testRemoveIgnoresNonExistingFiles()
  240. {
  241. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  242. mkdir($basePath.'dir');
  243. $files = array(
  244. $basePath.'dir', $basePath.'file',
  245. );
  246. $this->filesystem->remove($files);
  247. $this->assertTrue(!is_dir($basePath.'dir'));
  248. }
  249. public function testRemoveCleansInvalidLinks()
  250. {
  251. $this->markAsSkippedIfSymlinkIsMissing();
  252. $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
  253. mkdir($basePath);
  254. mkdir($basePath.'dir');
  255. // create symlink to nonexistent file
  256. @symlink($basePath.'file', $basePath.'link');
  257. $this->filesystem->remove($basePath);
  258. $this->assertTrue(!is_dir($basePath));
  259. }
  260. public function testFilesExists()
  261. {
  262. $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
  263. mkdir($basePath);
  264. touch($basePath.'file1');
  265. mkdir($basePath.'folder');
  266. $this->assertTrue($this->filesystem->exists($basePath.'file1'));
  267. $this->assertTrue($this->filesystem->exists($basePath.'folder'));
  268. }
  269. public function testFilesExistsTraversableObjectOfFilesAndDirectories()
  270. {
  271. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  272. mkdir($basePath.'dir');
  273. touch($basePath.'file');
  274. $files = new \ArrayObject(array(
  275. $basePath.'dir', $basePath.'file',
  276. ));
  277. $this->assertTrue($this->filesystem->exists($files));
  278. }
  279. public function testFilesNotExistsTraversableObjectOfFilesAndDirectories()
  280. {
  281. $basePath = $this->workspace.DIRECTORY_SEPARATOR;
  282. mkdir($basePath.'dir');
  283. touch($basePath.'file');
  284. touch($basePath.'file2');
  285. $files = new \ArrayObject(array(
  286. $basePath.'dir', $basePath.'file', $basePath.'file2',
  287. ));
  288. unlink($basePath.'file');
  289. $this->assertFalse($this->filesystem->exists($files));
  290. }
  291. public function testInvalidFileNotExists()
  292. {
  293. $basePath = $this->workspace.DIRECTORY_SEPARATOR.'directory'.DIRECTORY_SEPARATOR;
  294. $this->assertFalse($this->filesystem->exists($basePath.time()));
  295. }
  296. public function testChmodChangesFileMode()
  297. {
  298. $this->markAsSkippedIfChmodIsMissing();
  299. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  300. mkdir($dir);
  301. $file = $dir.DIRECTORY_SEPARATOR.'file';
  302. touch($file);
  303. $this->filesystem->chmod($file, 0400);
  304. $this->filesystem->chmod($dir, 0753);
  305. $this->assertFilePermissions(753, $dir);
  306. $this->assertFilePermissions(400, $file);
  307. }
  308. public function testChmodWrongMod()
  309. {
  310. $this->markAsSkippedIfChmodIsMissing();
  311. $dir = $this->workspace.DIRECTORY_SEPARATOR.'file';
  312. touch($dir);
  313. $this->filesystem->chmod($dir, 'Wrongmode');
  314. }
  315. public function testChmodRecursive()
  316. {
  317. $this->markAsSkippedIfChmodIsMissing();
  318. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  319. mkdir($dir);
  320. $file = $dir.DIRECTORY_SEPARATOR.'file';
  321. touch($file);
  322. $this->filesystem->chmod($file, 0400, 0000, true);
  323. $this->filesystem->chmod($dir, 0753, 0000, true);
  324. $this->assertFilePermissions(753, $dir);
  325. $this->assertFilePermissions(753, $file);
  326. }
  327. public function testChmodAppliesUmask()
  328. {
  329. $this->markAsSkippedIfChmodIsMissing();
  330. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  331. touch($file);
  332. $this->filesystem->chmod($file, 0770, 0022);
  333. $this->assertFilePermissions(750, $file);
  334. }
  335. public function testChmodChangesModeOfArrayOfFiles()
  336. {
  337. $this->markAsSkippedIfChmodIsMissing();
  338. $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
  339. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  340. $files = array($directory, $file);
  341. mkdir($directory);
  342. touch($file);
  343. $this->filesystem->chmod($files, 0753);
  344. $this->assertFilePermissions(753, $file);
  345. $this->assertFilePermissions(753, $directory);
  346. }
  347. public function testChmodChangesModeOfTraversableFileObject()
  348. {
  349. $this->markAsSkippedIfChmodIsMissing();
  350. $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
  351. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  352. $files = new \ArrayObject(array($directory, $file));
  353. mkdir($directory);
  354. touch($file);
  355. $this->filesystem->chmod($files, 0753);
  356. $this->assertFilePermissions(753, $file);
  357. $this->assertFilePermissions(753, $directory);
  358. }
  359. public function testChown()
  360. {
  361. $this->markAsSkippedIfPosixIsMissing();
  362. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  363. mkdir($dir);
  364. $this->filesystem->chown($dir, $this->getFileOwner($dir));
  365. }
  366. public function testChownRecursive()
  367. {
  368. $this->markAsSkippedIfPosixIsMissing();
  369. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  370. mkdir($dir);
  371. $file = $dir.DIRECTORY_SEPARATOR.'file';
  372. touch($file);
  373. $this->filesystem->chown($dir, $this->getFileOwner($dir), true);
  374. }
  375. public function testChownSymlink()
  376. {
  377. $this->markAsSkippedIfSymlinkIsMissing();
  378. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  379. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  380. touch($file);
  381. $this->filesystem->symlink($file, $link);
  382. $this->filesystem->chown($link, $this->getFileOwner($link));
  383. }
  384. /**
  385. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  386. */
  387. public function testChownSymlinkFails()
  388. {
  389. $this->markAsSkippedIfSymlinkIsMissing();
  390. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  391. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  392. touch($file);
  393. $this->filesystem->symlink($file, $link);
  394. $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
  395. }
  396. /**
  397. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  398. */
  399. public function testChownFail()
  400. {
  401. $this->markAsSkippedIfPosixIsMissing();
  402. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  403. mkdir($dir);
  404. $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
  405. }
  406. public function testChgrp()
  407. {
  408. $this->markAsSkippedIfPosixIsMissing();
  409. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  410. mkdir($dir);
  411. $this->filesystem->chgrp($dir, $this->getFileGroup($dir));
  412. }
  413. public function testChgrpRecursive()
  414. {
  415. $this->markAsSkippedIfPosixIsMissing();
  416. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  417. mkdir($dir);
  418. $file = $dir.DIRECTORY_SEPARATOR.'file';
  419. touch($file);
  420. $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true);
  421. }
  422. public function testChgrpSymlink()
  423. {
  424. $this->markAsSkippedIfSymlinkIsMissing();
  425. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  426. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  427. touch($file);
  428. $this->filesystem->symlink($file, $link);
  429. $this->filesystem->chgrp($link, $this->getFileGroup($link));
  430. }
  431. /**
  432. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  433. */
  434. public function testChgrpSymlinkFails()
  435. {
  436. $this->markAsSkippedIfSymlinkIsMissing();
  437. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  438. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  439. touch($file);
  440. $this->filesystem->symlink($file, $link);
  441. $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
  442. }
  443. /**
  444. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  445. */
  446. public function testChgrpFail()
  447. {
  448. $this->markAsSkippedIfPosixIsMissing();
  449. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  450. mkdir($dir);
  451. $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
  452. }
  453. public function testRename()
  454. {
  455. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  456. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  457. touch($file);
  458. $this->filesystem->rename($file, $newPath);
  459. $this->assertFileNotExists($file);
  460. $this->assertFileExists($newPath);
  461. }
  462. /**
  463. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  464. */
  465. public function testRenameThrowsExceptionIfTargetAlreadyExists()
  466. {
  467. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  468. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  469. touch($file);
  470. touch($newPath);
  471. $this->filesystem->rename($file, $newPath);
  472. }
  473. public function testRenameOverwritesTheTargetIfItAlreadyExists()
  474. {
  475. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  476. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  477. touch($file);
  478. touch($newPath);
  479. $this->filesystem->rename($file, $newPath, true);
  480. $this->assertFileNotExists($file);
  481. $this->assertFileExists($newPath);
  482. }
  483. /**
  484. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  485. */
  486. public function testRenameThrowsExceptionOnError()
  487. {
  488. $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid('fs_test_', true);
  489. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  490. $this->filesystem->rename($file, $newPath);
  491. }
  492. public function testSymlink()
  493. {
  494. if ('\\' === DIRECTORY_SEPARATOR) {
  495. $this->markTestSkipped('Windows does not support creating "broken" symlinks');
  496. }
  497. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  498. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  499. // $file does not exists right now: creating "broken" links is a wanted feature
  500. $this->filesystem->symlink($file, $link);
  501. $this->assertTrue(is_link($link));
  502. // Create the linked file AFTER creating the link
  503. touch($file);
  504. $this->assertEquals($file, readlink($link));
  505. }
  506. /**
  507. * @depends testSymlink
  508. */
  509. public function testRemoveSymlink()
  510. {
  511. $this->markAsSkippedIfSymlinkIsMissing();
  512. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  513. $this->filesystem->remove($link);
  514. $this->assertTrue(!is_link($link));
  515. }
  516. public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
  517. {
  518. $this->markAsSkippedIfSymlinkIsMissing();
  519. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  520. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  521. touch($file);
  522. symlink($this->workspace, $link);
  523. $this->filesystem->symlink($file, $link);
  524. $this->assertTrue(is_link($link));
  525. $this->assertEquals($file, readlink($link));
  526. }
  527. public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
  528. {
  529. $this->markAsSkippedIfSymlinkIsMissing();
  530. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  531. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  532. touch($file);
  533. symlink($file, $link);
  534. $this->filesystem->symlink($file, $link);
  535. $this->assertTrue(is_link($link));
  536. $this->assertEquals($file, readlink($link));
  537. }
  538. public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
  539. {
  540. $this->markAsSkippedIfSymlinkIsMissing();
  541. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  542. $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
  543. $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
  544. touch($file);
  545. $this->filesystem->symlink($file, $link1);
  546. $this->filesystem->symlink($file, $link2);
  547. $this->assertTrue(is_link($link1));
  548. $this->assertEquals($file, readlink($link1));
  549. $this->assertTrue(is_link($link2));
  550. $this->assertEquals($file, readlink($link2));
  551. }
  552. /**
  553. * @dataProvider providePathsForMakePathRelative
  554. */
  555. public function testMakePathRelative($endPath, $startPath, $expectedPath)
  556. {
  557. $path = $this->filesystem->makePathRelative($endPath, $startPath);
  558. $this->assertEquals($expectedPath, $path);
  559. }
  560. /**
  561. * @return array
  562. */
  563. public function providePathsForMakePathRelative()
  564. {
  565. $paths = array(
  566. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
  567. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
  568. array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
  569. array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
  570. array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
  571. array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
  572. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
  573. array('/aa/bb', '/aa/bb', './'),
  574. array('/aa/bb', '/aa/bb/', './'),
  575. array('/aa/bb/', '/aa/bb', './'),
  576. array('/aa/bb/', '/aa/bb/', './'),
  577. array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
  578. array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
  579. array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
  580. array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
  581. array('/aa/bb/cc', '/aa', 'bb/cc/'),
  582. array('/aa/bb/cc', '/aa/', 'bb/cc/'),
  583. array('/aa/bb/cc/', '/aa', 'bb/cc/'),
  584. array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
  585. array('/a/aab/bb', '/a/aa', '../aab/bb/'),
  586. array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
  587. array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
  588. array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
  589. array('/a/aab/bb/', '/', 'a/aab/bb/'),
  590. array('/a/aab/bb/', '/b/aab', '../../a/aab/bb/'),
  591. );
  592. if ('\\' === DIRECTORY_SEPARATOR) {
  593. $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
  594. }
  595. return $paths;
  596. }
  597. public function testMirrorCopiesFilesAndDirectoriesRecursively()
  598. {
  599. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  600. $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
  601. $file1 = $directory.'file1';
  602. $file2 = $sourcePath.'file2';
  603. mkdir($sourcePath);
  604. mkdir($directory);
  605. file_put_contents($file1, 'FILE1');
  606. file_put_contents($file2, 'FILE2');
  607. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  608. $this->filesystem->mirror($sourcePath, $targetPath);
  609. $this->assertTrue(is_dir($targetPath));
  610. $this->assertTrue(is_dir($targetPath.'directory'));
  611. $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
  612. $this->assertFileEquals($file2, $targetPath.'file2');
  613. $this->filesystem->remove($file1);
  614. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
  615. $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  616. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  617. $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  618. file_put_contents($file1, 'FILE1');
  619. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  620. $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  621. $this->filesystem->remove($directory);
  622. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  623. $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
  624. $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  625. }
  626. public function testMirrorCreatesEmptyDirectory()
  627. {
  628. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  629. mkdir($sourcePath);
  630. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  631. $this->filesystem->mirror($sourcePath, $targetPath);
  632. $this->assertTrue(is_dir($targetPath));
  633. $this->filesystem->remove($sourcePath);
  634. }
  635. public function testMirrorCopiesLinks()
  636. {
  637. $this->markAsSkippedIfSymlinkIsMissing();
  638. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  639. mkdir($sourcePath);
  640. file_put_contents($sourcePath.'file1', 'FILE1');
  641. symlink($sourcePath.'file1', $sourcePath.'link1');
  642. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  643. $this->filesystem->mirror($sourcePath, $targetPath);
  644. $this->assertTrue(is_dir($targetPath));
  645. $this->assertFileEquals($sourcePath.'file1', $targetPath.DIRECTORY_SEPARATOR.'link1');
  646. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  647. }
  648. public function testMirrorCopiesLinkedDirectoryContents()
  649. {
  650. $this->markAsSkippedIfSymlinkIsMissing();
  651. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  652. mkdir($sourcePath.'nested/', 0777, true);
  653. file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
  654. // Note: We symlink directory, not file
  655. symlink($sourcePath.'nested', $sourcePath.'link1');
  656. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  657. $this->filesystem->mirror($sourcePath, $targetPath);
  658. $this->assertTrue(is_dir($targetPath));
  659. $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
  660. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  661. }
  662. public function testMirrorCopiesRelativeLinkedContents()
  663. {
  664. $this->markAsSkippedIfSymlinkIsMissing();
  665. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  666. $oldPath = getcwd();
  667. mkdir($sourcePath.'nested/', 0777, true);
  668. file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
  669. // Note: Create relative symlink
  670. chdir($sourcePath);
  671. symlink('nested', 'link1');
  672. chdir($oldPath);
  673. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  674. $this->filesystem->mirror($sourcePath, $targetPath);
  675. $this->assertTrue(is_dir($targetPath));
  676. $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
  677. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  678. $this->assertEquals('\\' === DIRECTORY_SEPARATOR ? realpath($sourcePath.'\nested') : 'nested', readlink($targetPath.DIRECTORY_SEPARATOR.'link1'));
  679. }
  680. /**
  681. * @dataProvider providePathsForIsAbsolutePath
  682. */
  683. public function testIsAbsolutePath($path, $expectedResult)
  684. {
  685. $result = $this->filesystem->isAbsolutePath($path);
  686. $this->assertEquals($expectedResult, $result);
  687. }
  688. /**
  689. * @return array
  690. */
  691. public function providePathsForIsAbsolutePath()
  692. {
  693. return array(
  694. array('/var/lib', true),
  695. array('c:\\\\var\\lib', true),
  696. array('\\var\\lib', true),
  697. array('var/lib', false),
  698. array('../var/lib', false),
  699. array('', false),
  700. array(null, false),
  701. );
  702. }
  703. public function testTempnam()
  704. {
  705. $dirname = $this->workspace;
  706. $filename = $this->filesystem->tempnam($dirname, 'foo');
  707. $this->assertFileExists($filename);
  708. }
  709. public function testTempnamWithFileScheme()
  710. {
  711. $scheme = 'file://';
  712. $dirname = $scheme.$this->workspace;
  713. $filename = $this->filesystem->tempnam($dirname, 'foo');
  714. $this->assertStringStartsWith($scheme, $filename);
  715. $this->assertFileExists($filename);
  716. }
  717. public function testTempnamWithMockScheme()
  718. {
  719. stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream');
  720. $scheme = 'mock://';
  721. $dirname = $scheme.$this->workspace;
  722. $filename = $this->filesystem->tempnam($dirname, 'foo');
  723. $this->assertStringStartsWith($scheme, $filename);
  724. $this->assertFileExists($filename);
  725. }
  726. /**
  727. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  728. */
  729. public function testTempnamWithZlibSchemeFails()
  730. {
  731. $scheme = 'compress.zlib://';
  732. $dirname = $scheme.$this->workspace;
  733. // The compress.zlib:// stream does not support mode x: creates the file, errors "failed to open stream: operation failed" and returns false
  734. $this->filesystem->tempnam($dirname, 'bar');
  735. }
  736. public function testTempnamWithPHPTempSchemeFails()
  737. {
  738. $scheme = 'php://temp';
  739. $dirname = $scheme;
  740. $filename = $this->filesystem->tempnam($dirname, 'bar');
  741. $this->assertStringStartsWith($scheme, $filename);
  742. // The php://temp stream deletes the file after close
  743. $this->assertFileNotExists($filename);
  744. }
  745. /**
  746. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  747. */
  748. public function testTempnamWithPharSchemeFails()
  749. {
  750. // Skip test if Phar disabled phar.readonly must be 0 in php.ini
  751. if (!\Phar::canWrite()) {
  752. $this->markTestSkipped('This test cannot run when phar.readonly is 1.');
  753. }
  754. $scheme = 'phar://';
  755. $dirname = $scheme.$this->workspace;
  756. $pharname = 'foo.phar';
  757. new \Phar($this->workspace.'/'.$pharname, 0, $pharname);
  758. // The phar:// stream does not support mode x: fails to create file, errors "failed to open stream: phar error: "$filename" is not a file in phar "$pharname"" and returns false
  759. $this->filesystem->tempnam($dirname, $pharname.'/bar');
  760. }
  761. /**
  762. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  763. */
  764. public function testTempnamWithHTTPSchemeFails()
  765. {
  766. $scheme = 'http://';
  767. $dirname = $scheme.$this->workspace;
  768. // The http:// scheme is read-only
  769. $this->filesystem->tempnam($dirname, 'bar');
  770. }
  771. public function testTempnamOnUnwritableFallsBackToSysTmp()
  772. {
  773. $scheme = 'file://';
  774. $dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';
  775. $filename = $this->filesystem->tempnam($dirname, 'bar');
  776. $realTempDir = realpath(sys_get_temp_dir());
  777. $this->assertStringStartsWith(rtrim($scheme.$realTempDir, DIRECTORY_SEPARATOR), $filename);
  778. $this->assertFileExists($filename);
  779. // Tear down
  780. @unlink($filename);
  781. }
  782. public function testDumpFile()
  783. {
  784. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  785. $this->filesystem->dumpFile($filename, 'bar');
  786. $this->assertFileExists($filename);
  787. $this->assertSame('bar', file_get_contents($filename));
  788. }
  789. /**
  790. * @group legacy
  791. */
  792. public function testDumpFileAndSetPermissions()
  793. {
  794. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  795. $this->filesystem->dumpFile($filename, 'bar', 0753);
  796. $this->assertFileExists($filename);
  797. $this->assertSame('bar', file_get_contents($filename));
  798. // skip mode check on Windows
  799. if ('\\' !== DIRECTORY_SEPARATOR) {
  800. $this->assertFilePermissions(753, $filename);
  801. }
  802. }
  803. public function testDumpFileWithNullMode()
  804. {
  805. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  806. $this->filesystem->dumpFile($filename, 'bar', null);
  807. $this->assertFileExists($filename);
  808. $this->assertSame('bar', file_get_contents($filename));
  809. // skip mode check on Windows
  810. if ('\\' !== DIRECTORY_SEPARATOR) {
  811. $this->assertFilePermissions(600, $filename);
  812. }
  813. }
  814. public function testDumpFileOverwritesAnExistingFile()
  815. {
  816. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
  817. file_put_contents($filename, 'FOO BAR');
  818. $this->filesystem->dumpFile($filename, 'bar');
  819. $this->assertFileExists($filename);
  820. $this->assertSame('bar', file_get_contents($filename));
  821. }
  822. public function testDumpFileWithFileScheme()
  823. {
  824. if (defined('HHVM_VERSION')) {
  825. $this->markTestSkipped('HHVM does not handle the file:// scheme correctly');
  826. }
  827. $scheme = 'file://';
  828. $filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  829. $this->filesystem->dumpFile($filename, 'bar', null);
  830. $this->assertFileExists($filename);
  831. $this->assertSame('bar', file_get_contents($filename));
  832. }
  833. public function testDumpFileWithZlibScheme()
  834. {
  835. $scheme = 'compress.zlib://';
  836. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  837. $this->filesystem->dumpFile($filename, 'bar', null);
  838. // Zlib stat uses file:// wrapper so remove scheme
  839. $this->assertFileExists(str_replace($scheme, '', $filename));
  840. $this->assertSame('bar', file_get_contents($filename));
  841. }
  842. public function testCopyShouldKeepExecutionPermission()
  843. {
  844. $this->markAsSkippedIfChmodIsMissing();
  845. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  846. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  847. file_put_contents($sourceFilePath, 'SOURCE FILE');
  848. chmod($sourceFilePath, 0745);
  849. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  850. $this->assertFilePermissions(767, $targetFilePath);
  851. }
  852. }