diff --git a/.busted b/.busted new file mode 100644 index 0000000..03ce4cc --- /dev/null +++ b/.busted @@ -0,0 +1,6 @@ +-- vim:set ft=lua: +return { + _all = { + verbose = true, + } +} diff --git a/.travis.yml b/.travis.yml index 54556bc..b09dfdd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,9 +12,15 @@ before_install: - hererocks here -r^ --$LUA - export PATH=$PATH:$PWD/here/bin - eval `luarocks path --bin` - -install: - lua -v +install: + - luarocks install luacov-coveralls + - luarocks install cluacov + - luarocks install busted + script: - - lua test/eventable.lua + - busted -c + +after_success: + - luacov-coveralls diff --git a/spec/eventable_spec.lua b/spec/eventable_spec.lua new file mode 100644 index 0000000..fa10d11 --- /dev/null +++ b/spec/eventable_spec.lua @@ -0,0 +1,113 @@ +-- +-- eventable.lua +-- Copyright (C) 2016 Adrian Perez +-- +-- Distributed under terms of the MIT license. +-- + +local eventable = require "matrix.eventable" + +describe("matrix.eventable", function () + it("can be imported", function () + assert.is.table(eventable) + end) + + it("has a matrix.eventable.functions function", function () + assert.is_function(eventable.functions) + end) + + it("has a matrix.eventable.object function", function () + assert.is_function(eventable.object) + end) +end) + +describe("matrix.eventable.functions()", function () + it("returns three callable functions", function () + local s = spy.new(eventable.functions) + local fire, hook, unhook = s() + assert.spy(s).returned_with( + match.is_function(), + match.is_function(), + match.is_function()) + end) + + it("calls hooked handlers when firing events", function () + local flag = false + local handler = spy.new(function () flag = true end) + + local fire, hook = assert(eventable.functions()) + hook("foo", handler) + fire("foo") + + assert.spy(handler).was_called(1) + assert.is_true(flag) + end) + + it("stops at first handler that returs some value", function () + local fire, hook = assert(eventable.functions()) + local flag1, flag2, flag3 = false, false, false + hook("foo", function () flag1 = true end) + hook("foo", function () flag2 = true ; return 42 end) + hook("foo", function () flag3 = true ; return 0 end) + assert.is_equal(42, fire("foo")) + assert.is_true(flag1) + assert.is_true(flag2) + assert.is_false(flag3) + end) + + it("accepts a table where to store the event map", function () + local events = {} + local fire, hook = assert(eventable.functions(events)) + hook("foo", function () end) + assert.truthy(events.foo) + end) + + it("allows unhooking a handler", function () + local fire, hook, unhook = assert(eventable.functions()) + + local h1 = spy.new(function () end) + local h2 = spy.new(function () end) + hook("foo", h1) + hook("foo", h2) + fire("foo") + assert.spy(h1).was_called(1) + assert.spy(h2).was_called(1) + + unhook("foo", h2) + fire("foo") + assert.spy(h1).was_called(2) + assert.spy(h2).was_called(1) + end) +end) + +describe("matrix.eventable.object()", function () + it("creates a new table when no parameters are passed", function () + assert.is_table(eventable.object()) + end) + + it("adds methods to an existing table", function () + local t = {} + assert.is_equal(t, eventable.object(t)) + assert.is_function(t.fire) + assert.is_function(t.hook) + assert.is_function(t.unhook) + end) + + it("passes the table as first argument when firing events", function () + local t = assert(eventable.object()) + local h = spy.new(function (o) + assert.is_equal(t, o) + end) + t:hook("foo", h) + t:fire("foo") + assert.spy(h).was_called_with(t) + end) + + it("allows chaining :hook() and :unhook() calls", function () + local t = assert(eventable.object()) + local h = function () end + assert.is_equal(t, t:hook("foo", h)) + assert.is_equal(t, t:unhook("foo", h)) + assert.is_equal(t, t:hook("foo", h):unhook("foo", h)) + end) +end) diff --git a/test/eventable.lua b/test/eventable.lua deleted file mode 100644 index cc0bf4a..0000000 --- a/test/eventable.lua +++ /dev/null @@ -1,73 +0,0 @@ --- --- eventable.lua --- Copyright (C) 2016 Adrian Perez --- --- Distributed under terms of the MIT license. --- - -local eventable = require "matrix.eventable" - -do -- Simple event - local fire, hook = assert(eventable.functions()) - local flag = false - hook("foo", function () flag = true end) - fire("foo") - assert(flag) -end - -do -- Stop at first handler that returns some value - local fire, hook = assert(eventable.functions()) - local flag1, flag2, flag3 = false, false, false - hook("foo", function () flag1 = true end) - hook("foo", function () flag2 = true ; return 42 end) - hook("foo", function () flag3 = true ; return 0 end) - assert(fire("foo") == 42) - assert(flag1 == true) - assert(flag2 == true) - assert(flag3 == false) -end - -do -- Arguments to eventable() are passed to handlers - local obj = { answer = 42 } - local fire, hook = assert(eventable.functions(obj)) - hook("foo", function (o) - assert(o == obj) - assert(o.answer == 42) - o.answer = 0 -- Mutate - end) - fire("foo") - assert(obj.answer == 0) -end - -do -- Multiple arguments passed to eventable - local fire, hook = assert(eventable.functions(42, "bar", nil, { v=10 })) - hook("foo", function (a, s, n, o) - assert(a == 42) - assert(s == "bar") - assert(n == nil) - assert(o.v == 10) - end) - fire("foo") -end - -do -- Unhooking should work - local flag1, flag2 = false, false - local h1 = function () flag1 = true end - local h2 = function () flag2 = true end - - local fire, hook, unhook = assert(eventable.functions()) - hook("foo", h1) - hook("foo", h2) - fire("foo") - assert(flag1 == true) - assert(flag2 == true) - - flag1, flag2 = false, false - unhook("foo", h2) - fire("foo") - assert(flag1 == true) - assert(flag2 == false) - - flag1, flag2 = false, false - unhook("foo") -end