init(); Flight::eventDispatcher()->resetInstance(); // Clear any existing listeners } /** * Test registering and triggering a single listener. */ public function testRegisterAndTriggerSingleListener() { $called = false; Flight::onEvent('test.event', function () use (&$called) { $called = true; }); Flight::triggerEvent('test.event'); $this->assertTrue($called, 'Single listener should be called when event is triggered.'); } /** * Test registering multiple listeners for the same event. */ public function testRegisterMultipleListeners() { $counter = 0; Flight::onEvent('test.event', function () use (&$counter) { $counter++; }); Flight::onEvent('test.event', function () use (&$counter) { $counter++; }); Flight::triggerEvent('test.event'); $this->assertEquals(2, $counter, 'All registered listeners should be called.'); } /** * Test triggering an event with no listeners registered. */ public function testTriggerWithNoListeners() { // Should not throw any errors Flight::triggerEvent('non.existent.event'); $this->assertTrue(true, 'Triggering an event with no listeners should not throw an error.'); } /** * Test that a listener receives a single argument correctly. */ public function testListenerReceivesSingleArgument() { $received = null; Flight::onEvent('test.event', function ($arg) use (&$received) { $received = $arg; }); Flight::triggerEvent('test.event', 'hello'); $this->assertEquals('hello', $received, 'Listener should receive the passed argument.'); } /** * Test that a listener receives multiple arguments correctly. */ public function testListenerReceivesMultipleArguments() { $received = []; Flight::onEvent('test.event', function ($arg1, $arg2) use (&$received) { $received = [$arg1, $arg2]; }); Flight::triggerEvent('test.event', 'first', 'second'); $this->assertEquals(['first', 'second'], $received, 'Listener should receive all passed arguments.'); } /** * Test that listeners are called in the order they were registered. */ public function testListenersCalledInOrder() { $order = []; Flight::onEvent('test.event', function () use (&$order) { $order[] = 1; }); Flight::onEvent('test.event', function () use (&$order) { $order[] = 2; }); Flight::triggerEvent('test.event'); $this->assertEquals([1, 2], $order, 'Listeners should be called in registration order.'); } /** * Test that listeners are not called for unrelated events. */ public function testListenerNotCalledForOtherEvents() { $called = false; Flight::onEvent('test.event1', function () use (&$called) { $called = true; }); Flight::triggerEvent('test.event2'); $this->assertFalse($called, 'Listeners should not be called for different events.'); } /** * Test overriding the onEvent method. */ public function testOverrideOnEvent() { $called = false; Flight::map('onEvent', function ($event, $callback) use (&$called) { $called = true; }); Flight::onEvent('test.event', function () { }); $this->assertTrue($called, 'Overridden onEvent method should be called.'); } /** * Test overriding the triggerEvent method. */ public function testOverrideTriggerEvent() { $called = false; Flight::map('triggerEvent', function ($event, ...$args) use (&$called) { $called = true; }); Flight::triggerEvent('test.event'); $this->assertTrue($called, 'Overridden triggerEvent method should be called.'); } /** * Test that an overridden onEvent can still register listeners by calling the original method. */ public function testOverrideOnEventStillRegistersListener() { $overrideCalled = false; Flight::map('onEvent', function ($event, $callback) use (&$overrideCalled) { $overrideCalled = true; // Call the original method Flight::app()->_onEvent($event, $callback); }); $listenerCalled = false; Flight::onEvent('test.event', function () use (&$listenerCalled) { $listenerCalled = true; }); Flight::triggerEvent('test.event'); $this->assertTrue($overrideCalled, 'Overridden onEvent should be called.'); $this->assertTrue($listenerCalled, 'Listener should still be triggered after override.'); } /** * Test that an overridden triggerEvent can still trigger listeners by calling the original method. */ public function testOverrideTriggerEventStillTriggersListeners() { $overrideCalled = false; Flight::map('triggerEvent', function ($event, ...$args) use (&$overrideCalled) { $overrideCalled = true; // Call the original method Flight::app()->_triggerEvent($event, ...$args); }); $listenerCalled = false; Flight::onEvent('test.event', function () use (&$listenerCalled) { $listenerCalled = true; }); Flight::triggerEvent('test.event'); $this->assertTrue($overrideCalled, 'Overridden triggerEvent should be called.'); $this->assertTrue($listenerCalled, 'Listeners should still be triggered after override.'); } /** * Test that an invalid callable throws an exception (if applicable). */ public function testInvalidCallableThrowsException() { $this->expectException(TypeError::class); // Assuming the event system validates callables Flight::onEvent('test.event', 'not_a_callable'); } /** * Test that event propagation stops if a listener returns false. */ public function testStopPropagation() { $firstCalled = false; $secondCalled = false; $thirdCalled = false; Flight::onEvent('test.event', function () use (&$firstCalled) { $firstCalled = true; return true; // Continue propagation }); Flight::onEvent('test.event', function () use (&$secondCalled) { $secondCalled = true; return false; // Stop propagation }); Flight::onEvent('test.event', function () use (&$thirdCalled) { $thirdCalled = true; }); Flight::triggerEvent('test.event'); $this->assertTrue($firstCalled, 'First listener should be called'); $this->assertTrue($secondCalled, 'Second listener should be called'); $this->assertFalse($thirdCalled, 'Third listener should not be called after propagation stopped'); } /** * Test that hasListeners() correctly identifies events with listeners. */ public function testHasListeners() { $this->assertFalse(Flight::eventDispatcher()->hasListeners('test.event'), 'Event should not have listeners before registration'); Flight::onEvent('test.event', function () { }); $this->assertTrue(Flight::eventDispatcher()->hasListeners('test.event'), 'Event should have listeners after registration'); } /** * Test that getListeners() returns the correct listeners for an event. */ public function testGetListeners() { $callback1 = function () { }; $callback2 = function () { }; $this->assertEmpty(Flight::eventDispatcher()->getListeners('test.event'), 'Event should have no listeners before registration'); Flight::onEvent('test.event', $callback1); Flight::onEvent('test.event', $callback2); $listeners = Flight::eventDispatcher()->getListeners('test.event'); $this->assertCount(2, $listeners, 'Event should have two registered listeners'); $this->assertSame($callback1, $listeners[0], 'First listener should match the first callback'); $this->assertSame($callback2, $listeners[1], 'Second listener should match the second callback'); } /** * Test that getListeners() returns an empty array for events with no listeners. */ public function testGetListenersForNonexistentEvent() { $listeners = Flight::eventDispatcher()->getListeners('nonexistent.event'); $this->assertIsArray($listeners, 'Should return an array for nonexistent events'); $this->assertEmpty($listeners, 'Should return an empty array for nonexistent events'); } /** * Test that getAllRegisteredEvents() returns all event names with registered listeners. */ public function testGetAllRegisteredEvents() { $this->assertEmpty(Flight::eventDispatcher()->getAllRegisteredEvents(), 'No events should be registered initially'); Flight::onEvent('test.event1', function () { }); Flight::onEvent('test.event2', function () { }); $events = Flight::eventDispatcher()->getAllRegisteredEvents(); $this->assertCount(2, $events, 'Should return all registered event names'); $this->assertContains('test.event1', $events, 'Should contain the first event'); $this->assertContains('test.event2', $events, 'Should contain the second event'); } /** * Test that removeListener() correctly removes a specific listener from an event. */ public function testRemoveListener() { $callback1 = function () { return 'callback1'; }; $callback2 = function () { return 'callback2'; }; Flight::onEvent('test.event', $callback1); Flight::onEvent('test.event', $callback2); $this->assertCount(2, Flight::eventDispatcher()->getListeners('test.event'), 'Event should have two listeners initially'); Flight::eventDispatcher()->removeListener('test.event', $callback1); $listeners = Flight::eventDispatcher()->getListeners('test.event'); $this->assertCount(1, $listeners, 'Event should have one listener after removal'); $this->assertSame($callback2, $listeners[0], 'Remaining listener should be the second callback'); } /** * Test that removeAllListeners() correctly removes all listeners for an event. */ public function testRemoveAllListeners() { Flight::onEvent('test.event', function () { }); Flight::onEvent('test.event', function () { }); Flight::onEvent('another.event', function () { }); $this->assertTrue(Flight::eventDispatcher()->hasListeners('test.event'), 'Event should have listeners before removal'); $this->assertTrue(Flight::eventDispatcher()->hasListeners('another.event'), 'Another event should have listeners'); Flight::eventDispatcher()->removeAllListeners('test.event'); $this->assertFalse(Flight::eventDispatcher()->hasListeners('test.event'), 'Event should have no listeners after removal'); $this->assertTrue(Flight::eventDispatcher()->hasListeners('another.event'), 'Another event should still have listeners'); } /** * Test that trying to remove listeners for nonexistent events doesn't cause errors. */ public function testRemoveListenersForNonexistentEvent() { // Should not throw any errors Flight::eventDispatcher()->removeListener('nonexistent.event', function () { }); Flight::eventDispatcher()->removeAllListeners('nonexistent.event'); $this->assertTrue(true, 'Removing listeners for nonexistent events should not throw errors'); } }