submissionRepository = new InMemoryHomeworkSubmissionRepository(); $this->tempFile = tempnam(sys_get_temp_dir(), 'e2e_upload_'); file_put_contents($this->tempFile, 'fake PDF content'); } protected function tearDown(): void { if (file_exists($this->tempFile)) { unlink($this->tempFile); } } #[Test] public function itUploadsAttachmentForDraftSubmission(): void { $submission = $this->createDraftSubmission(); $this->submissionRepository->save($submission); $handler = $this->createHandler(); $command = new UploadSubmissionAttachmentCommand( tenantId: self::TENANT_ID, submissionId: (string) $submission->id, filename: 'devoir.pdf', mimeType: 'application/pdf', fileSize: 1024, tempFilePath: $this->tempFile, ); $attachment = $handler($command); self::assertSame('devoir.pdf', $attachment->filename); self::assertSame('application/pdf', $attachment->mimeType); self::assertSame(1024, $attachment->fileSize); self::assertStringContainsString('submissions/', $attachment->filePath); } #[Test] public function itRejectsUploadOnSubmittedSubmission(): void { $submission = $this->createDraftSubmission(); $submission->soumettre( dueDate: new DateTimeImmutable('2026-04-15'), now: new DateTimeImmutable('2026-03-24 11:00:00'), ); $this->submissionRepository->save($submission); $handler = $this->createHandler(); $command = new UploadSubmissionAttachmentCommand( tenantId: self::TENANT_ID, submissionId: (string) $submission->id, filename: 'devoir.pdf', mimeType: 'application/pdf', fileSize: 1024, tempFilePath: $this->tempFile, ); $this->expectException(RenduDejaSoumisException::class); $handler($command); } private function createDraftSubmission(): HomeworkSubmission { return HomeworkSubmission::creerBrouillon( tenantId: TenantId::fromString(self::TENANT_ID), homeworkId: HomeworkId::fromString(self::HOMEWORK_ID), studentId: UserId::fromString(self::STUDENT_ID), responseHtml: '
Ma réponse
', now: new DateTimeImmutable('2026-03-24 10:00:00'), ); } private function createHandler(): UploadSubmissionAttachmentHandler { $fileStorage = new class implements FileStorage { public function upload(string $path, mixed $content, string $mimeType): string { return $path; } public function delete(string $path): void { } public function readStream(string $path): mixed { /** @var resource $stream */ $stream = fopen('php://memory', 'r+'); return $stream; } }; $clock = new class implements Clock { public function now(): DateTimeImmutable { return new DateTimeImmutable('2026-03-24 10:00:00'); } }; return new UploadSubmissionAttachmentHandler( $this->submissionRepository, $fileStorage, $clock, ); } }