tmpDir = sys_get_temp_dir() . '/bf-uploads-' . bin2hex(random_bytes(4)); mkdir($this->tmpDir, 0700, true); } protected function tearDown(): void { if (is_dir($this->tmpDir)) { foreach (glob($this->tmpDir . '/*/*') as $file) { unlink($file); } foreach (glob($this->tmpDir . '/*') as $dir) { rmdir($dir); } rmdir($this->tmpDir); } } public function testItStoresAValidImageAndReturnsAStableUrl(): void { $service = new ImageUploadService('user-token-1', $this->tmpDir); $tmp = tempnam(sys_get_temp_dir(), 'bf-up'); file_put_contents($tmp, self::validPng(8, 8)); $url = $service->store($tmp, 'image/png'); self::assertStringStartsWith('/assets/uploads/user-token-1/', $url); self::assertStringEndsWith('.png', $url); $stored = $this->tmpDir . '/user-token-1/' . basename($url); self::assertFileExists($stored); } public function testItCreatesTheUserNamespaceDirectory(): void { $service = new ImageUploadService('fresh-user', $this->tmpDir); $tmp = tempnam(sys_get_temp_dir(), 'bf-up'); file_put_contents($tmp, self::validPng(8, 8)); $service->store($tmp, 'image/png'); self::assertDirectoryExists($this->tmpDir . '/fresh-user'); } public function testItProducesUniqueFilenamesForRepeatedUploads(): void { $service = new ImageUploadService('user-token-2', $this->tmpDir); $tmp1 = tempnam(sys_get_temp_dir(), 'bf-up'); $tmp2 = tempnam(sys_get_temp_dir(), 'bf-up'); file_put_contents($tmp1, self::validPng(8, 8)); file_put_contents($tmp2, self::validPng(8, 8)); $url1 = $service->store($tmp1, 'image/png'); $url2 = $service->store($tmp2, 'image/png'); self::assertNotSame($url1, $url2); } public function testItRejectsAnInvalidImage(): void { $service = new ImageUploadService('user-token-3', $this->tmpDir); $tmp = tempnam(sys_get_temp_dir(), 'bf-up'); file_put_contents($tmp, 'not an image'); $this->expectException(\BattleForge\Application\InvalidImageException::class); $service->store($tmp, 'image/png'); } private static function validPng(int $width, int $height): string { if ($width === 8 && $height === 8) { return base64_decode( 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAFElEQVR4nGNgYGD4z0AswK' . 'EWBgYGRgYGBkYGRgAAB4nCH2AAAAAElFTkSuQmCC', true, ); } throw new \InvalidArgumentException('Only 8x8 base PNG supported in tests.'); } }