assertSame('local', $config->driver); } public function testInvalidDriverFallsBackToLocal(): void { $previous = getenv('FILE_STORAGE_DRIVER'); putenv('FILE_STORAGE_DRIVER=invalid'); try { $config = new Storage(); $this->assertSame('local', $config->driver); } finally { if ($previous === false) { putenv('FILE_STORAGE_DRIVER'); } else { putenv('FILE_STORAGE_DRIVER=' . $previous); } } } public function testRetainLocalParsesBooleanEnv(): void { $previous = getenv('RETAIN_LOCAL'); putenv('RETAIN_LOCAL=true'); try { $config = new Storage(); $this->assertTrue($config->retainLocal); } finally { if ($previous === false) { putenv('RETAIN_LOCAL'); } else { putenv('RETAIN_LOCAL=' . $previous); } } } public function testS3DriverRequiresCredentials(): void { $config = new Storage(); $config->driver = 's3'; $config->s3Bucket = ''; $config->s3AccessKey = ''; $config->s3SecretKey = ''; $this->expectException(FileStorageException::class); $this->expectExceptionMessage('S3 storage is not configured'); new S3StorageDriver($config); } public function testFileStorageServiceReportsDriverMode(): void { $this->assertFalse(storage()->isS3()); $this->storageConfig->driver = 's3'; $this->storageConfig->s3Bucket = 'test-bucket'; $this->storageConfig->s3AccessKey = 'key'; $this->storageConfig->s3SecretKey = 'secret'; \Config\Services::injectMock('fileStorage', new \App\Services\FileStorageService($this->storageConfig)); $this->assertTrue(storage()->isS3()); } } /** * @internal */ final class LocalStorageDriverTest extends StorageTestCase { private LocalStorageDriver $driver; protected function setUp(): void { parent::setUp(); $this->driver = new LocalStorageDriver($this->storageConfig); } public function testUploadFromUploadedFileStoresUnderLocalRoot(): void { $file = $this->createUploadedFile('%PDF-1.4 policy', 'policy.pdf', 'application/pdf'); $key = 'uploads/policy/policy_pdf/test_policy.pdf'; $this->driver->upload($file, $key); $this->assertFileExists($this->localFilePath($key)); $this->assertSame('%PDF-1.4 policy', file_get_contents($this->localFilePath($key))); } public function testUploadFromLocalPathCopiesFile(): void { $source = tempnam(sys_get_temp_dir(), 'src_'); file_put_contents($source, 'receipt bytes'); $key = 'uploads/policy/policy_payment_receipt/receipt.pdf'; $this->driver->upload($source, $key); $this->assertFileExists($this->localFilePath($key)); $this->assertSame('receipt bytes', file_get_contents($this->localFilePath($key))); } public function testPutWriteRawContents(): void { $key = 'uploads/policy/policy_md/sample.md'; $this->driver->put($key, '# Markdown content'); $this->assertTrue($this->driver->exists($key)); $this->assertSame('# Markdown content', $this->driver->read($key)); } public function testExistsReturnsFalseForMissingFile(): void { $this->assertFalse($this->driver->exists('uploads/policy/policy_pdf/missing.pdf')); } public function testDeleteRemovesFile(): void { $key = 'uploads/endorsement/original.pdf'; $this->driver->put($key, 'endorsement'); $this->assertTrue($this->driver->delete($key)); $this->assertFalse($this->driver->exists($key)); } public function testDownloadToTempReturnsExistingLocalPath(): void { $key = 'uploads/policy/policy_pdf/read.pdf'; $this->driver->put($key, 'pdf-data'); $path = $this->driver->downloadToTemp($key); $this->assertSame($this->localFilePath($key), $path); } public function testCopyDuplicatesFile(): void { $from = 'uploads/policy/policy_pdf/source.pdf'; $to = 'uploads/policy/policy_pdf/copy.pdf'; $this->driver->put($from, 'copy-me'); $this->assertTrue($this->driver->copy($from, $to)); $this->assertSame('copy-me', $this->driver->read($to)); } public function testTemporaryUrlUsesBaseUrlForLocalDriver(): void { $key = 'uploads/policy/policy_pdf/url.pdf'; $this->driver->put($key, 'url'); $url = $this->driver->temporaryUrl($key); $this->assertStringContainsString('uploads/policy/policy_pdf/url.pdf', $url); } public function testStreamDownloadReturnsResponseWithBody(): void { $key = 'uploads/endorsement/endorsement_pdf/completion.pdf'; $this->driver->put($key, 'completion pdf'); $response = $this->driver->streamDownload($key, 'completion.pdf'); $this->assertInstanceOf(DownloadResponse::class, $response); $this->assertDownloadHeaders($response, 'attachment'); $this->assertSame(strlen('completion pdf'), $response->getContentLength()); } }