Files
BattleForge/tests/Unit/Domain/UnitStateTest.php
T

154 lines
4.9 KiB
PHP

<?php
declare(strict_types=1);
namespace BattleForge\Tests\Unit\Domain;
use BattleForge\Domain\Position;
use BattleForge\Domain\UnitState;
use InvalidArgumentException;
use PHPUnit\Framework\Attributes\DataProvider;
use PHPUnit\Framework\TestCase;
final class UnitStateTest extends TestCase
{
/**
* @param callable(): UnitState $createUnit
*/
#[DataProvider('invalidUnitProvider')]
public function testItRejectsInvalidConstructorArguments(callable $createUnit): void
{
$this->expectException(InvalidArgumentException::class);
$createUnit();
}
/**
* @return iterable<string, array{callable(): UnitState}>
*/
public static function invalidUnitProvider(): iterable
{
yield 'empty unit id' => [
static fn (): UnitState => new UnitState('', 'alpha', new Position(0, 0), 10, 10, 4, 2, 4, 2),
];
yield 'empty team id' => [
static fn (): UnitState => new UnitState('unit-1', '', new Position(0, 0), 10, 10, 4, 2, 4, 2),
];
yield 'zero maximum health' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 0, 0, 4, 2, 4, 2),
];
yield 'negative health' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, -1, 4, 2, 4, 2),
];
yield 'health above maximum' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 11, 4, 2, 4, 2),
];
yield 'negative attack' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 10, -1, 2, 4, 2),
];
yield 'negative defense' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 10, 4, -1, 4, 2),
];
yield 'zero speed' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 10, 4, 2, 0, 2),
];
yield 'negative actions remaining' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 10, 4, 2, 4, -1),
];
yield 'too many actions remaining' => [
static fn (): UnitState => new UnitState('unit-1', 'alpha', new Position(0, 0), 10, 10, 4, 2, 4, 3),
];
}
public function testItReportsWhetherItIsDefeated(): void
{
self::assertTrue($this->unit(health: 0)->isDefeated());
self::assertFalse($this->unit(health: 1)->isDefeated());
}
public function testMovingReturnsAChangedCopy(): void
{
$unit = $this->unit();
$moved = $unit->moveTo(new Position(2, 3));
self::assertNotSame($unit, $moved);
self::assertSame('0:0', $unit->position->key());
self::assertSame('2:3', $moved->position->key());
}
public function testSpendingAnActionReturnsAChangedCopyAndRejectsExhaustedUnits(): void
{
$unit = $this->unit(actionsRemaining: 1);
$spent = $unit->spendAction();
self::assertSame(1, $unit->actionsRemaining);
self::assertSame(0, $spent->actionsRemaining);
$this->expectException(InvalidArgumentException::class);
$spent->spendAction();
}
public function testDamageCannotReduceHealthBelowZero(): void
{
$unit = $this->unit(health: 3);
$damaged = $unit->takeDamage(5);
self::assertSame(3, $unit->health);
self::assertSame(0, $damaged->health);
}
public function testNegativeDamageIsANoOp(): void
{
$unit = $this->unit(health: 7);
$damaged = $unit->takeDamage(-3);
self::assertNotSame($unit, $damaged);
self::assertSame(7, $damaged->health);
}
public function testMarkingAttackedReturnsAChangedCopy(): void
{
$unit = $this->unit();
$attacked = $unit->markAttacked();
self::assertFalse($unit->hasAttacked);
self::assertTrue($attacked->hasAttacked);
}
public function testStartingTurnResetsALivingUnit(): void
{
$unit = $this->unit(actionsRemaining: 0, hasAttacked: true);
$started = $unit->startTurn();
self::assertNotSame($unit, $started);
self::assertSame(2, $started->actionsRemaining);
self::assertFalse($started->hasAttacked);
}
public function testStartingTurnReturnsTheSameDefeatedUnit(): void
{
$unit = $this->unit(health: 0, actionsRemaining: 0, hasAttacked: true);
self::assertSame($unit, $unit->startTurn());
}
private function unit(
int $health = 10,
int $actionsRemaining = 2,
bool $hasAttacked = false,
): UnitState {
return new UnitState(
'unit-1',
'alpha',
new Position(0, 0),
10,
$health,
4,
2,
4,
$actionsRemaining,
$hasAttacked,
);
}
}