128 lines
4.3 KiB
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();
|
|
}
|
|
}
|