test(generator): end-to-end structural verification against ProPresenter format
This commit is contained in:
parent
82a9673874
commit
9db2702b5f
|
|
@ -6,6 +6,9 @@ namespace ProPresenter\Parser\Tests;
|
||||||
|
|
||||||
use PHPUnit\Framework\Attributes\Test;
|
use PHPUnit\Framework\Attributes\Test;
|
||||||
use PHPUnit\Framework\TestCase;
|
use PHPUnit\Framework\TestCase;
|
||||||
|
use ProPresenter\Parser\PresentationBundle;
|
||||||
|
use ProPresenter\Parser\ProBundleReader;
|
||||||
|
use ProPresenter\Parser\ProBundleWriter;
|
||||||
use ProPresenter\Parser\ProFileGenerator;
|
use ProPresenter\Parser\ProFileGenerator;
|
||||||
use ProPresenter\Parser\ProFileReader;
|
use ProPresenter\Parser\ProFileReader;
|
||||||
use ProPresenter\Parser\ProFileWriter;
|
use ProPresenter\Parser\ProFileWriter;
|
||||||
|
|
@ -1014,4 +1017,140 @@ class ProFileGeneratorTest extends TestCase
|
||||||
$this->assertNotNull($image->getFile()->getLocalUrl());
|
$this->assertNotNull($image->getFile()->getLocalUrl());
|
||||||
$this->assertSame('file:///Users/test/AI/Media/test-image.png', $image->getFile()->getLocalUrl()->getAbsoluteString());
|
$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(),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue