tempRoot = sys_get_temp_dir() . '/ironkanban-test-' . bin2hex(random_bytes(4)); mkdir($this->tempRoot, 0775, true); mkdir($this->tempRoot . '/sample-project', 0775, true); mkdir($this->tempRoot . '/sample-project/tasks', 0775, true); } protected function tearDown(): void { $this->deleteDirectory($this->tempRoot); parent::tearDown(); } public function testCreateWritesTaskFileAndCanReadItBack(): void { $repo = $this->makeRepository(); $task = $repo->create([ 'projectId' => 'sample-project', 'title' => 'Build parser', 'body' => "Task body", 'column' => 'doing', 'priority' => 'high', ]); $this->assertSame('Build parser', $task->title); $this->assertSame('doing', $task->column); $this->assertSame('high', $task->priority); $this->assertFileExists($this->tempRoot . '/sample-project/tasks/' . $task->fileName); $loaded = $repo->get('sample-project', $task->id); $this->assertSame($task->id, $loaded->id); $this->assertSame('Build parser', $loaded->title); $this->assertSame('Task body', $loaded->body); $this->assertSame($task->fileName, $loaded->fileName); } public function testPreservesLegacyFilenameWhenReadingAndSaving(): void { $contents = <<tempRoot . '/sample-project/tasks/task-legacy-import.md'; file_put_contents($legacyPath, $contents); $repo = $this->makeRepository(); $task = $repo->get('sample-project', 'custom-task-id'); $this->assertSame('task-legacy-import.md', $task->fileName); $this->assertSame('back-burner', $task->column); $this->assertSame('keep-me', $task->meta['legacy_key']); $task->title = 'Legacy Task Updated'; $repo->save($task); $this->assertFileExists($legacyPath); $this->assertStringContainsString('Legacy Task Updated', (string) file_get_contents($legacyPath)); $this->assertStringContainsString('legacy_key: keep-me', (string) file_get_contents($legacyPath)); } public function testDeleteRemovesUnderlyingFile(): void { $repo = $this->makeRepository(); $task = $repo->create([ 'projectId' => 'sample-project', 'title' => 'Delete me', ]); $filePath = $this->tempRoot . '/sample-project/tasks/' . $task->fileName; $this->assertFileExists($filePath); $repo->delete('sample-project', $task->id); $this->assertFileDoesNotExist($filePath); } private function makeRepository(): TaskRepository { return new TaskRepository( new Paths($this->tempRoot), new FrontMatterParser(), new TaskMapper(), new IdGenerator() ); } private function deleteDirectory(string $path): void { if (!is_dir($path)) { return; } $items = scandir($path); if ($items === false) { return; } foreach ($items as $item) { if ($item === '.' || $item === '..') { continue; } $itemPath = $path . DIRECTORY_SEPARATOR . $item; if (is_dir($itemPath) && !is_link($itemPath)) { $this->deleteDirectory($itemPath); continue; } @unlink($itemPath); } @rmdir($path); } } // phpcs:enable