95 lines
3.3 KiB
PHP
95 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Service\Allocation;
|
|
|
|
use App\Entity\Bucket;
|
|
use App\Entity\Scenario;
|
|
use App\Enum\BucketAllocationType;
|
|
use App\Enum\BucketType;
|
|
use App\Service\Allocation\Result;
|
|
use PHPUnit\Framework\TestCase;
|
|
|
|
/**
|
|
* Unit tests for the Result value object.
|
|
*
|
|
* Pins Result as a DUMB HOLDER: it does not compute totalAllocated
|
|
* or unallocated itself. The constructor receives all three values directly
|
|
* and the getters return exactly what was passed in. Summing the allocation
|
|
* amounts is the Engine's responsibility, not the result object's
|
|
* (single responsibility — the engine knows the income amount and the fill
|
|
* rules; the result is a plain DTO carrying the engine's output).
|
|
*
|
|
* Pinned constructor:
|
|
* Result::__construct(array $allocations, int $totalAllocated, int $unallocated)
|
|
*
|
|
* Pinned shape (must match EngineTest's allocation entries):
|
|
* $allocations is list<array{bucket: Bucket, amount: int}>
|
|
*/
|
|
final class ResultTest extends TestCase
|
|
{
|
|
public function testGettersReturnConstructorValues(): void
|
|
{
|
|
$scenario = $this->makeScenario();
|
|
$bucketA = $this->makeBucket($scenario, priority: 1, name: 'Bucket A');
|
|
$bucketB = $this->makeBucket($scenario, priority: 2, name: 'Bucket B');
|
|
|
|
$allocations = [
|
|
['bucket' => $bucketA, 'amount' => 30000],
|
|
['bucket' => $bucketB, 'amount' => 20000],
|
|
];
|
|
|
|
$result = new Result($allocations, 50000, 0);
|
|
|
|
self::assertSame($allocations, $result->getAllocations());
|
|
self::assertSame(50000, $result->getTotalAllocated());
|
|
self::assertSame(0, $result->getUnallocated());
|
|
}
|
|
|
|
public function testEmptyAllocationsWithZeroTotals(): void
|
|
{
|
|
$result = new Result([], 0, 0);
|
|
|
|
self::assertSame([], $result->getAllocations());
|
|
self::assertSame(0, $result->getTotalAllocated());
|
|
self::assertSame(0, $result->getUnallocated());
|
|
}
|
|
|
|
public function testTotalsAreStoredNotComputedFromAllocations(): void
|
|
{
|
|
$scenario = $this->makeScenario();
|
|
$bucket = $this->makeBucket($scenario, priority: 1, name: 'Bucket A');
|
|
|
|
// Deliberately inconsistent: the allocation entry says 10000, but the
|
|
// constructor is told totalAllocated is 99999 and unallocated is 1.
|
|
// A dumb holder returns exactly what it was given, regardless of
|
|
// whether it matches the sum of $allocations.
|
|
$allocations = [
|
|
['bucket' => $bucket, 'amount' => 10000],
|
|
];
|
|
|
|
$result = new Result($allocations, 99999, 1);
|
|
|
|
self::assertSame($allocations, $result->getAllocations());
|
|
self::assertSame(99999, $result->getTotalAllocated());
|
|
self::assertSame(1, $result->getUnallocated());
|
|
}
|
|
|
|
private function makeScenario(): Scenario
|
|
{
|
|
return (new Scenario())
|
|
->setName('Household Budget');
|
|
}
|
|
|
|
private function makeBucket(Scenario $scenario, int $priority, string $name): Bucket
|
|
{
|
|
return (new Bucket())
|
|
->setScenario($scenario)
|
|
->setType(BucketType::NEED)
|
|
->setName($name)
|
|
->setPriority($priority)
|
|
->setAllocationType(BucketAllocationType::FIXED_LIMIT)
|
|
->setAllocationValue(50000)
|
|
->setStartingAmount(0)
|
|
->setBufferMultiplier('0.00');
|
|
}
|
|
}
|