first commit
This commit is contained in:
128
lib/knife/test.lua
Normal file
128
lib/knife/test.lua
Normal file
@@ -0,0 +1,128 @@
|
||||
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
|
||||
Reference in New Issue
Block a user