diff --git a/php/tests/ProFileGeneratorTest.php b/php/tests/ProFileGeneratorTest.php index 111ade5..7671d97 100644 --- a/php/tests/ProFileGeneratorTest.php +++ b/php/tests/ProFileGeneratorTest.php @@ -6,6 +6,9 @@ namespace ProPresenter\Parser\Tests; use PHPUnit\Framework\Attributes\Test; use PHPUnit\Framework\TestCase; +use ProPresenter\Parser\PresentationBundle; +use ProPresenter\Parser\ProBundleReader; +use ProPresenter\Parser\ProBundleWriter; use ProPresenter\Parser\ProFileGenerator; use ProPresenter\Parser\ProFileReader; use ProPresenter\Parser\ProFileWriter; @@ -1014,4 +1017,140 @@ class ProFileGeneratorTest extends TestCase $this->assertNotNull($image->getFile()->getLocalUrl()); $this->assertSame('file:///Users/test/AI/Media/test-image.png', $image->getFile()->getLocalUrl()->getAbsoluteString()); } + + #[Test] + public function testGeneratedProFileMatchesProPresenterNativeStructure(): void + { + $song = ProFileGenerator::generate( + 'TestBild', + [[ + 'name' => 'Verse 1', + 'color' => [0.0, 0.0, 0.0, 1.0], + 'slides' => [[ + 'label' => 'test-background', + 'media' => 'file:///Users/thorsten/AI/propresenter/ref/Media/test-background.png', + 'format' => 'png', + 'mediaWidth' => 200, + 'mediaHeight' => 150, + ]], + ]], + [['name' => 'normal', 'groupNames' => ['Verse 1']]], + ); + + $p = $song->getPresentation(); + + // Fix 1: UUIDs are uppercase + $this->assertMatchesRegularExpression( + '/^[A-F0-9]{8}-[A-F0-9]{4}-4[A-F0-9]{3}-[89AB][A-F0-9]{3}-[A-F0-9]{12}$/', + $p->getUuid()->getString(), + 'Presentation UUID must be uppercase', + ); + + // Fix 2: Separate platform and application versions + $appInfo = $p->getApplicationInfo(); + $this->assertSame(14, $appInfo->getPlatformVersion()->getMajorVersion()); + $this->assertSame(8, $appInfo->getPlatformVersion()->getMinorVersion()); + $this->assertSame(3, $appInfo->getPlatformVersion()->getPatchVersion()); + $this->assertSame(20, $appInfo->getApplicationVersion()->getMajorVersion()); + $this->assertSame('335544354', $appInfo->getApplicationVersion()->getBuild()); + + // Fix 3a: Background present + $this->assertNotNull($p->getBackground(), 'Background must be set'); + $this->assertSame(1.0, $p->getBackground()->getColor()->getAlpha()); + + // Fix 3b: ChordChart on Presentation + $this->assertNotNull($p->getChordChart(), 'Presentation chordChart must be set'); + + // Fix 3c: CCLI always present (even with no data) + $this->assertNotNull($p->getCcli(), 'CCLI must always be set'); + + // Fix 3d: Timeline + $this->assertNotNull($p->getTimeline(), 'Timeline must be set'); + $this->assertSame(300.0, $p->getTimeline()->getDuration()); + + // Fix 4: HotKey on Group and Cue + $this->assertNotNull($p->getCueGroups()[0]->getGroup()->getHotKey(), 'Group must have hotKey'); + $this->assertNotNull($p->getCues()[0]->getHotKey(), 'Cue must have hotKey'); + + // Fix 5a: Slide size 1920x1080 + $slidePresentation = $p->getCues()[0]->getActions()[0]->getSlide()->getPresentation(); + $size = $slidePresentation->getBaseSlide()->getSize(); + $this->assertNotNull($size, 'Slide must have size'); + $this->assertSame(1920.0, $size->getWidth()); + $this->assertSame(1080.0, $size->getHeight()); + + // Fix 5b: PresentationSlide chordChart + $this->assertNotNull($slidePresentation->getChordChart(), 'PresentationSlide must have chordChart'); + + // Fix 6: LOCAL PATH ROOT_USER_HOME for /Users/ paths + $mediaUrl = $p->getCues()[0]->getActions()[1]->getMedia()->getElement()->getUrl(); + $this->assertSame(2, $mediaUrl->getLocal()->getRoot(), 'Must use ROOT_USER_HOME (2) for /Users/ paths'); + $this->assertSame('AI/propresenter/ref/Media/test-background.png', $mediaUrl->getLocal()->getPath()); + + // Fix 7a: Media action name + $mediaAction = $p->getCues()[0]->getActions()[1]; + $this->assertSame('test-background', $mediaAction->getName()); + + // Fix 7b: MediaType.audio set (oneof discriminator) + $this->assertNotNull($mediaAction->getMedia()->getAudio(), 'MediaType must have audio set'); + + // Fix 7c: ImageTypeProperties with drawing and file + $img = $mediaAction->getMedia()->getElement()->getImage(); + $this->assertNotNull($img->getDrawing(), 'ImageTypeProperties must have drawing'); + $this->assertSame(200.0, $img->getDrawing()->getNaturalSize()->getWidth()); + $this->assertSame(150.0, $img->getDrawing()->getNaturalSize()->getHeight()); + $this->assertNotNull($img->getDrawing()->getCustomImageBounds()); + $this->assertNotNull($img->getDrawing()->getCropInsets()); + $this->assertNotNull($img->getFile(), 'ImageTypeProperties must have file'); + $this->assertNotNull($img->getFile()->getLocalUrl()); + $this->assertSame( + 'file:///Users/thorsten/AI/propresenter/ref/Media/test-background.png', + $img->getFile()->getLocalUrl()->getAbsoluteString(), + ); + } + + #[Test] + public function testBundleRoundTripWithGeneratedSong(): void + { + $song = ProFileGenerator::generate( + 'TestBild', + [[ + 'name' => 'Verse 1', + 'color' => [0.0, 0.0, 0.0, 1.0], + 'slides' => [[ + 'label' => 'test-background', + 'media' => 'file:///Users/thorsten/AI/propresenter/ref/Media/test-background.png', + 'format' => 'png', + 'mediaWidth' => 200, + 'mediaHeight' => 150, + ]], + ]], + [['name' => 'normal', 'groupNames' => ['Verse 1']]], + ); + + $fakeImageBytes = "\x89PNG\r\n\x1a\n" . str_repeat("\x00", 100); + + $bundle = new PresentationBundle( + $song, + 'TestBild.pro', + ['Media/test-background.png' => $fakeImageBytes], + ); + + $path = $this->tmpDir . '/TestBild.probundle'; + ProBundleWriter::write($bundle, $path); + + $this->assertFileExists($path); + + $read = ProBundleReader::read($path); + $this->assertSame('TestBild', $read->getName()); + $this->assertSame('TestBild.pro', $read->getProFilename()); + $this->assertSame(1, $read->getMediaFileCount()); + $this->assertTrue($read->hasMediaFile('Media/test-background.png')); + + // UUID preserved through serialization + $this->assertSame( + $song->getPresentation()->getUuid()->getString(), + $read->getSong()->getPresentation()->getUuid()->getString(), + ); + } }