It looks like you're new here. If you want to get involved, click one of these buttons!
A modified version of @jakesankey’s extremely helpful CodeaUnit.
Somebody might find this useful, as it’s been tweaked to do a few convenient things:
It’s been working for me, but I haven’t fully tested it (ironically), so there might still be a glitch here or there. If you find one please let me know.
--from an original by jakesankey
CodeaUnit = class()
CodeaUnit.isRunning = false
CodeaUnit.doBeforeAndAfter = true
function CodeaUnit:describe(feature, allTests)
print(string.format("\t****\n\t%s\n\t****", feature))
if self.skip == true then
print("\t * Tests Skipped")
else
self.tests = 0
self.subtests = 0
self.totalTests = 0
self.ignored = 0
self.failures = 0
self.message = "message not set"
self.debugReporting = false
self._before = function()
end
self._after = function()
end
allTests()
local passed = self.totalTests - self.failures
local summary = string.format("\t\t\t----------\n\t\t\tPass: %d\n\t\t\tIgnore: %d\n\t\t\tFail: %d", passed, self.ignored, self.failures)
print(summary)
end
end
function CodeaUnit:before(setup)
self._before = setup
end
function CodeaUnit:after(teardown)
self._after = teardown
end
function CodeaUnit:ignore(description, scenario)
self.description = tostring(description or "")
self.tests = self.tests + 1
self.ignored = self.ignored + 1
if CodeaUnit.detailed then
print(string.format("%d: %s -- Ignored", self.tests, self.description))
end
end
function CodeaUnit:test(description, scenario)
self.tests = self.tests + 1
self.totalTests = self.totalTests + 1
self._before()
local beforeString = "__________________\n*** First. CodeaUnit:test(...) description before assignment: "..tostring(self.description)
self.description = tostring(description or "")
local afterString = "*** CodeaUnit:test(...) description after assignment: "..tostring(self.description)
if self.debugReporting then
print(string.format("%s\n%s", beforeString, afterString))
end
local status, err = pcall(scenario)
if err then
self.failures = self.failures + 1
print(string.format("%d: %s -- %s", self.tests, self.description, err))
end
self._after()
if self.subtests ~= 0 then
self.totalTests = self.totalTests + self.subtests - 1
end
self.subtests = 0
self.description = nil
self.message = nil
end
--function CodeaUnit:expect(conditional)
--takes one or two arguments
--can take just the expected value, or a name for this individual 'expect' call plus the expected value
--this allows multiple 'expect' calls in a single test to all show different titles
function CodeaUnit:expect(...)
local encoding = "abcdefghijklmnopqrstuvwxyz"
local function letterFromNum(i)
return encoding:sub(i,i)
end
--detecting #args will mess up if expected value has returned nil, because nil isn't counted as a value
local args = {...}
if #args == 2 then multiTest = true end
local unpackedArgs = tostring(table.unpack(args))
if self.debugReporting then
local descriptionString = "*** Second. CodeaUnit:expect(...) self.description: "..tostring(self.description)
local argsExplained = "*** CodeaUnit:expect(...) args: "..#args..", unpacked: "..unpackedArgs
print(string.format("%s\n%s", descriptionString, argsExplained))
end
self.message = string.format("%d. %s:", (self.tests or 1), self.description)
if not multiTest then
conditional = args[1]
elseif #args == 2 then
local premessage = ""
self.subtests = self.subtests + 1
if self.subtests == 1 then
premessage = string.format("%s\n\n", self.message)
end
conditional = args[2]
self.message = string.format("%s %d.%s. %s", premessage, (self.tests or 1), letterFromNum(self.subtests), args[1])
end
local passed = function()
if CodeaUnit.detailed then
print(string.format("%s\n Expected: %s\n -- OK", self.message, self.expected))
end
end
local failed = function()
self.failures = self.failures + 1
local actual = tostring(conditional)
local expected = tostring(self.expected)
print(string.format("%s\n Expected: %s\n -- FAIL: found %s", self.message, expected, actual))
end
local notify = function(result)
if self.debugReporting then
print("notify() message: "..tostring(self.message)..", self.expected: "..tostring(self.expected))
end
if result then
passed()
else
failed()
end
end
local is = function(expected)
self.expected = expected
notify(conditional == expected)
end
local isnt = function(expected)
self.expected = expected
notify(conditional ~= expected)
end
local has = function(expected)
self.expected = expected
local found = false
for i,v in pairs(conditional) do
if v == expected then
found = true
end
end
if not found then
conditional = "no such value"
end
notify(found)
end
local throws = function(expected)
self.expected = expected
local status, error = pcall(conditional)
if not error then
conditional = "nothing thrown"
notify(false)
else
notify(string.find(error, expected, 1, true))
end
end
return {
is = is,
isnt = isnt,
has = has,
throws = throws
}
end
CodeaUnit.execute = function()
CodeaUnit.isRunning = true
for i,v in pairs(listProjectTabs()) do
local source = readProjectTab(v)
for match in string.gmatch(source, "function%s-(test.-%(%))") do
load(match)()
end
end
end
CodeaUnit.detailed = true
_ = CodeaUnit()
parameter.action("CodeaUnit Runner", function()
CodeaUnit.execute()
end)
Comments
And here’s an example of using it:
Interesting, I'll check it out. I should probably publish the one I'm using.
One thing I did differently is that I put the description of the test as the second, optional argument to "expect", which makes the code easier, as you can just default it rather than count the args etc.
@RonJeffries oooooo that looks sweet.
All the CodeaUnit code makes my head spin, honestly, and it was really hard for me to get my changes to work at all, so I’m a bit scared to mess with it, but this seems like a really good idea.
And it fits your general principle that if something is too complicated, you’re probably doing it the wrong way.