301 lines
7.8 KiB
Lua
301 lines
7.8 KiB
Lua
-- Eventloop behavior tests for the CraftOS-PC harness.
|
|
local createEventLoop = require('/apis/eventloop');
|
|
local createLibTest = require('/apis/libtest');
|
|
|
|
local testlib = createLibTest({ ... });
|
|
|
|
testlib.test('register dispatches queued event args', function()
|
|
local events = createEventLoop();
|
|
local called = 0;
|
|
|
|
events.register('eventloop_test_basic', function(a, b)
|
|
called = called + 1;
|
|
testlib.assertEquals(a, 'first');
|
|
testlib.assertEquals(b, 42);
|
|
events.stopLoop();
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_basic', 'first', 42);
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(called, 1);
|
|
testlib.assertTrue(not events.isRunningLoop());
|
|
end);
|
|
|
|
testlib.test('STOP unregisters handler after first call', function()
|
|
local events = createEventLoop();
|
|
local stoppedHandlerCalls = 0;
|
|
local observerCalls = 0;
|
|
|
|
events.register('eventloop_test_stop', function()
|
|
stoppedHandlerCalls = stoppedHandlerCalls + 1;
|
|
return events.STOP;
|
|
end);
|
|
|
|
events.register('eventloop_test_stop', function()
|
|
observerCalls = observerCalls + 1;
|
|
if observerCalls == 1 then
|
|
os.queueEvent('eventloop_test_stop');
|
|
else
|
|
events.stopLoop();
|
|
end
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_stop');
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(stoppedHandlerCalls, 1);
|
|
testlib.assertEquals(observerCalls, 2);
|
|
end);
|
|
|
|
testlib.test('manual unregister prevents dispatch', function()
|
|
local events = createEventLoop();
|
|
local called = 0;
|
|
local dispose = events.register('eventloop_test_unregister', function()
|
|
called = called + 1;
|
|
end);
|
|
|
|
events.setTimeout(function()
|
|
events.stopLoop();
|
|
end, 0);
|
|
dispose();
|
|
|
|
os.queueEvent('eventloop_test_unregister');
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(called, 0);
|
|
end);
|
|
|
|
testlib.test('setTimeout before runLoop fires once', function()
|
|
local events = createEventLoop();
|
|
local called = 0;
|
|
|
|
events.setTimeout(function()
|
|
called = called + 1;
|
|
events.stopLoop();
|
|
end, 0);
|
|
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(called, 1);
|
|
end);
|
|
|
|
testlib.test('setTimeout during runLoop fires after event handler', function()
|
|
local events = createEventLoop();
|
|
local order = '';
|
|
|
|
events.register('eventloop_test_runtime_timeout', function()
|
|
order = order .. 'event>';
|
|
events.setTimeout(function()
|
|
order = order .. 'timeout';
|
|
events.stopLoop();
|
|
end, 0);
|
|
return events.STOP;
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_runtime_timeout');
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(order, 'event>timeout');
|
|
end);
|
|
|
|
testlib.test('cleared timeout before runLoop does not fire', function()
|
|
local events = createEventLoop();
|
|
local called = 0;
|
|
|
|
local clear = events.setTimeout(function()
|
|
called = called + 1;
|
|
end, 0);
|
|
clear();
|
|
|
|
events.setTimeout(function()
|
|
events.stopLoop();
|
|
end, 0);
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(called, 0);
|
|
end);
|
|
|
|
testlib.test('onStart and onStop run around loop', function()
|
|
local events = createEventLoop();
|
|
local order = '';
|
|
|
|
events.onStart(function()
|
|
order = order .. 'start>';
|
|
end);
|
|
|
|
events.onStop(function()
|
|
order = order .. 'stop';
|
|
end);
|
|
|
|
events.setTimeout(function()
|
|
order = order .. 'timeout>';
|
|
events.stopLoop();
|
|
end, 0);
|
|
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(order, 'start>timeout>stop');
|
|
end);
|
|
|
|
testlib.test('same-loop stop does not leak to a sibling loop with the same id', function()
|
|
local createEventLoopA = assert(loadfile('/apis/eventloop.lua'))();
|
|
local createEventLoopB = assert(loadfile('/apis/eventloop.lua'))();
|
|
local bootEvents = createEventLoopA();
|
|
local verifierEvents = createEventLoopB();
|
|
local bootProbeHandled = false;
|
|
|
|
bootEvents.register('eventloop_test_same_loop_probe', function()
|
|
bootProbeHandled = true;
|
|
bootEvents.stopLoop();
|
|
end);
|
|
|
|
verifierEvents.register('eventloop_test_same_loop_stop', function()
|
|
verifierEvents.stopLoop();
|
|
os.queueEvent('eventloop_test_same_loop_probe');
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_same_loop_stop');
|
|
parallel.waitForAll(function() bootEvents.runLoop(true); end, function() verifierEvents.runLoop(); end);
|
|
|
|
testlib.assertTrue(bootProbeHandled);
|
|
end);
|
|
|
|
testlib.test('external stop events use ids unique across module instances', function()
|
|
local createEventLoopA = assert(loadfile('/apis/eventloop.lua'))();
|
|
local createEventLoopB = assert(loadfile('/apis/eventloop.lua'))();
|
|
local bootEvents = createEventLoopA();
|
|
local verifierEvents = createEventLoopB();
|
|
local bootProbeHandled = false;
|
|
|
|
bootEvents.register('eventloop_test_external_stop', function()
|
|
verifierEvents.stopLoop();
|
|
os.queueEvent('eventloop_test_external_probe');
|
|
end);
|
|
|
|
bootEvents.register('eventloop_test_external_probe', function()
|
|
bootProbeHandled = true;
|
|
bootEvents.stopLoop();
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_external_stop');
|
|
parallel.waitForAll(function() bootEvents.runLoop(true); end, function() verifierEvents.runLoop(true); end);
|
|
|
|
testlib.assertTrue(bootProbeHandled);
|
|
end);
|
|
|
|
testlib.test('protected dispatch reports errors and keeps the loop alive', function()
|
|
local errors = {};
|
|
local events = createEventLoop({
|
|
onError = function(eventName, err)
|
|
errors[#errors + 1] = { eventName = eventName, err = err };
|
|
end,
|
|
});
|
|
local siblingCalled = false;
|
|
local laterCalled = false;
|
|
|
|
events.register('eventloop_test_protected', function()
|
|
error('handler boom', 0);
|
|
end);
|
|
|
|
events.register('eventloop_test_protected', function()
|
|
siblingCalled = true;
|
|
os.queueEvent('eventloop_test_protected_later');
|
|
end);
|
|
|
|
events.register('eventloop_test_protected_later', function()
|
|
laterCalled = true;
|
|
events.stopLoop();
|
|
end);
|
|
|
|
os.queueEvent('eventloop_test_protected');
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(#errors, 1);
|
|
testlib.assertEquals(errors[1].eventName, 'eventloop_test_protected');
|
|
testlib.assertTrue(string.find(tostring(errors[1].err), 'handler boom', 1, true) ~= nil);
|
|
testlib.assertTrue(siblingCalled);
|
|
testlib.assertTrue(laterCalled);
|
|
end);
|
|
|
|
testlib.test('protected timeout dispatch reports errors and keeps the loop alive', function()
|
|
local errors = {};
|
|
local events = createEventLoop({
|
|
onError = function(eventName, err)
|
|
errors[#errors + 1] = { eventName = eventName, err = err };
|
|
end,
|
|
});
|
|
local laterCalled = false;
|
|
|
|
events.setTimeout(function()
|
|
error('timeout boom', 0);
|
|
end, 0);
|
|
|
|
events.setTimeout(function()
|
|
laterCalled = true;
|
|
events.stopLoop();
|
|
end, 0);
|
|
|
|
events.runLoop();
|
|
|
|
testlib.assertEquals(#errors, 1);
|
|
testlib.assertEquals(errors[1].eventName, 'timer');
|
|
testlib.assertTrue(string.find(tostring(errors[1].err), 'timeout boom', 1, true) ~= nil);
|
|
testlib.assertTrue(laterCalled);
|
|
end);
|
|
|
|
testlib.test('timeout handler can stop a loop with persistent handlers', function()
|
|
local events = createEventLoop();
|
|
|
|
events.register('eventloop_test_never_fired', function()
|
|
end);
|
|
|
|
events.setTimeout(function()
|
|
events.stopLoop();
|
|
end, 0);
|
|
|
|
events.runLoop();
|
|
|
|
testlib.assertTrue(not events.isRunningLoop());
|
|
end);
|
|
|
|
testlib.test('empty loop returns and runs onStop', function()
|
|
local events = createEventLoop();
|
|
local stopped = false;
|
|
|
|
events.onStop(function()
|
|
stopped = true;
|
|
end);
|
|
|
|
events.runLoop();
|
|
|
|
testlib.assertTrue(stopped);
|
|
testlib.assertTrue(not events.isRunningLoop());
|
|
end);
|
|
|
|
testlib.test('error contracts are enforced', function()
|
|
local events = createEventLoop();
|
|
local function handler()
|
|
end
|
|
|
|
events.register('eventloop_test_errors', handler);
|
|
|
|
testlib.assertErrors(function()
|
|
events.register('eventloop_test_errors', handler);
|
|
end, 'handler already registered');
|
|
|
|
testlib.assertErrors(function()
|
|
events.stopLoop();
|
|
end, 'loop is already stopped');
|
|
|
|
testlib.assertErrors(function()
|
|
events.register(1, handler);
|
|
end, 'string expected');
|
|
|
|
testlib.assertErrors(function()
|
|
events.register('eventloop_test_errors_2', 'not a function');
|
|
end, 'function expected');
|
|
end);
|
|
|
|
testlib.run();
|