allows('name')->andReturn($name); $ability->allows('isDirect')->andReturn(false); return $ability; }, $names); $integration = Mockery::mock(Integration::class); $integration->allows('id')->andReturn('divi'); $integration->allows('isAvailable')->andReturn(true); $integration->allows('abilities')->andReturn($abilities); return new IntegrationRegistry($integration); } /** The temporal coupling of the former use-by-reference closures: they answered false until Plugin set $policy. */ public function testAQuestionBeforeBindIsAWiringErrorNotFalse(): void { $tools = new ToolAvailability(); foreach ([ static fn (): bool => $tools->groupEnabled('divi-library'), static fn (): bool => $tools->groupWritable('divi-library'), static fn (): bool => $tools->allows('lit/divi-insert'), ] as $ask) { try { $ask(); self::fail('answered before bind()'); } catch (LogicException $e) { self::assertSame('ToolAvailability asked before Plugin bound it.', $e->getMessage()); } } } /** A gate built before bind() (as DiviIntegration builds its gates) answers from the policy bound later. */ public function testAGateBuiltBeforeBindResolvesLazily(): void { $tools = new ToolAvailability(); $libraryVisible = static fn (): bool => $tools->groupEnabled('divi-library'); $libraryWritable = static fn (): bool => $tools->groupWritable('divi-library'); $diviWritable = static fn (): bool => $tools->allows('lit/divi-insert'); $tools->bind(self::registry('lit/divi-insert'), new ExposurePolicy(['@readonly:divi-library' => true])); self::assertTrue($libraryVisible()); self::assertFalse($libraryWritable()); self::assertTrue($diviWritable()); } public function testFollowsTheBoundPolicy(): void { $tools = new ToolAvailability(); $tools->bind( self::registry('lit/divi-insert', 'lit/library-insert'), new ExposurePolicy([ '@group:divi-theme-builder' => ExposurePolicy::DISABLED, 'lit/library-insert' => ExposurePolicy::DISABLED, ]) ); self::assertFalse($tools->groupEnabled('divi-theme-builder')); self::assertFalse($tools->groupWritable('divi-theme-builder')); self::assertTrue($tools->groupEnabled('divi-library')); self::assertTrue($tools->groupWritable('divi-library')); self::assertTrue($tools->allows('lit/divi-insert')); self::assertFalse($tools->allows('lit/library-insert')); self::assertFalse($tools->allows('lit/unknown'), 'not registered = not allowed (ExposurePolicy::allows)'); } public function testBindsOnlyOnce(): void { $tools = new ToolAvailability(); $tools->bind(self::registry(), new ExposurePolicy()); $this->expectException(LogicException::class); $this->expectExceptionMessage('ToolAvailability is already bound.'); $tools->bind(self::registry(), new ExposurePolicy()); } }