Files
BattleForge/tests/Unit/Application/ScenarioSerializerTest.php
T

176 lines
9.1 KiB
PHP

<?php
declare(strict_types=1);
namespace BattleForge\Tests\Unit\Application;
use BattleForge\Application\ScenarioSerializer;
use BattleForge\Domain\Archetype;
use BattleForge\Domain\Battlefield;
use BattleForge\Domain\DeploymentZone;
use BattleForge\Domain\MatchState;
use BattleForge\Domain\ObjectiveMarker;
use BattleForge\Domain\Position;
use BattleForge\Domain\Scenario;
use BattleForge\Domain\Terrain;
use BattleForge\Domain\UnitState;
use BattleForge\Domain\VictoryCondition;
use PHPUnit\Framework\TestCase;
final class ScenarioSerializerTest extends TestCase
{
public function testItRoundTripsACompleteScenario(): void
{
$scenario = new Scenario(
id: 'demo',
name: 'Demo',
battlefield: new Battlefield(8, 8, ['0:0' => Terrain::Forest]),
units: [
new UnitState('alpha-1', 'alpha', new Position(0, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, ['buff'], 0, false),
new UnitState('alpha-2', 'alpha', new Position(1, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, [], 0, false),
new UnitState('alpha-3', 'alpha', new Position(2, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, [], 0, false),
new UnitState('bravo-1', 'bravo', new Position(7, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, ['area_damage'], 0, false),
new UnitState('bravo-2', 'bravo', new Position(6, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, [], 0, false),
new UnitState('bravo-3', 'bravo', new Position(5, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, [], 0, false),
],
deploymentZones: [
'alpha' => new DeploymentZone('alpha', [new Position(0, 0), new Position(1, 0), new Position(2, 0)]),
'bravo' => new DeploymentZone('bravo', [new Position(7, 7), new Position(6, 7), new Position(5, 7)]),
],
objectives: [],
victoryCondition: VictoryCondition::EliminateAll,
holdRoundsRequired: 1,
);
$array = ScenarioSerializer::scenarioToArray($scenario);
$reconstructed = ScenarioSerializer::scenarioFromArray($array);
self::assertSame($scenario->id, $reconstructed->id);
self::assertSame($scenario->name, $reconstructed->name);
self::assertSame($scenario->battlefield->width, $reconstructed->battlefield->width);
self::assertSame($scenario->battlefield->height, $reconstructed->battlefield->height);
self::assertSame('forest', $reconstructed->battlefield->terrainAt(new Position(0, 0))->value);
self::assertCount(6, $reconstructed->units);
self::assertSame('alpha-1', $reconstructed->units[0]->id);
self::assertSame(Archetype::Defender, $reconstructed->units[0]->archetype);
self::assertSame(['buff'], $reconstructed->units[0]->abilities);
self::assertSame(12, $reconstructed->units[0]->maxHealth);
self::assertSame(3, $reconstructed->units[0]->attack);
self::assertSame(4, $reconstructed->units[0]->defense);
self::assertSame(2, $reconstructed->units[0]->speed);
self::assertSame($scenario->victoryCondition, $reconstructed->victoryCondition);
}
public function testItRoundTripsAHoldObjectiveScenario(): void
{
$scenario = new Scenario(
id: 'hold',
name: 'Hold',
battlefield: new Battlefield(8, 8),
units: [
new UnitState('alpha-1', 'alpha', new Position(0, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, [], 0, false),
new UnitState('alpha-2', 'alpha', new Position(1, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, [], 0, false),
new UnitState('alpha-3', 'alpha', new Position(2, 0), 12, 12, 3, 4, 2, 2, false, Archetype::Defender, [], 0, false),
new UnitState('bravo-1', 'bravo', new Position(7, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, [], 0, false),
new UnitState('bravo-2', 'bravo', new Position(6, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, [], 0, false),
new UnitState('bravo-3', 'bravo', new Position(5, 7), 8, 8, 5, 2, 3, 2, false, Archetype::Striker, [], 0, false),
],
deploymentZones: [
'alpha' => new DeploymentZone('alpha', [new Position(0, 0), new Position(1, 0), new Position(2, 0)]),
'bravo' => new DeploymentZone('bravo', [new Position(7, 7), new Position(6, 7), new Position(5, 7)]),
],
objectives: ['objective-1' => new ObjectiveMarker('objective-1', new Position(4, 4))],
victoryCondition: VictoryCondition::HoldObjective,
holdRoundsRequired: 3,
);
$reconstructed = ScenarioSerializer::scenarioFromArray(ScenarioSerializer::scenarioToArray($scenario));
self::assertSame(VictoryCondition::HoldObjective, $reconstructed->victoryCondition);
self::assertSame(3, $reconstructed->holdRoundsRequired);
self::assertArrayHasKey('objective-1', $reconstructed->objectives);
self::assertSame('4:4', $reconstructed->objectives['objective-1']->position->key());
}
public function testItRoundTripsAMatchState(): void
{
$scenario = new Scenario(
id: 'demo',
name: 'Demo',
battlefield: new Battlefield(8, 8),
units: [
new UnitState('alpha-1', 'alpha', new Position(0, 0), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
new UnitState('alpha-2', 'alpha', new Position(1, 0), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
new UnitState('alpha-3', 'alpha', new Position(2, 0), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
new UnitState('bravo-1', 'bravo', new Position(7, 7), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
new UnitState('bravo-2', 'bravo', new Position(6, 7), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
new UnitState('bravo-3', 'bravo', new Position(5, 7), 6, 6, 4, 2, 4, 2, false, Archetype::Scout, [], 0, false),
],
deploymentZones: [
'alpha' => new DeploymentZone('alpha', [new Position(0, 0), new Position(1, 0), new Position(2, 0)]),
'bravo' => new DeploymentZone('bravo', [new Position(7, 7), new Position(6, 7), new Position(5, 7)]),
],
objectives: [],
victoryCondition: VictoryCondition::EliminateAll,
holdRoundsRequired: 1,
);
$match = $scenario->startMatch('alpha');
$reconstructed = ScenarioSerializer::matchFromArray(ScenarioSerializer::matchToArray($match));
self::assertSame('alpha', $reconstructed->activeTeamId);
self::assertSame(1, $reconstructed->round);
self::assertCount(6, $reconstructed->units);
self::assertSame(2, $reconstructed->units[0]->actionsRemaining);
self::assertFalse($reconstructed->units[0]->hasAttacked);
self::assertSame(0, $reconstructed->units[0]->attackBonus);
}
public function testItRejectsShapeErrors(): void
{
$this->expectException(\InvalidArgumentException::class);
ScenarioSerializer::scenarioFromArray([
'id' => 'demo',
// missing 'name', 'battlefield', 'units', etc.
]);
}
public function testMatchRoundTripsItsObjectives(): void
{
$battlefield = new Battlefield(10, 8);
$units = [
new UnitState('a1', 'alpha', new Position(0, 0), 10, 10, 3, 3, 2, 2, false),
new UnitState('a2', 'alpha', new Position(1, 0), 10, 10, 3, 3, 2, 2, false),
new UnitState('a3', 'alpha', new Position(2, 0), 10, 10, 3, 3, 2, 2, false),
new UnitState('b1', 'bravo', new Position(9, 7), 10, 10, 3, 3, 2, 2, false),
new UnitState('b2', 'bravo', new Position(8, 7), 10, 10, 3, 3, 2, 2, false),
new UnitState('b3', 'bravo', new Position(7, 7), 10, 10, 3, 3, 2, 2, false),
];
$objective = new ObjectiveMarker('objective-1', new Position(5, 4));
$original = new MatchState(
battlefield: $battlefield,
units: $units,
activeTeamId: 'alpha',
objectives: ['objective-1' => $objective],
victoryCondition: VictoryCondition::HoldObjective,
holdRoundsRequired: 3,
);
$array = ScenarioSerializer::matchToArray($original);
self::assertArrayHasKey('objectives', $array);
self::assertSame(
['id' => 'objective-1', 'position' => ['x' => 5, 'y' => 4]],
$array['objectives']['objective-1'] ?? null,
);
$rebuilt = ScenarioSerializer::matchFromArray($array);
self::assertArrayHasKey('objective-1', $rebuilt->objectives);
self::assertSame('objective-1', $rebuilt->objectives['objective-1']->id);
self::assertSame(5, $rebuilt->objectives['objective-1']->position->x);
self::assertSame(4, $rebuilt->objectives['objective-1']->position->y);
self::assertSame(VictoryCondition::HoldObjective, $rebuilt->victoryCondition);
self::assertSame(3, $rebuilt->holdRoundsRequired);
}
}