root = dirname(__DIR__, 3) . '/.phpunit.cache/fs-' . bin2hex(random_bytes(6)); mkdir($this->root, 0777, true); self::assertTrue(class_exists(LocalFilesystem::class), 'LocalFilesystem must exist'); } protected function tearDown(): void { foreach (glob($this->root . '/*') as $path) { if (is_link($path) || is_file($path)) { unlink($path); } else { if (is_dir($path . '/nested')) { rmdir($path . '/nested'); } rmdir($path); } } rmdir($this->root); } public function testNativeMetadataAndStreamOperations(): void { $fs = new LocalFilesystem(); self::assertInstanceOf(FilesystemInterface::class, $fs); $path = $this->root . '/sample.txt'; $stream = $fs->writeStream($path); self::assertIsResource($stream); try { self::assertSame(12, fwrite($stream, "hello world\n")); } finally { fclose($stream); } self::assertSame(realpath($path), $fs->realpath($path)); self::assertTrue($fs->isReadable($path)); self::assertTrue($fs->isFile($path)); self::assertFalse($fs->isDir($path)); self::assertFalse($fs->isSymlink($path)); self::assertTrue($fs->isDir($this->root)); self::assertSame(12, $fs->getSize($path)); self::assertSame('text/plain', $fs->getMimeType($path)); self::assertGreaterThan(0, $fs->freeSpace($this->root)); $stream = $fs->readStream($path); self::assertIsResource($stream); try { self::assertSame("hello world\n", stream_get_contents($stream)); } finally { fclose($stream); } self::assertTrue($fs->rename($path, $this->root . '/renamed.txt')); self::assertFalse($fs->isFile($path)); self::assertTrue($fs->unlink($this->root . '/renamed.txt')); self::assertTrue($fs->mkdir($this->root . '/directory/nested', 0777, true)); self::assertTrue($fs->isDir($this->root . '/directory/nested')); } public function testDirectoryEntriesExcludeDotsAndFailuresReturnFalse(): void { $fs = new LocalFilesystem(); self::assertSame([], $fs->readDirectory($this->root)); file_put_contents($this->root . '/file.txt', 'text'); mkdir($this->root . '/nested'); self::assertSame(['file.txt', 'nested'], $fs->readDirectory($this->root)); self::assertFalse($fs->readDirectory($this->root . '/missing')); self::assertFalse($fs->readDirectory($this->root . '/file.txt')); } public function testFailuresReturnFalseWithoutWarnings(): void { $fs = new LocalFilesystem(); $missing = $this->root . '/absent/file'; foreach ( ['realpath', 'isReadable', 'isFile', 'isDir', 'isSymlink', 'getSize', 'getMimeType', 'readStream', 'writeStream', 'unlink', 'freeSpace'] as $operation ) { self::assertFalse($fs->$operation($missing), $operation); } self::assertFalse($fs->rename($missing, $this->root . '/other')); self::assertFalse($fs->mkdir($missing)); self::assertFalse($fs->mkdir($this->root)); } public function testSymlinkMetadataIncludesDanglingLinks(): void { $link = $this->root . '/link'; if (!function_exists('symlink') || !@symlink($this->root . '/absent', $link)) { self::markTestSkipped('Creating symlinks is not supported or permitted on this host.'); } $fs = new LocalFilesystem(); self::assertTrue($fs->isSymlink($link)); self::assertFalse($fs->realpath($link)); self::assertTrue($fs->unlink($link)); self::assertFalse($fs->isSymlink($link)); } }