pp-planer/tests/Feature/AgendaItemDownloadTest.php
Thorsten Bus bdbf0c65e3 refactor(php): rename SongGroup references throughout controllers/services/tests
Replace all SongGroup/SongArrangementGroup model usages with Label/SongArrangementLabel
after the schema migration to global labels. Updates 12 app files and 11 test files:

- SongService: createDefaultGroups now finds-or-creates global Labels by name
- ArrangementController: validates label_id (labels are global, no song-ownership)
- ProImportService: imports groups as Labels (firstOrCreate by name); does not
  overwrite existing label colors per spec
- ProExportService/SongPdfController/TranslationService/etc: traverse via
  arrangements -> arrangementLabels -> label -> songSlides chain
- All test factories and assertions adapted to label-based schema
2026-05-03 22:55:02 +02:00

245 lines
8.1 KiB
PHP

<?php
namespace Tests\Feature;
use App\Models\Label;
use App\Models\Service;
use App\Models\ServiceAgendaItem;
use App\Models\ServiceSong;
use App\Models\Slide;
use App\Models\Song;
use App\Models\SongArrangement;
use App\Models\SongArrangementLabel;
use App\Models\SongSlide;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Tests\TestCase;
use ZipArchive;
final class AgendaItemDownloadTest extends TestCase
{
use RefreshDatabase;
public function test_agenda_item_mit_slides_liefert_probundle(): void
{
Storage::fake('public');
$user = User::factory()->create();
$service = Service::factory()->create();
$agendaItem = ServiceAgendaItem::factory()->create([
'service_id' => $service->id,
'title' => 'Predigt',
'sort_order' => 1,
'service_song_id' => null,
'is_before_event' => false,
]);
Storage::disk('public')->put('slides/predigt-1.jpg', 'fake-image-1');
Storage::disk('public')->put('slides/predigt-2.jpg', 'fake-image-2');
Slide::factory()->create([
'service_id' => $service->id,
'service_agenda_item_id' => $agendaItem->id,
'type' => 'sermon',
'stored_filename' => 'slides/predigt-1.jpg',
'original_filename' => 'Predigt Folie 1.jpg',
'sort_order' => 0,
]);
Slide::factory()->create([
'service_id' => $service->id,
'service_agenda_item_id' => $agendaItem->id,
'type' => 'sermon',
'stored_filename' => 'slides/predigt-2.jpg',
'original_filename' => 'Predigt Folie 2.jpg',
'sort_order' => 1,
]);
$response = $this->actingAs($user)->get(
route('services.agenda-item.download', [
'service' => $service,
'agendaItem' => $agendaItem,
])
);
$response->assertOk();
$response->assertHeader('content-type', 'application/zip');
$baseResponse = $response->baseResponse;
$this->assertInstanceOf(BinaryFileResponse::class, $baseResponse);
$copiedPath = sys_get_temp_dir().'/agenda-test-'.uniqid().'.probundle';
copy($baseResponse->getFile()->getPathname(), $copiedPath);
$zip = new ZipArchive;
$this->assertTrue($zip->open($copiedPath) === true);
$this->assertSame(3, $zip->numFiles);
$names = [];
for ($i = 0; $i < $zip->numFiles; $i++) {
$name = $zip->getNameIndex($i);
if ($name !== false) {
$names[] = $name;
}
}
$proEntry = array_values(array_filter($names, fn (string $n) => str_ends_with($n, '.pro')));
$this->assertCount(1, $proEntry, '.probundle muss genau eine .pro Datei enthalten');
$this->assertContains('predigt-1.jpg', $names);
$this->assertContains('predigt-2.jpg', $names);
$this->assertSame('fake-image-1', $zip->getFromName('predigt-1.jpg'));
$this->assertSame('fake-image-2', $zip->getFromName('predigt-2.jpg'));
$zip->close();
@unlink($copiedPath);
}
public function test_song_agenda_item_liefert_probundle_mit_pro_daten(): void
{
$user = User::factory()->create();
$service = Service::factory()->create();
$song = Song::factory()->create(['title' => 'Amazing Grace']);
$label = Label::factory()->create(['name' => 'Verse 1']);
SongSlide::factory()->create(['label_id' => $label->id, 'text_content' => 'Amazing grace how sweet the sound', 'order' => 1]);
$arrangement = SongArrangement::factory()->create([
'song_id' => $song->id,
'is_default' => true,
]);
SongArrangementLabel::factory()->create([
'song_arrangement_id' => $arrangement->id,
'label_id' => $label->id,
'order' => 1,
]);
$serviceSong = ServiceSong::create([
'service_id' => $service->id,
'song_id' => $song->id,
'song_arrangement_id' => null,
'use_translation' => false,
'order' => 1,
'cts_song_name' => 'Amazing Grace',
'cts_ccli_id' => '12345',
]);
$agendaItem = ServiceAgendaItem::factory()->create([
'service_id' => $service->id,
'title' => 'Amazing Grace',
'sort_order' => 1,
'service_song_id' => $serviceSong->id,
'is_before_event' => false,
]);
$response = $this->actingAs($user)->get(
route('services.agenda-item.download', [
'service' => $service,
'agendaItem' => $agendaItem,
])
);
$response->assertOk();
$response->assertHeader('content-type', 'application/zip');
$baseResponse = $response->baseResponse;
$this->assertInstanceOf(BinaryFileResponse::class, $baseResponse);
$copiedPath = sys_get_temp_dir().'/agenda-song-test-'.uniqid().'.probundle';
copy($baseResponse->getFile()->getPathname(), $copiedPath);
$zip = new ZipArchive;
$this->assertTrue($zip->open($copiedPath) === true);
$this->assertSame(1, $zip->numFiles);
$this->assertTrue(str_ends_with($zip->getNameIndex(0), '.pro'), '.probundle muss eine .pro Datei enthalten');
$proContent = $zip->getFromName($zip->getNameIndex(0));
$this->assertNotFalse($proContent);
$this->assertGreaterThan(0, strlen($proContent));
$zip->close();
@unlink($copiedPath);
}
public function test_agenda_item_von_anderem_service_liefert_404(): void
{
$user = User::factory()->create();
$service = Service::factory()->create();
$otherService = Service::factory()->create();
$agendaItem = ServiceAgendaItem::factory()->create([
'service_id' => $otherService->id,
'title' => 'Fremd',
'sort_order' => 1,
'is_before_event' => false,
]);
$response = $this->actingAs($user)->get(
route('services.agenda-item.download', [
'service' => $service,
'agendaItem' => $agendaItem,
])
);
$response->assertNotFound();
}
public function test_agenda_item_ohne_slides_und_ohne_song_liefert_leeres_probundle(): void
{
$user = User::factory()->create();
$service = Service::factory()->create();
$agendaItem = ServiceAgendaItem::factory()->create([
'service_id' => $service->id,
'title' => 'Leer',
'sort_order' => 1,
'service_song_id' => null,
'is_before_event' => false,
]);
$response = $this->actingAs($user)->get(
route('services.agenda-item.download', [
'service' => $service,
'agendaItem' => $agendaItem,
])
);
$response->assertOk();
$baseResponse = $response->baseResponse;
$this->assertInstanceOf(BinaryFileResponse::class, $baseResponse);
$copiedPath = sys_get_temp_dir().'/agenda-empty-test-'.uniqid().'.probundle';
copy($baseResponse->getFile()->getPathname(), $copiedPath);
$zip = new ZipArchive;
$this->assertTrue($zip->open($copiedPath) === true);
$this->assertSame(1, $zip->numFiles);
$this->assertTrue(str_ends_with($zip->getNameIndex(0), '.pro'), 'Einziger Eintrag muss .pro Datei sein');
$zip->close();
@unlink($copiedPath);
}
public function test_erfordert_authentifizierung(): void
{
$service = Service::factory()->create();
$agendaItem = ServiceAgendaItem::factory()->create([
'service_id' => $service->id,
'is_before_event' => false,
]);
$response = $this->get(
route('services.agenda-item.download', [
'service' => $service,
'agendaItem' => $agendaItem,
])
);
$response->assertRedirect(route('login'));
}
}