Skip to content

Instantly share code, notes, and snippets.

@bcatcho
Created November 9, 2012 08:34
Show Gist options
  • Save bcatcho/4044468 to your computer and use it in GitHub Desktop.
Save bcatcho/4044468 to your computer and use it in GitHub Desktop.
CodeaProject:Common Test update
--# CaptureCode
local code = ""
function Tab(tabName)
local tabCode = debug.getinfo(2)
if #code > 0 then code = code.."\n" end
code = code.."--# "..tabName.."\n"..tabCode.source
end
function SaveTabs(key)
print("Saving "..key)
saveGlobalData(key, code)
end
Tab("CaptureCode")
--# Debug
Tab("Debug")
dbg = {}
setmetatable(dbg, { __index = dbg })
dbg.traceback = function()
local level = 1
while true do
local info = debug.getinfo(level, "Sl")
if not info then break end
if info.what == "C" then -- is a C function?
print(level, "C function")
else -- a Lua function
print(string.format("[%s]:%d", info.short_src, info.currentline))
end
level = level + 1
end
end
dbg.timeFunc = function (func, ...)
local t = os.clock()
local result = func(unpack(arg))
return result, os.clock() - t
end
dbg.printTime = function (func, ...)
local r, t = dbg.timeFunc(func, unpack(arg))
print(t)
return r
end
--# ObserverTable
Tab("ObserverTable")
ObserverTable = class()
function ObserverTable:init()
-- you can accept and set parameters here
self.t = {}
end
function ObserverTable:observe(key, topic, delegagte)
if self.t[key] == nil then
self.t[key] = {}
end
if self.t[key][topic] == nil then
self.t[key][topic] = {}
end
table.insert(self.t[key][topic], delegate)
end
function ObserverTable:notify(key, topic, ...)
if self.t[key] ~= nil then
if self.t[key][topic] ~= nil then
for key, d in ipairs(self.t[key][topic]) do
d(unpack(arg))
end
end
end
end
--# State
Tab("State")
State = class()
function State:init(...)
self.sm = nil
self:initState(unpack(arg))
end
function State:setStateMachine(stateMachine)
self.sm = stateMachine
end
function State:goState(state)
self.sm:transitionTo(state)
end
function State:shared()
return self.sm:getSharedProps()
end
-- virtual
function State:initState()
end
-- virtual
function State:enter()
end
-- virtual
function State:exit()
end
--# stateMachine
Tab("stateMachine")
StateMachine = class()
function StateMachine:init()
self.state = nil
self._sharedProps = {}
end
function StateMachine:startWith(initialState)
self.state = initialState
self.state:setStateMachine(self)
self.state:enter()
end
-- properties that will be passed from state to state
function StateMachine:setSharedProperties(props)
for k,v in pairs(props) do
self._sharedProps[k] = v
end
end
function StateMachine:getSharedProps()
return self._sharedProps
end
function StateMachine:transitionTo(nextState)
self.state:exit()
self.state = nextState
self.state:setStateMachine(self)
self.state:enter()
end
function StateMachine:current()
return self.state
end
--# MathExtensions
Tab("MathExtensions")
math.betweenI = function(val, low, high)
return val >= low and val <= high
end
math.isInRect = function(pointX, pointY, rectX, rectY, rectWidth, rectHeight)
return math.betweenI(pointX, rectX, rectX+rectWidth)
and math.betweenI(pointY, rectY, rectY+rectHeight)
end
math.constrain = function(val, low, high)
return math.max(math.min(val, high), low)
end
math.wrap = function(val, low, high)
return (val > high) and low
or (val < low) and high
or val
end
--# TableExtensions
Tab("TableExtensions")
function T(t)
return setmetatable(t, {__index = table})
end
table.reduceMethods = {
sum = function (i, tot) return i + tot end
}
table.reduce = function(tbl, seed, func )
local sum = seed
for k,v in pairs(tbl) do
sum = func(v, sum)
end
return sum
end
table.sum = function(tbl, seed)
return table.reduce(tbl, seed, table.reduceMethods.sum)
end
table.doXY = function(cols, rows, func)
for r = 1, rows do
for c = 1, cols do
func(c, r)
end
end
end
table.map = function(tbl, func)
local result = T{}
for k, v in pairs(tbl) do
result:insert(func(v, k) )
end
return result
end
table.each = function(tbl, func)
for k, v in pairs(tbl) do
func(v, k)
end
end
table.eachIf = function(tbl, filter, func)
local result = T{}
for k, v in pairs(tbl) do
if filter(v,k) then
result[k] = func(v,k)
end
end
return result
end
table.eachIfA = function(tbl, filter, func)
local result = T{}
for k, v in pairs(tbl) do
if filter(v,k) then
result:insert(func(v,k))
end
end
return result
end
table.eachUntil = function(tbl, success, func)
for k, v in pairs(tbl) do
if func(v,k) == success then
return true
end
end
return false
end
table.call = function(tbl, methodName, ...)
for k, v in ipairs(tbl) do
v[methodName](v, unpack(arg))
end
end
table.filter = function(tbl, func)
local result = T{}
for k, v in pairs(tbl) do
if func(v,k) then
result[k] = v
end
end
return result
end
table.filterA = function(tbl, func)
local result = T{}
for k, v in ipairs(tbl) do
if func(v,k) then
result[#result+1] = v
end
end
return result
end
table.mapSet = function(tbl, func)
local result = T{}
local track = {} -- keep track of the values we have seen
local ouput -- optimization
for k, v in pairs(tbl) do
output = func(v, k)
if track[output] == nil then
result:insert(output)
track[output] = true
end
end
return result
end
table.cycle = function(tbl)
tbl:insert(tbl[1])
tbl:remove(1)
end
table.first = function(tbl, func)
if func then
for k,v in pairs(tbl) do
if func(v, k) then return v, k end
end
return nil, nil
end
return tbl[1]
end
table.dump = function(tbl, recurse, indent)
recurse = (recurse ~= nil) and recurse or false
indent = (indent ~= nil) and indent or 1
local function _tab(x) return string.rep(" ", x) end
print(_tab(indent - 1).."{")
for k,v in pairs(tbl) do
if type(v) == "table" then
print(_tab(indent)..k..": <table>")
v:dump(recurse, indent+1)
else
print(_tab(indent)..k..": "..tostring(v)..",")
end
end
print(_tab(indent - 1).."}")
end
--# TGrid
Tab("TGrid")
TGrid = class(ObserverTable)
function TGrid:init(w, h)
ObserverTable.init(self)
-- you can accept and set parameters here
self.w = w
self.h = h
self.grid = {}
self.gridByY = {}
end
-- iterator by Y value from top of screen to bottom
function TGrid:listTtoB()
local w, h = self.w, self.h
local fn = function(state, loopvar)
if state.y > 0 then
state.x = state.x+1
if state.x > w then
state.x = 1
state.y = state.y - 1
end
return self:get(state.x, state.y)
end
return nil
end
return fn, {x = 0, y = h}, 0
end
function TGrid:listBtoT()
local w, h = self.w, self.h
local fn = function(state, loopvar)
if state.y <= h then
state.x = state.x+1
if state.x > w then
state.x = 1
state.y = state.y + 1
end
return self:get(state.x, state.y)
end
return nil
end
return fn, {x = 0, y = 1}, 0
end
function TGrid:gIndex(x,y)
return x..','..y
end
function TGrid:add(x, y, value)
self.grid[self:gIndex(x,y)] = value
--table.insert(self.gridByY, (y-1), self:get(x,y))
end
function TGrid:get(x,y)
return self.grid[self:gIndex(x,y)]
end
function TGrid:getN(x,y)
return self:get(x,y-1)
end
function TGrid:getE(x,y)
return self:get(x+1,y)
end
function TGrid:getS(x,y)
return self:get(x,y+1)
end
function TGrid:getW(x,y)
return self:get(x-1,y)
end
function TGrid:set(x,y, value)
self.grid[self:gIndex(x,y)] = value
end
function TGrid:setk(x,y, key, value)
self.grid[self:gIndex(x,y)][key] = value
end
function TGrid:getAround(x,y)
return {
self:getN(x,y),
self:getE(x,y),
self:getS(x,y),
self:getW(x,y)
}
end
--# Util
Tab("Util")
-- String.format
_fmt = function(...)
return string.format(unpack(arg))
end
--# Main
Tab("Main")
-- Common
-- this project is just a container for common classes and utilities
local output = ""
local pass, fail = 0, 0
function test(name, t)
local outputFunc = function(...)
print(" "..string.format(unpack(arg)))
end
local expected, actual = t(outputFunc)
if expected == actual then
output = output.."."
pass = pass + 1
else
print(output)
output = ""
print("!! "..name)
print(" "..tostring(expected).."\n "..tostring(actual).."\n")
fail = fail + 1
end
end
function setup()
SaveTabs("Common")
test( "table.reduce",
function ()
return 6, T{2,3}:reduce(1, function(i,tot) return i*tot end)
end)
test( "table.sum",
function ()
return 5, T{2,3}:sum(0)
end)
test( "table.doXY",
function ()
local total = 0
table.doXY(2,2, function(x,y) total = total + x + y end)
return 12, total
end)
test("table.map",
function ()
local map = table.map({"yar","word","to"}, string.len)
return 4, map[2]
end)
test("table.mapSet",
function ()
local map = table.mapSet({"yar","yar","to"}, string.format)
return "to", map[2]
end)
test("table.eachIf",
function ()
local t = T{1,3,"adf"}
local result = t:eachIf(function (v) return type(v) == "string" end, string.upper )
return "ADF", result[3]
end)
test("table.eachIfA",
function ()
local t = T{1,3,"adf"}
local result = t:eachIfA(function (v) return type(v) == "string" end, string.upper )
return "ADF", result[1]
end)
test("table.call",
function ()
local sum = 0
local function makeTbl(x)
return {val=x, fn=function(inst) sum=sum+inst.val end}
end
local t = T{ makeTbl(1), makeTbl(2), makeTbl(3)}
t:call("fn")
return 6, sum
end)
test("table.filterA",
function ()
local filteredList = table.filterA({1,2,3}, function (v,k) return v > 2 end)
return 3, filteredList[1]
end)
test("table.filter",
function ()
local filteredList = table.filter({a=1,b=2,c=3}, function (v,k) return v > 2 end)
return 3, filteredList.c
end)
test("table.cycle",
function ()
local t = T{"a", "b", "c"}
t:cycle()
return "bca", t[1]..t[2]..t[3]
end)
test("table.first",
function ()
local function gt2(n) return n > 2 end
return 3, T{0,1,2,3,4,5,6}:first(gt2)
end)
test("T()",
function ()
local tbl = T{}
tbl:insert(1.5)
tbl = tbl:map(math.floor)
return 1, tbl[1]
end)
test("_fmt",
function ()
local result = _fmt("%d,%i,%f", 123.0, 123.0, 123.0)
return "123,123,123.000000", result
end)
test("dbg.timeFunc",
function ()
local function f (a)
local sum = 0
for i=1, a do sum = sum + 1 end
return sum
end
local result, time = dbg.timeFunc(f, 100000)
return "100000,true", result..","..tostring(time < 1 and time > 0)
end)
test("math.betweenI::TestBoundaries",
function ()
return true, (math.betweenI(1, 1, 2) and math.betweenI(2,1,2))
end)
test("math.betweenI::Inside",
function ()
return true, math.betweenI(2, 1, 3)
end)
test("math.betweenI::Outside",
function ()
return false, math.betweenI(3, 1, 2) and math.betweenI(0, 1, 2)
end)
test("math.isInRect::Inside",
function ()
return true, math.isInRect(2,2, 1,1,3,3)
end)
test("math.isInRect::Boundaries",
function ()
return true, math.isInRect(1,2, 1,1,3,3)
end)
test("math.constrain",
function ()
return 3, math.constrain(10, 1, 3)
end)
test("math.wrap::inside",
function ()
return 5, math.wrap(5, 1, 10)
end)
test("math.wrap::highAndLow",
function ()
return "1,10", _fmt("%d,%d",math.wrap(11, 1, 10), math.wrap(0, 1, 10))
end)
test("table.dump",
function ()
T{
colors = T{ "red", "blue", "green" },
cheese = "please",
num = 3
}:dump()
return true, true
end)
print(output)
print((fail == 0) and "All tests passed" or _fmt("%d/%d tests passed",pass,pass+fail))
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment