em = self::getContainer()->get(EntityManagerInterface::class); } public function testItPersistsAStreamLinkedToItsScenarioAndBucket(): void { $scenario = new Scenario(); $scenario->setName('Household Budget'); $scenario->setOwner($this->persistOwner()); $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'); $scenario->setOwner($this->persistOwner()); $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.', ); } }