feat: catalog curated unit archetypes and templates

This commit is contained in:
Keith Solomon
2026-07-05 18:41:53 -05:00
parent 78fc802cdc
commit 0ac8c06c5e
5 changed files with 250 additions and 0 deletions
@@ -0,0 +1,56 @@
<?php
declare(strict_types=1);
namespace BattleForge\Tests\Unit\Domain;
use BattleForge\Domain\Archetype;
use BattleForge\Domain\ArchetypeCatalog;
use BattleForge\Domain\ArchetypeTemplate;
use PHPUnit\Framework\TestCase;
final class ArchetypeCatalogTest extends TestCase
{
public function testItExposesExactlyTheFourPlannedArchetypes(): void
{
$keys = array_keys(ArchetypeCatalog::templates());
sort($keys);
self::assertSame(['defender', 'scout', 'striker', 'support'], $keys);
}
public function testEveryArchetypeTemplateCarriesAllFourStatRanges(): void
{
foreach (ArchetypeCatalog::templates() as $key => $template) {
self::assertInstanceOf(ArchetypeTemplate::class, $template);
self::assertLessThanOrEqual($template->maxHealth, $template->minHealth);
self::assertLessThanOrEqual($template->maxAttack, $template->minAttack);
self::assertLessThanOrEqual($template->maxDefense, $template->minDefense);
self::assertLessThanOrEqual($template->maxSpeed, $template->minSpeed);
self::assertGreaterThanOrEqual(1, $template->minSpeed);
}
}
public function testEveryArchetypeTemplateDefaultsToTheCenterOfItsRanges(): void
{
foreach (ArchetypeCatalog::templates() as $template) {
$defaults = $template->defaultStats();
self::assertSame((int) ceil(($template->minHealth + $template->maxHealth) / 2), $defaults['maxHealth']);
self::assertSame((int) ceil(($template->minAttack + $template->maxAttack) / 2), $defaults['attack']);
self::assertSame((int) ceil(($template->minDefense + $template->maxDefense) / 2), $defaults['defense']);
self::assertSame((int) ceil(($template->minSpeed + $template->maxSpeed) / 2), $defaults['speed']);
}
}
public function testDefaultStatsReturnAllFourKeys(): void
{
$template = ArchetypeCatalog::templates()[Archetype::Defender->value];
self::assertSame(
['maxHealth', 'attack', 'defense', 'speed'],
array_keys($template->defaultStats()),
);
}
}
@@ -0,0 +1,62 @@
<?php
declare(strict_types=1);
namespace BattleForge\Tests\Unit\Domain;
use BattleForge\Domain\ArchetypeTemplate;
use PHPUnit\Framework\TestCase;
final class ArchetypeTemplateTest extends TestCase
{
public function testItRejectsInvertedStatRanges(): void
{
$this->expectException(\InvalidArgumentException::class);
new ArchetypeTemplate(
minHealth: 10,
maxHealth: 5,
minAttack: 1,
maxAttack: 3,
minDefense: 0,
maxDefense: 2,
minSpeed: 1,
maxSpeed: 4,
allowedAbilities: [],
);
}
public function testItRejectsZeroMinimumSpeed(): void
{
$this->expectException(\InvalidArgumentException::class);
new ArchetypeTemplate(
minHealth: 5,
maxHealth: 10,
minAttack: 1,
maxAttack: 3,
minDefense: 0,
maxDefense: 2,
minSpeed: 0,
maxSpeed: 4,
allowedAbilities: [],
);
}
public function testItExposesAllowedAbilitiesVerbatim(): void
{
$template = new ArchetypeTemplate(
minHealth: 5,
maxHealth: 10,
minAttack: 1,
maxAttack: 3,
minDefense: 0,
maxDefense: 2,
minSpeed: 1,
maxSpeed: 4,
allowedAbilities: ['heal', 'buff'],
);
self::assertSame(['heal', 'buff'], $template->allowedAbilities);
}
}