buckets/tests/Entity/BucketPersistenceTest.php

128 lines
4.3 KiB
PHP

<?php
namespace App\Tests\Entity;
use App\Entity\Bucket;
use App\Entity\Scenario;
use App\Enum\BucketAllocationType;
use App\Enum\BucketType;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
final class BucketPersistenceTest extends KernelTestCase
{
private EntityManagerInterface $em;
protected function setUp(): void
{
self::bootKernel();
$this->em = self::getContainer()->get(EntityManagerInterface::class);
}
public function testItPersistsABucketLinkedToItsScenario(): void
{
$scenario = new Scenario();
$scenario->setName('Household Budget');
$this->em->persist($scenario);
$this->em->flush();
$scenarioId = $scenario->getId();
$bucket = new Bucket();
$bucket->setScenario($scenario);
$bucket->setType(BucketType::NEED);
$bucket->setName('Rent');
$bucket->setPriority(3);
$bucket->setSortOrder(2);
$bucket->setAllocationType(BucketAllocationType::FIXED_LIMIT);
$bucket->setAllocationValue(150000);
$bucket->setStartingAmount(5000);
$bucket->setBufferMultiplier('1.50');
$this->em->persist($bucket);
$this->em->flush();
$bucketId = $bucket->getId();
$this->em->clear();
$reloaded = $this->em->find(Bucket::class, $bucketId);
self::assertNotNull($reloaded, 'Bucket must be retrievable from the database after an identity-map clear.');
self::assertInstanceOf(Scenario::class, $reloaded->getScenario());
self::assertSame(
(string) $scenarioId,
(string) $reloaded->getScenario()->getId(),
'Reloaded bucket must be linked to the same scenario it was persisted with.',
);
self::assertInstanceOf(
BucketType::class,
$reloaded->getType(),
'type must hydrate as a BucketType enum instance, not a raw string.',
);
self::assertSame(BucketType::NEED, $reloaded->getType());
self::assertSame('Rent', $reloaded->getName());
self::assertSame(3, $reloaded->getPriority());
self::assertSame(2, $reloaded->getSortOrder());
self::assertInstanceOf(
BucketAllocationType::class,
$reloaded->getAllocationType(),
'allocation_type must hydrate as a BucketAllocationType enum instance, not a raw string.',
);
self::assertSame(BucketAllocationType::FIXED_LIMIT, $reloaded->getAllocationType());
self::assertSame(
150000,
$reloaded->getAllocationValue(),
'allocation_value must round-trip as an int (cents), not a string or float.',
);
self::assertSame(5000, $reloaded->getStartingAmount());
self::assertSame(
'1.50',
$reloaded->getBufferMultiplier(),
'buffer_multiplier is a Doctrine decimal column — it hydrates as a numeric string, not a float (precision-safe).',
);
}
public function testScenarioPriorityUniquenessIsEnforced(): void
{
$scenario = new Scenario();
$scenario->setName('Household Budget');
$this->em->persist($scenario);
$this->em->flush();
$first = new Bucket();
$first->setScenario($scenario);
$first->setType(BucketType::NEED);
$first->setName('Rent');
$first->setPriority(3);
$first->setSortOrder(1);
$first->setAllocationType(BucketAllocationType::FIXED_LIMIT);
$first->setAllocationValue(150000);
$first->setStartingAmount(5000);
$first->setBufferMultiplier('0.00');
$this->em->persist($first);
$this->em->flush();
$second = new Bucket();
$second->setScenario($scenario);
$second->setType(BucketType::NEED);
$second->setName('Utilities');
$second->setPriority(3);
$second->setSortOrder(2);
$second->setAllocationType(BucketAllocationType::FIXED_LIMIT);
$second->setAllocationValue(50000);
$second->setStartingAmount(3000);
$second->setBufferMultiplier('0.00');
$this->em->persist($second);
$this->expectException(UniqueConstraintViolationException::class);
$this->em->flush();
}
}