PathTest.php 60 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501
  1. <?php
  2. namespace Path\Tests\unit;
  3. use http\Params;
  4. use Path\BuiltinProxy;
  5. use Path\Exception\FileExistsException;
  6. use Path\Exception\FileNotFoundException;
  7. use Path\Exception\IOException;
  8. use Path\Path;
  9. use PHPUnit\Framework\MockObject\MockObject;
  10. use PHPUnit\Framework\TestCase;
  11. class TestablePath extends Path {
  12. public function setBuiltin(BuiltinProxy $builtinProxy): void
  13. {
  14. $this->builtin = $builtinProxy;
  15. }
  16. public function cast(string|Path $path): Path
  17. {
  18. return parent::cast($path);
  19. }
  20. public function rrmdir(): bool {
  21. return $this->rrmdir();
  22. }
  23. public function getDirectoryIterator(): \DirectoryIterator
  24. {
  25. return parent::getDirectoryIterator();
  26. }
  27. }
  28. class PathTest extends TestCase
  29. {
  30. private BuiltinProxy | MockObject $builtin;
  31. public function setUp(): void
  32. {
  33. $this->builtin = $this->getMockBuilder(BuiltinProxy::class)->getMock();
  34. }
  35. public function getMock(string $path, string $methodName): TestablePath | MockObject
  36. {
  37. $mock = $this
  38. ->getMockBuilder(TestablePath::class)
  39. ->setConstructorArgs([$path])
  40. ->setMethodsExcept(['__toString', 'setBuiltin', $methodName])
  41. ->getMock();
  42. $mock->setBuiltin($this->builtin);
  43. return $mock;
  44. }
  45. /**
  46. * Test 'join' method.
  47. */
  48. public function testJoin(): void
  49. {
  50. // One part
  51. $this->assertEquals(
  52. '/home/user',
  53. Path::join('/home', 'user')
  54. );
  55. // Multiple parts
  56. $this->assertEquals(
  57. '/home/user/documents',
  58. Path::join('/home', 'user', 'documents')
  59. );
  60. // Absolute path passed in $parts
  61. $this->assertEquals(
  62. '/user/documents',
  63. Path::join('home', '/user', 'documents')
  64. );
  65. }
  66. public function testToString(): void
  67. {
  68. $path = new Path('/foo/bar');
  69. $this->assertEquals('/foo/bar', $path->__toString());
  70. }
  71. public function testPath()
  72. {
  73. $path = $this->getMock('bar', 'path');
  74. $this->assertEquals(
  75. 'bar',
  76. $path->path()
  77. );
  78. }
  79. public function testEq(): void
  80. {
  81. $path = $this->getMock('bar', 'eq');
  82. $path
  83. ->method('path')
  84. ->willReturn('bar');
  85. $path2 = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  86. $path2
  87. ->method('path')
  88. ->willReturn('bar');
  89. $path3 = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  90. $path3
  91. ->method('path')
  92. ->willReturn('/foo/bar');
  93. $path->method('cast')->willReturnMap(
  94. [
  95. [$path2, $path2],
  96. [$path3, $path3],
  97. ['bar', $path2],
  98. ['/foo/bar', $path3],
  99. ]
  100. );
  101. $this->assertTrue($path->eq($path2));
  102. $this->assertFalse($path->eq($path3));
  103. $this->assertTrue($path->eq('bar'));
  104. $this->assertFalse($path->eq('/foo/bar'));
  105. }
  106. /**
  107. * @throws IOException
  108. */
  109. public function testAbsPath(): void {
  110. $path = $this->getMock('bar', 'absPath');
  111. $this->builtin
  112. ->expects(self::once())
  113. ->method('realpath')
  114. ->with('bar')
  115. ->willReturn('/foo/bar');
  116. $newPath = $this->getMockBuilder(TestablePath::class)
  117. ->disableOriginalConstructor()
  118. ->getMock();
  119. $newPath->method('path')->willReturn('/foo/bar');
  120. $path->method('cast')->with('/foo/bar')->willReturn($newPath);
  121. $this->assertEquals(
  122. '/foo/bar',
  123. $path->absPath()->path()
  124. );
  125. }
  126. /**
  127. * @throws IOException
  128. */
  129. public function testRealPath()
  130. {
  131. $path = $this->getMock('bar', 'realpath');
  132. $newPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  133. $newPath
  134. ->method('eq')
  135. ->with('/foo/bar')
  136. ->willReturn(True);
  137. $path
  138. ->expects(self::once())
  139. ->method('absPath')
  140. ->willReturn($newPath);
  141. $this->assertTrue(
  142. $path->realpath()->eq('/foo/bar')
  143. );
  144. }
  145. public function testAccessFileExist(): void
  146. {
  147. $path = $this->getMock('bar', 'access');
  148. $this->builtin
  149. ->expects(self::once())
  150. ->method('file_exists')
  151. ->with('bar')
  152. ->willReturn(true);
  153. $this->builtin
  154. ->expects(self::never())
  155. ->method('is_readable')
  156. ->with('bar')
  157. ->willReturn(true);
  158. $this->builtin
  159. ->expects(self::never())
  160. ->method('is_writable')
  161. ->with('bar')
  162. ->willReturn(true);
  163. $this->builtin
  164. ->expects(self::never())
  165. ->method('is_executable')
  166. ->with('bar')
  167. ->willReturn(true);
  168. $this->assertTrue(
  169. $path->access(Path::F_OK)
  170. );
  171. }
  172. public function testAccessIsReadable(): void
  173. {
  174. $path = $this->getMock('bar', 'access');
  175. $this->builtin
  176. ->expects(self::never())
  177. ->method('file_exists')
  178. ->with('bar')
  179. ->willReturn(true);
  180. $this->builtin
  181. ->expects(self::once())
  182. ->method('is_readable')
  183. ->with('bar')
  184. ->willReturn(true);
  185. $this->builtin
  186. ->expects(self::never())
  187. ->method('is_writable')
  188. ->with('bar')
  189. ->willReturn(true);
  190. $this->builtin
  191. ->expects(self::never())
  192. ->method('is_executable')
  193. ->with('bar')
  194. ->willReturn(true);
  195. $this->assertTrue(
  196. $path->access(Path::R_OK)
  197. );
  198. }
  199. public function testAccessIsWritable(): void
  200. {
  201. $path = $this->getMock('bar', 'access');
  202. $this->builtin
  203. ->expects(self::never())
  204. ->method('file_exists')
  205. ->with('bar')
  206. ->willReturn(true);
  207. $this->builtin
  208. ->expects(self::never())
  209. ->method('is_readable')
  210. ->with('bar')
  211. ->willReturn(true);
  212. $this->builtin
  213. ->expects(self::once())
  214. ->method('is_writable')
  215. ->with('bar')
  216. ->willReturn(true);
  217. $this->builtin
  218. ->expects(self::never())
  219. ->method('is_executable')
  220. ->with('bar')
  221. ->willReturn(true);
  222. $this->assertTrue(
  223. $path->access(Path::W_OK)
  224. );
  225. }
  226. public function testAccessIsExecutable(): void
  227. {
  228. $path = $this->getMock('bar', 'access');
  229. $this->builtin
  230. ->expects(self::never())
  231. ->method('file_exists')
  232. ->with('bar')
  233. ->willReturn(true);
  234. $this->builtin
  235. ->expects(self::never())
  236. ->method('is_readable')
  237. ->with('bar')
  238. ->willReturn(true);
  239. $this->builtin
  240. ->expects(self::never())
  241. ->method('is_writable')
  242. ->with('bar')
  243. ->willReturn(true);
  244. $this->builtin
  245. ->expects(self::once())
  246. ->method('is_executable')
  247. ->with('bar')
  248. ->willReturn(true);
  249. $this->assertTrue(
  250. $path->access(Path::X_OK)
  251. );
  252. }
  253. public function testAccessInvalidMode(): void
  254. {
  255. $path = $this->getMock('bar', 'access');
  256. $this->builtin
  257. ->expects(self::never())
  258. ->method('file_exists')
  259. ->with('bar')
  260. ->willReturn(true);
  261. $this->builtin
  262. ->expects(self::never())
  263. ->method('is_readable')
  264. ->with('bar')
  265. ->willReturn(true);
  266. $this->builtin
  267. ->expects(self::never())
  268. ->method('is_writable')
  269. ->with('bar')
  270. ->willReturn(true);
  271. $this->builtin
  272. ->expects(self::never())
  273. ->method('is_executable')
  274. ->with('bar')
  275. ->willReturn(true);
  276. $this->expectException(\RuntimeException::class);
  277. $path->access(-1);
  278. }
  279. public function testATime(): void
  280. {
  281. $path = $this->getMock('bar', 'atime');
  282. $this->builtin
  283. ->expects(self::once())
  284. ->method('fileatime')
  285. ->with('bar')
  286. ->willReturn(1000);
  287. $date = '2000-01-01';
  288. $this->builtin
  289. ->expects(self::once())
  290. ->method('date')
  291. ->with('Y-m-d H:i:s', 1000)
  292. ->willReturn($date);
  293. $this->assertEquals(
  294. $date,
  295. $path->atime()
  296. );
  297. }
  298. public function testATimeError(): void
  299. {
  300. $path = $this->getMock('bar', 'atime');
  301. $this->builtin
  302. ->expects(self::once())
  303. ->method('fileatime')
  304. ->with('bar')
  305. ->willReturn(false);
  306. $this->assertEquals(
  307. null,
  308. $path->atime()
  309. );
  310. }
  311. public function testCTime(): void
  312. {
  313. $path = $this->getMock('bar', 'ctime');
  314. $this->builtin
  315. ->expects(self::once())
  316. ->method('filectime')
  317. ->with('bar')
  318. ->willReturn(1000);
  319. $date = '2000-01-01';
  320. $this->builtin
  321. ->expects(self::once())
  322. ->method('date')
  323. ->with('Y-m-d H:i:s', 1000)
  324. ->willReturn($date);
  325. $this->assertEquals(
  326. $date,
  327. $path->ctime()
  328. );
  329. }
  330. public function testCTimeError(): void
  331. {
  332. $path = $this->getMock('bar', 'ctime');
  333. $this->builtin
  334. ->expects(self::once())
  335. ->method('filectime')
  336. ->with('bar')
  337. ->willReturn(false);
  338. $this->assertEquals(
  339. null,
  340. $path->ctime()
  341. );
  342. }
  343. public function testMTime(): void
  344. {
  345. $path = $this->getMock('bar', 'mtime');
  346. $this->builtin
  347. ->expects(self::once())
  348. ->method('filemtime')
  349. ->with('bar')
  350. ->willReturn(1000);
  351. $date = '2000-01-01';
  352. $this->builtin
  353. ->expects(self::once())
  354. ->method('date')
  355. ->with('Y-m-d H:i:s', 1000)
  356. ->willReturn($date);
  357. $this->assertEquals(
  358. $date,
  359. $path->mtime()
  360. );
  361. }
  362. public function testMTimeError(): void
  363. {
  364. $path = $this->getMock('bar', 'mtime');
  365. $this->builtin
  366. ->expects(self::once())
  367. ->method('filemtime')
  368. ->with('bar')
  369. ->willReturn(false);
  370. $this->assertEquals(
  371. null,
  372. $path->mtime()
  373. );
  374. }
  375. public function testIsFile(): void
  376. {
  377. $path = $this->getMock('bar', 'isFile');
  378. $this->builtin
  379. ->expects(self::once())
  380. ->method('is_file')
  381. ->with('bar')
  382. ->willReturn(true);
  383. $this->assertTrue(
  384. $path->isFile()
  385. );
  386. }
  387. public function testIsDir(): void
  388. {
  389. $path = $this->getMock('bar', 'isDir');
  390. $this->builtin
  391. ->expects(self::once())
  392. ->method('is_dir')
  393. ->with('bar')
  394. ->willReturn(true);
  395. $this->assertTrue(
  396. $path->isDir()
  397. );
  398. }
  399. public function testExt(): void
  400. {
  401. $path = $this->getMock('bar.ext', 'ext');
  402. $this->builtin
  403. ->expects(self::once())
  404. ->method('pathinfo')
  405. ->with('bar.ext', PATHINFO_EXTENSION)
  406. ->willReturn('ext');
  407. $this->assertEquals(
  408. 'ext',
  409. $path->ext()
  410. );
  411. }
  412. public function testBaseName(): void
  413. {
  414. $path = $this->getMock('bar.ext', 'basename');
  415. $this->builtin
  416. ->expects(self::once())
  417. ->method('pathinfo')
  418. ->with('bar.ext', PATHINFO_BASENAME)
  419. ->willReturn('bar.ext');
  420. $this->assertEquals(
  421. 'bar.ext',
  422. $path->basename()
  423. );
  424. }
  425. public function testCD(): void
  426. {
  427. $path = $this->getMock('bar', 'cd');
  428. $this->builtin
  429. ->expects(self::once())
  430. ->method('chdir')
  431. ->with('foo')
  432. ->willReturn(true);
  433. $this->assertTrue(
  434. $path->cd('foo')
  435. );
  436. }
  437. public function testChDir(): void
  438. {
  439. $path = $this->getMock('bar', 'chdir');
  440. $path
  441. ->expects(self::once())
  442. ->method('cd')
  443. ->with('foo')
  444. ->willReturn(true);
  445. $this->assertTrue(
  446. $path->cd('foo')
  447. );
  448. }
  449. public function testName(): void
  450. {
  451. $path = $this->getMock('bar.ext', 'name');
  452. $this->builtin
  453. ->expects(self::once())
  454. ->method('pathinfo')
  455. ->with('bar.ext', PATHINFO_FILENAME)
  456. ->willReturn('bar');
  457. $this->assertEquals(
  458. 'bar',
  459. $path->name()
  460. );
  461. }
  462. /**
  463. * @throws IOException
  464. * @throws FileExistsException
  465. */
  466. public function testMkDir(): void
  467. {
  468. $path = $this->getMock('foo', 'mkdir');
  469. $path->method('isDir')->willReturn(False);
  470. $path->method('isFile')->willReturn(False);
  471. $this->builtin
  472. ->expects(self::once())
  473. ->method('mkdir')
  474. ->with('foo', 0777, false)
  475. ->willReturn(true);
  476. $path->mkdir();
  477. }
  478. /**
  479. * @throws IOException
  480. */
  481. public function testMkDirAlreadyExist(): void
  482. {
  483. $path = $this->getMock('foo', 'mkdir');
  484. $path->method('isDir')->willReturn(True);
  485. $this->expectException(FileExistsException::class);
  486. $path->mkdir();
  487. }
  488. /**
  489. * @throws IOException
  490. * @throws FileExistsException
  491. */
  492. public function testMkDirAlreadyExistButRecursive(): void
  493. {
  494. $path = $this->getMock('foo', 'mkdir');
  495. $path->method('isDir')->willReturn(True);
  496. $this->builtin
  497. ->expects(self::never())
  498. ->method('mkdir');
  499. $path->mkdir(0777, true);
  500. }
  501. /**
  502. * @throws IOException
  503. * @throws FileExistsException
  504. */
  505. public function testMkDirFileExists(): void
  506. {
  507. $path = $this->getMock('foo', 'mkdir');
  508. $path->method('isDir')->willReturn(False);
  509. $path->method('isFile')->willReturn(True);
  510. $this->expectException(FileExistsException::class);
  511. $path->mkdir();
  512. }
  513. /**
  514. * @throws IOException
  515. * @throws FileExistsException
  516. */
  517. public function testMkDirFileExistsButRecursive(): void
  518. {
  519. $path = $this->getMock('foo', 'mkdir');
  520. $path->method('isDir')->willReturn(False);
  521. $path->method('isFile')->willReturn(True);
  522. $this->expectException(FileExistsException::class);
  523. $path->mkdir(0777, true);
  524. }
  525. /**
  526. * @throws IOException
  527. * @throws FileExistsException
  528. */
  529. public function testMkDirIoError(): void
  530. {
  531. $path = $this->getMock('foo', 'mkdir');
  532. $path->method('isDir')->willReturn(False);
  533. $path->method('isFile')->willReturn(False);
  534. $this->builtin
  535. ->expects(self::once())
  536. ->method('mkdir')
  537. ->with('foo', 0777, false)
  538. ->willReturn(false);
  539. $this->expectException(IOException::class);
  540. $path->mkdir();
  541. }
  542. /**
  543. * @throws IOException
  544. * @throws FileNotFoundException
  545. */
  546. public function testDeleteIsFile(): void
  547. {
  548. $path = $this->getMock('foo', 'delete');
  549. $path->method('isFile')->willReturn(True);
  550. $path->method('isDir')->willReturn(False);
  551. $this->builtin
  552. ->expects(self::once())
  553. ->method('unlink')
  554. ->with('foo')
  555. ->willReturn(true);
  556. $path->delete();
  557. }
  558. /**
  559. * @throws IOException
  560. * @throws FileNotFoundException
  561. */
  562. public function testDeleteIsFileWithError(): void
  563. {
  564. $path = $this->getMock('foo', 'delete');
  565. $path->method('isFile')->willReturn(True);
  566. $path->method('isDir')->willReturn(False);
  567. $this->builtin
  568. ->expects(self::once())
  569. ->method('unlink')
  570. ->with('foo')
  571. ->willReturn(false);
  572. $this->expectException(IOException::class);
  573. $path->delete();
  574. }
  575. /**
  576. * @throws IOException
  577. * @throws FileNotFoundException
  578. */
  579. public function testDeleteIsDir(): void
  580. {
  581. $path = $this->getMock('foo', 'delete');
  582. $path->method('isFile')->willReturn(False);
  583. $path->method('isDir')->willReturn(True);
  584. $this->builtin
  585. ->expects(self::once())
  586. ->method('rmdir')
  587. ->with('foo')
  588. ->willReturn(true);
  589. $path->delete();
  590. }
  591. /**
  592. * @throws IOException
  593. * @throws FileNotFoundException
  594. */
  595. public function testDeleteIsDirWithError(): void
  596. {
  597. $path = $this->getMock('foo', 'delete');
  598. $path->method('isFile')->willReturn(False);
  599. $path->method('isDir')->willReturn(True);
  600. $this->builtin
  601. ->expects(self::once())
  602. ->method('rmdir')
  603. ->with('foo')
  604. ->willReturn(false);
  605. $this->expectException(IOException::class);
  606. $path->delete();
  607. }
  608. /**
  609. * @throws IOException
  610. * @throws FileNotFoundException
  611. */
  612. public function testDeleteNonExistentFile(): void
  613. {
  614. $path = $this->getMock('foo', 'delete');
  615. $path->method('isFile')->willReturn(False);
  616. $path->method('isDir')->willReturn(False);
  617. $this->builtin
  618. ->expects(self::never())
  619. ->method('unlink');
  620. $this->builtin
  621. ->expects(self::never())
  622. ->method('rmdir');
  623. $this->expectException(FileNotFoundException::class);
  624. $path->delete();
  625. }
  626. /**
  627. * @throws IOException
  628. * @throws FileNotFoundException
  629. * @throws FileExistsException
  630. */
  631. public function testCopy()
  632. {
  633. $path = $this->getMock('foo.ext', 'copy');
  634. $path->method('isFile')->willReturn(True);
  635. $destination = "/bar/foo2.ext";
  636. $this->builtin
  637. ->expects(self::once())
  638. ->method('is_dir')
  639. ->with($destination)
  640. ->willReturn(False);
  641. $this->builtin
  642. ->expects(self::once())
  643. ->method('file_exists')
  644. ->with($destination)
  645. ->willReturn(False);
  646. $this->builtin
  647. ->expects(self::once())
  648. ->method('copy')
  649. ->with('foo.ext', $destination)
  650. ->willReturn(True);
  651. $newPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  652. $newPath->method('eq')->with($destination)->willReturn(True);
  653. $path->method('cast')->with($destination)->willReturn($newPath);
  654. $result = $path->copy($destination);
  655. $this->assertTrue(
  656. $result->eq($destination)
  657. );
  658. }
  659. /**
  660. * @throws IOException
  661. * @throws FileNotFoundException
  662. * @throws FileExistsException
  663. */
  664. public function testCopyFileDoesNotExist()
  665. {
  666. $path = $this->getMock('foo.ext', 'copy');
  667. $path->method('isFile')->willReturn(False);
  668. $destination = "/bar/foo2.ext";
  669. $this->builtin
  670. ->expects(self::never())
  671. ->method('is_dir');
  672. $this->builtin
  673. ->expects(self::never())
  674. ->method('file_exists');
  675. $this->builtin
  676. ->expects(self::never())
  677. ->method('copy');
  678. $this->expectException(FileNotFoundException::class);
  679. $path->copy($destination);
  680. }
  681. /**
  682. * @throws IOException
  683. * @throws FileNotFoundException
  684. * @throws FileExistsException
  685. */
  686. public function testCopyDestIsDir()
  687. {
  688. $path = $this->getMock('foo.ext', 'copy');
  689. $path->method('isFile')->willReturn(True);
  690. $path->method('basename')->willReturn('foo.ext');
  691. $destination = "/bar";
  692. $this->builtin
  693. ->expects(self::once())
  694. ->method('is_dir')
  695. ->with($destination)
  696. ->willReturn(True);
  697. $newDest = $destination . "/foo.ext";
  698. $this->builtin
  699. ->expects(self::once())
  700. ->method('file_exists')
  701. ->with($newDest)
  702. ->willReturn(False);
  703. $this->builtin
  704. ->expects(self::once())
  705. ->method('copy')
  706. ->with('foo.ext', $newDest)
  707. ->willReturn(True);
  708. $newPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  709. $newPath->method('eq')->with($newDest)->willReturn(True);
  710. $path->method('cast')->with($newDest)->willReturn($newPath);
  711. $result = $path->copy($destination);
  712. $this->assertTrue(
  713. $result->eq($newDest)
  714. );
  715. }
  716. /**
  717. * @throws IOException
  718. * @throws FileNotFoundException
  719. * @throws FileExistsException
  720. */
  721. public function testCopyFileAlreadyExists()
  722. {
  723. $path = $this->getMock('foo.ext', 'copy');
  724. $path->method('isFile')->willReturn(True);
  725. $destination = "/bar/foo2.ext";
  726. $this->builtin
  727. ->expects(self::once())
  728. ->method('is_dir')
  729. ->with($destination)
  730. ->willReturn(False);
  731. $this->builtin
  732. ->expects(self::once())
  733. ->method('file_exists')
  734. ->with($destination)
  735. ->willReturn(True);
  736. $this->builtin
  737. ->expects(self::never())
  738. ->method('copy');
  739. $this->expectException(FileExistsException::class);
  740. $path->copy($destination);
  741. }
  742. /**
  743. * @throws IOException
  744. * @throws FileNotFoundException
  745. * @throws FileExistsException
  746. */
  747. public function testCopyFileDestIsDirButFileAlreadyExists()
  748. {
  749. $path = $this->getMock('foo.ext', 'copy');
  750. $path->method('isFile')->willReturn(True);
  751. $path->method('basename')->willReturn('foo.ext');
  752. $destination = "/bar";
  753. $this->builtin
  754. ->expects(self::once())
  755. ->method('is_dir')
  756. ->with($destination)
  757. ->willReturn(True);
  758. $newDest = $destination . "/foo.ext";
  759. $this->builtin
  760. ->expects(self::once())
  761. ->method('file_exists')
  762. ->with($newDest)
  763. ->willReturn(True);
  764. $this->builtin
  765. ->expects(self::never())
  766. ->method('copy');
  767. $this->expectException(FileExistsException::class);
  768. $path->copy($destination);
  769. }
  770. /**
  771. * @throws IOException
  772. * @throws FileNotFoundException
  773. * @throws FileExistsException
  774. */
  775. public function testCopyFileWithError()
  776. {
  777. $path = $this->getMock('foo.ext', 'copy');
  778. $path->method('isFile')->willReturn(True);
  779. $destination = "/bar/foo2.ext";
  780. $this->builtin
  781. ->expects(self::once())
  782. ->method('is_dir')
  783. ->with($destination)
  784. ->willReturn(False);
  785. $this->builtin
  786. ->expects(self::once())
  787. ->method('file_exists')
  788. ->with($destination)
  789. ->willReturn(False);
  790. $this->builtin
  791. ->expects(self::once())
  792. ->method('copy')
  793. ->with('foo.ext', $destination)
  794. ->willReturn(False);
  795. $this->expectException(IOException::class);
  796. $path->copy($destination);
  797. }
  798. // public function testCopyTree(): void {
  799. // TODO: implement
  800. // }
  801. /**
  802. * @throws IOException
  803. * @throws FileExistsException
  804. */
  805. public function testMove()
  806. {
  807. $path = $this->getMock('foo.ext', 'move');
  808. $destination = "/bar/foo2.ext";
  809. $this->builtin
  810. ->expects(self::once())
  811. ->method('is_dir')
  812. ->with($destination)
  813. ->willReturn(False);
  814. $this->builtin
  815. ->expects(self::once())
  816. ->method('file_exists')
  817. ->with($destination)
  818. ->willReturn(False);
  819. $this->builtin
  820. ->expects(self::once())
  821. ->method('rename')
  822. ->with('foo.ext', $destination)
  823. ->willReturn(True);
  824. $destinationPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  825. $destinationPath->method('eq')->with($destination)->willReturn(True);
  826. $path->method('cast')->with($destination)->willReturn($destinationPath);
  827. $result = $path->move($destination);
  828. $this->assertTrue(
  829. $result->eq($destination)
  830. );
  831. }
  832. /**
  833. * @throws IOException
  834. * @throws FileExistsException
  835. */
  836. public function testMoveWithPath()
  837. {
  838. $path = $this->getMock('foo.ext', 'move');
  839. $destination = new Path("/bar/foo2.ext");
  840. $this->builtin
  841. ->expects(self::once())
  842. ->method('is_dir')
  843. ->with($destination)
  844. ->willReturn(False);
  845. $this->builtin
  846. ->expects(self::once())
  847. ->method('file_exists')
  848. ->with($destination)
  849. ->willReturn(False);
  850. $this->builtin
  851. ->expects(self::once())
  852. ->method('rename')
  853. ->with('foo.ext', $destination)
  854. ->willReturn(True);
  855. $destinationPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  856. $destinationPath->method('eq')->with($destination)->willReturn(True);
  857. $path->method('cast')->with($destination)->willReturn($destinationPath);
  858. $result = $path->move($destination);
  859. $this->assertTrue(
  860. $result->eq($destination)
  861. );
  862. }
  863. /**
  864. * @throws IOException
  865. * @throws FileExistsException
  866. */
  867. public function testMoveDestIsDir()
  868. {
  869. $path = $this->getMock('foo.ext', 'move');
  870. $path->method('basename')->willReturn('foo.ext');
  871. $destination = "/bar";
  872. $this->builtin
  873. ->expects(self::once())
  874. ->method('is_dir')
  875. ->with($destination)
  876. ->willReturn(True);
  877. $newDestination = $destination . "/foo.ext";
  878. $this->builtin
  879. ->expects(self::once())
  880. ->method('file_exists')
  881. ->with($newDestination)
  882. ->willReturn(False);
  883. $this->builtin
  884. ->expects(self::once())
  885. ->method('rename')
  886. ->with('foo.ext', $newDestination)
  887. ->willReturn(True);
  888. $destinationPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  889. $destinationPath->method('eq')->with($newDestination)->willReturn(True);
  890. $path->method('cast')->with($newDestination)->willReturn($destinationPath);
  891. $result = $path->move($destination);
  892. $this->assertTrue(
  893. $result->eq($newDestination)
  894. );
  895. }
  896. /**
  897. * @throws IOException
  898. * @throws FileExistsException
  899. */
  900. public function testMoveFileExist()
  901. {
  902. $path = $this->getMock('foo.ext', 'move');
  903. $path->method('basename')->willReturn('foo.ext');
  904. $destination = "/bar/foo2.ext";
  905. $this->builtin
  906. ->expects(self::once())
  907. ->method('is_dir')
  908. ->with($destination)
  909. ->willReturn(False);
  910. $this->builtin
  911. ->expects(self::once())
  912. ->method('file_exists')
  913. ->with($destination)
  914. ->willReturn(True);
  915. $this->builtin
  916. ->expects(self::never())
  917. ->method('rename');
  918. $this->expectException(FileExistsException::class);
  919. $path->move($destination);
  920. }
  921. /**
  922. * @throws IOException
  923. * @throws FileExistsException
  924. */
  925. public function testMoveWithError()
  926. {
  927. $path = $this->getMock('foo.ext', 'move');
  928. $path->method('basename')->willReturn('foo.ext');
  929. $destination = "/bar/foo2.ext";
  930. $this->builtin
  931. ->expects(self::once())
  932. ->method('is_dir')
  933. ->with($destination)
  934. ->willReturn(False);
  935. $this->builtin
  936. ->expects(self::once())
  937. ->method('file_exists')
  938. ->with($destination)
  939. ->willReturn(False);
  940. $this->builtin
  941. ->expects(self::once())
  942. ->method('rename')
  943. ->with('foo.ext', $destination)
  944. ->willReturn(False);
  945. $this->expectException(IOException::class);
  946. $path->move($destination);
  947. }
  948. /**
  949. * @throws IOException
  950. */
  951. public function testTouchWithNoTimestamps()
  952. {
  953. $path = $this->getMock('foo.ext', 'touch');
  954. $this->builtin
  955. ->expects(self::once())
  956. ->method('touch')
  957. ->with('foo.ext', null, null)
  958. ->willReturn(True);
  959. $path->touch();
  960. }
  961. /**
  962. * @throws IOException
  963. */
  964. public function testTouchWithTimestamps()
  965. {
  966. $path = $this->getMock('foo.ext', 'touch');
  967. $this->builtin
  968. ->expects(self::once())
  969. ->method('touch')
  970. ->with('foo.ext', 123, 456)
  971. ->willReturn(True);
  972. $path->touch(123, 456);
  973. }
  974. /**
  975. * @throws IOException
  976. */
  977. public function testTouchWithDatetimes()
  978. {
  979. $path = $this->getMock('foo.ext', 'touch');
  980. $datetime1 = $this->getMockBuilder(\DateTime::class)->getMock();
  981. $datetime1->method('getTimestamp')->willReturn(123);
  982. $datetime2 = $this->getMockBuilder(\DateTime::class)->getMock();
  983. $datetime2->method('getTimestamp')->willReturn(456);
  984. $this->builtin
  985. ->expects(self::once())
  986. ->method('touch')
  987. ->with('foo.ext', 123, 456)
  988. ->willReturn(True);
  989. $path->touch($datetime1, $datetime2);
  990. }
  991. /**
  992. * @throws IOException
  993. */
  994. public function testTouchWithError()
  995. {
  996. $path = $this->getMock('foo.ext', 'touch');
  997. $this->builtin
  998. ->expects(self::once())
  999. ->method('touch')
  1000. ->with('foo.ext')
  1001. ->willReturn(False);
  1002. $this->expectException(IOException::class);
  1003. $path->touch();
  1004. }
  1005. /**
  1006. * @throws IOException
  1007. * @throws FileNotFoundException
  1008. */
  1009. public function testSize()
  1010. {
  1011. $path = $this->getMock('foo.ext', 'size');
  1012. $path->method('isFile')->willReturn(True);
  1013. $this->builtin
  1014. ->expects(self::once())
  1015. ->method('filesize')
  1016. ->with('foo.ext')
  1017. ->willReturn(123456);
  1018. $this->assertEquals(
  1019. 123456,
  1020. $path->size()
  1021. );
  1022. }
  1023. /**
  1024. * @throws IOException
  1025. * @throws FileNotFoundException
  1026. */
  1027. public function testSizeFileNotExist()
  1028. {
  1029. $path = $this->getMock('foo.ext', 'size');
  1030. $path->method('isFile')->willReturn(False);
  1031. $this->builtin
  1032. ->expects(self::never())
  1033. ->method('filesize');
  1034. $this->expectException(FileNotFoundException::class);
  1035. $path->size();
  1036. }
  1037. /**
  1038. * @throws IOException
  1039. * @throws FileNotFoundException
  1040. */
  1041. public function testSizeFileWithError()
  1042. {
  1043. $path = $this->getMock('foo.ext', 'size');
  1044. $path->method('isFile')->willReturn(True);
  1045. $this->builtin
  1046. ->expects(self::once())
  1047. ->method('filesize')
  1048. ->with('foo.ext')
  1049. ->willReturn(False);
  1050. $this->expectException(IOException::class);
  1051. $path->size();
  1052. }
  1053. public function testParent(): void
  1054. {
  1055. $path = $this->getMock('/foo/foo.ext', 'parent');
  1056. $this->builtin
  1057. ->expects(self::once())
  1058. ->method('dirname')
  1059. ->with('/foo/foo.ext')
  1060. ->willReturn('/foo');
  1061. $newPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  1062. $path->method('cast')->with('/foo')->willReturn($newPath);
  1063. $newPath->method('eq')->with('/foo')->willReturn(True);
  1064. $this->assertTrue(
  1065. $path->parent()->eq('/foo')
  1066. );
  1067. }
  1068. public function testDirName(): void
  1069. {
  1070. $path = $this->getMock('/foo/foo.ext', 'dirname');
  1071. $newPath = $this->getMockBuilder(TestablePath::class)->disableOriginalConstructor()->getMock();
  1072. $newPath->method('eq')->with('/foo')->willReturn(True);
  1073. $path
  1074. ->expects(self::once())
  1075. ->method('parent')
  1076. ->willReturn($newPath);
  1077. $this->assertTrue(
  1078. $path->dirname()->eq('/foo')
  1079. );
  1080. }
  1081. /**
  1082. * @throws FileNotFoundException
  1083. */
  1084. public function testDirs()
  1085. {
  1086. $path = $this->getMock('/foo', 'dirs');
  1087. $this->builtin
  1088. ->method('is_dir')
  1089. ->willReturnMap(
  1090. [
  1091. ['/foo', True],
  1092. ['/foo/file.ext', False],
  1093. ['/foo/dir1', True],
  1094. ['/foo/dir2', True],
  1095. ]
  1096. );
  1097. $results = [
  1098. '..',
  1099. '.',
  1100. 'file.ext',
  1101. 'dir1',
  1102. 'dir2'
  1103. ];
  1104. $this->builtin
  1105. ->expects(self::once())
  1106. ->method('scandir')
  1107. ->with('/foo')
  1108. ->willReturn($results);
  1109. $this->assertEquals(
  1110. ['dir1', 'dir2'],
  1111. $path->dirs()
  1112. );
  1113. }
  1114. /**
  1115. * @throws FileNotFoundException
  1116. */
  1117. public function testDirsIsNotDir()
  1118. {
  1119. $path = $this->getMock('/foo', 'dirs');
  1120. $this->builtin
  1121. ->method('is_dir')
  1122. ->with('/foo')
  1123. ->willReturn(False);
  1124. $this->expectException(FileNotFoundException::class);
  1125. $path->dirs();
  1126. }
  1127. /**
  1128. * @throws FileNotFoundException
  1129. */
  1130. public function testFiles()
  1131. {
  1132. $path = $this->getMock('/foo', 'files');
  1133. $this->builtin
  1134. ->method('is_dir')
  1135. ->with('/foo')
  1136. ->willReturn(True);
  1137. $this->builtin
  1138. ->method('is_file')
  1139. ->willReturnMap(
  1140. [
  1141. ['/foo/file1.ext', True],
  1142. ['/foo/file2.ext', True],
  1143. ['/foo/dir1', False],
  1144. ]
  1145. );
  1146. $results = [
  1147. '..',
  1148. '.',
  1149. 'file1.ext',
  1150. 'file2.ext',
  1151. 'dir1'
  1152. ];
  1153. $this->builtin
  1154. ->expects(self::once())
  1155. ->method('scandir')
  1156. ->with('/foo')
  1157. ->willReturn($results);
  1158. $this->assertEquals(
  1159. ['file1.ext', 'file2.ext'],
  1160. $path->files()
  1161. );
  1162. }
  1163. /**
  1164. * @throws FileNotFoundException
  1165. */
  1166. public function testFilesIsNotDir()
  1167. {
  1168. $path = $this->getMock('/foo', 'files');
  1169. $this->builtin
  1170. ->method('is_dir')
  1171. ->with('/foo')
  1172. ->willReturn(False);
  1173. $this->expectException(FileNotFoundException::class);
  1174. $path->files();
  1175. }
  1176. // public function testFnMatch(): void
  1177. // {
  1178. // //TODO: implements
  1179. // }
  1180. /**
  1181. * @throws IOException
  1182. * @throws FileNotFoundException
  1183. */
  1184. public function testGetContent(): void
  1185. {
  1186. $path = $this->getMock('/foo/file.ext', 'getContent');
  1187. $this->builtin
  1188. ->method('is_file')
  1189. ->with('/foo/file.ext')
  1190. ->willReturn(True);
  1191. $this->builtin
  1192. ->method('file_get_contents')
  1193. ->with('/foo/file.ext')
  1194. ->willReturn('azerty');
  1195. $this->assertEquals(
  1196. 'azerty',
  1197. $path->getContent()
  1198. );
  1199. }
  1200. /**
  1201. * @throws IOException
  1202. * @throws FileNotFoundException
  1203. */
  1204. public function testGetContentFileDoesNotExist(): void
  1205. {
  1206. $path = $this->getMock('/foo/file.ext', 'getContent');
  1207. $this->builtin
  1208. ->method('is_file')
  1209. ->with('/foo/file.ext')
  1210. ->willReturn(False);
  1211. $this->builtin
  1212. ->expects(self::never())
  1213. ->method('file_get_contents');
  1214. $this->expectException(FileNotFoundException::class);
  1215. $path->getContent();
  1216. }
  1217. /**
  1218. * @throws IOException
  1219. * @throws FileNotFoundException
  1220. */
  1221. public function testGetContentErrorWhileReading(): void
  1222. {
  1223. $path = $this->getMock('/foo/file.ext', 'getContent');
  1224. $this->builtin
  1225. ->method('is_file')
  1226. ->with('/foo/file.ext')
  1227. ->willReturn(True);
  1228. $this->builtin
  1229. ->method('file_get_contents')
  1230. ->with('/foo/file.ext')
  1231. ->willReturn(False);
  1232. $this->expectException(IOException::class);
  1233. $path->getContent();
  1234. }
  1235. /**
  1236. * @throws IOException
  1237. * @throws FileNotFoundException
  1238. */
  1239. public function testPutContent(): void
  1240. {
  1241. $path = $this->getMock('/foo/file.ext', 'putContent');
  1242. $this->builtin
  1243. ->method('is_file')
  1244. ->with('/foo/file.ext')
  1245. ->willReturn(True);
  1246. $this->builtin
  1247. ->expects(self::once())
  1248. ->method('file_put_contents')
  1249. ->with('/foo/file.ext', 'azerty')
  1250. ->willReturn(6);
  1251. $this->assertEquals(
  1252. 6,
  1253. $path->putContent('azerty')
  1254. );
  1255. }
  1256. /**
  1257. * @throws IOException
  1258. * @throws FileNotFoundException
  1259. */
  1260. public function testPutContentAndAppend(): void
  1261. {
  1262. $path = $this->getMock('/foo/file.ext', 'putContent');
  1263. $this->builtin
  1264. ->method('is_file')
  1265. ->with('/foo/file.ext')
  1266. ->willReturn(True);
  1267. $this->builtin
  1268. ->expects(self::once())
  1269. ->method('file_put_contents')
  1270. ->with('/foo/file.ext', 'azerty', FILE_APPEND)
  1271. ->willReturn(6);
  1272. $this->assertEquals(
  1273. 6,
  1274. $path->putContent('azerty', True)
  1275. );
  1276. }
  1277. /**
  1278. * @throws IOException
  1279. * @throws FileNotFoundException
  1280. */
  1281. public function testPutContentFileDoesNotExist(): void
  1282. {
  1283. $path = $this->getMock('/foo/file.ext', 'putContent');
  1284. $this->builtin
  1285. ->method('is_file')
  1286. ->with('/foo/file.ext')
  1287. ->willReturn(False);
  1288. $this->builtin
  1289. ->expects(self::never())
  1290. ->method('file_put_contents');
  1291. $this->expectException(FileNotFoundException::class);
  1292. $path->putContent('azerty');
  1293. }
  1294. /**
  1295. * @throws IOException
  1296. * @throws FileNotFoundException
  1297. */
  1298. public function testPutContentErrorWhileWriting(): void
  1299. {
  1300. $path = $this->getMock('/foo/file.ext', 'putContent');
  1301. $this->builtin
  1302. ->method('is_file')
  1303. ->with('/foo/file.ext')
  1304. ->willReturn(True);
  1305. $this->builtin
  1306. ->method('file_put_contents')
  1307. ->with('/foo/file.ext')
  1308. ->willReturn(False);
  1309. $this->expectException(IOException::class);
  1310. $path->putContent('azerty');
  1311. }
  1312. /**
  1313. * @throws IOException
  1314. * @throws FileNotFoundException
  1315. */
  1316. public function testPutLines(): void
  1317. {
  1318. $path = $this->getMock('/foo/file.ext', 'putLines');
  1319. $lines = [
  1320. 'once upon a time',
  1321. 'a man and a spoon',
  1322. 'had a great time drinking coffee'
  1323. ];
  1324. $path
  1325. ->expects(self::once())
  1326. ->method('putContent')
  1327. ->with(implode(PHP_EOL, $lines))
  1328. ->willReturn(123);
  1329. $this->assertEquals(
  1330. 123,
  1331. $path->putLines($lines)
  1332. );
  1333. }
  1334. /**
  1335. * @throws IOException
  1336. * @throws FileNotFoundException
  1337. */
  1338. public function testGetPermissions(): void
  1339. {
  1340. $path = $this->getMock('/foo/file.ext', 'getPermissions');
  1341. $path->method('isFile')->willReturn(True);
  1342. $this->builtin
  1343. ->method('fileperms')
  1344. ->with('/foo/file.ext')
  1345. ->willReturn(16895);
  1346. $this->assertEquals(
  1347. 777,
  1348. $path->getPermissions()
  1349. );
  1350. }
  1351. /**
  1352. * @throws IOException
  1353. * @throws FileNotFoundException
  1354. */
  1355. public function testGetPermissionsFileDoesNotExist(): void
  1356. {
  1357. $path = $this->getMock('/foo/file.ext', 'getPermissions');
  1358. $path->method('isFile')->willReturn(False);
  1359. $this->builtin
  1360. ->expects(self::never())
  1361. ->method('fileperms');
  1362. $this->expectException(FileNotFoundException::class);
  1363. $path->getPermissions();
  1364. }
  1365. /**
  1366. * @throws IOException
  1367. * @throws FileNotFoundException
  1368. */
  1369. public function testGetPermissionsWithError(): void
  1370. {
  1371. $path = $this->getMock('/foo/file.ext', 'getPermissions');
  1372. $path->method('isFile')->willReturn(True);
  1373. $this->builtin
  1374. ->method('fileperms')
  1375. ->with('/foo/file.ext')
  1376. ->willReturn(False);
  1377. $this->expectException(IOException::class);
  1378. $path->getPermissions();
  1379. }
  1380. /**
  1381. * @throws FileNotFoundException|IOException
  1382. */
  1383. public function testSetPermissions(): void
  1384. {
  1385. $path = $this->getMock('/foo/file.ext', 'setPermissions');
  1386. $path->method('isFile')->willReturn(True);
  1387. $this->builtin
  1388. ->method('chmod')
  1389. ->with('/foo/file.ext', 0777)
  1390. ->willReturn(True);
  1391. $this->builtin
  1392. ->expects(self::once())
  1393. ->method('clearstatcache');
  1394. $path->setPermissions(0777);
  1395. }
  1396. /**
  1397. * @throws FileNotFoundException|IOException
  1398. */
  1399. public function testSetPermissionsFileDoesNotExist(): void
  1400. {
  1401. $path = $this->getMock('/foo/file.ext', 'setPermissions');
  1402. $path->method('isFile')->willReturn(False);
  1403. $this->builtin
  1404. ->expects(self::never())
  1405. ->method('clearstatcache');
  1406. $this->builtin
  1407. ->expects(self::never())
  1408. ->method('chmod');
  1409. $this->expectException(FileNotFoundException::class);
  1410. $path->setPermissions(0777);
  1411. }
  1412. /**
  1413. * @throws FileNotFoundException
  1414. */
  1415. public function testSetPermissionsWithError(): void
  1416. {
  1417. $path = $this->getMock('/foo/file.ext', 'setPermissions');
  1418. $path->method('isFile')->willReturn(True);
  1419. $this->builtin
  1420. ->expects(self::once())
  1421. ->method('clearstatcache');
  1422. $this->builtin
  1423. ->method('chmod')
  1424. ->with('/foo/file.ext', 0777)
  1425. ->willReturn(False);
  1426. $this->expectException(IOException::class);
  1427. $path->setPermissions(0777);
  1428. }
  1429. /**
  1430. * @throws FileNotFoundException
  1431. * @throws IOException
  1432. */
  1433. public function testSetOwner(): void
  1434. {
  1435. $path = $this->getMock('/foo/file.ext', 'setOwner');
  1436. $path->method('isFile')->willReturn(True);
  1437. $this->builtin
  1438. ->expects(self::once())
  1439. ->method('clearstatcache');
  1440. $this->builtin
  1441. ->method('chown')
  1442. ->with('/foo/file.ext', 'user')
  1443. ->willReturn(True);
  1444. $this->builtin
  1445. ->method('chgrp')
  1446. ->with('/foo/file.ext', 'group')
  1447. ->willReturn(True);
  1448. $path->setOwner('user', 'group');
  1449. }
  1450. /**
  1451. * @throws FileNotFoundException|IOException
  1452. */
  1453. public function testSetOwnerFileDoesNotExist(): void
  1454. {
  1455. $path = $this->getMock('/foo/file.ext', 'setOwner');
  1456. $path->method('isFile')->willReturn(False);
  1457. $this->builtin
  1458. ->expects(self::never())
  1459. ->method('clearstatcache');
  1460. $this->builtin
  1461. ->expects(self::never())
  1462. ->method('chown');
  1463. $this->builtin
  1464. ->expects(self::never())
  1465. ->method('chgrp');
  1466. $this->expectException(FileNotFoundException::class);
  1467. $path->setOwner('user', 'group');
  1468. }
  1469. /**
  1470. * @throws FileNotFoundException
  1471. */
  1472. public function testSetPermissionsWithChownError(): void
  1473. {
  1474. $path = $this->getMock('/foo/file.ext', 'setOwner');
  1475. $path->method('isFile')->willReturn(True);
  1476. $this->builtin
  1477. ->expects(self::once())
  1478. ->method('clearstatcache');
  1479. $this->builtin
  1480. ->method('chown')
  1481. ->with('/foo/file.ext', 'user')
  1482. ->willReturn(False);
  1483. $this->builtin
  1484. ->method('chgrp')
  1485. ->with('/foo/file.ext', 'group')
  1486. ->willReturn(True);
  1487. $this->expectException(IOException::class);
  1488. $path->setOwner('user', 'group');
  1489. }
  1490. /**
  1491. * @throws FileNotFoundException
  1492. */
  1493. public function testSetPermissionsWithChGroupError(): void
  1494. {
  1495. $path = $this->getMock('/foo/file.ext', 'setOwner');
  1496. $path->method('isFile')->willReturn(True);
  1497. $this->builtin
  1498. ->method('chown')
  1499. ->with('/foo/file.ext', 'user')
  1500. ->willReturn(True);
  1501. $this->builtin
  1502. ->method('chgrp')
  1503. ->with('/foo/file.ext', 'group')
  1504. ->willReturn(False);
  1505. $this->expectException(IOException::class);
  1506. $path->setOwner('user', 'group');
  1507. }
  1508. public function testExists(): void
  1509. {
  1510. $path = $this->getMock('/foo/file.ext', 'exists');
  1511. $this->builtin
  1512. ->expects(self::once())
  1513. ->method('file_exists')
  1514. ->with('/foo/file.ext')
  1515. ->willReturn(True);
  1516. $this->assertTrue(
  1517. $path->exists()
  1518. );
  1519. }
  1520. /**
  1521. * @throws IOException
  1522. * @throws FileNotFoundException
  1523. */
  1524. public function testGlob(): void {
  1525. $path = $this->getMock('/foo', 'glob');
  1526. $path->method('isDir')->willReturn(True);
  1527. $this->builtin
  1528. ->expects(self::once())
  1529. ->method('glob')
  1530. ->with('/foo/*')
  1531. ->willReturn(['a', 'b', 'c']);
  1532. $this->assertEquals(
  1533. ['a', 'b', 'c'],
  1534. array_map(
  1535. function (Path $p) { return (string)$p; },
  1536. $path->glob('*')
  1537. )
  1538. );
  1539. }
  1540. /**
  1541. * @throws IOException
  1542. */
  1543. public function testGlobDirDoesNotExist(): void {
  1544. $path = $this->getMock('/foo', 'glob');
  1545. $path->method('isDir')->willReturn(False);
  1546. $this->builtin
  1547. ->expects(self::never())
  1548. ->method('glob');
  1549. $this->expectException(FileNotFoundException::class);
  1550. $path->glob('*');
  1551. }
  1552. /**
  1553. * @throws FileNotFoundException
  1554. */
  1555. public function testGlobWithError(): void {
  1556. $path = $this->getMock('/foo', 'glob');
  1557. $path->method('isDir')->willReturn(True);
  1558. $this->builtin
  1559. ->expects(self::once())
  1560. ->method('glob')
  1561. ->with('/foo/*')
  1562. ->willReturn(False);
  1563. $this->expectException(IOException::class);
  1564. $path->glob('*');
  1565. }
  1566. /**
  1567. * @throws FileNotFoundException
  1568. * @throws IOException
  1569. */
  1570. public function testRmDirNonRecursive(): void
  1571. {
  1572. $path = $this->getMock('/foo', 'rmdir');
  1573. $path->method('isDir')->willReturn(True);
  1574. $this->builtin
  1575. ->method('rmdir')
  1576. ->with('/foo')
  1577. ->willReturn(True);
  1578. $path
  1579. ->expects(self::never())
  1580. ->method('rrmdir');
  1581. $path->rmdir();
  1582. }
  1583. /**
  1584. * @throws FileNotFoundException
  1585. * @throws IOException
  1586. */
  1587. public function testRmDirRecursive(): void
  1588. {
  1589. $path = $this->getMock('/foo', 'rmdir');
  1590. $path->method('isDir')->willReturn(True);
  1591. $this->builtin
  1592. ->expects(self::never())
  1593. ->method('rmdir');
  1594. $path
  1595. ->method('rrmdir')
  1596. ->willReturn(True);
  1597. $path->rmdir(True);
  1598. }
  1599. /**
  1600. * @throws IOException
  1601. * @throws FileNotFoundException
  1602. */
  1603. public function testOpen(): void
  1604. {
  1605. $path = $this->getMock('/foo/file.ext', 'open');
  1606. $path->method('isFile')->willReturn(True);
  1607. $this->builtin
  1608. ->expects(self::once())
  1609. ->method('fopen')
  1610. ->with('/foo/file.ext', 'r')
  1611. ->willReturn('the_handle');
  1612. $this->assertEquals(
  1613. 'the_handle',
  1614. $path->open()
  1615. );
  1616. }
  1617. /**
  1618. * @throws IOException
  1619. * @throws FileNotFoundException
  1620. */
  1621. public function testOpenWithMode(): void
  1622. {
  1623. $path = $this->getMock('/foo/file.ext', 'open');
  1624. $path->method('isFile')->willReturn(True);
  1625. $this->builtin
  1626. ->expects(self::once())
  1627. ->method('fopen')
  1628. ->with('/foo/file.ext', 'w')
  1629. ->willReturn('the_handle');
  1630. $this->assertEquals(
  1631. 'the_handle',
  1632. $path->open('w')
  1633. );
  1634. }
  1635. /**
  1636. * @throws IOException
  1637. * @throws FileNotFoundException
  1638. */
  1639. public function testOpenFileDoesNotExist(): void
  1640. {
  1641. $path = $this->getMock('/foo/file.ext', 'open');
  1642. $path->method('isFile')->willReturn(False);
  1643. $this->builtin
  1644. ->expects(self::never())
  1645. ->method('fopen');
  1646. $this->expectException(FileNotFoundException::class);
  1647. $path->open();
  1648. }
  1649. /**
  1650. * @throws IOException
  1651. * @throws FileNotFoundException
  1652. */
  1653. public function testOpenWithError(): void
  1654. {
  1655. $path = $this->getMock('/foo/file.ext', 'open');
  1656. $path->method('isFile')->willReturn(True);
  1657. $this->builtin
  1658. ->expects(self::once())
  1659. ->method('fopen')
  1660. ->with('/foo/file.ext', 'r')
  1661. ->willReturn(False);
  1662. $this->expectException(IOException::class);
  1663. $path->open();
  1664. }
  1665. /**
  1666. * @throws \Throwable
  1667. */
  1668. public function testWith(): void
  1669. {
  1670. $path = $this->getMock('/foo/file.ext', 'with');
  1671. $path->method('open')->with('r')->willReturn('the_handle');
  1672. $callback = function ($handle) {
  1673. $this->assertEquals('the_handle', $handle);
  1674. return 'content';
  1675. };
  1676. $this->builtin
  1677. ->expects(self::once())
  1678. ->method('fclose')
  1679. ->with('the_handle')
  1680. ->willReturn(True);
  1681. $this->assertEquals(
  1682. 'content',
  1683. $path->with($callback)
  1684. );
  1685. }
  1686. /**
  1687. * @throws \Throwable
  1688. */
  1689. public function testWithWithMode(): void
  1690. {
  1691. $path = $this->getMock('/foo/file.ext', 'with');
  1692. $path->method('open')->with('w+')->willReturn('the_handle');
  1693. $callback = function ($handle) {
  1694. $this->assertEquals('the_handle', $handle);
  1695. return 'content';
  1696. };
  1697. $this->builtin
  1698. ->expects(self::once())
  1699. ->method('fclose')
  1700. ->with('the_handle')
  1701. ->willReturn(True);
  1702. $this->assertEquals(
  1703. 'content',
  1704. $path->with($callback, 'w+')
  1705. );
  1706. }
  1707. /**
  1708. * @throws \Throwable
  1709. */
  1710. public function testWithWithCallbackError(): void
  1711. {
  1712. $path = $this->getMock('/foo/file.ext', 'with');
  1713. $path->method('open')->with('w+')->willReturn('the_handle');
  1714. $callback = function ($handle) {
  1715. $this->assertEquals('the_handle', $handle);
  1716. throw new \Exception('some_error');
  1717. };
  1718. $this->builtin
  1719. ->expects(self::once())
  1720. ->method('fclose')
  1721. ->with('the_handle')
  1722. ->willReturn(True);
  1723. $this->expectException(\Exception::class);
  1724. $path->with($callback, 'w+');
  1725. }
  1726. /**
  1727. * @throws \Throwable
  1728. */
  1729. public function testWithWithCallbackErrorAndClosingError(): void
  1730. {
  1731. $path = $this->getMock('/foo/file.ext', 'with');
  1732. $path->method('open')->with('w+')->willReturn('the_handle');
  1733. $callback = function ($handle) {
  1734. $this->assertEquals('the_handle', $handle);
  1735. throw new \Exception('some_error');
  1736. };
  1737. $this->builtin
  1738. ->expects(self::once())
  1739. ->method('fclose')
  1740. ->with('the_handle')
  1741. ->willReturn(False);
  1742. $this->expectException(\Exception::class);
  1743. $this->expectException(IOException::class);
  1744. $path->with($callback, 'w+');
  1745. }
  1746. /**
  1747. * @throws IOException
  1748. * @throws FileNotFoundException
  1749. * @throws \Throwable
  1750. */
  1751. public function testChunks(): void
  1752. {
  1753. $path = $this->getMock('/foo/file.ext', 'chunks');
  1754. $path->method('open')->with('rb')->willReturn('the_handle');
  1755. $this->builtin
  1756. ->method('feof')
  1757. ->with('the_handle')
  1758. ->willReturnOnConsecutiveCalls(
  1759. False,
  1760. False,
  1761. False,
  1762. True
  1763. );
  1764. $this->builtin
  1765. ->method('fread')
  1766. ->with('the_handle', 8192)
  1767. ->willReturnOnConsecutiveCalls(
  1768. 'abc',
  1769. 'def',
  1770. 'ghi'
  1771. );
  1772. $this->builtin
  1773. ->expects(self::once())
  1774. ->method('fclose')
  1775. ->with('the_handle')
  1776. ->willReturn(True);
  1777. $this->assertEquals(
  1778. ['abc', 'def', 'ghi'],
  1779. iterator_to_array($path->chunks())
  1780. );
  1781. }
  1782. /**
  1783. * @throws IOException
  1784. * @throws FileNotFoundException
  1785. * @throws \Throwable
  1786. */
  1787. public function testChunksWithDifferentLength(): void
  1788. {
  1789. $path = $this->getMock('/foo/file.ext', 'chunks');
  1790. $path->method('open')->with('rb')->willReturn('the_handle');
  1791. $this->builtin
  1792. ->method('feof')
  1793. ->with('the_handle')
  1794. ->willReturnOnConsecutiveCalls(
  1795. False,
  1796. False,
  1797. False,
  1798. True
  1799. );
  1800. $this->builtin
  1801. ->method('fread')
  1802. ->with('the_handle', 123)
  1803. ->willReturnOnConsecutiveCalls(
  1804. 'abc',
  1805. 'def',
  1806. 'ghi'
  1807. );
  1808. $this->builtin
  1809. ->expects(self::once())
  1810. ->method('fclose')
  1811. ->with('the_handle')
  1812. ->willReturn(True);
  1813. $this->assertEquals(
  1814. ['abc', 'def', 'ghi'],
  1815. iterator_to_array($path->chunks(123))
  1816. );
  1817. }
  1818. /**
  1819. * @throws \Throwable
  1820. */
  1821. public function testChunksWithClosingError(): void
  1822. {
  1823. $path = $this->getMock('/foo/file.ext', 'chunks');
  1824. $path->method('open')->with('rb')->willReturn('the_handle');
  1825. $this->builtin
  1826. ->method('feof')
  1827. ->with('the_handle')
  1828. ->willReturnOnConsecutiveCalls(
  1829. False,
  1830. False,
  1831. False,
  1832. True
  1833. );
  1834. $this->builtin
  1835. ->method('fread')
  1836. ->with('the_handle', 8192)
  1837. ->willReturnOnConsecutiveCalls(
  1838. 'abc',
  1839. 'def',
  1840. 'ghi'
  1841. );
  1842. $this->builtin
  1843. ->expects(self::once())
  1844. ->method('fclose')
  1845. ->with('the_handle')
  1846. ->willReturn(False);
  1847. $this->expectException(IOException::class);
  1848. iterator_to_array($path->chunks());
  1849. }
  1850. public function testIsAbs(): void
  1851. {
  1852. $path = $this->getMock('/foo/file.ext', 'isAbs');
  1853. $this->assertTrue(
  1854. $path->isAbs()
  1855. );
  1856. }
  1857. public function testIsAbsWithRelative(): void
  1858. {
  1859. $path = $this->getMock('foo/file.ext', 'isAbs');
  1860. $this->assertFalse(
  1861. $path->isAbs()
  1862. );
  1863. }
  1864. /**
  1865. * @throws IOException
  1866. * @throws FileNotFoundException
  1867. */
  1868. public function testChmod(): void
  1869. {
  1870. $path = $this->getMock('foo/file.ext', 'chmod');
  1871. $path
  1872. ->expects(self::once())
  1873. ->method('setPermissions')
  1874. ->with('777');
  1875. $path->chmod(777);
  1876. }
  1877. /**
  1878. * @throws IOException
  1879. * @throws FileNotFoundException
  1880. */
  1881. public function testChown(): void
  1882. {
  1883. $path = $this->getMock('foo/file.ext', 'chown');
  1884. $path
  1885. ->expects(self::once())
  1886. ->method('setOwner')
  1887. ->with('user', 'group');
  1888. $path->chown('user', 'group');
  1889. }
  1890. /**
  1891. * @throws IOException
  1892. */
  1893. public function testChRoot(): void
  1894. {
  1895. $path = $this->getMock('/foo', 'chroot');
  1896. $this->builtin
  1897. ->expects(self::once())
  1898. ->method('chroot')
  1899. ->with('/foo')
  1900. ->willReturn(True);
  1901. $path->chroot();
  1902. }
  1903. /**
  1904. * @throws IOException
  1905. */
  1906. public function testChRootWithError(): void
  1907. {
  1908. $path = $this->getMock('/foo', 'chroot');
  1909. $this->builtin
  1910. ->expects(self::once())
  1911. ->method('chroot')
  1912. ->with('/foo')
  1913. ->willReturn(False);
  1914. $this->expectException(IOException::class);
  1915. $path->chroot();
  1916. }
  1917. public function testIsLink(): void
  1918. {
  1919. $path = $this->getMock('/foo/file.ext', 'isLink');
  1920. $this->builtin
  1921. ->expects(self::once())
  1922. ->method('is_link')
  1923. ->with('/foo/file.ext')
  1924. ->willReturn(True);
  1925. $this->assertTrue(
  1926. $path->isLink()
  1927. );
  1928. }
  1929. public function testIsLinkIsNot(): void
  1930. {
  1931. $path = $this->getMock('/foo/file.ext', 'isLink');
  1932. $this->builtin
  1933. ->expects(self::once())
  1934. ->method('is_link')
  1935. ->with('/foo/file.ext')
  1936. ->willReturn(False);
  1937. $this->assertFalse(
  1938. $path->isLink()
  1939. );
  1940. }
  1941. /**
  1942. * @throws FileNotFoundException
  1943. */
  1944. public function testIterDir(): void
  1945. {
  1946. $path = $this->getMock('/foo', 'iterDir');
  1947. $path->method('isDir')->willReturn(True);
  1948. $fileInfo1 = $this->getMockBuilder(\DirectoryIterator::class)->disableOriginalConstructor()->getMock();
  1949. $fileInfo1->expects(self::once())->method('isDot')->willReturn(True);
  1950. $fileInfo1->expects(self::never())->method('getFilename');
  1951. $fileInfo2 = $this->getMockBuilder(\DirectoryIterator::class)->disableOriginalConstructor()->getMock();
  1952. $fileInfo2->expects(self::once())->method('isDot')->willReturn(False);
  1953. $fileInfo2->expects(self::once())->method('getFilename')->willReturn('file1.ext');
  1954. $fileInfo3 = $this->getMockBuilder(\DirectoryIterator::class)->disableOriginalConstructor()->getMock();
  1955. $fileInfo3->expects(self::once())->method('isDot')->willReturn(False);
  1956. $fileInfo3->expects(self::once())->method('getFilename')->willReturn('file2.ext');
  1957. $result = [$fileInfo1, $fileInfo2, $fileInfo3];
  1958. $directoryIterator = $this->getMockBuilder(\DirectoryIterator::class)->disableOriginalConstructor()->getMock();
  1959. $directoryIterator->method('current')->willReturnCallback(function () use (&$result) {
  1960. return current($result);
  1961. });
  1962. $directoryIterator->method('key')->willReturnCallback(function () use (&$result) {
  1963. return key($result);
  1964. });
  1965. $directoryIterator->method('next')->willReturnCallback(function () use (&$result) {
  1966. return next($result);
  1967. });
  1968. $directoryIterator->method('valid')->willReturnCallback(function () use (&$result) {
  1969. $key = key($result);
  1970. return ($key !== NULL);
  1971. });
  1972. $path
  1973. ->method('getDirectoryIterator')
  1974. ->willReturn($directoryIterator);
  1975. $this->assertEquals(
  1976. ['file1.ext', 'file2.ext'],
  1977. iterator_to_array($path->iterDir())
  1978. );
  1979. }
  1980. /**
  1981. * @throws FileNotFoundException
  1982. */
  1983. public function testIterDirDirDoesNotExist(): void
  1984. {
  1985. $path = $this->getMock('/foo', 'iterDir');
  1986. $path->method('isDir')->willReturn(False);
  1987. $this->expectException(FileNotFoundException::class);
  1988. iterator_to_array($path->iterDir());
  1989. }
  1990. /**
  1991. * @throws IOException
  1992. * @throws FileNotFoundException
  1993. * @throws FileExistsException
  1994. */
  1995. public function testLink(): void
  1996. {
  1997. $path = $this->getMock('/foo/file.ext', 'link');
  1998. $path->method('isFile')->willReturn(True);
  1999. $target = $this
  2000. ->getMockBuilder(TestablePath::class)
  2001. ->disableOriginalConstructor()
  2002. ->getMock();
  2003. $target->method('isFile')->willReturn(False);
  2004. $target->method('__toString')->willReturn('/bar/link.ext');
  2005. $this->builtin
  2006. ->expects(self::once())
  2007. ->method('link')
  2008. ->with('/foo/file.ext', '/bar/link.ext')
  2009. ->willReturn(True);
  2010. $path->link($target);
  2011. }
  2012. }