PathTest.php 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462
  1. <?php
  2. namespace Path\Tests;
  3. use Path\Exception\FileExistsException;
  4. use Path\Exception\FileNotFoundException;
  5. use Path\Exception\IOException;
  6. use Path\Path;
  7. use PHPUnit\Framework\TestCase;
  8. // TODO: tested args should be both typed Path and string
  9. class PathTest extends TestCase
  10. {
  11. const TEMP_TEST_DIR = __DIR__ . "/temp";
  12. // TODO: consider using sys_get_temp_dir()
  13. protected Path $pathClass;
  14. public function setUp(): void
  15. {
  16. clearstatcache();
  17. mkdir(self::TEMP_TEST_DIR, 0777, true);
  18. chdir(self::TEMP_TEST_DIR);
  19. }
  20. private function rmDirs(string $dir): void {
  21. // Remove and replace by a proper tempdir method
  22. foreach(scandir($dir) as $file) {
  23. if ('.' === $file || '..' === $file) continue;
  24. if (is_dir($dir . DIRECTORY_SEPARATOR . $file)) $this->rmDirs($dir . DIRECTORY_SEPARATOR . $file);
  25. else unlink($dir . DIRECTORY_SEPARATOR . $file);
  26. }
  27. rmdir($dir);
  28. }
  29. public function tearDown(): void
  30. {
  31. $this->rmDirs(self::TEMP_TEST_DIR);
  32. chdir(__DIR__);
  33. }
  34. public function testToString(): void
  35. {
  36. $path = new Path('/foo/bar');
  37. $this->assertEquals('/foo/bar', $path->__toString());
  38. }
  39. /**
  40. * Test 'join' method.
  41. */
  42. public function testJoin(): void
  43. {
  44. // One part
  45. $this->assertEquals(
  46. '/home/user',
  47. Path::join('/home', 'user')
  48. );
  49. // Multiple parts
  50. $this->assertEquals(
  51. '/home/user/documents',
  52. Path::join('/home', 'user', 'documents')
  53. );
  54. // Absolute path passed in $parts
  55. $this->assertEquals(
  56. '/user/documents',
  57. Path::join('home', '/user', 'documents')
  58. );
  59. }
  60. /**
  61. * Test 'Path' class 'copy_dir' method to copy a directory
  62. *
  63. * @return void
  64. * @throws FileExistsException
  65. * @throws FileNotFoundException
  66. */
  67. public function testCopyDir(): void
  68. {
  69. $src = self::TEMP_TEST_DIR . "/some_dir";
  70. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  71. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  72. mkdir($src);
  73. touch($srcContent);
  74. mkdir($dst);
  75. Path::copy_dir($src, $dst);
  76. $this->assertTrue(
  77. file_exists($dst . DIRECTORY_SEPARATOR . "foo.txt")
  78. );
  79. }
  80. /**
  81. * Test 'Path' class 'copy_dir' method when the destination directory does not exist
  82. *
  83. * @throws FileNotFoundException|FileExistsException
  84. */
  85. public function testCopyDirWhenDestinationDirectoryNotExists(): void
  86. {
  87. $src = self::TEMP_TEST_DIR . "/some_dir";
  88. $dst = self::TEMP_TEST_DIR . "/non_existing_dir";
  89. mkdir($src);
  90. touch($src . DIRECTORY_SEPARATOR . "foo.txt");
  91. $this->expectException(FileNotFoundException::class);
  92. $this->expectExceptionMessage("Directory does not exist : " . $dst);
  93. Path::copy_dir($src, $dst);
  94. }
  95. /**
  96. * Test 'Path' class 'copy_dir' method when the destination directory already exists.
  97. *
  98. * @throws FileNotFoundException|FileExistsException if the destination directory already exists.
  99. */
  100. public function testCopyDirWhenDirectoryAlreadyExistsAtDestination(): void
  101. {
  102. $src = self::TEMP_TEST_DIR . "/some_dir";
  103. $dst = self::TEMP_TEST_DIR . "/other_dir";
  104. mkdir($src);
  105. touch($src . DIRECTORY_SEPARATOR . "foo.txt");
  106. mkdir($dst);
  107. mkdir($dst . DIRECTORY_SEPARATOR . "some_dir");
  108. $this->expectException(FileExistsException::class);
  109. $this->expectExceptionMessage("Directory already exists : " . $dst);
  110. Path::copy_dir($src, $dst);
  111. }
  112. /**
  113. * Test `eq` method with equal paths.
  114. *
  115. * Check that the method returns the correct result when the paths are equal.
  116. */
  117. public function testEqWithEqualPaths(): void
  118. {
  119. $path = new Path('/foo/bar');
  120. $this->assertTrue($path->eq('/foo/bar'));
  121. }
  122. /**
  123. * Test `eq` method with different paths.
  124. *
  125. * Check that the method returns the correct result when the paths are different.
  126. */
  127. public function testEqWithDifferentPaths(): void
  128. {
  129. $path = new Path('/foo/bar');
  130. $this->assertFalse($path->eq('/foo/zzz'));
  131. }
  132. /**
  133. * Test `eq` method with empty path.
  134. *
  135. * Check that the method returns the correct result when the path is empty.
  136. */
  137. public function testEqWithEmptyPath(): void
  138. {
  139. $path = new Path('/foo/bar');
  140. $this->assertFalse($path->eq(''));
  141. }
  142. /**
  143. * Test the append method of the Path class.
  144. *
  145. * @return void
  146. */
  147. public function testAppend(): void
  148. {
  149. $path = new Path('/foo');
  150. $this->assertEquals(
  151. "/foo/bar",
  152. $path->append('bar')
  153. );
  154. // One part
  155. $this->assertTrue(
  156. (new Path('/home'))->append('user')->eq('/home/user')
  157. );
  158. // Multiple parts
  159. $this->assertTrue(
  160. (new Path('/home'))->append('user', 'documents')->eq('/home/user/documents')
  161. );
  162. // Absolute path passed in $parts
  163. $this->assertTrue(
  164. (new Path('/home'))->append('/user', 'documents')->eq('/user/documents')
  165. );
  166. }
  167. /**
  168. * Test the abspath method of the Path class.
  169. *
  170. * @return void
  171. */
  172. public function testAbsPath(): void
  173. {
  174. touch(self::TEMP_TEST_DIR . "/foo");
  175. chdir(self::TEMP_TEST_DIR);
  176. $this->assertEquals(
  177. self::TEMP_TEST_DIR . "/foo",
  178. (new Path('foo'))->abspath()
  179. );
  180. }
  181. /**
  182. * Test the abspath method of the Path class with a relative path.
  183. *
  184. * @return void
  185. */
  186. public function testAbsPathWithRelative(): void
  187. {
  188. mkdir(self::TEMP_TEST_DIR . "/foo");
  189. touch(self::TEMP_TEST_DIR . "/bar");
  190. chdir(self::TEMP_TEST_DIR . "/foo");
  191. $this->assertEquals(
  192. self::TEMP_TEST_DIR . "/bar",
  193. (new Path('../bar'))->abspath()
  194. );
  195. }
  196. /**
  197. * Test 'Path' class 'access' method to check existence of the file
  198. */
  199. public function testAccessCheckExistenceOfFile(): void
  200. {
  201. $filePath = self::TEMP_TEST_DIR . "/foo";
  202. touch($filePath);
  203. chmod($filePath, 777);
  204. $result = (new Path('foo'))->access(Path::F_OK);
  205. $this->assertTrue($result);
  206. }
  207. /**
  208. * Test 'Path' class 'access' method to check existence of the non-existent file
  209. */
  210. public function testAccessCheckExistenceOfNonExistingFile(): void
  211. {
  212. $result = (new Path('foo'))->access(Path::F_OK);
  213. $this->assertFalse($result);
  214. }
  215. /**
  216. * Test 'Path' class 'access' method to check read permission of the file
  217. */
  218. public function testAccessCheckReadPermissionOfFile(): void
  219. {
  220. $filePath = self::TEMP_TEST_DIR . "/foo";
  221. touch($filePath);
  222. chmod($filePath, 777);
  223. $result = (new Path('foo'))->access(Path::R_OK);
  224. $this->assertTrue($result);
  225. }
  226. // /**
  227. // * Test 'Path' class 'access' method to check read permission of the file (no permission)
  228. // */
  229. // public function testAccessCheckReadPermissionOfFileNoRight(): void
  230. // {
  231. // $filePath = self::TEMP_TEST_DIR . "/foo";
  232. // touch($filePath);
  233. // chmod($filePath, 000);
  234. //
  235. // $result = (new Path('foo'))->access(Path::R_OK);
  236. // $this->assertFalse($result);
  237. // }
  238. /**
  239. * Test 'Path' class 'access' method to check write permission of the file
  240. */
  241. public function testAccessCheckWritePermissionOfFile(): void
  242. {
  243. $filePath = self::TEMP_TEST_DIR . "/foo";
  244. touch($filePath);
  245. chmod($filePath, 777);
  246. $result = (new Path('foo'))->access(Path::W_OK);
  247. $this->assertTrue($result);
  248. }
  249. // /**
  250. // * Test 'Path' class 'access' method to check write permission of the file (no permission)
  251. // */
  252. // public function testAccessCheckWritePermissionOfFileNoRight(): void
  253. // {
  254. // $filePath = self::TEMP_TEST_DIR . "/foo";
  255. // touch($filePath);
  256. // chmod($filePath, 000);
  257. //
  258. // $result = (new Path('foo'))->access(Path::W_OK);
  259. // $this->assertFalse($result);
  260. // }
  261. /**
  262. * Test 'Path' class 'access' method to check execute permission of the file
  263. */
  264. public function testAccessCheckExecutePermissionOfFile(): void
  265. {
  266. $filePath = self::TEMP_TEST_DIR . "/foo";
  267. touch($filePath);
  268. chmod($filePath, 777);
  269. $result = (new Path('foo'))->access(Path::X_OK);
  270. $this->assertTrue($result);
  271. }
  272. /**
  273. * Test 'Path' class 'access' method to check existence of the file
  274. */
  275. public function testAccessCheckExecutePermissionOfFileNoRight(): void
  276. {
  277. $filePath = self::TEMP_TEST_DIR . "/foo";
  278. touch($filePath);
  279. chmod($filePath, 000);
  280. $result = (new Path('foo'))->access(Path::X_OK);
  281. $this->assertFalse($result);
  282. }
  283. /**
  284. * Test 'Path' class 'access' method with an invalid mode parameter
  285. */
  286. public function testAccessInvalidModeParameter(): void
  287. {
  288. $this->expectException(\RuntimeException::class);
  289. (new Path('foo'))->access(123);
  290. }
  291. /**
  292. * Test 'Path' class 'atime' method to get the access time of a file
  293. *
  294. * @return void
  295. */
  296. public function testATime()
  297. {
  298. touch(self::TEMP_TEST_DIR . "/foo");
  299. $atime = (new Path('foo'))->atime();
  300. $this->assertTrue(abs(time() - strtotime($atime)) <= 60);
  301. $this->assertMatchesRegularExpression(
  302. "/\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}/",
  303. $atime
  304. );
  305. }
  306. /**
  307. * Test 'Path' class 'isFile' method to check if the file exists
  308. *
  309. * @return void
  310. */
  311. public function testIsFileOnActualFile(): void
  312. {
  313. touch(self::TEMP_TEST_DIR . "/foo");
  314. $this->assertTrue((new Path('foo'))->isFile());
  315. }
  316. /**
  317. * Test 'Path' class 'isFile' method to check if a non-existent file exists
  318. *
  319. * @return void
  320. */
  321. public function testIsFileOnNonExistentFile(): void
  322. {
  323. $this->assertFalse((new Path('foo'))->isFile());
  324. }
  325. /**
  326. * Test 'Path' class 'isFile' method to check if a file exists on the given directory
  327. *
  328. * @return void
  329. */
  330. public function testIsFileOnExistentDir(): void
  331. {
  332. mkdir(self::TEMP_TEST_DIR . "/some_dir");
  333. $this->assertFalse((new Path('some_dir'))->isFile());
  334. }
  335. /**
  336. * Test 'Path' class 'isDir' method to check if the path is a directory
  337. *
  338. * @return void
  339. */
  340. public function testIsDirOnActualDir(): void
  341. {
  342. mkdir(self::TEMP_TEST_DIR . "/some_dir");
  343. $this->assertTrue((new Path('some_dir'))->isDir());
  344. }
  345. /**
  346. * Test 'Path' class 'isDir' method to check if a file's path is a directory
  347. *
  348. * @return void
  349. */
  350. public function testIsDirOnExistentFile(): void
  351. {
  352. touch(self::TEMP_TEST_DIR . "/foo");
  353. $this->assertFalse((new Path('some_dir'))->isDir());
  354. }
  355. /**
  356. * Test 'Path' class 'isDir' method on a non-existent directory
  357. *
  358. * @return void
  359. */
  360. public function testIsDirOnNonExistentDir(): void
  361. {
  362. $this->assertFalse((new Path('some_dir'))->isDir());
  363. }
  364. /**
  365. * Test 'Path' class 'ext' method to get the extension of the file
  366. *
  367. * @return void
  368. */
  369. public function testFileExtension(): void
  370. {
  371. $this->assertEquals(
  372. 'txt',
  373. (new Path("foo.txt"))->ext()
  374. );
  375. }
  376. /**
  377. * Test 'Path' class 'ext' method to get the extension of the file
  378. *
  379. * @return void
  380. */
  381. public function testEmptyExtension(): void
  382. {
  383. $this->assertEquals(
  384. '',
  385. (new Path("foo"))->ext()
  386. );
  387. }
  388. /**
  389. * Test 'Path' class 'basename' method to get the base name of a file
  390. *
  391. * @return void
  392. */
  393. public function testBaseName()
  394. {
  395. touch(self::TEMP_TEST_DIR . "/foo.txt");
  396. $this->assertEquals(
  397. 'foo.txt',
  398. (new Path("foo.txt"))->basename()
  399. );
  400. }
  401. /**
  402. * Test 'Path' class 'name' method to get the name of the file without extension
  403. *
  404. * @return void
  405. */
  406. public function testName()
  407. {
  408. touch(self::TEMP_TEST_DIR . "/foo");
  409. $this->assertEquals(
  410. 'foo',
  411. (new Path("foo"))->name()
  412. );
  413. }
  414. /**
  415. * Test 'Path' class 'name' method to get the name of the file with extension
  416. *
  417. * @return void
  418. */
  419. public function testNameWithExt()
  420. {
  421. touch(self::TEMP_TEST_DIR . "/foo.txt");
  422. $this->assertEquals(
  423. 'foo',
  424. (new Path("foo.txt"))->name()
  425. );
  426. }
  427. /**
  428. * Test 'Path' class 'mkdir' method to create a directory
  429. *
  430. * @return void
  431. * @throws FileExistsException
  432. */
  433. public function testMkDir(): void
  434. {
  435. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  436. $path->mkdir();
  437. $this->assertTrue($path->isDir());
  438. }
  439. /**
  440. * Test 'Path' class 'mkdir' method when directory already exists
  441. *
  442. * @throws FileExistsException If directory already exists
  443. */
  444. public function testMkDirExistingDir(): void {
  445. mkdir(self::TEMP_TEST_DIR . "/foo");
  446. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  447. $this->expectException(FileExistsException::class);
  448. $this->expectExceptionMessage("Directory already exists : " . self::TEMP_TEST_DIR . "/foo");
  449. $path->mkdir();
  450. }
  451. /**
  452. * Test 'Path' class 'mkdir' method to create a directory with existing directory and recursive option
  453. *
  454. * @return void
  455. * @throws FileExistsException
  456. */
  457. public function testMkDirExistingDirAndRecursive(): void {
  458. mkdir(self::TEMP_TEST_DIR . "/foo");
  459. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  460. $path->mkdir(0777, true);
  461. $this->assertTrue($path->isDir());
  462. }
  463. /**
  464. * Test 'Path' class 'mkdir' method to create a directory when a file with the same name already exists
  465. *
  466. * @return void
  467. * @throws FileExistsException When a file with the same name already exists
  468. */
  469. public function testMkDirExistingFile(): void {
  470. touch(self::TEMP_TEST_DIR . "/foo");
  471. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  472. $this->expectException(FileExistsException::class);
  473. $this->expectExceptionMessage("A file with this name already exists : " . self::TEMP_TEST_DIR . "/foo");
  474. $path->mkdir();
  475. }
  476. /**
  477. * Test 'Path' class 'mkdir' method to create a directory recursively
  478. *
  479. * @return void
  480. * @throws FileExistsException
  481. */
  482. public function testMkDirRecursive(): void {
  483. $path = new Path(self::TEMP_TEST_DIR . "/foo/bar");
  484. $path->mkdir(0777, true);
  485. $this->assertTrue($path->isDir());
  486. }
  487. /**
  488. * Test 'Path' class 'delete' method to delete a file.
  489. *
  490. * @return void
  491. * @throws FileNotFoundException
  492. */
  493. public function testDeleteFileSuccess(): void
  494. {
  495. touch(self::TEMP_TEST_DIR . "/foo");
  496. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  497. $this->assertTrue($path->isFile());
  498. $path->delete();
  499. $this->assertFalse($path->isFile());
  500. }
  501. /**
  502. * Test 'Path' class 'delete' method to delete a directory successfully
  503. *
  504. * @return void
  505. * @throws FileNotFoundException
  506. */
  507. public function testDeleteDirSuccess(): void
  508. {
  509. mkdir(self::TEMP_TEST_DIR . "/foo");
  510. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  511. $this->assertTrue($path->isDir());
  512. $path->delete();
  513. $this->assertFalse($path->isDir());
  514. }
  515. /**
  516. * Test 'Path' class 'delete' method to delete a non-existing file or dir
  517. *
  518. * @throws FileNotFoundException When the file does not exist
  519. */
  520. public function testDeleteNonExistingFile(): void
  521. {
  522. $path = new Path(self::TEMP_TEST_DIR . "/foo");
  523. $this->assertFalse($path->isDir());
  524. $this->expectException(FileNotFoundException::class);
  525. $this->expectExceptionMessage("File does not exist : " . self::TEMP_TEST_DIR . "/foo");
  526. $path->delete();
  527. }
  528. /**
  529. * Test 'Path' class 'copy_dir' method to copy a file
  530. *
  531. * @return void
  532. * @throws FileExistsException
  533. * @throws FileNotFoundException
  534. */
  535. public function testCopyWithFile(): void
  536. {
  537. $src = self::TEMP_TEST_DIR . "/some_dir";
  538. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  539. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  540. mkdir($src);
  541. mkdir($dst);
  542. touch($srcContent);
  543. $path = new Path($srcContent);
  544. $path->copy($dst);
  545. $this->assertTrue(
  546. file_exists($dst . DIRECTORY_SEPARATOR . "foo.txt")
  547. );
  548. }
  549. /**
  550. * Test 'Path' class 'copy_dir' method to copy a directory
  551. *
  552. * @return void
  553. * @throws FileExistsException
  554. * @throws FileNotFoundException
  555. */
  556. public function testCopyWithDir(): void
  557. {
  558. $src = self::TEMP_TEST_DIR . "/some_dir";
  559. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  560. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  561. mkdir($src);
  562. mkdir($dst);
  563. touch($srcContent);
  564. $path = new Path($src);
  565. $path->copy($dst);
  566. $this->assertTrue(
  567. file_exists($srcContent)
  568. );
  569. }
  570. /**
  571. * Test 'Path' class 'copy' method when the source file does not exist.
  572. *
  573. * @return void
  574. * @throws FileExistsException
  575. * @throws FileNotFoundException
  576. */
  577. public function testCopyFileNotExists(): void
  578. {
  579. $src = self::TEMP_TEST_DIR . "/some_dir";
  580. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  581. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  582. mkdir($src);
  583. mkdir($dst);
  584. touch($srcContent);
  585. $path = new Path($src);
  586. $path->copy($dst);
  587. $this->assertTrue(
  588. file_exists($srcContent)
  589. );
  590. }
  591. /**
  592. * Test 'Path' class 'copy' method when the source file does not exist.
  593. *
  594. * @return void
  595. * @throws FileExistsException
  596. * @throws FileNotFoundException
  597. */
  598. public function testCopyDirDestAlreadyExists(): void
  599. {
  600. $src = self::TEMP_TEST_DIR . "/some_dir";
  601. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  602. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  603. $dstContent = $dst . DIRECTORY_SEPARATOR . "foo.txt";
  604. mkdir($src);
  605. touch($srcContent);
  606. mkdir($dst);
  607. mkdir($dstContent);
  608. $this->expectException(FileExistsException::class);
  609. $this->expectExceptionMessage("File or dir already exists : " . $dstContent);
  610. $path = new Path($srcContent);
  611. $path->copy($dst);
  612. }
  613. /**
  614. * Test 'Path' class 'copy' method when the source file does not exist.
  615. *
  616. * @return void
  617. * @throws FileExistsException
  618. * @throws FileNotFoundException
  619. */
  620. public function testCopyFileDestAlreadyExists(): void
  621. {
  622. $src = self::TEMP_TEST_DIR . "/some_dir";
  623. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  624. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  625. $dstContent = $dst . DIRECTORY_SEPARATOR . "foo.txt";
  626. mkdir($src);
  627. touch($srcContent);
  628. mkdir($dst);
  629. touch($dstContent);
  630. $this->expectException(FileExistsException::class);
  631. $this->expectExceptionMessage("File or dir already exists : " . $dstContent);
  632. $path = new Path($srcContent);
  633. $path->copy($dst);
  634. }
  635. /**
  636. * Test 'Path' class 'move' method to move a file from source directory to destination directory
  637. * @throws FileExistsException
  638. */
  639. public function testMoveWithFile(): void
  640. {
  641. $src = self::TEMP_TEST_DIR . "/some_dir";
  642. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  643. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  644. $dstContent = $dst . DIRECTORY_SEPARATOR . "foo.txt";
  645. mkdir($src);
  646. touch($srcContent);
  647. mkdir($dst);
  648. $path = new Path($srcContent);
  649. $path->move($dst);
  650. $this->assertFalse(
  651. file_exists($srcContent)
  652. );
  653. $this->assertTrue(
  654. file_exists($dstContent)
  655. );
  656. }
  657. /**
  658. * Test 'Path' class 'move' method to move a directory to a different location
  659. *
  660. * @return void
  661. * @throws FileExistsException
  662. */
  663. public function testMoveWithDir(): void
  664. {
  665. $src = self::TEMP_TEST_DIR . "/some_dir";
  666. $srcContent = $src . DIRECTORY_SEPARATOR . "foo.txt";
  667. $dst = self::TEMP_TEST_DIR . "/some_other_dir";
  668. $dstContent = $dst . DIRECTORY_SEPARATOR . "foo.txt";
  669. mkdir($src);
  670. touch($srcContent);
  671. $path = new Path($src);
  672. $path->move($dst);
  673. $this->assertFalse(
  674. file_exists($srcContent)
  675. );
  676. $this->assertTrue(
  677. file_exists($dstContent)
  678. );
  679. }
  680. /**
  681. * Test 'Path' class 'touch' method to create a file that does not exist
  682. *
  683. * @return void
  684. */
  685. public function testTouchFileDoesNotExist(): void
  686. {
  687. $src = self::TEMP_TEST_DIR . "/foo.txt";
  688. $path = new Path($src);
  689. $this->assertFalse(is_file($src));
  690. $path->touch();
  691. $this->assertTrue(is_file($src));
  692. }
  693. public function testTouchFileExistsNothingChange(): void {
  694. $src = self::TEMP_TEST_DIR . "/foo.txt";
  695. touch($src);
  696. $this->assertTrue(is_file($src));
  697. $path = new Path($src);
  698. $path->touch();
  699. $this->assertTrue(is_file($src));
  700. }
  701. public function testTouchFileExistsUpdateMtimeWithInt(): void {
  702. $src = self::TEMP_TEST_DIR . "/foo.txt";
  703. touch($src);
  704. $path = new Path($src);
  705. $timestamp = 1000;
  706. $path->touch($timestamp);
  707. $this->assertEquals(
  708. $timestamp,
  709. filemtime($src)
  710. );
  711. }
  712. public function testTouchFileExistsUpdateMtimeWithDatetime(): void {
  713. $src = self::TEMP_TEST_DIR . "/foo.txt";
  714. touch($src);
  715. $path = new Path($src);
  716. $dateTime = new \DateTime("2000-01-01");
  717. $path->touch($dateTime);
  718. $this->assertEquals(
  719. $dateTime->getTimestamp(),
  720. filemtime($src)
  721. );
  722. }
  723. public function testTouchFileExistsUpdateAtimeWithInt(): void {
  724. $src = self::TEMP_TEST_DIR . "/foo.txt";
  725. touch($src);
  726. $path = new Path($src);
  727. $timestamp = 1000;
  728. $path->touch($timestamp, $timestamp);
  729. $this->assertEquals(
  730. $timestamp,
  731. fileatime($src)
  732. );
  733. }
  734. public function testTouchFileExistsUpdateAtimeWithDatetime(): void {
  735. $src = self::TEMP_TEST_DIR . "/foo.txt";
  736. touch($src);
  737. $path = new Path($src);
  738. $dateTime = new \DateTime("2000-01-01");
  739. $path->touch($dateTime, $dateTime);
  740. $this->assertEquals(
  741. $dateTime->getTimestamp(),
  742. fileatime($src)
  743. );
  744. }
  745. public function testLastModified(): void {
  746. $src = self::TEMP_TEST_DIR . "/foo.txt";
  747. $dateTime = new \DateTime("2000-01-01");
  748. touch($src, $dateTime->getTimestamp());
  749. $path = new Path($src);
  750. $this->assertEquals(
  751. $dateTime->getTimestamp(),
  752. $path->lastModified()
  753. );
  754. }
  755. /**
  756. * Test 'Path' class 'size' method to get the size of the file
  757. *
  758. * @return void
  759. * @throws FileNotFoundException
  760. */
  761. public function testSize(): void {
  762. $src = self::TEMP_TEST_DIR . "/foo.txt";
  763. file_put_contents($src, "nova");
  764. $path = new Path($src);
  765. $this->assertEquals(
  766. 4,
  767. $path->size()
  768. );
  769. }
  770. /**
  771. * Test 'Path' class 'size' method to get the size of the file
  772. *
  773. * @return void
  774. * @throws FileNotFoundException
  775. */
  776. public function testSizeNotExistingFile(): void {
  777. $src = self::TEMP_TEST_DIR . "/foo.txt";
  778. $path = new Path($src);
  779. $this->expectException(FileNotFoundException::class);
  780. $this->expectExceptionMessage("File does not exist : " . $src);
  781. $path->size();
  782. }
  783. public function testParent(): void
  784. {
  785. $this->assertEquals(
  786. '/foo/bar',
  787. (new Path('/foo/bar/baz'))->parent()
  788. );
  789. $this->assertEquals(
  790. '/foo/bar',
  791. (new Path('/foo/bar/baz.txt'))->parent()
  792. );
  793. $this->assertEquals(
  794. '/',
  795. (new Path('/foo'))->parent()
  796. );
  797. }
  798. /**
  799. * Test 'Path' class 'getContent' method to retrieve the content of a file
  800. *
  801. * @return void
  802. * @throws FileNotFoundException
  803. */
  804. public function testGetContent(): void {
  805. $src = self::TEMP_TEST_DIR . "/foo.txt";
  806. file_put_contents($src, "nova");
  807. $path = new Path($src);
  808. $this->assertEquals(
  809. "nova",
  810. $path->getContent()
  811. );
  812. }
  813. /**
  814. * Test 'Path' class 'getContent' method to get the content of a non-existing file
  815. *
  816. * @throws FileNotFoundException If the file does not exist
  817. */
  818. public function testGetContentNotExistingFile(): void {
  819. $src = self::TEMP_TEST_DIR . "/foo.txt";
  820. $path = new Path($src);
  821. $this->expectException(FileNotFoundException::class);
  822. $this->expectExceptionMessage("File does not exist : " . $src);
  823. $path->getContent();
  824. }
  825. public function testPutContent(): void {
  826. $src = self::TEMP_TEST_DIR . "/foo.txt";
  827. $path = new Path($src);
  828. $path->putContent("ocarina");
  829. $this->assertEquals(
  830. "ocarina",
  831. file_get_contents($src)
  832. );
  833. }
  834. public function testAppendContent(): void {
  835. $src = self::TEMP_TEST_DIR . "/foo.txt";
  836. touch($src);
  837. file_put_contents($src, "oca");
  838. $path = new Path($src);
  839. $path->appendContent("rina");
  840. $this->assertEquals(
  841. "ocarina",
  842. file_get_contents($src)
  843. );
  844. }
  845. /**
  846. * Test 'Path' class 'getPermissions' method to retrieve the file permissions
  847. *
  848. * @return void
  849. * @throws FileNotFoundException
  850. */
  851. public function testGetPermissions(): void
  852. {
  853. $src = self::TEMP_TEST_DIR . "/foo.txt";
  854. touch($src);
  855. chmod($src, 0777);
  856. $path = new Path($src);
  857. $this->assertEquals(
  858. 777,
  859. $path->getPermissions()
  860. );
  861. }
  862. /**
  863. * Test 'Path' class 'getPermissions' method to retrieve file permissions
  864. * @throws FileNotFoundException
  865. */
  866. public function testGetPermissionsAlt(): void
  867. {
  868. $src = self::TEMP_TEST_DIR . "/foo.txt";
  869. touch($src);
  870. chmod($src, 0755);
  871. $path = new Path($src);
  872. $this->assertEquals(
  873. 755,
  874. $path->getPermissions()
  875. );
  876. }
  877. /**
  878. * Test 'Path' class 'getPermissions' method to retrieve file permissions
  879. * @throws FileNotFoundException
  880. */
  881. public function testGetPermissionsFileNotExists(): void
  882. {
  883. $src = self::TEMP_TEST_DIR . "/foo.txt";
  884. $path = new Path($src);
  885. $this->expectException(FileNotFoundException::class);
  886. $this->expectExceptionMessage("File or dir does not exist : " . $src);
  887. $path->getPermissions();
  888. }
  889. /**
  890. * Test 'Path' class 'setPermissions' method to change the permissions of a file
  891. * @throws FileNotFoundException
  892. */
  893. public function testSetPermissions(): void
  894. {
  895. $src = self::TEMP_TEST_DIR . "/foo.txt";
  896. touch($src);
  897. chmod($src, 0777);
  898. $path = new Path($src);
  899. $result = $path->setPermissions(0666);
  900. $this->assertTrue($result);
  901. $this->assertEquals(
  902. '0666',
  903. substr(sprintf('%o', fileperms($src)), -4)
  904. );
  905. }
  906. /**
  907. * Test 'Path' class 'setPermissions' method when file does not exist
  908. *
  909. * @throws FileNotFoundException If the file does not exist
  910. */
  911. public function testSetPermissionsFileNotExists(): void
  912. {
  913. $src = self::TEMP_TEST_DIR . "/foo.txt";
  914. $path = new Path($src);
  915. $this->expectException(FileNotFoundException::class);
  916. $this->expectExceptionMessage("File or dir does not exist : " . $src);
  917. $path->setPermissions(777);
  918. }
  919. /**
  920. * Test 'Path' class 'exists' method to check existence of the file
  921. *
  922. * @return void
  923. */
  924. public function testExistsExistingFile(): void
  925. {
  926. $src = self::TEMP_TEST_DIR . "/foo.txt";
  927. touch($src);
  928. $path = new Path($src);
  929. $this->assertTrue(
  930. $path->exists()
  931. );
  932. }
  933. /**
  934. * Test 'Path' class 'exists' method to check existence of the directory
  935. *
  936. * @return void
  937. */
  938. public function testExistsExistingDir(): void
  939. {
  940. $src = self::TEMP_TEST_DIR . "/foo";
  941. mkdir($src);
  942. $path = new Path($src);
  943. $this->assertTrue(
  944. $path->exists()
  945. );
  946. }
  947. /**
  948. * Test 'Path' class 'exists' method to check existence of a non-existing file
  949. *
  950. * @return void
  951. */
  952. public function testExistsNonExistingFile(): void
  953. {
  954. $src = self::TEMP_TEST_DIR . "/foo.txt";
  955. $path = new Path($src);
  956. $this->assertFalse(
  957. $path->exists()
  958. );
  959. }
  960. /**
  961. * Test 'Path' class 'glob' method to match and retrieve file names in a directory
  962. *
  963. * @return void
  964. */
  965. public function testGlob(): void
  966. {
  967. $src = self::TEMP_TEST_DIR;
  968. touch($src . "/foo.txt");
  969. touch($src . "/bar.txt");
  970. touch($src . "/pic.png");
  971. $path = new Path($src);
  972. $results = [];
  973. foreach ($path->glob('*.txt') as $filename) {
  974. $results[] = (string)$filename;
  975. }
  976. $this->assertEquals(
  977. ['bar.txt', 'foo.txt'],
  978. $results
  979. );
  980. }
  981. /**
  982. * Test 'Path' class 'rmdir' method to remove a directory and its contents
  983. *
  984. * @return void
  985. * @throws FileNotFoundException
  986. */
  987. public function testRmDir(): void
  988. {
  989. $src = self::TEMP_TEST_DIR . "/foo";
  990. mkdir($src);
  991. $path = new Path($src);
  992. $path->rmdir();
  993. $this->assertFalse(
  994. is_dir($src)
  995. );
  996. }
  997. public function testRmDirIsFile(): void {
  998. $src = self::TEMP_TEST_DIR . "/foo";
  999. touch($src);
  1000. $path = new Path($src);
  1001. $this->expectException(FileNotFoundException::class);
  1002. $this->expectExceptionMessage($src . " is not a directory");
  1003. $path->rmdir();
  1004. }
  1005. public function testRmDirNonExistingDir(): void {
  1006. $src = self::TEMP_TEST_DIR . "/foo";
  1007. $path = new Path($src);
  1008. $this->expectException(FileNotFoundException::class);
  1009. $this->expectExceptionMessage($src . " is not a directory");
  1010. $path->rmdir();
  1011. }
  1012. /**
  1013. * Test 'Path' class 'rmdir' method to remove a directory and its contents recursively
  1014. *
  1015. * @return void
  1016. * @throws FileNotFoundException
  1017. */
  1018. public function testRmDirRecursive(): void {
  1019. $src = self::TEMP_TEST_DIR . "/foo/bar";
  1020. mkdir($src, 0777, true);
  1021. touch($src . "/file.txt");
  1022. $path = new Path($src);
  1023. $path->rmdir(true);
  1024. $this->assertFalse(
  1025. is_dir($src)
  1026. );
  1027. }
  1028. /**
  1029. * @throws IOException
  1030. * @throws FileNotFoundException
  1031. */
  1032. public function testOpen(): void {
  1033. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1034. touch($src);
  1035. $path = new Path($src);
  1036. $handle = $path->open();
  1037. $this->assertIsResource($handle);
  1038. }
  1039. /**
  1040. * @throws IOException
  1041. * @throws FileNotFoundException
  1042. */
  1043. public function testOpenNotExistingFile(): void {
  1044. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1045. $path = new Path($src);
  1046. $this->expectException(FileNotFoundException::class);
  1047. $this->expectExceptionMessage(self::TEMP_TEST_DIR . "/foo.txt is not a file");
  1048. $path->open();
  1049. }
  1050. /**
  1051. * @throws IOException
  1052. * @throws FileNotFoundException
  1053. */
  1054. public function testOpenIsDir(): void {
  1055. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1056. $path = new Path($src);
  1057. $this->expectException(FileNotFoundException::class);
  1058. $this->expectExceptionMessage(self::TEMP_TEST_DIR . "/foo.txt is not a file");
  1059. $path->open();
  1060. }
  1061. public function testIsAbs() {
  1062. $path1 = new Path('/absolute/path');
  1063. $this->assertTrue($path1->isAbs());
  1064. $path2 = new Path('relative/path');
  1065. $this->assertFalse($path2->isAbs());
  1066. }
  1067. /**
  1068. * @throws FileNotFoundException
  1069. */
  1070. public function testChmod(): void
  1071. {
  1072. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1073. $path = $this
  1074. ->getMockBuilder(Path::class)
  1075. ->onlyMethods(['setPermissions'])
  1076. ->setConstructorArgs([$src])
  1077. ->getMock();
  1078. $path->expects(self::once())->method('setPermissions')->with(0770);
  1079. $path->chmod(0770);
  1080. }
  1081. /**
  1082. * @throws FileNotFoundException
  1083. */
  1084. public function testChown(): void
  1085. {
  1086. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1087. $path = $this
  1088. ->getMockBuilder(Path::class)
  1089. ->onlyMethods(['setOwner'])
  1090. ->setConstructorArgs([$src])
  1091. ->getMock();
  1092. $path->expects(self::once())->method('setOwner')->with(2, 2);
  1093. $path->chown(2, 2);
  1094. }
  1095. public function testIsLink(): void
  1096. {
  1097. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1098. touch($src);
  1099. $path1 = new Path($src);
  1100. $target = self::TEMP_TEST_DIR . "/link.txt";
  1101. symlink($src, $target);
  1102. $path2 = new Path($target);
  1103. $this->assertFalse($path1->isLink());
  1104. $this->assertTrue($path2->isLink());
  1105. }
  1106. /**
  1107. * @throws FileNotFoundException
  1108. */
  1109. public function testIterDir(): void {
  1110. $dir = self::TEMP_TEST_DIR . "/foo";
  1111. mkdir($dir);
  1112. $file1 = $dir . "/file1.ext";
  1113. touch($file1);
  1114. $file2 = $dir . "/file2.ext";
  1115. touch($file2);
  1116. $subDir = $dir . "/sub_dir";
  1117. mkdir($subDir);
  1118. $path = new Path($dir);
  1119. // TODO: test the generator behavior without array conversion
  1120. $this->assertEquals(
  1121. ['file1.ext', 'file2.ext', 'sub_dir'],
  1122. iterator_to_array($path->iterDir())
  1123. );
  1124. }
  1125. /**
  1126. * @throws FileNotFoundException
  1127. */
  1128. public function testIterDirNotExisting(): void {
  1129. $dir = self::TEMP_TEST_DIR . "/foo";
  1130. $path = new Path($dir);
  1131. $this->expectException(FileNotFoundException::class);
  1132. $this->expectExceptionMessage($dir . " is not a directory");
  1133. iterator_to_array($path->iterDir());
  1134. }
  1135. /**
  1136. * @throws FileNotFoundException
  1137. */
  1138. public function testIterDirIsFile(): void {
  1139. $src = self::TEMP_TEST_DIR . "/foo";
  1140. touch($src);
  1141. $path = new Path($src);
  1142. $this->expectException(FileNotFoundException::class);
  1143. $this->expectExceptionMessage($src . " is not a directory");
  1144. iterator_to_array($path->iterDir());
  1145. }
  1146. public function testLink(): void
  1147. {
  1148. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1149. touch($src);
  1150. $dst = self::TEMP_TEST_DIR . "/link.txt";
  1151. $path = new Path($src);
  1152. $path->link($dst);
  1153. $this->assertTrue(file_exists($dst));
  1154. }
  1155. public function testLinkWithPath(): void
  1156. {
  1157. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1158. touch($src);
  1159. $dst = self::TEMP_TEST_DIR . "/link.txt";
  1160. $path = new Path($src);
  1161. $path->link(new Path($dst));
  1162. $this->assertTrue(file_exists($dst));
  1163. }
  1164. public function testLstat(): void
  1165. {
  1166. $src = self::TEMP_TEST_DIR . "/foo.txt";
  1167. file_put_contents($src,'foo');
  1168. $path = new Path($src);
  1169. self::assertSame(
  1170. lstat($src),
  1171. $path->lstat()
  1172. );
  1173. }
  1174. public function testParts(): void
  1175. {
  1176. $path = new Path("foo/bar/my_file.txt");
  1177. self::assertEquals(
  1178. ['foo', 'bar', 'my_file.txt'],
  1179. $path->parts()
  1180. );
  1181. }
  1182. public function testPartsWithLeadingSeparator(): void
  1183. {
  1184. $path = new Path("/foo/bar/my_file.txt");
  1185. self::assertEquals(
  1186. ['/', 'foo', 'bar', 'my_file.txt'],
  1187. $path->parts()
  1188. );
  1189. }
  1190. /**
  1191. * @throws FileNotFoundException
  1192. */
  1193. public function testGetRelativePath()
  1194. {
  1195. $src = self::TEMP_TEST_DIR . "/foo";
  1196. touch($src);
  1197. $path = new Path($src);
  1198. $this->assertSame(
  1199. "foo",
  1200. $path->getRelativePath(self::TEMP_TEST_DIR)
  1201. );
  1202. }
  1203. }