$title, 'ccli_id' => fake()->unique()->numerify('#####'), 'author' => 'Test Author', ]); $label = Label::firstOrCreate(['name' => 'Verse 1 - '.$title], ['color' => '#2196F3']); $section = $song->sections()->create(['label_id' => $label->id, 'order' => 0]); $section->slides()->create(['order' => 0, 'text_content' => 'Inhalt']); $arrangement = $song->arrangements()->create(['name' => 'normal', 'is_default' => true]); $arrangement->arrangementSections()->create(['song_section_id' => $section->id, 'order' => 0]); return $song; } /** Build a minimal valid .probundle and register it as a prefix ExportProFile on the local disk. */ private function registerPrefixBundle(string $proName = 'IntroBundle'): ExportProFile { $song = ProFileGenerator::generate( $proName, [[ 'name' => 'Intro', 'color' => [0, 0, 0, 1], 'slides' => [['text' => 'Willkommen']], ]], [['name' => 'normal', 'groupNames' => ['Intro']]], ); $bundle = new PresentationBundle($song, $proName.'.pro', []); $tmp = tempnam(sys_get_temp_dir(), 'fixture-').'.probundle'; ProBundleWriter::write($bundle, $tmp); $bytes = file_get_contents($tmp); @unlink($tmp); $storedPath = 'export-pro-files/'.$proName.'.probundle'; Storage::disk('local')->put($storedPath, $bytes); return ExportProFile::create([ 'type' => 'prefix', 'original_name' => $proName.'.probundle', 'stored_path' => $storedPath, 'order' => 1, ]); } public function test_vorab_hinzugefuegtes_probundle_ergibt_nicht_leere_playlist(): void { $service = Service::factory()->create(['finalized_at' => now(), 'title' => 'Mit Prefix']); $song = $this->createSongWithContent('Hauptlied'); ServiceSong::create([ 'service_id' => $service->id, 'song_id' => $song->id, 'cts_song_name' => 'Hauptlied', 'order' => 1, ]); $this->registerPrefixBundle('IntroBundle'); $capturedItems = []; $capturedFiles = []; $exportService = new class($capturedItems, $capturedFiles) extends PlaylistExportService { /** @var array */ private array $items; /** @var array */ private array $files; public function __construct(array &$items, array &$files) { $this->items = &$items; $this->files = &$files; } protected function writeProFile(string $path, string $name, array $groups, array $arrangements): void { file_put_contents($path, 'mock-pro:'.$name); } protected function writePlaylistFile(string $path, string $name, array $items, array $embeddedFiles): void { $this->items = $items; $this->files = $embeddedFiles; file_put_contents($path, 'mock-playlist:'.$name); } }; $result = $exportService->generatePlaylist($service); $this->assertFileExists($result['path']); // The prefix .pro must be present as a playlist item and embedded with non-empty bytes. $prefixItem = collect($capturedItems)->first( fn ($item) => str_starts_with($item['path'] ?? '', 'PREFIX_') && str_ends_with($item['path'], '.pro') ); $this->assertNotNull($prefixItem, 'Pre-added .probundle should produce a PREFIX_*.pro playlist item.'); $embeddedKey = $prefixItem['path']; $this->assertArrayHasKey($embeddedKey, $capturedFiles); $this->assertNotSame('', $capturedFiles[$embeddedKey], 'Embedded .pro from .probundle must be non-empty.'); $this->assertGreaterThan(0, strlen($capturedFiles[$embeddedKey])); $this->cleanupTempDir($result['temp_dir']); } private function cleanupTempDir(string $dir): void { if (! is_dir($dir)) { return; } foreach (scandir($dir) as $item) { if ($item === '.' || $item === '..') { continue; } $path = $dir.'/'.$item; is_dir($path) ? $this->cleanupTempDir($path) : unlink($path); } rmdir($dir); } }