FilesystemTest.php 43 KB

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