parse(metadataOnlyPaste()); expect($result)->toBeInstanceOf(ParsedCcliSong::class) ->and($result->title)->toBe('Instrumental Intro') ->and($result->ccliId)->toBe('9999500') ->and($result->year)->toBe('2024') ->and($result->sections)->toBe([]); }); test('parser wirft weiterhin wenn weder Titel noch CCLI vorhanden', function (): void { $parser = new CcliPasteParser; expect(fn () => $parser->parse(" \n \n")) ->toThrow(InvalidArgumentException::class); }); test('import von Metadaten-only erzeugt Song ohne Inhalts-Sektionen aber mit Copyright+Blank', function (): void { $service = app(CcliImportService::class); $result = $service->import(metadataOnlyPaste()); $song = $result['song']->fresh(); expect($result['status'])->toBe('created') ->and($song->ccli_id)->toBe('9999500') ->and($song->has_translation)->toBeFalse(); // normal-Arrangement existiert trotz fehlender Inhalts-Sektionen. $arrangement = $song->arrangements()->where('name', 'normal')->first(); expect($arrangement)->not->toBeNull() ->and($arrangement->is_default)->toBeTrue(); // Genau zwei Folien: eine COPYRIGHT-Folie, eine BLANK-Folie. expect(SongSlide::count())->toBe(2); $prefixLabelId = (int) Setting::get('song_prefix_label_id'); $copyrightSlide = $song->sections() ->where('label_id', $prefixLabelId) ->first() ->slides() ->first(); expect($copyrightSlide->text_content)->toContain('Instrumental Intro') ->and($copyrightSlide->text_content)->toContain('CCLI-Liednr. 9999500'); }); test('songHasContent bleibt false fuer Metadaten-only Song (Duplikat-Guard behandelt als leer)', function (): void { $service = app(CcliImportService::class); // Erster Import legt den leeren Song an. $service->import(metadataOnlyPaste()); // Zweiter Import darf NICHT als Duplikat geworfen werden, da kein Inhalt. // Status 'restored' (Song existiert), aber keine DuplicateCcliSongException. $result = $service->import(metadataOnlyPaste()); expect($result['status'])->toBe('restored') ->and(Song::where('ccli_id', '9999500')->count())->toBe(1); });