diff --git a/CHANGELOG.md b/CHANGELOG.md index b14232c..db4bc33 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [0.13.0] - 2026-04-05 + ### Added +- Added test helper methods in `RequestConverterTest` for temp file cleanup and request creation ([#88](https://github.com/crazy-goat/workerman-bundle/issues/88)) + - Added `tearDown()` for automatic temp file cleanup + - Added `createTempFile()` helper method + - Added `createRequestWithFiles()` helper method + - Reduces test boilerplate and improves readability + - Added `QUERY_STRING` to server bag in `RequestConverter` ([#66](https://github.com/crazy-goat/workerman-bundle/issues/66)) - Enables `$request->server->get('QUERY_STRING')` to return query string - Enables Symfony's `getQueryString()` to work correctly diff --git a/tests/RequestConverterTest.php b/tests/RequestConverterTest.php index 04a2604..1d1b0e0 100644 --- a/tests/RequestConverterTest.php +++ b/tests/RequestConverterTest.php @@ -14,6 +14,19 @@ */ final class RequestConverterTest extends TestCase { + /** @var string[] */ + private array $tempFiles = []; + + protected function tearDown(): void + { + foreach ($this->tempFiles as $file) { + @unlink($file); + } + $this->tempFiles = []; + + parent::tearDown(); + } + public function testValidFileStructureIsAccepted(): void { $buffer = $this->createMultipartRequest( @@ -116,37 +129,17 @@ public function testMalformedFileDataThrowsException(): void $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('missing required field'); - // Create a temp file so Workerman doesn't clear our files array - $tmpFile = tempnam(sys_get_temp_dir(), 'test_'); - file_put_contents($tmpFile, 'test content'); + $tmpFile = $this->createTempFile('test content'); $buffer = "POST /test HTTP/1.1\r\nHost: localhost\r\n\r\n"; - $rawRequest = new Request($buffer); - - // Manually inject malformed file data (missing required fields) but with valid tmp_name - // so Workerman's file() method doesn't clear it - $reflection = new \ReflectionClass($rawRequest); - $dataProperty = $reflection->getProperty('data'); - $dataProperty->setValue($rawRequest, [ - 'files' => [ - 'malformed_file' => [ - 'name' => 'test.txt', - 'tmp_name' => $tmpFile, - // Missing 'type', 'size', 'error' - should trigger validation error - ], + $rawRequest = $this->createRequestWithFiles($buffer, [ + 'malformed_file' => [ + 'name' => 'test.txt', + 'tmp_name' => $tmpFile, ], ]); - try { - // This should throw InvalidArgumentException - RequestConverter::toSymfonyRequest($rawRequest); - // If we get here, delete the file - unlink($tmpFile); - } catch (InvalidArgumentException $e) { - // Exception thrown as expected, clean up - unlink($tmpFile); - throw $e; - } + RequestConverter::toSymfonyRequest($rawRequest); } public function testHeadersAreAvailableInServerBag(): void @@ -425,4 +418,34 @@ private function createMultipartRequest(string $boundary, array $fields): string return $buffer . $body; } + + private function createTempFile(string $content = 'test'): string + { + $tmpFile = tempnam(sys_get_temp_dir(), 'test_'); + if ($tmpFile === false) { + throw new \RuntimeException('Failed to create temp file'); + } + if (file_put_contents($tmpFile, $content) === false) { + throw new \RuntimeException('Failed to write to temp file'); + } + $this->tempFiles[] = $tmpFile; + + return $tmpFile; + } + + /** + * @param array> $files + */ + private function createRequestWithFiles(string $buffer, array $files): Request + { + $rawRequest = new Request($buffer); + + // Workerman's Request does not expose a public API for file injection. + // Reflection is required to simulate malformed file uploads for testing. + $reflection = new \ReflectionClass($rawRequest); + $dataProperty = $reflection->getProperty('data'); + $dataProperty->setValue($rawRequest, ['files' => $files]); + + return $rawRequest; + } }