ability('lit/a', true); $indirect = $this->ability('lit/b', false); $hidden = $this->ability('lit/c', true); $registry = new IntegrationRegistry( $this->integration('core', true, [$direct, $indirect]), $this->integration('divi', false, [$hidden]) ); self::assertSame(['core'], array_map(static fn ($i) => $i->id(), $registry->available())); self::assertSame([$direct, $indirect], $registry->abilities()); } public function testGroupsAbilitiesByIntegrationIdAndMapsNamesToGroups(): void { $guide = $this->ability('lit/guide', true); $outline = $this->ability('lit/divi-outline', true); $hidden = $this->ability('lit/pods-x', true); $divi = Mockery::mock(Integration::class); $divi->allows('id')->andReturn('divi'); $divi->allows('isAvailable')->andReturn(true); $divi->expects('abilities')->once()->andReturn([$outline]); $registry = new IntegrationRegistry( $this->integration('core', true, [$guide]), $divi, $this->integration('pods', false, [$hidden]) ); self::assertSame([$guide, $outline], $registry->abilities()); self::assertSame(['core' => [$guide], 'divi' => [$outline]], $registry->grouped()); self::assertSame(['lit/guide' => 'core', 'lit/divi-outline' => 'divi'], $registry->groupMap()); self::assertSame(['core', 'divi', 'pods'], $registry->ids()); } public function testLabelsOfTheAvailableIntegrations(): void { $core = $this->integration('core', true, []); $core->allows('label')->andReturn('Grundlagen'); $registry = new IntegrationRegistry($core, $this->integration('pods', false, [])); self::assertSame(['core' => 'Grundlagen'], $registry->labels()); } /** M9: the integrations own their admin labels (formerly hard-coded in ToolsTab). */ public function testEveryIntegrationNamesItsGroup(): void { Functions\stubTranslationFunctions(); $schema = Mockery::mock(ContentSchema::class); self::assertSame('Grundlagen', (new CoreIntegration(''))->label()); self::assertSame('WordPress', (new WordPressIntegration($schema, FakeChangeLog::forbidden()))->label()); self::assertSame('Medien', (new MediaIntegration($schema, FakeChangeLog::forbidden(), new Limits()))->label()); self::assertSame('Divi', (new DiviIntegration($schema, FakeChangeLog::forbidden()))->label()); } /** Integration-owned boot steps run once each, in registry order, whether or not the integration is available. */ public function testBootsEveryBootableIntegrationOnce(): void { $booted = []; $bootable = function (string $id, bool $available) use (&$booted): Integration { $integration = Mockery::mock(Integration::class . ', ' . Bootable::class); $integration->allows('id')->andReturn($id); $integration->allows('isAvailable')->andReturn($available); $integration->expects('abilities')->never(); $integration->expects('boot')->once()->andReturnUsing(static function () use (&$booted, $id): void { $booted[] = $id; }); return $integration; }; $registry = new IntegrationRegistry( $this->integration('core', true, []), $bootable('divi', false), $bootable('pods', true) ); $registry->boot(); $registry->boot(); self::assertSame(['divi', 'pods'], $booted); } public function testCompatibilitiesOfAllProvidersInRegistryOrderEvenUnavailable(): void { $first = new Profile(id: 'a', label: 'A', tier: Tier::ReportOnly, capabilities: []); $second = new Profile(id: 'b', label: 'B', tier: Tier::ReportOnly, capabilities: []); $provider = static function (string $id, bool $available, array $profiles): Integration { $integration = Mockery::mock(Integration::class . ', ' . ProvidesCompatibility::class); $integration->allows('id')->andReturn($id); $integration->allows('isAvailable')->andReturn($available); $integration->allows('compatibilities')->andReturn($profiles); return $integration; }; $registry = new IntegrationRegistry( $this->integration('core', true, []), $provider('x', false, [$first]), $provider('y', true, [$second]) ); self::assertSame([$first, $second], $registry->compatibilities()); self::assertSame(['a', 'b'], array_map( static fn (Profile $profile): string => $profile->id, $registry->compatibility()->profiles() )); self::assertSame($registry->compatibility(), $registry->compatibility(), 'one shared instance'); self::assertSame([], (new IntegrationRegistry($this->integration('core', true, [])))->compatibilities()); } private function ability(string $name, bool $direct): Ability { $ability = Mockery::mock(Ability::class); $ability->allows('name')->andReturn($name); $ability->allows('isDirect')->andReturn($direct); return $ability; } /** @param list $abilities */ private function integration(string $id, bool $available, array $abilities): Integration { $integration = Mockery::mock(Integration::class); $integration->allows('id')->andReturn($id); $integration->allows('isAvailable')->andReturn($available); $integration->allows('abilities')->andReturn($abilities); return $integration; } }