createMock(LoggerInterface::class); $sut = new FeatureFlagManager([], $logger); $this->assertFalse($sut->isFeatureActive('UnknownFeature')); } public function testIsFeatureActiveLogsDebugMessageIfFeatureNotFound() { $logger = $this->createMock(LoggerInterface::class); $logger->expects($this->once()) ->method('debug') ->with('isFeatureActive failed due to class not implementing FeatureFlagInterface', [ 'featureFlag' => 'UnknownFeature', ]); $sut = new FeatureFlagManager([], $logger); $sut->isFeatureActive('UnknownFeature'); } /** * @dataProvider listOfStorages */ public function testIsFeatureActiveOverridesBasedOnOrderOfStorage(array $storageResponses, bool $expectedOutcome): void { $storages = []; $logger = $this->createMock(LoggerInterface::class); foreach ($storageResponses as $storageResponse) { $mock = $this->createMock(FeatureFlagStorageInterface::class); $mock->method('isFeatureActive')->willReturn($storageResponse); $storages[] = $mock; } $mockFeature = $this->createMock(FeatureFlagInterface::class); $sut = new FeatureFlagManager( $storages, $logger ); $this->assertEquals($expectedOutcome, $sut->isFeatureActive(get_class($mockFeature))); } public function testIsFeatureActiveReturnsForcedStateWithoutConsultingStorages(): void { $storage = $this->createMock(FeatureFlagStorageInterface::class); $storage->expects($this->never())->method('isFeatureActive'); $logger = $this->createMock(LoggerInterface::class); $sut = new FeatureFlagManager([$storage], $logger); $featureFlag = new class () implements FeatureFlagInterface, ForcedFeatureFlagStateInterface { public function getName(): string { return 'ForcedEnabledFeature'; } public function getForcedFeatureFlagState(): bool { return true; } }; $this->assertTrue($sut->isFeatureActive(get_class($featureFlag))); } public function listOfStorages(): \Generator { yield [ [ // The return values for isFeatureActive on the storage true, false, true, ], // Expected outcome true, ]; yield [ [ // The return values for isFeatureActive on the storage false, null, false, ], // Expected outcome false, ]; yield [ [ // The return values for isFeatureActive on the storage null, null, true, ], // Expected outcome true, ]; yield [ [ // The return values for isFeatureActive on the storage true, true, false, ], // Expected outcome false, ]; yield [ [ // The return values for isFeatureActive on the storage true, true, null, ], // Expected outcome true, ]; yield [ [], // Expected outcome false, ]; } }