Beacon/tests/Integration/DiscoveryIntegrationTest.php

134 lines
3.8 KiB
PHP

<?php
declare(strict_types=1);
namespace Phred\Beacon\Tests\Integration;
use PHPUnit\Framework\TestCase;
use Phred\Beacon\AsEventListener;
use Phred\Beacon\AsSubscriber;
use Phred\Beacon\EventDispatcher;
use Phred\Beacon\ListenerDiscovery;
use Phred\Beacon\ListenerProvider;
use Phred\BeaconContracts\SubscriberInterface;
use Psr\Container\ContainerInterface;
class DiscoveryIntegrationTest extends TestCase
{
private string $tempDir;
protected function setUp(): void
{
$this->tempDir = sys_get_temp_dir() . '/beacon_discovery_test_' . uniqid();
mkdir($this->tempDir);
}
protected function tearDown(): void
{
$this->removeDir($this->tempDir);
}
public function test_it_discovers_attributed_listeners(): void
{
$this->createTestClass('TestListener', <<<'PHP'
namespace Phred\Discovery;
use Phred\Beacon\AsEventListener;
class TestListener {
#[AsEventListener(event: 'stdClass', priority: 10)]
public function onEvent($event): void { $event->called = true; }
}
PHP
);
$provider = new ListenerProvider();
$discovery = new ListenerDiscovery([$this->tempDir]);
$discovery->discover($provider);
$dispatcher = new EventDispatcher($provider);
$event = new \stdClass();
$event->called = false;
$dispatcher->dispatch($event);
$this->assertTrue($event->called);
}
public function test_it_discovers_subscribers(): void
{
$this->createTestClass('TestSubscriber', <<<'PHP'
namespace Phred\Discovery;
use Phred\Beacon\AsSubscriber;
use Phred\BeaconContracts\SubscriberInterface;
#[AsSubscriber]
class TestSubscriber implements SubscriberInterface {
public static function getSubscribedEvents(): array {
return ['stdClass' => 'onEvent'];
}
public function onEvent($event): void { $event->sub_called = true; }
}
PHP
);
$provider = new ListenerProvider();
$discovery = new ListenerDiscovery([$this->tempDir]);
$discovery->discover($provider);
$dispatcher = new EventDispatcher($provider);
$event = new \stdClass();
$event->sub_called = false;
$dispatcher->dispatch($event);
$this->assertTrue($event->sub_called);
}
public function test_lazy_loading_via_container(): void
{
$this->createTestClass('LazyListener', <<<'PHP'
namespace Phred\Discovery;
use Phred\Beacon\AsEventListener;
class LazyListener {
#[AsEventListener(event: 'stdClass')]
public function __invoke($event): void { $event->lazy_called = true; }
}
PHP
);
$container = $this->createMock(ContainerInterface::class);
$container->expects($this->once())
->method('get')
->with('Phred\Discovery\LazyListener')
->willReturn(new class {
public function __invoke($event) { $event->lazy_called = true; }
});
$provider = new ListenerProvider($container);
$discovery = new ListenerDiscovery([$this->tempDir]);
$discovery->discover($provider);
$dispatcher = new EventDispatcher($provider);
$event = new \stdClass();
$event->lazy_called = false;
$dispatcher->dispatch($event);
$this->assertTrue($event->lazy_called);
}
private function createTestClass(string $name, string $content): void
{
file_put_contents($this->tempDir . '/' . $name . '.php', "<?php\n" . $content);
require_once $this->tempDir . '/' . $name . '.php';
}
private function removeDir(string $dir): void
{
$files = array_diff(scandir($dir), ['.', '..']);
foreach ($files as $file) {
$path = $dir . '/' . $file;
is_dir($path) ? $this->removeDir($path) : unlink($path);
}
rmdir($dir);
}
}