feat: add JSON serializer for scenarios and match state
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
<?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.
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user