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

https://gitlab.com/alexandresgv/siteentec · PHP · 1135 lines · 754 code · 293 blank · 88 comment · 7 complexity · 3b6389849654e7ecbae9e970a7883e2c 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 testChmodChangesZeroModeOnSubdirectoriesOnRecursive()
  360. {
  361. $this->markAsSkippedIfChmodIsMissing();
  362. $directory = $this->workspace.DIRECTORY_SEPARATOR.'directory';
  363. $subdirectory = $directory.DIRECTORY_SEPARATOR.'subdirectory';
  364. mkdir($directory);
  365. mkdir($subdirectory);
  366. chmod($subdirectory, 0000);
  367. $this->filesystem->chmod($directory, 0753, 0000, true);
  368. $this->assertFilePermissions(753, $subdirectory);
  369. }
  370. public function testChown()
  371. {
  372. $this->markAsSkippedIfPosixIsMissing();
  373. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  374. mkdir($dir);
  375. $this->filesystem->chown($dir, $this->getFileOwner($dir));
  376. }
  377. public function testChownRecursive()
  378. {
  379. $this->markAsSkippedIfPosixIsMissing();
  380. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  381. mkdir($dir);
  382. $file = $dir.DIRECTORY_SEPARATOR.'file';
  383. touch($file);
  384. $this->filesystem->chown($dir, $this->getFileOwner($dir), true);
  385. }
  386. public function testChownSymlink()
  387. {
  388. $this->markAsSkippedIfSymlinkIsMissing();
  389. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  390. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  391. touch($file);
  392. $this->filesystem->symlink($file, $link);
  393. $this->filesystem->chown($link, $this->getFileOwner($link));
  394. }
  395. /**
  396. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  397. */
  398. public function testChownSymlinkFails()
  399. {
  400. $this->markAsSkippedIfSymlinkIsMissing();
  401. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  402. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  403. touch($file);
  404. $this->filesystem->symlink($file, $link);
  405. $this->filesystem->chown($link, 'user'.time().mt_rand(1000, 9999));
  406. }
  407. /**
  408. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  409. */
  410. public function testChownFail()
  411. {
  412. $this->markAsSkippedIfPosixIsMissing();
  413. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  414. mkdir($dir);
  415. $this->filesystem->chown($dir, 'user'.time().mt_rand(1000, 9999));
  416. }
  417. public function testChgrp()
  418. {
  419. $this->markAsSkippedIfPosixIsMissing();
  420. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  421. mkdir($dir);
  422. $this->filesystem->chgrp($dir, $this->getFileGroup($dir));
  423. }
  424. public function testChgrpRecursive()
  425. {
  426. $this->markAsSkippedIfPosixIsMissing();
  427. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  428. mkdir($dir);
  429. $file = $dir.DIRECTORY_SEPARATOR.'file';
  430. touch($file);
  431. $this->filesystem->chgrp($dir, $this->getFileGroup($dir), true);
  432. }
  433. public function testChgrpSymlink()
  434. {
  435. $this->markAsSkippedIfSymlinkIsMissing();
  436. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  437. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  438. touch($file);
  439. $this->filesystem->symlink($file, $link);
  440. $this->filesystem->chgrp($link, $this->getFileGroup($link));
  441. }
  442. /**
  443. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  444. */
  445. public function testChgrpSymlinkFails()
  446. {
  447. $this->markAsSkippedIfSymlinkIsMissing();
  448. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  449. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  450. touch($file);
  451. $this->filesystem->symlink($file, $link);
  452. $this->filesystem->chgrp($link, 'user'.time().mt_rand(1000, 9999));
  453. }
  454. /**
  455. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  456. */
  457. public function testChgrpFail()
  458. {
  459. $this->markAsSkippedIfPosixIsMissing();
  460. $dir = $this->workspace.DIRECTORY_SEPARATOR.'dir';
  461. mkdir($dir);
  462. $this->filesystem->chgrp($dir, 'user'.time().mt_rand(1000, 9999));
  463. }
  464. public function testRename()
  465. {
  466. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  467. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  468. touch($file);
  469. $this->filesystem->rename($file, $newPath);
  470. $this->assertFileNotExists($file);
  471. $this->assertFileExists($newPath);
  472. }
  473. /**
  474. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  475. */
  476. public function testRenameThrowsExceptionIfTargetAlreadyExists()
  477. {
  478. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  479. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  480. touch($file);
  481. touch($newPath);
  482. $this->filesystem->rename($file, $newPath);
  483. }
  484. public function testRenameOverwritesTheTargetIfItAlreadyExists()
  485. {
  486. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  487. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  488. touch($file);
  489. touch($newPath);
  490. $this->filesystem->rename($file, $newPath, true);
  491. $this->assertFileNotExists($file);
  492. $this->assertFileExists($newPath);
  493. }
  494. /**
  495. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  496. */
  497. public function testRenameThrowsExceptionOnError()
  498. {
  499. $file = $this->workspace.DIRECTORY_SEPARATOR.uniqid('fs_test_', true);
  500. $newPath = $this->workspace.DIRECTORY_SEPARATOR.'new_file';
  501. $this->filesystem->rename($file, $newPath);
  502. }
  503. public function testSymlink()
  504. {
  505. if ('\\' === DIRECTORY_SEPARATOR) {
  506. $this->markTestSkipped('Windows does not support creating "broken" symlinks');
  507. }
  508. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  509. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  510. // $file does not exists right now: creating "broken" links is a wanted feature
  511. $this->filesystem->symlink($file, $link);
  512. $this->assertTrue(is_link($link));
  513. // Create the linked file AFTER creating the link
  514. touch($file);
  515. $this->assertEquals($file, readlink($link));
  516. }
  517. /**
  518. * @depends testSymlink
  519. */
  520. public function testRemoveSymlink()
  521. {
  522. $this->markAsSkippedIfSymlinkIsMissing();
  523. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  524. $this->filesystem->remove($link);
  525. $this->assertTrue(!is_link($link));
  526. }
  527. public function testSymlinkIsOverwrittenIfPointsToDifferentTarget()
  528. {
  529. $this->markAsSkippedIfSymlinkIsMissing();
  530. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  531. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  532. touch($file);
  533. symlink($this->workspace, $link);
  534. $this->filesystem->symlink($file, $link);
  535. $this->assertTrue(is_link($link));
  536. $this->assertEquals($file, readlink($link));
  537. }
  538. public function testSymlinkIsNotOverwrittenIfAlreadyCreated()
  539. {
  540. $this->markAsSkippedIfSymlinkIsMissing();
  541. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  542. $link = $this->workspace.DIRECTORY_SEPARATOR.'link';
  543. touch($file);
  544. symlink($file, $link);
  545. $this->filesystem->symlink($file, $link);
  546. $this->assertTrue(is_link($link));
  547. $this->assertEquals($file, readlink($link));
  548. }
  549. public function testSymlinkCreatesTargetDirectoryIfItDoesNotExist()
  550. {
  551. $this->markAsSkippedIfSymlinkIsMissing();
  552. $file = $this->workspace.DIRECTORY_SEPARATOR.'file';
  553. $link1 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'link';
  554. $link2 = $this->workspace.DIRECTORY_SEPARATOR.'dir'.DIRECTORY_SEPARATOR.'subdir'.DIRECTORY_SEPARATOR.'link';
  555. touch($file);
  556. $this->filesystem->symlink($file, $link1);
  557. $this->filesystem->symlink($file, $link2);
  558. $this->assertTrue(is_link($link1));
  559. $this->assertEquals($file, readlink($link1));
  560. $this->assertTrue(is_link($link2));
  561. $this->assertEquals($file, readlink($link2));
  562. }
  563. /**
  564. * @dataProvider providePathsForMakePathRelative
  565. */
  566. public function testMakePathRelative($endPath, $startPath, $expectedPath)
  567. {
  568. $path = $this->filesystem->makePathRelative($endPath, $startPath);
  569. $this->assertEquals($expectedPath, $path);
  570. }
  571. /**
  572. * @return array
  573. */
  574. public function providePathsForMakePathRelative()
  575. {
  576. $paths = array(
  577. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component', '../'),
  578. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/src/Symfony/Component/', '../'),
  579. array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component', '../'),
  580. array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'),
  581. array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'),
  582. array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'),
  583. array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'),
  584. array('/aa/bb', '/aa/bb', './'),
  585. array('/aa/bb', '/aa/bb/', './'),
  586. array('/aa/bb/', '/aa/bb', './'),
  587. array('/aa/bb/', '/aa/bb/', './'),
  588. array('/aa/bb/cc', '/aa/bb/cc/dd', '../'),
  589. array('/aa/bb/cc', '/aa/bb/cc/dd/', '../'),
  590. array('/aa/bb/cc/', '/aa/bb/cc/dd', '../'),
  591. array('/aa/bb/cc/', '/aa/bb/cc/dd/', '../'),
  592. array('/aa/bb/cc', '/aa', 'bb/cc/'),
  593. array('/aa/bb/cc', '/aa/', 'bb/cc/'),
  594. array('/aa/bb/cc/', '/aa', 'bb/cc/'),
  595. array('/aa/bb/cc/', '/aa/', 'bb/cc/'),
  596. array('/a/aab/bb', '/a/aa', '../aab/bb/'),
  597. array('/a/aab/bb', '/a/aa/', '../aab/bb/'),
  598. array('/a/aab/bb/', '/a/aa', '../aab/bb/'),
  599. array('/a/aab/bb/', '/a/aa/', '../aab/bb/'),
  600. array('/a/aab/bb/', '/', 'a/aab/bb/'),
  601. array('/a/aab/bb/', '/b/aab', '../../a/aab/bb/'),
  602. );
  603. if ('\\' === DIRECTORY_SEPARATOR) {
  604. $paths[] = array('c:\var\lib/symfony/src/Symfony/', 'c:/var/lib/symfony/', 'src/Symfony/');
  605. }
  606. return $paths;
  607. }
  608. public function testMirrorCopiesFilesAndDirectoriesRecursively()
  609. {
  610. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  611. $directory = $sourcePath.'directory'.DIRECTORY_SEPARATOR;
  612. $file1 = $directory.'file1';
  613. $file2 = $sourcePath.'file2';
  614. mkdir($sourcePath);
  615. mkdir($directory);
  616. file_put_contents($file1, 'FILE1');
  617. file_put_contents($file2, 'FILE2');
  618. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  619. $this->filesystem->mirror($sourcePath, $targetPath);
  620. $this->assertTrue(is_dir($targetPath));
  621. $this->assertTrue(is_dir($targetPath.'directory'));
  622. $this->assertFileEquals($file1, $targetPath.'directory'.DIRECTORY_SEPARATOR.'file1');
  623. $this->assertFileEquals($file2, $targetPath.'file2');
  624. $this->filesystem->remove($file1);
  625. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => false));
  626. $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  627. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  628. $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  629. file_put_contents($file1, 'FILE1');
  630. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  631. $this->assertTrue($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  632. $this->filesystem->remove($directory);
  633. $this->filesystem->mirror($sourcePath, $targetPath, null, array('delete' => true));
  634. $this->assertFalse($this->filesystem->exists($targetPath.'directory'));
  635. $this->assertFalse($this->filesystem->exists($targetPath.'directory'.DIRECTORY_SEPARATOR.'file1'));
  636. }
  637. public function testMirrorCreatesEmptyDirectory()
  638. {
  639. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  640. mkdir($sourcePath);
  641. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  642. $this->filesystem->mirror($sourcePath, $targetPath);
  643. $this->assertTrue(is_dir($targetPath));
  644. $this->filesystem->remove($sourcePath);
  645. }
  646. public function testMirrorCopiesLinks()
  647. {
  648. $this->markAsSkippedIfSymlinkIsMissing();
  649. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  650. mkdir($sourcePath);
  651. file_put_contents($sourcePath.'file1', 'FILE1');
  652. symlink($sourcePath.'file1', $sourcePath.'link1');
  653. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  654. $this->filesystem->mirror($sourcePath, $targetPath);
  655. $this->assertTrue(is_dir($targetPath));
  656. $this->assertFileEquals($sourcePath.'file1', $targetPath.DIRECTORY_SEPARATOR.'link1');
  657. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  658. }
  659. public function testMirrorCopiesLinkedDirectoryContents()
  660. {
  661. $this->markAsSkippedIfSymlinkIsMissing();
  662. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  663. mkdir($sourcePath.'nested/', 0777, true);
  664. file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
  665. // Note: We symlink directory, not file
  666. symlink($sourcePath.'nested', $sourcePath.'link1');
  667. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  668. $this->filesystem->mirror($sourcePath, $targetPath);
  669. $this->assertTrue(is_dir($targetPath));
  670. $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
  671. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  672. }
  673. public function testMirrorCopiesRelativeLinkedContents()
  674. {
  675. $this->markAsSkippedIfSymlinkIsMissing();
  676. $sourcePath = $this->workspace.DIRECTORY_SEPARATOR.'source'.DIRECTORY_SEPARATOR;
  677. $oldPath = getcwd();
  678. mkdir($sourcePath.'nested/', 0777, true);
  679. file_put_contents($sourcePath.'/nested/file1.txt', 'FILE1');
  680. // Note: Create relative symlink
  681. chdir($sourcePath);
  682. symlink('nested', 'link1');
  683. chdir($oldPath);
  684. $targetPath = $this->workspace.DIRECTORY_SEPARATOR.'target'.DIRECTORY_SEPARATOR;
  685. $this->filesystem->mirror($sourcePath, $targetPath);
  686. $this->assertTrue(is_dir($targetPath));
  687. $this->assertFileEquals($sourcePath.'/nested/file1.txt', $targetPath.DIRECTORY_SEPARATOR.'link1/file1.txt');
  688. $this->assertTrue(is_link($targetPath.DIRECTORY_SEPARATOR.'link1'));
  689. $this->assertEquals('\\' === DIRECTORY_SEPARATOR ? realpath($sourcePath.'\nested') : 'nested', readlink($targetPath.DIRECTORY_SEPARATOR.'link1'));
  690. }
  691. /**
  692. * @dataProvider providePathsForIsAbsolutePath
  693. */
  694. public function testIsAbsolutePath($path, $expectedResult)
  695. {
  696. $result = $this->filesystem->isAbsolutePath($path);
  697. $this->assertEquals($expectedResult, $result);
  698. }
  699. /**
  700. * @return array
  701. */
  702. public function providePathsForIsAbsolutePath()
  703. {
  704. return array(
  705. array('/var/lib', true),
  706. array('c:\\\\var\\lib', true),
  707. array('\\var\\lib', true),
  708. array('var/lib', false),
  709. array('../var/lib', false),
  710. array('', false),
  711. array(null, false),
  712. );
  713. }
  714. public function testTempnam()
  715. {
  716. $dirname = $this->workspace;
  717. $filename = $this->filesystem->tempnam($dirname, 'foo');
  718. $this->assertFileExists($filename);
  719. }
  720. public function testTempnamWithFileScheme()
  721. {
  722. $scheme = 'file://';
  723. $dirname = $scheme.$this->workspace;
  724. $filename = $this->filesystem->tempnam($dirname, 'foo');
  725. $this->assertStringStartsWith($scheme, $filename);
  726. $this->assertFileExists($filename);
  727. }
  728. public function testTempnamWithMockScheme()
  729. {
  730. stream_wrapper_register('mock', 'Symfony\Component\Filesystem\Tests\Fixtures\MockStream\MockStream');
  731. $scheme = 'mock://';
  732. $dirname = $scheme.$this->workspace;
  733. $filename = $this->filesystem->tempnam($dirname, 'foo');
  734. $this->assertStringStartsWith($scheme, $filename);
  735. $this->assertFileExists($filename);
  736. }
  737. /**
  738. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  739. */
  740. public function testTempnamWithZlibSchemeFails()
  741. {
  742. $scheme = 'compress.zlib://';
  743. $dirname = $scheme.$this->workspace;
  744. // The compress.zlib:// stream does not support mode x: creates the file, errors "failed to open stream: operation failed" and returns false
  745. $this->filesystem->tempnam($dirname, 'bar');
  746. }
  747. public function testTempnamWithPHPTempSchemeFails()
  748. {
  749. $scheme = 'php://temp';
  750. $dirname = $scheme;
  751. $filename = $this->filesystem->tempnam($dirname, 'bar');
  752. $this->assertStringStartsWith($scheme, $filename);
  753. // The php://temp stream deletes the file after close
  754. $this->assertFileNotExists($filename);
  755. }
  756. /**
  757. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  758. */
  759. public function testTempnamWithPharSchemeFails()
  760. {
  761. // Skip test if Phar disabled phar.readonly must be 0 in php.ini
  762. if (!\Phar::canWrite()) {
  763. $this->markTestSkipped('This test cannot run when phar.readonly is 1.');
  764. }
  765. $scheme = 'phar://';
  766. $dirname = $scheme.$this->workspace;
  767. $pharname = 'foo.phar';
  768. new \Phar($this->workspace.'/'.$pharname, 0, $pharname);
  769. // 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
  770. $this->filesystem->tempnam($dirname, $pharname.'/bar');
  771. }
  772. /**
  773. * @expectedException \Symfony\Component\Filesystem\Exception\IOException
  774. */
  775. public function testTempnamWithHTTPSchemeFails()
  776. {
  777. $scheme = 'http://';
  778. $dirname = $scheme.$this->workspace;
  779. // The http:// scheme is read-only
  780. $this->filesystem->tempnam($dirname, 'bar');
  781. }
  782. public function testTempnamOnUnwritableFallsBackToSysTmp()
  783. {
  784. $scheme = 'file://';
  785. $dirname = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'does_not_exist';
  786. $filename = $this->filesystem->tempnam($dirname, 'bar');
  787. $realTempDir = realpath(sys_get_temp_dir());
  788. $this->assertStringStartsWith(rtrim($scheme.$realTempDir, DIRECTORY_SEPARATOR), $filename);
  789. $this->assertFileExists($filename);
  790. // Tear down
  791. @unlink($filename);
  792. }
  793. public function testDumpFile()
  794. {
  795. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  796. $this->filesystem->dumpFile($filename, 'bar');
  797. $this->assertFileExists($filename);
  798. $this->assertSame('bar', file_get_contents($filename));
  799. // skip mode check on Windows
  800. if ('\\' !== DIRECTORY_SEPARATOR) {
  801. $this->assertFilePermissions(600, $filename);
  802. }
  803. }
  804. public function testDumpFileOverwritesAnExistingFile()
  805. {
  806. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo.txt';
  807. file_put_contents($filename, 'FOO BAR');
  808. $this->filesystem->dumpFile($filename, 'bar');
  809. $this->assertFileExists($filename);
  810. $this->assertSame('bar', file_get_contents($filename));
  811. }
  812. public function testDumpFileWithFileScheme()
  813. {
  814. if (defined('HHVM_VERSION')) {
  815. $this->markTestSkipped('HHVM does not handle the file:// scheme correctly');
  816. }
  817. $scheme = 'file://';
  818. $filename = $scheme.$this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  819. $this->filesystem->dumpFile($filename, 'bar', null);
  820. $this->assertFileExists($filename);
  821. $this->assertSame('bar', file_get_contents($filename));
  822. }
  823. public function testDumpFileWithZlibScheme()
  824. {
  825. $scheme = 'compress.zlib://';
  826. $filename = $this->workspace.DIRECTORY_SEPARATOR.'foo'.DIRECTORY_SEPARATOR.'baz.txt';
  827. $this->filesystem->dumpFile($filename, 'bar', null);
  828. // Zlib stat uses file:// wrapper so remove scheme
  829. $this->assertFileExists(str_replace($scheme, '', $filename));
  830. $this->assertSame('bar', file_get_contents($filename));
  831. }
  832. public function testCopyShouldKeepExecutionPermission()
  833. {
  834. $this->markAsSkippedIfChmodIsMissing();
  835. $sourceFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_source_file';
  836. $targetFilePath = $this->workspace.DIRECTORY_SEPARATOR.'copy_target_file';
  837. file_put_contents($sourceFilePath, 'SOURCE FILE');
  838. chmod($sourceFilePath, 0745);
  839. $this->filesystem->copy($sourceFilePath, $targetFilePath);
  840. $this->assertFilePermissions(767, $targetFilePath);
  841. }
  842. }