manual block > scored > clean. * Score-vs-policy lands in M07; until then, anything not on a list is * `Clean`. */ final class EffectiveStatusServiceTest extends TestCase { public function testAllowlistWinsOverManualBlock(): void { $bin = IpAddress::fromString('198.51.100.5')->binary(); $factory = $this->factoryReturning(new CidrEvaluator( manualIpBins: [$bin], manualSubnets: [], allowlistIpBins: [$bin], allowlistSubnets: [], )); $service = new EffectiveStatusService($factory); self::assertSame( EffectiveStatus::Allowlisted, $service->forIp(IpAddress::fromString('198.51.100.5')) ); } public function testManualBlockReturnedWhenNotAllowlisted(): void { $bin = IpAddress::fromString('203.0.113.42')->binary(); $factory = $this->factoryReturning(new CidrEvaluator([$bin], [], [], [])); $service = new EffectiveStatusService($factory); self::assertSame( EffectiveStatus::ManuallyBlocked, $service->forIp(IpAddress::fromString('203.0.113.42')) ); } public function testIpInsideAllowlistedSubnetEvenWithSeparateManualBlockIsAllowlisted(): void { $allow = Cidr::fromString('203.0.113.0/24'); $factory = $this->factoryReturning(new CidrEvaluator( manualIpBins: [IpAddress::fromString('203.0.113.42')->binary()], manualSubnets: [], allowlistIpBins: [], allowlistSubnets: [$allow], )); $service = new EffectiveStatusService($factory); self::assertSame( EffectiveStatus::Allowlisted, $service->forIp(IpAddress::fromString('203.0.113.42')) ); } public function testCleanWhenNothingMatches(): void { $factory = $this->factoryReturning(new CidrEvaluator([], [], [], [])); $service = new EffectiveStatusService($factory); self::assertSame( EffectiveStatus::Clean, $service->forIp(IpAddress::fromString('203.0.113.99')) ); } private function factoryReturning(CidrEvaluator $evaluator): CidrEvaluatorFactory { return new class ($evaluator) extends CidrEvaluatorFactory { public function __construct(private readonly CidrEvaluator $fixed) { // Deliberately not calling parent::__construct — this stub // never queries the DB. } public function get(): CidrEvaluator { return $this->fixed; } public function invalidate(): void { // no-op } }; } }