toBeTrue(); })->with([ 'Verse 1', 'Chorus', 'Bridge', 'Pre-Chorus', 'Tag', 'Ending', 'Intro', 'Interlude', 'Outro', 'Misc', ]); test('isSectionLabel detects german labels', function (string $label) { expect(CcliLabels::isSectionLabel($label))->toBeTrue(); })->with([ 'Strophe 1', 'Refrain', 'Brücke', 'Vorrefrain', 'Schluss', 'Zwischenspiel', ]); test('isSectionLabel detects label variants', function (string $label) { expect(CcliLabels::isSectionLabel($label))->toBeTrue(); })->with([ 'Verse 2a', 'Chorus 1 (Repeat)', 'Bridge x2', 'Verse 2b', ]); test('isSectionLabel rejects non labels', function (string $text) { expect(CcliLabels::isSectionLabel($text))->toBeFalse(); })->with([ 'Random text', 'We are singing', 'CCLI # 123456', '© 2024 Publisher', '', 'Amazing grace how sweet', ]); test('isMetadataLine detects metadata lines', function (string $line) { expect(CcliLabels::isMetadataLine($line))->toBeTrue(); })->with([ '© 2020 Hillsong Music', 'CCLI # 4760', 'CCLI-Nr. 1234567', 'ccli.com/license', 'SongSelect Terms', 'All rights reserved', 'Alle Rechte vorbehalten', ]); test('isMetadataLine rejects normal lines', function (string $line) { expect(CcliLabels::isMetadataLine($line))->toBeFalse(); })->with([ 'Verse 1', 'Amazing grace how sweet the sound', 'Test Song 1', ]); test('normalizeLabelName converts german labels to english', function (string $input, string $expected) { expect(CcliLabels::normalizeLabelName($input))->toBe($expected); })->with([ ['Strophe 1', 'Verse 1'], ['Refrain', 'Chorus'], ['Brücke', 'Bridge'], ['Vorrefrain', 'Pre-Chorus'], ['Schluss', 'Ending'], ['Zwischenspiel', 'Interlude'], ]); test('normalizeLabelName keeps english labels unchanged', function (string $input) { expect(CcliLabels::normalizeLabelName($input))->toBe($input); })->with([ 'Verse 1', 'Chorus', 'Bridge', ]); test('normalizeLabelName keeps unknown labels unchanged', function () { expect(CcliLabels::normalizeLabelName('Foobar'))->toBe('Foobar'); expect(CcliLabels::normalizeLabelName(''))->toBe(''); }); test('parseLabel returns structured data for labels', function (string $label, string $kind, ?string $number, ?string $modifier) { $result = CcliLabels::parseLabel($label); expect($result)->not->toBeNull(); expect($result['kind'])->toBe($kind); expect($result['number'])->toBe($number); expect($result['modifier'])->toBe($modifier); })->with([ ['Verse 1', 'Verse', '1', null], ['Chorus', 'Chorus', null, null], ['Verse 2a', 'Verse', '2a', null], ['Chorus 1 (Repeat)', 'Chorus', '1', 'Repeat'], ['Strophe 2', 'Strophe', '2', null], ]); test('parseLabel rejects non labels', function (string $text) { expect(CcliLabels::parseLabel($text))->toBeNull(); })->with([ 'Random text', 'CCLI # 123', '', 'Amazing grace', ]);