$title, 'ccli_id' => fake()->unique()->numerify('#####'), 'author' => 'Test Author', 'copyright_text' => 'Test Publisher', ]); $label = Label::firstOrCreate( ['name' => 'Verse - '.$title], ['color' => '#2196F3'], ); $section = $song->sections()->create(['label_id' => $label->id, 'order' => 0]); $section->slides()->create(['order' => 0, 'text_content' => 'Erste Zeile']); $arrangement = $song->arrangements()->create(['name' => 'normal', 'is_default' => true]); $arrangement->arrangementSections()->create(['song_section_id' => $section->id, 'order' => 0]); return $song; } private function addSongAgendaItem(Service $service, Song $song, string $title, int $sortOrder): void { $serviceSong = ServiceSong::create([ 'service_id' => $service->id, 'song_id' => $song->id, 'cts_song_name' => $song->title, 'order' => $sortOrder, ]); ServiceAgendaItem::factory()->create([ 'service_id' => $service->id, 'title' => $title, 'service_song_id' => $serviceSong->id, 'sort_order' => $sortOrder, 'is_before_event' => false, ]); } private function cleanupTempDir(string $dir): void { if (! is_dir($dir)) { return; } $items = scandir($dir); if ($items === false) { return; } foreach ($items as $item) { if ($item === '.' || $item === '..') { continue; } $path = $dir.'/'.$item; is_dir($path) ? $this->cleanupTempDir($path) : unlink($path); } rmdir($dir); } public function test_keyword_datei_wird_direkt_nach_passendem_ablaufpunkt_eingefuegt(): void { $service = Service::factory()->create([ 'title' => 'Keyword Service', 'date' => now(), ]); // Uppercase title vs lowercase keyword proves case-insensitive substring match. $this->addSongAgendaItem($service, $this->createSongWithContent('Abendmahlslied'), 'ABENDMAHL feiern', 1); $this->addSongAgendaItem($service, $this->createSongWithContent('Predigtlied'), 'Predigt', 2); $storedPath = 'export-pro-files/keyword/kommunion.pro'; Storage::disk('local')->put($storedPath, 'kommunion-pro-bytes'); ExportProFile::create([ 'type' => 'keyword', 'keyword' => 'abendmahl', 'original_name' => 'kommunion.pro', 'stored_path' => $storedPath, 'order' => 1, ]); $result = app(PlaylistExportService::class)->generatePlaylist($service); $playlist = ProPlaylistReader::read($result['path']); $entryNames = array_map(fn ($e) => $e->getName(), $playlist->getEntries()); $abendmahlPos = array_search('Abendmahlslied', $entryNames, true); $predigtPos = array_search('Predigtlied', $entryNames, true); $kommunionPositions = array_keys($entryNames, 'kommunion', true); $this->assertNotFalse($abendmahlPos, 'Abendmahl song entry not found'); $this->assertNotFalse($predigtPos, 'Predigt song entry not found'); $this->assertCount(1, $kommunionPositions, 'Keyword presentation must be injected exactly once'); $kommunionPos = $kommunionPositions[0]; $this->assertSame($abendmahlPos + 1, $kommunionPos, 'Keyword presentation must appear immediately after the matched item'); $this->assertLessThan($predigtPos, $kommunionPos, 'Keyword presentation must not appear after the non-matching item'); $embeddedFiles = $playlist->getEmbeddedFiles(); $this->assertArrayHasKey('KEYWORD_1_kommunion.pro', $embeddedFiles); $this->assertSame('kommunion-pro-bytes', $embeddedFiles['KEYWORD_1_kommunion.pro']); $this->cleanupTempDir($result['temp_dir']); } public function test_leeres_keyword_wird_nicht_injiziert(): void { $service = Service::factory()->create([ 'title' => 'Kein Keyword Service', 'date' => now(), ]); $this->addSongAgendaItem($service, $this->createSongWithContent('Abendmahlslied'), 'Abendmahl feiern', 1); $storedPath = 'export-pro-files/keyword/leer.pro'; Storage::disk('local')->put($storedPath, 'leer-pro-bytes'); ExportProFile::create([ 'type' => 'keyword', 'keyword' => '', 'original_name' => 'leer.pro', 'stored_path' => $storedPath, 'order' => 1, ]); $result = app(PlaylistExportService::class)->generatePlaylist($service); $playlist = ProPlaylistReader::read($result['path']); $entryNames = array_map(fn ($e) => $e->getName(), $playlist->getEntries()); $this->assertNotContains('leer', $entryNames, 'Files with an empty keyword must never be injected'); $this->cleanupTempDir($result['temp_dir']); } }