mirror of
https://github.com/Reuh/classtoi.git
synced 2025-10-27 12:19:31 +00:00
156 lines
4.6 KiB
Lua
156 lines
4.6 KiB
Lua
--[[
|
|
knife.test - A fixture-free test framework.
|
|
|
|
https://github.com/airstruck/knife
|
|
|
|
The MIT License (MIT)
|
|
|
|
Copyright (c) 2015 airstruck
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
]]
|
|
|
|
local test, testAssert, testError
|
|
|
|
-- Create a node representing a test section
|
|
local function createNode (parent, description, process)
|
|
return setmetatable({
|
|
parent = parent,
|
|
description = description,
|
|
process = process,
|
|
nodes = {},
|
|
activeNodeIndex = 1,
|
|
currentNodeIndex = 0,
|
|
assert = testAssert,
|
|
error = testError,
|
|
}, { __call = test })
|
|
end
|
|
|
|
-- Run a node
|
|
local function runNode (node)
|
|
node.currentNodeIndex = 0
|
|
return node:process()
|
|
end
|
|
|
|
-- Get the root node for a given node
|
|
local function getRootNode (node)
|
|
local parent = node.parent
|
|
return parent and getRootNode(parent) or node
|
|
end
|
|
|
|
-- Update the active child node of the given node
|
|
local function updateActiveNode (node, description, process)
|
|
local activeNodeIndex = node.activeNodeIndex
|
|
local nodes = node.nodes
|
|
local activeNode = nodes[activeNodeIndex]
|
|
|
|
if not activeNode then
|
|
activeNode = createNode(node, description, process)
|
|
nodes[activeNodeIndex] = activeNode
|
|
else
|
|
activeNode.process = process
|
|
end
|
|
|
|
getRootNode(node).lastActiveLeaf = activeNode
|
|
|
|
return activeNode
|
|
end
|
|
|
|
-- Run the active child node of the given node
|
|
local function runActiveNode (node, description, process)
|
|
local activeNode = updateActiveNode(node, description, process)
|
|
return runNode(activeNode)
|
|
end
|
|
|
|
-- Get ancestors of a node, including the node
|
|
local function getAncestors (node)
|
|
local ancestors = { node }
|
|
for ancestor in function () return node.parent end do
|
|
ancestors[#ancestors + 1] = ancestor
|
|
node = ancestor
|
|
end
|
|
return ancestors
|
|
end
|
|
|
|
-- Print a message describing one execution path in the test scenario
|
|
local function printScenario (node)
|
|
local ancestors = getAncestors(node)
|
|
for i = #ancestors, 1, -1 do
|
|
io.stderr:write(ancestors[i].description or '')
|
|
io.stderr:write('\n')
|
|
end
|
|
end
|
|
|
|
-- Print a message and stop the test scenario when an assertion fails
|
|
local function failAssert (node, description, message)
|
|
io.stderr:write(message or '')
|
|
io.stderr:write('\n\n')
|
|
printScenario(node)
|
|
io.stderr:write(description or '')
|
|
io.stderr:write('\n\n')
|
|
error(message or '', 2)
|
|
end
|
|
|
|
-- Create a branch node for a test scenario
|
|
test = function (node, description, process)
|
|
node.currentNodeIndex = node.currentNodeIndex + 1
|
|
if node.currentNodeIndex == node.activeNodeIndex then
|
|
return runActiveNode(node, description, process)
|
|
end
|
|
end
|
|
|
|
-- Test an assertion
|
|
testAssert = function (self, value, description)
|
|
if not value then
|
|
return failAssert(self, description, 'Test failed: assertion failed')
|
|
end
|
|
return value
|
|
end
|
|
|
|
-- Expect function f to fail
|
|
testError = function (self, f, description)
|
|
if pcall(f) then
|
|
return failAssert(self, description, 'Test failed: expected error')
|
|
end
|
|
end
|
|
|
|
-- Create the root node for a test scenario
|
|
local function T (description, process)
|
|
local root = createNode(nil, description, process)
|
|
|
|
runNode(root)
|
|
while root.activeNodeIndex <= #root.nodes do
|
|
local lastActiveBranch = root.lastActiveLeaf.parent
|
|
lastActiveBranch.activeNodeIndex = lastActiveBranch.activeNodeIndex + 1
|
|
runNode(root)
|
|
end
|
|
|
|
return root
|
|
end
|
|
|
|
-- Run any other files passed from CLI.
|
|
if arg and arg[0] and arg[0]:gmatch('test.lua') then
|
|
_G.T = T
|
|
for i = 1, #arg do
|
|
dofile(arg[i])
|
|
end
|
|
_G.T = nil
|
|
end
|
|
|
|
return T
|