service = new AgendaMatcherService; }); // Exact match test('matches exact title', function () { expect($this->service->matches('Predigt', 'Predigt'))->toBeTrue(); }); // Wildcard suffix test('matches wildcard suffix pattern', function () { expect($this->service->matches('Predigt – Thema XY', 'Predigt*'))->toBeTrue(); }); // Wildcard prefix test('matches wildcard prefix pattern', function () { expect($this->service->matches('Die Predigt', '*Predigt'))->toBeTrue(); }); // Wildcard both test('matches wildcard both sides pattern', function () { expect($this->service->matches('Die Predigt heute', '*Predigt*'))->toBeTrue(); }); // Case insensitive test('matches case insensitive', function () { expect($this->service->matches('Predigt – Thema', 'predigt*'))->toBeTrue(); }); // No match test('does not match unrelated title', function () { expect($this->service->matches('Lobpreis', 'Predigt*'))->toBeFalse(); }); // Multiple patterns — matchesAny test('matchesAny returns true if any pattern matches', function () { $patterns = ['Predigt*', 'Sermon*']; expect($this->service->matchesAny('Predigt – Thema', $patterns))->toBeTrue(); }); test('matchesAny returns false if no pattern matches', function () { $patterns = ['Predigt*', 'Sermon*']; expect($this->service->matchesAny('Lobpreis', $patterns))->toBeFalse(); }); // findFirstMatch returns matching item test('findFirstMatch returns first matching ServiceAgendaItem', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Lobpreis']), ServiceAgendaItem::factory()->create(['title' => 'Predigt – Thema']), ServiceAgendaItem::factory()->create(['title' => 'Gebet']), ]; $result = $this->service->findFirstMatch($items, 'Predigt*'); expect($result)->toBeInstanceOf(ServiceAgendaItem::class); expect($result->title)->toBe('Predigt – Thema'); }); test('findFirstMatch returns null when no match', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Lobpreis']), ServiceAgendaItem::factory()->create(['title' => 'Gebet']), ]; $result = $this->service->findFirstMatch($items, 'Predigt*'); expect($result)->toBeNull(); }); // filterBetween with both start and end test('filterBetween filters items between start and end (both excluded)', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Info']), ServiceAgendaItem::factory()->create(['title' => 'Start']), ServiceAgendaItem::factory()->create(['title' => 'Lied 1']), ServiceAgendaItem::factory()->create(['title' => 'Lied 2']), ServiceAgendaItem::factory()->create(['title' => 'End']), ServiceAgendaItem::factory()->create(['title' => 'Segen']), ]; $result = $this->service->filterBetween($items, 'Start', 'End'); expect($result)->toHaveCount(2); expect($result[0]->title)->toBe('Lied 1'); expect($result[1]->title)->toBe('Lied 2'); }); // filterBetween with start only test('filterBetween from start boundary to end of items', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Info']), ServiceAgendaItem::factory()->create(['title' => 'Start']), ServiceAgendaItem::factory()->create(['title' => 'Lied 1']), ServiceAgendaItem::factory()->create(['title' => 'Lied 2']), ]; $result = $this->service->filterBetween($items, 'Start', null); expect($result)->toHaveCount(2); expect($result[0]->title)->toBe('Lied 1'); expect($result[1]->title)->toBe('Lied 2'); }); // filterBetween with neither test('filterBetween with no start or end patterns returns all items', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Info']), ServiceAgendaItem::factory()->create(['title' => 'Lied 1']), ServiceAgendaItem::factory()->create(['title' => 'Lied 2']), ]; $result = $this->service->filterBetween($items, null, null); expect($result)->toHaveCount(3); }); // filterBetween with no matching start test('filterBetween with no matching start pattern returns empty array', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Lied 1']), ServiceAgendaItem::factory()->create(['title' => 'Lied 2']), ]; $result = $this->service->filterBetween($items, 'Nonexistent*', null); expect($result)->toBeEmpty(); }); // findFirstMatch with comma-separated patterns test('findFirstMatch splits comma-separated patterns and matches', function () { $items = [ ServiceAgendaItem::factory()->create(['title' => 'Lobpreis']), ServiceAgendaItem::factory()->create(['title' => 'Predigt – Thema']), ]; $result = $this->service->findFirstMatch($items, 'Lied*,Predigt*'); expect($result)->toBeInstanceOf(ServiceAgendaItem::class); expect($result->title)->toBe('Predigt – Thema'); }); // Edge case: empty items array test('findFirstMatch with empty items returns null', function () { $result = $this->service->findFirstMatch([], 'Predigt*'); expect($result)->toBeNull(); }); test('filterBetween with empty items returns empty array', function () { $result = $this->service->filterBetween([], 'Start', 'End'); expect($result)->toBeEmpty(); });