89 lines
2.9 KiB
PHP
89 lines
2.9 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace BattleForge\Tests\Unit\Domain;
|
|
|
|
use BattleForge\Domain\Battlefield;
|
|
use BattleForge\Domain\CombatEngine;
|
|
use BattleForge\Domain\CombatException;
|
|
use BattleForge\Domain\MatchState;
|
|
use BattleForge\Domain\Position;
|
|
use BattleForge\Domain\UnitState;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
final class CombatEngineTest extends TestCase
|
|
{
|
|
public function testMatchAndUnitStateAreImmutable(): void
|
|
{
|
|
$unit = $this->unit('unit-1', 'alpha', new Position(0, 0));
|
|
$match = new MatchState(new Battlefield(8, 8), [$unit], 'alpha');
|
|
|
|
$moved = $unit->moveTo(new Position(1, 0))->spendAction();
|
|
$next = $match->withUnit($moved);
|
|
|
|
self::assertSame('0:0', $match->unit('unit-1')->position->key());
|
|
self::assertSame('1:0', $next->unit('unit-1')->position->key());
|
|
self::assertSame(1, $next->unit('unit-1')->actionsRemaining);
|
|
}
|
|
|
|
public function testMoveUpdatesUnitAndAppendsActionLogWithoutMutatingMatch(): void
|
|
{
|
|
$match = new MatchState(
|
|
new Battlefield(8, 8),
|
|
[
|
|
$this->unit('alpha-1', 'alpha', new Position(0, 0)),
|
|
$this->unit('bravo-1', 'bravo', new Position(7, 7)),
|
|
],
|
|
'alpha',
|
|
);
|
|
|
|
$next = (new CombatEngine())->move($match, 'alpha-1', new Position(2, 0));
|
|
|
|
self::assertSame('0:0', $match->unit('alpha-1')->position->key());
|
|
self::assertSame('2:0', $next->unit('alpha-1')->position->key());
|
|
self::assertSame(1, $next->unit('alpha-1')->actionsRemaining);
|
|
self::assertSame(['alpha-1 moved to 2:0'], $next->actionLog);
|
|
}
|
|
|
|
public function testMoveRejectsUnitFromInactiveTeam(): void
|
|
{
|
|
$match = new MatchState(
|
|
new Battlefield(8, 8),
|
|
[
|
|
$this->unit('alpha-1', 'alpha', new Position(0, 0)),
|
|
$this->unit('bravo-1', 'bravo', new Position(7, 7)),
|
|
],
|
|
'alpha',
|
|
);
|
|
|
|
$this->expectException(CombatException::class);
|
|
$this->expectExceptionMessage("It is not this unit's turn.");
|
|
|
|
(new CombatEngine())->move($match, 'bravo-1', new Position(6, 7));
|
|
}
|
|
|
|
public function testMoveRejectsOccupiedDestination(): void
|
|
{
|
|
$match = new MatchState(
|
|
new Battlefield(8, 8),
|
|
[
|
|
$this->unit('alpha-1', 'alpha', new Position(0, 0)),
|
|
$this->unit('alpha-2', 'alpha', new Position(1, 0)),
|
|
$this->unit('bravo-1', 'bravo', new Position(7, 7)),
|
|
],
|
|
'alpha',
|
|
);
|
|
|
|
$this->expectException(CombatException::class);
|
|
$this->expectExceptionMessage('Destination is not reachable.');
|
|
|
|
(new CombatEngine())->move($match, 'alpha-1', new Position(1, 0));
|
|
}
|
|
|
|
private function unit(string $id, string $team, Position $position): UnitState
|
|
{
|
|
return new UnitState($id, $team, $position, 10, 10, 4, 2, 4, 2);
|
|
}
|
|
}
|