container = new DefaultContainer(); $this->container->instance(MethodInvoker::class, new MethodInvoker( $this->container, new SimpleReflectionService() )); $this->discoveryRegistry = new DiscoveryRegistry( attributes: new AttributeRegistry() ); $callbackExecutor = new CallbackExecutor($this->container); $this->runner = new AttributeRunner( discoveryRegistry: $this->discoveryRegistry, container: $this->container, callbackExecutor: $callbackExecutor ); $this->extractor = new CallbackMetadataExtractor(); } public function testPatternAHandlerWorkflow(): void { // Pattern A: Handler-Klasse $metadata = $this->extractor->extract([PermissionGuard::class, [['edit_post']]]); $this->assertEquals(\App\Framework\Attributes\Execution\CallbackType::HANDLER, $metadata->callbackType); $this->assertEquals(PermissionGuard::class, $metadata->class); $this->assertTrue($metadata->isCacheable()); // Test Serialisierung $array = $metadata->toArray(); $restored = \App\Framework\Attributes\Execution\CallbackMetadata::fromArray($array); $this->assertEquals($metadata->callbackType, $restored->callbackType); } public function testPatternBStaticMethodWorkflow(): void { // Pattern B: First-Class Callable $metadata = $this->extractor->extract([UserPolicies::class, 'isAdmin']); $this->assertEquals(\App\Framework\Attributes\Execution\CallbackType::STATIC_METHOD, $metadata->callbackType); $this->assertEquals(UserPolicies::class, $metadata->class); $this->assertEquals('isAdmin', $metadata->method); $this->assertTrue($metadata->isCacheable()); // Test Ausführung $context = AttributeExecutionContext::forClass( $this->container, ClassName::create('TestClass') ); $executor = new CallbackExecutor($this->container); $result = $executor->execute($metadata, $context); $this->assertIsBool($result); } public function testPatternCFactoryWorkflow(): void { // Pattern C: Closure-Factory // Für Factory-Pattern müssen wir die Factory-Methode explizit identifizieren $metadata = $this->extractor->extractFromFactoryCall( Policies::class, 'requirePermission', ['edit_post'] ); $this->assertEquals(\App\Framework\Attributes\Execution\CallbackType::FACTORY, $metadata->callbackType); $this->assertEquals(Policies::class, $metadata->class); $this->assertEquals('requirePermission', $metadata->method); $this->assertEquals(['edit_post'], $metadata->args); $this->assertTrue($metadata->isCacheable()); // Test Ausführung $context = AttributeExecutionContext::forClass( $this->container, ClassName::create('TestClass') ); $executor = new CallbackExecutor($this->container); $closure = $executor->execute($metadata, $context); $this->assertInstanceOf(\Closure::class, $closure); $result = $closure($context); $this->assertIsBool($result); } public function testDiscoveredAttributeCallbackMetadataExtraction(): void { $discovered = new DiscoveredAttribute( className: ClassName::create('TestClass'), attributeClass: Guard::class, target: AttributeTarget::TARGET_CLASS, arguments: [PermissionGuard::class, [['edit_post']]] ); $metadata = $discovered->getCallbackMetadata(); $this->assertNotNull($metadata); $this->assertEquals(\App\Framework\Attributes\Execution\CallbackType::HANDLER, $metadata->callbackType); } public function testCacheSerializationRoundTrip(): void { $discovered = new DiscoveredAttribute( className: ClassName::create('TestClass'), attributeClass: Guard::class, target: AttributeTarget::TARGET_CLASS, arguments: [PermissionGuard::class, [['edit_post']]] ); // Serialisiere $array = $discovered->toArray(); // Deserialisiere $restored = DiscoveredAttribute::fromArray($array); // Prüfe dass Callback-Metadata erhalten bleibt $originalMetadata = $discovered->getCallbackMetadata(); $restoredMetadata = $restored->getCallbackMetadata(); $this->assertNotNull($originalMetadata); $this->assertNotNull($restoredMetadata); $this->assertEquals($originalMetadata->callbackType, $restoredMetadata->callbackType); $this->assertEquals($originalMetadata->class, $restoredMetadata->class); } }