From 8451a0817a01c0a6949cf7c1f6e08b4118e9b23e Mon Sep 17 00:00:00 2001 From: rxi Date: Tue, 4 Mar 2014 23:10:34 +0000 Subject: [PATCH] Added tester.lua script and tests in test_lume.lua --- test/test_lume.lua | 301 +++++++++++++++++++++++++++++++++++++++++++++ test/tester.lua | 154 +++++++++++++++++++++++ 2 files changed, 455 insertions(+) create mode 100644 test/test_lume.lua create mode 100644 test/tester.lua diff --git a/test/test_lume.lua b/test/test_lume.lua new file mode 100644 index 0000000..ee14221 --- /dev/null +++ b/test/test_lume.lua @@ -0,0 +1,301 @@ +local tester = require "tester" + +package.path = "../?.lua;" .. package.path + +local lume = require "lume" + +local tests = {} +local testeq = tester.test.equal + +-- lume.clamp +tests["lume.clamp"] = function() + testeq( lume.clamp(8, 5, 10), 8 ) + testeq( lume.clamp(12, 5, 10), 10 ) + testeq( lume.clamp(-1, 5, 10), 5 ) + testeq( lume.clamp(-1, -10, 10), -1 ) + testeq( lume.clamp(-100, -10, 10), -10 ) + testeq( lume.clamp(13, 8, 8), 8 ) + testeq( lume.clamp(3, 8, 8), 8 ) +end + +-- lume.round +tests["lume.round"] = function() + testeq( lume.round(.5), 1 ) + testeq( lume.round(-.5), -1 ) + testeq( lume.round(2.4), 2 ) + testeq( lume.round(123, 10), 120 ) + testeq( lume.round(129, 64), 128 ) + testeq( lume.round(-123.45, .1), -123.5 ) + testeq( lume.round(0), 0 ) +end + +-- lume.sign +tests["lume.sign"] = function() + testeq( lume.sign(-10), -1 ) + testeq( lume.sign(10), 1 ) + testeq( lume.sign(0), 1 ) +end + +-- lume.lerp +tests["lume.lerp"] = function() + testeq( lume.lerp(100, 200, .5), 150 ) + testeq( lume.lerp(100, 200, .25), 125 ) + testeq( lume.lerp(100, 200, 2), 200 ) + testeq( lume.lerp(100, 200, -2), 100 ) +end + +-- lume.smooth +tests["lume.smooth"] = function() + testeq( lume.smooth(100, 200, .5), 150 ) + testeq( lume.smooth(100, 200, 0), 100 ) + testeq( lume.smooth(100, 200, 1), 200 ) + testeq( lume.smooth(100, 200, 2), 200 ) + testeq( lume.smooth(100, 200, -2), 100 ) +end + +-- lume.pingpong +tests["lume.pingpong"] = function() + testeq( lume.pingpong(0), 0 ) + testeq( lume.pingpong(1.5), .5 ) + testeq( lume.pingpong(-.2), .2 ) + testeq( lume.pingpong(-1.6), .4 ) + testeq( lume.pingpong(1.8), .2 ) +end + +-- lume.distance +tests["lume.distance"] = function() + testeq( lume.distance(10, 20, 10, 20), 0 ) + testeq( lume.distance(10, 20, 20, 20), 10 ) + local x = lume.distance(1, 2, 5, 7) + testeq( lume.distance(1, 2, 5, 7, true), x * x ) + testeq( lume.distance(10, 10, 10, 20, true), 10 * 10 ) +end + +-- lume.angle +tests["lume.angle"] = function() + testeq( lume.angle(10, 10, 10, 10), math.rad(0) ) + testeq( lume.angle(10, 10, 20, 10), math.rad(0) ) + testeq( lume.angle(10, 10, 5, 10), math.rad(180) ) + testeq( lume.angle(10, 10, 20, 20), math.rad(45) ) + testeq( lume.angle(10, 10, 10, 30), math.rad(90) ) +end + +-- lume.random +tests["lume.random"] = function() +end + +-- lume.randomchoice +tests["lume.randomchoice"] = function() + local t = {} + for i = 0, 1000 do + t[lume.randomchoice({"a", "b", "c", "d"})] = true + end + testeq( t.a and t.b and t.c and t.d, true ) + testeq( lume.randomchoice({true}), true ) +end + +-- lume.shuffle +tests["lume.shuffle"] = function() + local t = {1, 2, 3, 4, 5} + lume.shuffle(t) + table.sort(t) + testeq( t, {1, 2, 3, 4, 5} ) + testeq( lume.shuffle({}), {} ) +end + + +-- lume.array +tests["lume.array"] = function() + local t = lume.array(pairs({a=0, b=0, c=0})) + table.sort(t) + testeq( t, {"a", "b", "c"} ) + testeq( lume.array(ipairs({0, 0, 0})), {1, 2, 3} ) +end + +-- lume.each +tests["lume.each"] = function() + local acc = 1 + lume.each({1, 2, 3}, function(x) acc = acc + x end) + testeq( acc, 7 ) + + local acc = 1 + local f = function(o, x) acc = acc + x end + local f2 = function() end + local t = {a = {f = f}, b = {f = f}, c = {f = f2}} + lume.each(t, "f", 10) + testeq( acc, 21 ) +end + +-- lume.map +tests["lume.map"] = function() + testeq( lume.map({1, 2, 3}, function(x) return x * 2 end), {2, 4, 6} ) + testeq( lume.map({a=2,b=3}, function(x) return x * 2 end), {a=4,b=6} ) +end + +-- lume.all +tests["lume.all"] = function() + testeq( lume.all({true, true, false, true}), false ) + testeq( lume.all({true, true, true, true}), true ) + testeq( lume.all({2, 3, 4, 5}, function(x) return x % 2 == 0 end), false ) + testeq( lume.all({2, 4, 6, 8}, function(x) return x % 2 == 0 end), true ) +end + +-- lume.any +tests["lume.any"] = function() + testeq( lume.any({true, true, false, true}), true ) + testeq( lume.any({false, false, false}), false ) + testeq( lume.any({2, 3, 4, 5}, function(x) return x % 2 == 0 end), true ) + testeq( lume.any({1, 3, 5, 7}, function(x) return x % 2 == 0 end), false ) +end + +-- lume.reduce +tests["lume.reduce"] = function() + local concat = function(a, b) return a .. b end + testeq( lume.reduce({"cat", "dog"}, concat, ""), "catdog" ) + testeq( lume.reduce({"cat", "dog"}, concat, "pig"), "pigcatdog" ) +end + +-- lume.set +tests["lume.set"] = function() + local t = lume.set({1, 2, 3, 2, 5, 6, 6}) + table.sort(t) + testeq( t, {1, 2, 3, 5, 6} ) + local t = lume.set({"a", "b", "c", "b", "d"}) + table.sort(t) + testeq( t, {"a", "b", "c", "d"} ) +end + +-- lume.filter +tests["lume.filter"] = function() + local t = lume.filter({1, 2, 3, 4, 5}, function(x) return x % 2 == 0 end ) + testeq( t, {2, 4} ) + local t = lume.filter({a=1, b=2, c=3}, function(x) return x == 2 end, true) + testeq( t, {b=2} ) +end + +-- lume.merge +tests["lume.merge"] = function() + testeq( lume.merge({1, 2, 3}, {8, 9, 0}), {1, 2, 3, 8, 9, 0} ) + testeq( lume.merge({a=1, b=2}, {b=3, c=4}, true), {a=1, b=3, c=4} ) +end + +-- lume.find +tests["lume.find"] = function() + testeq( lume.find({"a", "b", "c"}, "b"), 2 ) + testeq( lume.find({"a", "b", "c"}, "c"), 3 ) + testeq( lume.find({a=1, b=5, c=7}, 5), "b" ) +end + +-- lume.slice +tests["lume.slice"] = function() + testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 4), {"b", "c", "d"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, -2), {"b", "c", "d"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 3, -1), {"c", "d", "e"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 3), {"c", "d", "e"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 4), {"d", "e"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 1, 1), {"a"} ) + testeq( lume.slice({"a", "b", "c", "d", "e"}, 2, 1), {} ) +end + +-- lume.clone +tests["lume.clone"] = function() + local t = {6, 7, 4, 5} + testeq( lume.clone(t) ~= t, true ) + testeq( lume.clone(t), {6, 7, 4, 5} ) + testeq( lume.clone({x=2, y="a"}), {x=2, y="a"} ) +end + +-- lume.fn +tests["lume.fn"] = function() + local f = lume.fn(function(a, b) return a + b end, 10) + testeq( f(5), 15 ) +end + +-- lume.once +tests["lume.once"] = function() + local f = lume.once(function(a, b) return a + b end, 10) + testeq( f(5), 15 ) + testeq( f(5), nil ) +end + +-- lume.time +tests["lume.time"] = function() + local t, a, b, c = lume.time(function(x) return 50, 60, x end, 70) + testeq( type(t), "number" ) + testeq( {a, b, c}, {50, 60, 70} ) +end + +-- lume.serialize / lume.deserialize +tests["lume.serialize, lume.deserialize"] = function() + local t = { 1, 2, 3, 4, true, false, "cat", "dog", {1, 2, 3} } + local s = lume.serialize(t) + testeq( lume.deserialize(s), t ) +end + +-- lume.split +tests["lume.split"] = function() + testeq( lume.split("cat dog pig"), {"cat", "dog", "pig"} ) + testeq( lume.split(",cat,dog,pig", ","), {"cat", "dog", "pig"} ) + testeq( lume.split(",cat,dog;pig", ",;"), {"cat", "dog", "pig"} ) +end + +-- lume.trim +tests["lume.trim"] = function() + testeq( lume.trim(" hello world "), "hello world" ) + testeq( lume.trim("-=-hello-world===", "-="), "hello-world" ) + testeq( lume.trim("***hello world*-*", "*"), "hello world*-" ) +end + +-- lume.format +tests["lume.format"] = function() + local str = lume.format("a {a} in a {b}", {a = "mouse", b = "house"}) + testeq( str, "a mouse in a house" ) + testeq( lume.format("number {num}", {num = 13}), "number 13" ) + testeq( lume.format("{missing} {keys}", {}), "{missing} {keys}" ) + testeq( lume.format("A {missing} table"), "A {missing} table" ) + testeq( lume.format("{1} idx {2}", {"an", "test"}), "an idx test" ) + testeq( lume.format("bad idx {-1}", {"x"}), "bad idx {-1}" ) + testeq( lume.format("empty {}", {"idx"}), "empty {}" ) +end + +-- lume.trace +tests["lume.trace"] = function() + local oldprint = print + local file, line, msg + print = function(x) + file, line, msg = x:match("%[(.-):(.-)%] (.*)") + end + lume.trace("Hi world") + print = oldprint + testeq( file:match(".lua$"), ".lua" ) + testeq( tonumber(line) ~= nil, true ) + testeq( msg, "Hi world" ) +end + +-- lume.dostring +tests["lume.dostring"] = function() + testeq( lume.dostring([[return "hello!"]]), "hello!" ) + testeq( lume.dostring([[return 12345]]), 12345 ) +end + +-- lume.hotswap +tests["lume.hotswap"] = function() + local ok, err = lume.hotswap("bad_module_name") + testeq( ok, nil ) + testeq( type(err), "string" ) +end + +-- lume.rgba +tests["lume.rgba"] = function() + local r, g, b, a = lume.rgba(0x12345678) + testeq( a, 0x12 ) + testeq( r, 0x34 ) + testeq( g, 0x56 ) + testeq( b, 0x78 ) +end + + +tester.dotests(tests) +tester.test.global() +tester.printresults() + diff --git a/test/tester.lua b/test/tester.lua new file mode 100644 index 0000000..99fe7aa --- /dev/null +++ b/test/tester.lua @@ -0,0 +1,154 @@ + + +local tester = { + test = {}, + linecache = {}, + globals = {}, + passcount = 0, + failcount = 0 +} + + +local function isequal(a, b) + if type(a) ~= type(b) then return nil end + local t = {} + function t.table(a, b) + for k, v in pairs(a) do if not isequal(b[k], v) then return nil end end + for k, v in pairs(b) do if not isequal(a[k], v) then return nil end end + return true + end + function t.number(a, b) return math.abs(a - b) < 10e-9 end + return t[type(a)] and t[type(a)](a, b) or (a == b) +end + + +local function stringify(x) + if type(x) == "number" then return string.format("%.2f", x) end + return string.format("%q", tostring(x)) +end + + +local function getline(file, line) + if not tester.linecache[file] then + local t = {} + for line in io.lines(file) do + t[#t + 1] = line + end + tester.linecache[file] = t + end + return tester.linecache[file][line] +end + + +local function truncate(str, max) + max = max or 72 + if #str > max then + return str:sub(1, max - 3) .. "..." + end + return str +end + + +local function has(t, value) + for k, v in pairs(t) do + if v == value then return true end + end + return false +end + + +local function makelogstr(passed, file, line) + local t = {} + t[#t + 1] = passed and "[\27[32mPASS\27[0m]" or "[\27[31mFAIL\27[0m]" + t[#t + 1] = file .. ":" .. line .. ":" + t[#t + 1] = getline(file, line) :gsub(" %s+", " ") :gsub("^ *", "") + return truncate(table.concat(t, " ")) +end + + +local function dopass(file, line) + print(makelogstr(true, file, line)) + tester.passcount = tester.passcount + 1 +end + + +local function dofail(file, line) + print(makelogstr(false, file, line)) + tester.failcount = tester.failcount + 1 +end + + +local function printfailmsg(str) + print(string.rep(" ", 7) .. str) +end + + + + +function tester.init() + for k, v in pairs(_G) do + tester.globals[k] = v + end + return tester +end + + +function tester.test.global(expectedglobals) + expectedglobals = expectedglobals or {} + local info = debug.getinfo(2) + local unexpected = {} + for k in pairs(_G) do + if not tester.globals[k] and not has(expectedglobals, k) then + table.insert(unexpected, "Unexpected global '" .. k .. "'") + end + end + if #unexpected == 0 then + dopass(info.short_src, info.currentline) + else + dofail(info.short_src, info.currentline) + for _, v in pairs(unexpected) do printfailmsg(v) end + end +end + + +function tester.test.equal(result, expected) + local passed = isequal(result, expected) + local info = debug.getinfo(2) + if passed then + dopass(info.short_src, info.currentline) + else + dofail(info.short_src, info.currentline) + if type(expected) == "table" and type(result) == "table" then + printfailmsg("Tables do not match") + else + printfailmsg(string.format("Expected %s got %s", + stringify(expected), stringify(result) )) + end + end +end + + +function tester.dotests(t) + local keys = {} + for k in pairs(t) do table.insert(keys, k) end + table.sort(keys) + for _, k in pairs(keys) do + print("\27[33m-- " .. k .. "\27[0m") + t[k]() + end +end + + +function tester.printresults() + local str = table.concat{ + "-- ", + string.format("Results: %d Total", tester.passcount + tester.failcount), + " ", string.format("%d Passed", tester.passcount), + " ", string.format("%d Failed", tester.failcount), + " --", } + local b = string.rep("-", #str) + print(table.concat{b, "\n", str, "\n", b}) +end + + +return tester.init()