test/EventDispatcherTest.php
<?php
/**
* test Event Dispatcher class
*
* @package BlueEvent
* @subpackage Test
* @author MichaĆ Adamiak <chajr@bluetree.pl>
* @copyright chajr/bluetree
*/
namespace BlueEventTest;
use BlueEvent\Event\Base\Interfaces\EventInterface;
use BlueEvent\Event\Base\EventDispatcher;
use PHPUnit\Framework\TestCase;
class EventDispatcherTest extends TestCase
{
/**
* name of test event log file
*/
const EVENT_LOG_NAME = '/debug.log';
/**
* store information that even was triggered
*
* @var bool
*/
public static $eventTriggered = 0;
/**
* store generated log file path
*
* @var string
*/
protected $logPath;
/**
* actions launched before test starts
*/
protected function setUp(): void
{
$this->logPath = __DIR__ . '/log';
$this->clearLog();
}
/**
* test event initialize
*
* @param array $options
* @dataProvider configDataProvider
*/
public function testEventCreation($options)
{
$instance = new EventDispatcher;
$this->assertInstanceOf('BlueEvent\Event\Base\EventDispatcher', $instance);
$this->assertFalse($instance->hasErrors());
$instance = new EventDispatcher($options);
$this->assertEquals($options['events'], $instance->getEventConfiguration());
}
/**
* test read configuration
*
* @param array $options
* @dataProvider configDataProvider
*/
public function testSetEventDispatcherConfiguration($options)
{
$eventDispatcher = new EventDispatcher;
$eventDispatcher->setEventConfiguration($options['events']);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
$eventDispatcher->setEventConfiguration([
'test_event_code' => [
'listeners' => [
'newListener'
]
]
]);
$options['events']['test_event_code']['listeners'][] = 'newListener';
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
unset($options['events']['test_event_code']['listeners'][3]);
$eventDispatcher = new EventDispatcher;
$eventDispatcher->readEventConfiguration(
$this->getEventFileConfigPath('array'),
'array'
);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
$eventDispatcher = new EventDispatcher;
$eventDispatcher->readEventConfiguration(
$this->getEventFileConfigPath('json'),
'json'
);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
$eventDispatcher = new EventDispatcher;
$eventDispatcher->readEventConfiguration(
$this->getEventFileConfigPath('ini'),
'ini'
);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
$eventDispatcher = new EventDispatcher(
[
'from_file' => $this->getEventFileConfigPath('xml'),
'type' => 'xml'
]
);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
$eventDispatcher = new EventDispatcher(
[
'from_file' => $this->getEventFileConfigPath('yaml'),
'type' => 'yaml'
]
);
$this->assertEquals($options['events'], $eventDispatcher->getEventConfiguration());
}
/**
* check for error if configuration file don't exists
*/
public function testTryToLoadConfigFromMissingFile(): void
{
$this->expectException(\InvalidArgumentException::class);
$eventDispatcher = new EventDispatcher();
$eventDispatcher->readEventConfiguration(
$this->getEventFileConfigPath('txt'),
'txt'
);
}
public function testTryToLoadConfigWithIncorrectType(): void
{
$this->expectExceptionMessage("Incorrect configuration type: incorrect");
$this->expectException(\InvalidArgumentException::class);
$eventDispatcher = new EventDispatcher();
$eventDispatcher->readEventConfiguration(
$this->getEventFileConfigPath('incorrect'),
'incorrect'
);
}
/**
* test that event is called correctly
*/
public function testTriggerEvent()
{
$instance = new EventDispatcher;
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::trigger',
function ($event) {
/** @var $event \BlueEvent\Event\BaseEvent */
self::$eventTriggered += $event->getEventParameters()['value'];
}
]
],
]);
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertEquals(3, self::$eventTriggered);
}
public function testTriggerNoneExistingEvent()
{
$instance = new EventDispatcher;
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertEquals(3, self::$eventTriggered);
}
/**
* test trigger event with stop propagation before next listener
*/
public function testTriggerWithStopPropagation()
{
$instance = new EventDispatcher;
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::triggerStop',
function ($event) {
/** @var $event \BlueEvent\Event\BaseEvent */
self::$eventTriggered += $event->getEventParameters()['value'];
}
]
],
]);
$this->assertEquals(3, self::$eventTriggered);
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertEquals(4, self::$eventTriggered);
}
public function testAddListenerForNoneExistingKey()
{
$instance = new EventDispatcher;
$instance->addEventListener(
'test_event',
[
function ($event) {
/** @var $event \BlueEvent\Event\BaseEvent */
self::$eventTriggered += $event->getEventParameters()['value'];
}
]
);
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertEquals(8, self::$eventTriggered);
}
/**
* test dynamically add new listener or listeners for given event name
*/
public function testAddListenerAndTriggerEvent()
{
$instance = new EventDispatcher;
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::trigger'
]
],
]);
$instance->addEventListener(
'test_event',
[
function ($event) {
/** @var $event \BlueEvent\Event\BaseEvent */
self::$eventTriggered += $event->getEventParameters()['value'];
}
]
);
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertEquals(11, self::$eventTriggered);
}
/**
* test trigger event with exception
*/
public function testTriggerEventWithError()
{
$instance = new EventDispatcher;
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::triggerError',
]
],
]);
$this->assertFalse($instance->hasErrors());
$this->assertEquals([], $instance->getErrors());
$instance->triggerEvent('test_event');
$this->assertTrue($instance->hasErrors());
$this->assertEquals(
'Test error',
$instance->getErrors()[0]['message']
);
$instance->clearErrors();
$this->assertFalse($instance->hasErrors());
$this->assertEquals([], $instance->getErrors());
}
/**
* check for error if invalid object was declared as listener
*/
public function testGetInvalidEventObject(): void
{
$this->expectException(\LogicException::class);
$instance = new EventDispatcher();
$instance->setEventConfiguration([
'invalid_object_event' => [
'object' => InvalidEventObject::class,
'listeners' => []
],
]);
$instance->triggerEvent('invalid_object_event');
}
/**
* test that event log can be enabled/disabled
*/
public function testGetConfiguration()
{
$instance = new EventDispatcher;
$this->assertEquals(
[
'type' => 'array',
'log_events' => false,
'log_all_events' => true,
'from_file' => false,
'log_object' => false,
'log_config' => [
'log_path' => './log',
'level' => 'debug',
'storage' => \SimpleLog\Storage\File::class,
],
'events' => [],
],
$instance->getConfiguration()
);
}
/**
* test that event log can be enabled/disabled
*/
public function testEnableAndDisableEventLog()
{
$instance = new EventDispatcher;
$this->assertFalse($instance->getConfiguration('log_events'));
$instance->setEventLog(false);
$this->assertFalse($instance->getConfiguration('log_events'));
$instance->setEventLog(true);
$this->assertTrue($instance->getConfiguration('log_events'));
$instance = new EventDispatcher([
'log_events' => true
]);
$this->assertTrue($instance->getConfiguration('log_events'));
$instance->setEventLog(false);
$this->assertFalse($instance->getConfiguration('log_events'));
}
/**
* test that log file was created correctly
*/
public function testEventLog(): void
{
$instance = new EventDispatcher([
'log_events' => true,
'log_config' => ['log_path' => $this->logPath],
]);
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
[__CLASS__, 'trigger'],
'BlueEventTest\EventDispatcherTest::triggerError',
function () {
}
]
],
]);
$this->assertFileDoesNotExist($this->logPath . self::EVENT_LOG_NAME);
$instance->triggerEvent('test_event');
$this->assertFileExists($this->logPath . self::EVENT_LOG_NAME);
}
/**
* check calling additional log object and listener as array
*/
public function testEventLogWithExternalObjects()
{
$instance = new EventDispatcher([
'log_all_events' => true,
'log_path' => $this->logPath,
'log_object' => new \SimpleLog\Log,
]);
$instance->setEventLog(true);
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
[new self, 'trigger']
]
],
]);
$instance->triggerEvent('test_event');
$this->assertFileExists($this->logPath);
}
/**
* test log event with direct given all events
*/
public function testEventLogWithGivenEvents()
{
$instance = new EventDispatcher([
'log_path' => $this->logPath
]);
$instance->setEventLog(true)->logAllEvents();
$this->assertTrue($instance->getConfiguration('log_all_events'));
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::trigger',
]
],
]);
$instance->triggerEvent('test_event');
$this->assertFileExists($this->logPath);
}
/**
* test log event with direct given specified event key
*/
public function testEventLogWithSpecifiedEvents()
{
$instance = new EventDispatcher([
'log_path' => $this->logPath,
'log_all_events' => false
]);
$instance->setEventLog(true);
$instance->logEvent(['test_event']);
$instance->setEventConfiguration([
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'BlueEventTest\EventDispatcherTest::trigger',
]
],
]);
$this->assertEquals(
['test_event'],
$instance->getAllEventsToLog()
);
$instance->triggerEvent('test_event');
$this->assertFileExists($this->logPath);
}
/**
* config data for test
*
* @return array
*/
public function configDataProvider()
{
return [
[
'options' => [
'type' => 'array',
'from_file' => false,
'events' => [
'test_event_code' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
'ClassOne::method',
'ClassSecond::method',
'someFunction',
]
]
],
]
]
];
}
/**
* config data for test from file
*
* @param string $type
* @return string
*/
public function getEventFileConfigPath($type)
{
$extension = $type;
if ($type === 'array') {
$extension = 'php';
}
return __DIR__ . '/Config/testConfig/config.' . $extension;
}
/**
* method to test event triggering
*/
public static function trigger()
{
self::$eventTriggered++;
}
/**
* method to test event triggering
*
* @throws \Exception
*/
public static function triggerError()
{
throw new \Exception('Test error');
}
/**
* method to test event triggering
*
* @param EventInterface $event
*/
public static function triggerStop(EventInterface $event)
{
$event->stopPropagation();
self::$eventTriggered++;
}
/**
* test that event is called correctly
*/
public function testTriggerMultipleEvents()
{
$testData = [];
$instance = new EventDispatcher(['events' => [
'test_event' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
function ($event) use (&$testData) {
/** @var $event \BlueEvent\Event\BaseEvent */
$testData['test_event'] = $event->getEventParameters();
}
]
],
'test_event_other' => [
'object' => 'BlueEvent\Event\BaseEvent',
'listeners' => [
function ($event) use (&$testData) {
/** @var $event \BlueEvent\Event\BaseEvent */
$testData['test_event_other'] = $event->getEventParameters();
}
]
],
]]);
$instance->triggerEvent('test_event', ['value' => 2]);
$this->assertArrayHasKey('test_event', $testData);
$this->assertEquals(
['value' => 2],
$testData['test_event']
);
$instance->triggerEvent('test_event_other', ['value' => 5]);
$this->assertArrayHasKey('test_event_other', $testData);
$this->assertEquals(
['value' => 5],
$testData['test_event_other']
);
}
protected function clearLog()
{
$logFile = $this->logPath . self::EVENT_LOG_NAME;
if (file_exists($logFile)) {
unlink($logFile);
}
}
/**
* actions launched after test was finished
*/
protected function tearDown(): void
{
$this->clearLog();
}
}