container = Mockery::mock(Container::class); // Create attribute registry with test poll $this->attributeRegistry = new AttributeRegistry(); $this->testPoll = new DiscoveredAttribute( className: ClassName::create('App\\Test\\TestComponent'), attributeClass: Poll::class, target: AttributeTarget::METHOD, methodName: MethodName::create('checkData'), arguments: [ 'interval' => 2000, 'enabled' => true, 'event' => 'test.checked', 'stopOnError' => false ] ); $this->attributeRegistry->add(Poll::class, $this->testPoll); // Create discovery registry $this->discoveryRegistry = new DiscoveryRegistry( attributes: $this->attributeRegistry ); // Create service $this->pollService = new PollService( $this->discoveryRegistry, $this->container ); }); afterEach(function () { Mockery::close(); }); it('finds all polls from discovery registry', function () { $polls = $this->pollService->getAllPolls(); expect($polls)->toHaveCount(1); expect($polls[0]['poll'])->toBeInstanceOf(Poll::class); expect($polls[0]['discovered'])->toBeInstanceOf(DiscoveredAttribute::class); }); it('reconstructs poll attribute from arguments', function () { $polls = $this->pollService->getAllPolls(); $poll = $polls[0]['poll']; expect($poll->interval)->toBe(2000); expect($poll->enabled)->toBeTrue(); expect($poll->event)->toBe('test.checked'); expect($poll->stopOnError)->toBeFalse(); }); it('gets polls for specific class', function () { $polls = $this->pollService->getPollsForClass('App\\Test\\TestComponent'); expect($polls)->toHaveCount(1); expect($polls[0]['method'])->toBe('checkData'); expect($polls[0]['poll']->interval)->toBe(2000); }); it('returns empty array for class without polls', function () { $polls = $this->pollService->getPollsForClass('App\\Test\\NonExistent'); expect($polls)->toBeEmpty(); }); it('finds specific poll by class and method', function () { $poll = $this->pollService->findPoll( 'App\\Test\\TestComponent', 'checkData' ); expect($poll)->toBeInstanceOf(Poll::class); expect($poll->interval)->toBe(2000); }); it('returns null for non-existent poll', function () { $poll = $this->pollService->findPoll( 'App\\Test\\TestComponent', 'nonExistentMethod' ); expect($poll)->toBeNull(); }); it('checks if method is pollable', function () { expect($this->pollService->isPollable( 'App\\Test\\TestComponent', 'checkData' ))->toBeTrue(); expect($this->pollService->isPollable( 'App\\Test\\TestComponent', 'nonExistentMethod' ))->toBeFalse(); }); it('counts total polls', function () { expect($this->pollService->getPollCount())->toBe(1); }); it('gets only enabled polls', function () { // Add disabled poll $disabledPoll = new DiscoveredAttribute( className: ClassName::create('App\\Test\\DisabledComponent'), attributeClass: Poll::class, target: AttributeTarget::METHOD, methodName: MethodName::create('disabledMethod'), arguments: [ 'interval' => 1000, 'enabled' => false ] ); $this->attributeRegistry->add(Poll::class, $disabledPoll); $enabledPolls = $this->pollService->getEnabledPolls(); expect($enabledPolls)->toHaveCount(1); expect($enabledPolls[0]['poll']->enabled)->toBeTrue(); }); it('executes poll method via container', function () { $mockComponent = new class { public function checkData(): array { return ['status' => 'ok']; } }; $this->container->shouldReceive('get') ->with('App\\Test\\TestComponent') ->andReturn($mockComponent); $result = $this->pollService->executePoll( 'App\\Test\\TestComponent', 'checkData' ); expect($result)->toBe(['status' => 'ok']); }); it('throws exception for non-existent method', function () { $mockComponent = new class { // No checkData method }; $this->container->shouldReceive('get') ->with('App\\Test\\TestComponent') ->andReturn($mockComponent); $this->pollService->executePoll( 'App\\Test\\TestComponent', 'checkData' ); })->throws(BadMethodCallException::class); it('wraps execution errors', function () { $mockComponent = new class { public function checkData(): array { throw new RuntimeException('Internal error'); } }; $this->container->shouldReceive('get') ->with('App\\Test\\TestComponent') ->andReturn($mockComponent); $this->pollService->executePoll( 'App\\Test\\TestComponent', 'checkData' ); })->throws(RuntimeException::class, 'Failed to execute poll'); });