propresenter-php/php/tests/ProFileGeneratorTest.php
Thorsten Bus 22d98e2225 [AI] add ProFileGenerator to create .pro files from scratch
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-opencode)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
2026-03-01 16:34:04 +01:00

322 lines
11 KiB
PHP

<?php
declare(strict_types=1);
namespace ProPresenter\Parser\Tests;
use PHPUnit\Framework\Attributes\Test;
use PHPUnit\Framework\TestCase;
use ProPresenter\Parser\ProFileGenerator;
use ProPresenter\Parser\ProFileReader;
use ProPresenter\Parser\ProFileWriter;
class ProFileGeneratorTest extends TestCase
{
private string $tmpDir;
protected function setUp(): void
{
$this->tmpDir = sys_get_temp_dir() . '/propresenter-generator-test-' . uniqid();
mkdir($this->tmpDir, 0777, true);
}
protected function tearDown(): void
{
if (!is_dir($this->tmpDir)) {
return;
}
foreach (scandir($this->tmpDir) ?: [] as $entry) {
if ($entry === '.' || $entry === '..') {
continue;
}
@unlink($this->tmpDir . '/' . $entry);
}
@rmdir($this->tmpDir);
}
#[Test]
public function testGenerateCreatesValidSong(): void
{
$song = ProFileGenerator::generate(
'Simple Song',
[
[
'name' => 'Verse 1',
'color' => [0.1, 0.2, 0.3, 1.0],
'slides' => [
['text' => 'Hello World'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['Verse 1']],
],
);
$this->assertSame('Simple Song', $song->getName());
$this->assertCount(1, $song->getGroups());
$this->assertCount(1, $song->getSlides());
$this->assertSame('Hello World', $song->getSlides()[0]->getPlainText());
$arrangement = $song->getArrangementByName('normal');
$this->assertNotNull($arrangement);
$groups = $song->getGroupsForArrangement($arrangement);
$this->assertCount(1, $groups);
$this->assertSame('Verse 1', $groups[0]->getName());
}
#[Test]
public function testGenerateWithMultipleGroupsAndArrangements(): void
{
$song = ProFileGenerator::generate(
'Multi Song',
[
[
'name' => 'Verse 1',
'color' => [0.1, 0.2, 0.3, 1.0],
'slides' => [
['text' => 'V1.1'],
['text' => 'V1.2'],
],
],
[
'name' => 'Chorus',
'color' => [0.4, 0.5, 0.6, 1.0],
'slides' => [
['text' => 'C1'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['Verse 1', 'Chorus']],
['name' => 'short', 'groupNames' => ['Chorus']],
],
);
$this->assertSame(['Verse 1', 'Chorus'], array_map(fn ($group) => $group->getName(), $song->getGroups()));
$verse1 = $song->getGroupByName('Verse 1');
$this->assertNotNull($verse1);
$verseSlides = $song->getSlidesForGroup($verse1);
$this->assertSame(['V1.1', 'V1.2'], array_map(fn ($slide) => $slide->getPlainText(), $verseSlides));
$chorus = $song->getGroupByName('Chorus');
$this->assertNotNull($chorus);
$chorusSlides = $song->getSlidesForGroup($chorus);
$this->assertSame(['C1'], array_map(fn ($slide) => $slide->getPlainText(), $chorusSlides));
$normal = $song->getArrangementByName('normal');
$this->assertNotNull($normal);
$this->assertSame(
['Verse 1', 'Chorus'],
array_map(fn ($group) => $group->getName(), $song->getGroupsForArrangement($normal)),
);
$short = $song->getArrangementByName('short');
$this->assertNotNull($short);
$this->assertSame(
['Chorus'],
array_map(fn ($group) => $group->getName(), $song->getGroupsForArrangement($short)),
);
}
#[Test]
public function testGenerateWithTranslation(): void
{
$song = ProFileGenerator::generate(
'Translation Song',
[
[
'name' => 'Verse 1',
'color' => [0.1, 0.2, 0.3, 1.0],
'slides' => [
['text' => 'Original', 'translation' => 'Translated'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['Verse 1']],
],
);
$slide = $song->getSlides()[0];
$this->assertTrue($slide->hasTranslation());
$this->assertSame('Translated', $slide->getTranslation()?->getPlainText());
}
#[Test]
public function testGenerateWithCcliMetadata(): void
{
$song = ProFileGenerator::generate(
'CCLI Song',
[
[
'name' => 'Verse 1',
'color' => [0.1, 0.2, 0.3, 1.0],
'slides' => [
['text' => 'Line'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['Verse 1']],
],
[
'author' => 'Author Name',
'song_title' => 'Song Title',
'publisher' => 'Publisher Name',
'copyright_year' => 2024,
'song_number' => 12345,
'display' => true,
'artist_credits' => 'Artist Credits',
'album' => 'Album Name',
],
);
$this->assertSame('Author Name', $song->getCcliAuthor());
$this->assertSame('Song Title', $song->getCcliSongTitle());
$this->assertSame('Publisher Name', $song->getCcliPublisher());
$this->assertSame(2024, $song->getCcliCopyrightYear());
$this->assertSame(12345, $song->getCcliSongNumber());
$this->assertTrue($song->getCcliDisplay());
$this->assertSame('Artist Credits', $song->getCcliArtistCredits());
$this->assertSame('Album Name', $song->getCcliAlbum());
}
#[Test]
public function testRoundTripFromTestPro(): void
{
$original = ProFileReader::read('/Users/thorsten/AI/propresenter/ref/Test.pro');
$groups = [];
foreach ($original->getGroups() as $group) {
$color = $group->getColor();
$slides = [];
foreach ($original->getSlidesForGroup($group) as $slide) {
$slides[] = [
'text' => $slide->getPlainText(),
'translation' => $slide->hasTranslation() ? $slide->getTranslation()?->getPlainText() : null,
];
}
$groups[] = [
'name' => $group->getName(),
'color' => [
$color['r'] ?? 0.0,
$color['g'] ?? 0.0,
$color['b'] ?? 0.0,
$color['a'] ?? 1.0,
],
'slides' => $slides,
];
}
$arrangements = [];
foreach ($original->getArrangements() as $arrangement) {
$arrangements[] = [
'name' => $arrangement->getName(),
'groupNames' => array_map(
fn ($group) => $group->getName(),
$original->getGroupsForArrangement($arrangement),
),
];
}
$ccli = [
'author' => $original->getCcliAuthor(),
'song_title' => $original->getCcliSongTitle(),
'publisher' => $original->getCcliPublisher(),
'copyright_year' => $original->getCcliCopyrightYear(),
'song_number' => $original->getCcliSongNumber(),
'display' => $original->getCcliDisplay(),
'artist_credits' => $original->getCcliArtistCredits(),
'album' => $original->getCcliAlbum(),
];
$generated = ProFileGenerator::generate($original->getName(), $groups, $arrangements, $ccli);
$filePath = $this->tmpDir . '/test-roundtrip.pro';
ProFileWriter::write($generated, $filePath);
$roundTrip = ProFileReader::read($filePath);
$this->assertSame($original->getName(), $roundTrip->getName());
$this->assertSame(
array_map(fn ($group) => $group->getName(), $original->getGroups()),
array_map(fn ($group) => $group->getName(), $roundTrip->getGroups()),
);
foreach ($original->getGroups() as $group) {
$actualGroup = $roundTrip->getGroupByName($group->getName());
$this->assertNotNull($actualGroup);
$expectedSlides = $original->getSlidesForGroup($group);
$actualSlides = $roundTrip->getSlidesForGroup($actualGroup);
$this->assertCount(count($expectedSlides), $actualSlides);
foreach ($expectedSlides as $index => $expectedSlide) {
$actualSlide = $actualSlides[$index];
$this->assertSame($expectedSlide->getPlainText(), $actualSlide->getPlainText());
$this->assertSame($expectedSlide->hasTranslation(), $actualSlide->hasTranslation());
if ($expectedSlide->hasTranslation()) {
$this->assertSame(
$expectedSlide->getTranslation()?->getPlainText(),
$actualSlide->getTranslation()?->getPlainText(),
);
}
}
}
$this->assertSame(
array_map(fn ($arrangement) => $arrangement->getName(), $original->getArrangements()),
array_map(fn ($arrangement) => $arrangement->getName(), $roundTrip->getArrangements()),
);
foreach ($original->getArrangements() as $arrangement) {
$roundTripArrangement = $roundTrip->getArrangementByName($arrangement->getName());
$this->assertNotNull($roundTripArrangement);
$expectedNames = array_map(
fn ($group) => $group->getName(),
$original->getGroupsForArrangement($arrangement),
);
$actualNames = array_map(
fn ($group) => $group->getName(),
$roundTrip->getGroupsForArrangement($roundTripArrangement),
);
$this->assertSame($expectedNames, $actualNames);
}
}
#[Test]
public function testGenerateAndWriteCreatesFile(): void
{
$filePath = $this->tmpDir . '/generated.pro';
ProFileGenerator::generateAndWrite(
$filePath,
'Write Song',
[
[
'name' => 'Verse 1',
'color' => [0.1, 0.2, 0.3, 1.0],
'slides' => [
['text' => 'Line 1'],
],
],
],
[
['name' => 'normal', 'groupNames' => ['Verse 1']],
],
);
$this->assertFileExists($filePath);
$song = ProFileReader::read($filePath);
$this->assertSame('Write Song', $song->getName());
}
}