buckets/tests/Entity/StreamPersistenceTest.php

159 lines
5.2 KiB
PHP
Raw Normal View History

<?php
namespace App\Tests\Entity;
use App\Entity\Bucket;
use App\Entity\Scenario;
use App\Entity\Stream;
use App\Enum\BucketAllocationType;
use App\Enum\BucketType;
use App\Enum\StreamFrequency;
use App\Enum\StreamType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase;
final class StreamPersistenceTest extends KernelTestCase
{
private EntityManagerInterface $em;
protected function setUp(): void
{
self::bootKernel();
$this->em = self::getContainer()->get(EntityManagerInterface::class);
}
public function testItPersistsAStreamLinkedToItsScenarioAndBucket(): void
{
$scenario = new Scenario();
$scenario->setName('Household Budget');
$this->em->persist($scenario);
$bucket = new Bucket();
$bucket->setScenario($scenario);
$bucket->setType(BucketType::NEED);
$bucket->setName('Rent');
$bucket->setPriority(1);
$bucket->setSortOrder(0);
$bucket->setAllocationType(BucketAllocationType::FIXED_LIMIT);
$bucket->setAllocationValue(150000);
$bucket->setStartingAmount(0);
$bucket->setBufferMultiplier('0.00');
$this->em->persist($bucket);
$this->em->flush();
$scenarioId = $scenario->getId();
$bucketId = $bucket->getId();
$stream = new Stream();
$stream->setScenario($scenario);
$stream->setBucket($bucket);
$stream->setName('Paycheck');
$stream->setAmount(250000);
$stream->setType(StreamType::INCOME);
$stream->setFrequency(StreamFrequency::BIWEEKLY);
$stream->setStartDate(new \DateTimeImmutable('2026-01-01'));
$stream->setEndDate(new \DateTimeImmutable('2026-12-31'));
$stream->setIsActive(true);
$stream->setDescription('Primary employer income.');
$this->em->persist($stream);
$this->em->flush();
$streamId = $stream->getId();
$this->em->clear();
$reloaded = $this->em->find(Stream::class, $streamId);
self::assertNotNull($reloaded, 'Stream 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 stream must be linked to the same scenario it was persisted with.',
);
self::assertInstanceOf(Bucket::class, $reloaded->getBucket());
self::assertSame(
(string) $bucketId,
(string) $reloaded->getBucket()->getId(),
'Reloaded stream must be linked to the same bucket it was persisted with.',
);
self::assertSame('Paycheck', $reloaded->getName());
self::assertSame(
250000,
$reloaded->getAmount(),
'amount must round-trip as an int (cents), not a string or float.',
);
self::assertInstanceOf(
StreamType::class,
$reloaded->getType(),
'type must hydrate as a StreamType enum instance, not a raw string.',
);
self::assertSame(StreamType::INCOME, $reloaded->getType());
self::assertInstanceOf(
StreamFrequency::class,
$reloaded->getFrequency(),
'frequency must hydrate as a StreamFrequency enum instance, not a raw string.',
);
self::assertSame(StreamFrequency::BIWEEKLY, $reloaded->getFrequency());
self::assertInstanceOf(\DateTimeImmutable::class, $reloaded->getStartDate());
self::assertSame('2026-01-01', $reloaded->getStartDate()->format('Y-m-d'));
self::assertInstanceOf(\DateTimeImmutable::class, $reloaded->getEndDate());
self::assertSame('2026-12-31', $reloaded->getEndDate()->format('Y-m-d'));
self::assertTrue($reloaded->isActive());
self::assertSame('Primary employer income.', $reloaded->getDescription());
}
public function testItPersistsAStreamWithoutABucket(): void
{
$scenario = new Scenario();
$scenario->setName('Household Budget');
$this->em->persist($scenario);
$this->em->flush();
$stream = new Stream();
$stream->setScenario($scenario);
$stream->setName('Freelance Income');
$stream->setAmount(50000);
$stream->setType(StreamType::INCOME);
$stream->setFrequency(StreamFrequency::MONTHLY);
$stream->setStartDate(new \DateTimeImmutable('2026-02-01'));
$this->em->persist($stream);
$this->em->flush();
$streamId = $stream->getId();
$this->em->clear();
$reloaded = $this->em->find(Stream::class, $streamId);
self::assertNotNull($reloaded, 'Stream must be retrievable from the database after an identity-map clear.');
self::assertNull(
$reloaded->getBucket(),
'bucket must be nullable — a stream is not required to link to a bucket.',
);
self::assertNull(
$reloaded->getEndDate(),
'end_date must be nullable when not explicitly set.',
);
self::assertTrue(
$reloaded->isActive(),
'is_active must default to true when setIsActive() is never called.',
);
}
}