policies = Mockery::mock(PolicyRepository::class); $this->versions = Mockery::mock(PolicyVersionRepository::class); $this->service = new PolicyService($this->policies, $this->versions); } public function testCreatePolicyInsertsPolicy(): void { $this->policies->shouldReceive('insert') ->once() ->with(Mockery::on(static fn (Policy $p): bool => $p->title === 'Cancellation' && $p->slug === 'cancellation')) ->andReturn(7); self::assertSame(7, $this->service->createPolicy('Cancellation', 'cancellation')); } public function testAddDraftVersionNumbersAfterLatest(): void { $this->versions->shouldReceive('maxVersionNumber')->once()->with(4)->andReturn(2); $this->versions->shouldReceive('insert') ->once() ->with(Mockery::on(static function (PolicyVersion $v): bool { return $v->policyId === 4 && $v->versionNumber === 3 && $v->status === PolicyVersion::STATUS_DRAFT; })) ->andReturn(15); self::assertSame(15, $this->service->addDraftVersion(4, '
draft
')); } public function testPublishArchivesPriorCurrentAndPointsPolicyAtNewVersion(): void { Functions\expect('current_time')->with('mysql')->andReturn('2026-06-01 12:00:00'); $this->policies->shouldReceive('findById')->once()->with(4)->andReturn(new Policy('T', 't', 8, id: 4)); $this->versions->shouldReceive('findById')->once()->with(9)->andReturn(new PolicyVersion(4, 2, 'x
', PolicyVersion::STATUS_DRAFT, null, 9)); $this->versions->shouldReceive('updateStatus')->once()->with(8, PolicyVersion::STATUS_ARCHIVED); $this->versions->shouldReceive('updateStatus')->once()->with(9, PolicyVersion::STATUS_PUBLISHED, '2026-06-01 12:00:00'); $this->policies->shouldReceive('updateCurrentVersion')->once()->with(4, 9)->andReturn(true); self::assertTrue($this->service->publishVersion(4, 9)); } public function testPublishFirstVersionDoesNotArchive(): void { Functions\expect('current_time')->andReturn('2026-06-01 12:00:00'); $this->policies->shouldReceive('findById')->once()->with(4)->andReturn(new Policy('T', 't', null, id: 4)); $this->versions->shouldReceive('findById')->once()->with(9)->andReturn(new PolicyVersion(4, 1, null, PolicyVersion::STATUS_DRAFT, null, 9)); // No archive call expected (no prior current version). $this->versions->shouldReceive('updateStatus')->once()->with(9, PolicyVersion::STATUS_PUBLISHED, '2026-06-01 12:00:00'); $this->policies->shouldReceive('updateCurrentVersion')->once()->with(4, 9)->andReturn(true); self::assertTrue($this->service->publishVersion(4, 9)); } public function testPublishRejectsVersionFromAnotherPolicy(): void { $this->policies->shouldReceive('findById')->once()->with(4)->andReturn(new Policy('T', 't', null, id: 4)); $this->versions->shouldReceive('findById')->once()->with(9)->andReturn(new PolicyVersion(99, 1, null, PolicyVersion::STATUS_DRAFT, null, 9)); // No status/current-version writes when the version belongs elsewhere. self::assertFalse($this->service->publishVersion(4, 9)); } }