Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
7
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/_manifest.lua
vendored
Normal file
7
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/_manifest.lua
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
return {
|
||||
"self-test.lua",
|
||||
"test_assertions.lua",
|
||||
"test_declare.lua",
|
||||
"test_helpers.lua",
|
||||
"test_runner.lua"
|
||||
}
|
106
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/self-test.lua
vendored
Normal file
106
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/self-test.lua
vendored
Normal file
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
-- self-test/self-test.lua
|
||||
--
|
||||
-- An automated test framework for Premake and its add-on modules.
|
||||
--
|
||||
-- Author Jason Perkins
|
||||
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
|
||||
---
|
||||
|
||||
|
||||
local p = premake
|
||||
|
||||
p.modules.self_test = {}
|
||||
local m = p.modules.self_test
|
||||
|
||||
m._VERSION = p._VERSION
|
||||
|
||||
|
||||
|
||||
newaction {
|
||||
trigger = "self-test",
|
||||
shortname = "Test Premake",
|
||||
description = "Run Premake's own local unit test suites",
|
||||
execute = function()
|
||||
m.executeSelfTest()
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
|
||||
newoption {
|
||||
trigger = "test-only",
|
||||
value = "suite[.test]",
|
||||
description = "For self-test action; run specific suite or test"
|
||||
}
|
||||
|
||||
|
||||
|
||||
function m.executeSelfTest()
|
||||
m.detectDuplicateTests = true
|
||||
m.loadTestsFromManifests()
|
||||
m.detectDuplicateTests = false
|
||||
|
||||
local tests = {}
|
||||
local isAction = true
|
||||
for i, arg in ipairs(_ARGS) do
|
||||
local _tests, err = m.getTestsWithIdentifier(arg)
|
||||
if err then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
tests = table.join(tests, _tests)
|
||||
end
|
||||
|
||||
if #tests == 0 or _OPTIONS["test-only"] ~= nil then
|
||||
local _tests, err = m.getTestsWithIdentifier(_OPTIONS["test-only"])
|
||||
if err then
|
||||
error(err, 0)
|
||||
end
|
||||
|
||||
tests = table.join(tests, _tests)
|
||||
end
|
||||
|
||||
local passed, failed = m.runTest(tests)
|
||||
|
||||
if failed > 0 then
|
||||
printf("\n %d FAILED TEST%s", failed, iif(failed > 1, "S", ""))
|
||||
os.exit(5)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.loadTestsFromManifests()
|
||||
local mask = path.join(_MAIN_SCRIPT_DIR, "**/tests/_tests.lua")
|
||||
local manifests = os.matchfiles(mask)
|
||||
|
||||
-- TODO: "**" should also match "." but doesn't currently
|
||||
local top = path.join(_MAIN_SCRIPT_DIR, "tests/_tests.lua")
|
||||
if os.isfile(top) then
|
||||
table.insert(manifests, 1, top)
|
||||
end
|
||||
|
||||
for i = 1, #manifests do
|
||||
local manifest = manifests[i]
|
||||
|
||||
_TESTS_DIR = path.getdirectory(manifest)
|
||||
|
||||
local files = dofile(manifest)
|
||||
for i = 1, #files do
|
||||
local filename = path.join(_TESTS_DIR, files[i])
|
||||
dofile(filename)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
dofile("test_assertions.lua")
|
||||
dofile("test_declare.lua")
|
||||
dofile("test_helpers.lua")
|
||||
dofile("test_runner.lua")
|
||||
|
||||
|
||||
|
||||
return m
|
240
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_assertions.lua
vendored
Normal file
240
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_assertions.lua
vendored
Normal file
|
@ -0,0 +1,240 @@
|
|||
---
|
||||
-- test_assertions.lua
|
||||
--
|
||||
-- Assertion functions for unit tests.
|
||||
--
|
||||
-- Author Jason Perkins
|
||||
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
|
||||
---
|
||||
|
||||
local p = premake
|
||||
|
||||
local m = p.modules.self_test
|
||||
|
||||
local _ = {}
|
||||
|
||||
|
||||
|
||||
function m.capture(expected)
|
||||
local actual = p.captured() .. p.eol()
|
||||
|
||||
-- create line-by-line iterators for both values
|
||||
local ait = actual:gmatch("(.-)" .. p.eol())
|
||||
local eit = expected:gmatch("(.-)\n")
|
||||
|
||||
-- compare each value line by line
|
||||
local linenum = 1
|
||||
local atxt = ait()
|
||||
local etxt = eit()
|
||||
while etxt do
|
||||
if (etxt ~= atxt) then
|
||||
m.fail("(%d) expected:\n%s\n...but was:\n%s\nfulltext:\n%s", linenum, etxt, atxt, actual)
|
||||
end
|
||||
|
||||
linenum = linenum + 1
|
||||
atxt = ait()
|
||||
etxt = eit()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.closedfile(expected)
|
||||
if expected and not m.value_closedfile then
|
||||
m.fail("expected file to be closed")
|
||||
elseif not expected and m.value_closedfile then
|
||||
m.fail("expected file to remain open")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.contains(expected, actual)
|
||||
if type(expected) == "table" then
|
||||
for i, v in ipairs(expected) do
|
||||
m.contains(v, actual)
|
||||
end
|
||||
elseif not table.contains(actual, expected) then
|
||||
m.fail("expected value %s not found", expected)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.excludes(expected, actual)
|
||||
if type(expected) == "table" then
|
||||
for i, v in ipairs(expected) do
|
||||
m.excludes(v, actual)
|
||||
end
|
||||
elseif table.contains(actual, expected) then
|
||||
m.fail("excluded value %s found", expected)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.fail(format, ...)
|
||||
-- if format is a number then it is the stack depth
|
||||
local depth = 3
|
||||
local arg = {...}
|
||||
if type(format) == "number" then
|
||||
depth = depth + format
|
||||
format = table.remove(arg, 1)
|
||||
end
|
||||
|
||||
-- convert nils into something more usefuls
|
||||
for i = 1, #arg do
|
||||
if (arg[i] == nil) then
|
||||
arg[i] = "(nil)"
|
||||
elseif (type(arg[i]) == "table") then
|
||||
arg[i] = "{" .. table.concat(arg[i], ", ") .. "}"
|
||||
end
|
||||
end
|
||||
|
||||
local msg = string.format(format, table.unpack(arg))
|
||||
error(debug.traceback(msg, depth), depth)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.filecontains(expected, fn)
|
||||
local f = io.open(fn)
|
||||
local actual = f:read("*a")
|
||||
f:close()
|
||||
if (expected ~= actual) then
|
||||
m.fail("expected %s but was %s", expected, actual)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.hasoutput()
|
||||
local actual = p.captured()
|
||||
if actual == "" then
|
||||
m.fail("expected output, received none");
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isemptycapture()
|
||||
local actual = p.captured()
|
||||
if actual ~= "" then
|
||||
m.fail("expected empty capture, but was %s", actual);
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isequal(expected, actual, depth)
|
||||
depth = depth or 0
|
||||
if type(expected) == "table" then
|
||||
if expected and not actual then
|
||||
m.fail(depth, "expected table, got nil")
|
||||
end
|
||||
if #expected < #actual then
|
||||
m.fail(depth, "expected %d items, got %d", #expected, #actual)
|
||||
end
|
||||
for k,v in pairs(expected) do
|
||||
m.isequal(expected[k], actual[k], depth + 1)
|
||||
end
|
||||
else
|
||||
if (expected ~= actual) then
|
||||
m.fail(depth, "expected %s but was %s", expected, actual or "nil")
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isfalse(value)
|
||||
if (value) then
|
||||
m.fail("expected false but was true")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isnil(value)
|
||||
if (value ~= nil) then
|
||||
m.fail("expected nil but was " .. tostring(value))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isnotnil(value)
|
||||
if (value == nil) then
|
||||
m.fail("expected not nil")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.issame(expected, action)
|
||||
if expected ~= action then
|
||||
m.fail("expected same value")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.istrue(value)
|
||||
if (not value) then
|
||||
m.fail("expected true but was false")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.missing(value, actual)
|
||||
if table.contains(actual, value) then
|
||||
m.fail("unexpected value %s found", value)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.openedfile(fname)
|
||||
if fname ~= m.value_openedfilename then
|
||||
local msg = "expected to open file '" .. fname .. "'"
|
||||
if m.value_openedfilename then
|
||||
msg = msg .. ", got '" .. m.value_openedfilename .. "'"
|
||||
end
|
||||
m.fail(msg)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.success(fn, ...)
|
||||
local ok, err = pcall(fn, ...)
|
||||
if not ok then
|
||||
m.fail("call failed: " .. err)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.stderr(expected)
|
||||
if not expected and m.stderr_capture then
|
||||
m.fail("Unexpected: " .. m.stderr_capture)
|
||||
elseif expected then
|
||||
if not m.stderr_capture or not m.stderr_capture:find(expected) then
|
||||
m.fail(string.format("expected '%s'; got %s", expected, m.stderr_capture or "(nil)"))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.notstderr(expected)
|
||||
if not expected and not m.stderr_capture then
|
||||
m.fail("Expected output on stderr; none received")
|
||||
elseif expected then
|
||||
if m.stderr_capture and m.stderr_capture:find(expected) then
|
||||
m.fail(string.format("stderr contains '%s'; was %s", expected, m.stderr_capture))
|
||||
end
|
||||
end
|
||||
end
|
246
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_declare.lua
vendored
Normal file
246
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_declare.lua
vendored
Normal file
|
@ -0,0 +1,246 @@
|
|||
---
|
||||
-- test_declare.lua
|
||||
--
|
||||
-- Declare unit test suites, and fetch tests from them.
|
||||
--
|
||||
-- Author Jason Perkins
|
||||
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
|
||||
---
|
||||
|
||||
local p = premake
|
||||
local m = p.modules.self_test
|
||||
|
||||
local _ = {}
|
||||
|
||||
|
||||
_.suites = {}
|
||||
_.suppressed = {}
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Declare a new test suite.
|
||||
--
|
||||
-- @param suiteName
|
||||
-- A unique name for the suite. This name will be displayed as part of
|
||||
-- test failure messages, and also to select the suite when using the
|
||||
-- `--test-only` command line parameter. Best to avoid spaces and special
|
||||
-- characters which might not be command line friendly. An error will be
|
||||
-- raised if the name is not unique.
|
||||
-- @return
|
||||
-- The new test suite object.
|
||||
---
|
||||
|
||||
function m.declare(suiteName)
|
||||
if _.suites[suiteName] then
|
||||
error('Duplicate test suite "'.. suiteName .. '"', 2)
|
||||
end
|
||||
|
||||
local _suite = {}
|
||||
-- Setup a metatable for the test suites to use, this will catch duplicate tests
|
||||
local suite = setmetatable({}, {
|
||||
__index = _suite,
|
||||
__newindex = function (table, key, value)
|
||||
if m.detectDuplicateTests and _suite[key] ~= nil then
|
||||
error('Duplicate test "'.. key .. '"', 2)
|
||||
end
|
||||
_suite[key] = value
|
||||
end,
|
||||
__pairs = function (table) return pairs(_suite) end,
|
||||
__ipairs = function (table) return ipairs(_suite) end,
|
||||
})
|
||||
|
||||
suite._SCRIPT_DIR = _SCRIPT_DIR
|
||||
suite._TESTS_DIR = _TESTS_DIR
|
||||
|
||||
_.suites[suiteName] = suite
|
||||
return suite
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Prevent a particular test or suite of tests from running.
|
||||
--
|
||||
-- @param identifier
|
||||
-- A test or suite identifier, indicating which tests should be suppressed,
|
||||
-- in the form "suiteName" or "suiteName.testName".
|
||||
---
|
||||
|
||||
function m.suppress(identifier)
|
||||
if type(identifier) == "table" then
|
||||
for i = 1, #identifier do
|
||||
m.suppress(identifier[i])
|
||||
end
|
||||
else
|
||||
_.suppressed[identifier] = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.isSuppressed(identifier)
|
||||
return _.suppressed[identifier]
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Returns true if the provided test object represents a valid test.
|
||||
---
|
||||
|
||||
function m.isValid(test)
|
||||
if type(test.testFunction) ~= "function" then
|
||||
return false
|
||||
end
|
||||
if test.testName == "setup" or test.testName == "teardown" then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Return the table of declared test suites.
|
||||
---
|
||||
|
||||
function m.getSuites()
|
||||
return _.suites
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Fetch test objects via the string identifier.
|
||||
--
|
||||
-- @param identifier
|
||||
-- An optional test or suite identifier, indicating which tests should be
|
||||
-- run, in the form "suiteName" or "suiteName.testName". If not specified,
|
||||
-- the global test object, representing all test suites, will be returned.
|
||||
-- Use "*" to match any part of a suite or test name
|
||||
-- @return
|
||||
-- On success, returns an array of test objects, which should be considered opaque.
|
||||
-- On failure, returns `nil` and an error.
|
||||
---
|
||||
|
||||
function m.getTestsWithIdentifier(identifier)
|
||||
local suiteName, testName = m.parseTestIdentifier(identifier)
|
||||
|
||||
if suiteName ~= nil and string.contains(suiteName, "*") then
|
||||
local tests = {}
|
||||
|
||||
local pattern = string.gsub(suiteName, "*", ".*")
|
||||
for _suiteName, suite in pairs(_.suites) do
|
||||
local length = string.len(_suiteName)
|
||||
local start, finish = string.find(_suiteName, pattern)
|
||||
if start == 1 and finish == length then
|
||||
if testName ~= nil then
|
||||
if string.contains(testName, "*") then
|
||||
local testPattern = string.gsub(testName, "*", ".*")
|
||||
for _testName, test in pairs(suite) do
|
||||
length = string.len(_testName)
|
||||
start, finish = string.find(_testName, testPattern)
|
||||
if start == 1 and finish == length then
|
||||
table.insert(tests, {
|
||||
suiteName = _suiteName,
|
||||
suite = suite,
|
||||
testName = _testName,
|
||||
testFunction = test,
|
||||
})
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(tests, {
|
||||
suiteName = _suiteName,
|
||||
suite = suite,
|
||||
testName = testName,
|
||||
testFunction = suite[testName],
|
||||
})
|
||||
end
|
||||
else
|
||||
table.insert(tests, {
|
||||
suiteName = _suiteName,
|
||||
suite = suite,
|
||||
testName = nil,
|
||||
testFunction = nil,
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return tests
|
||||
else
|
||||
local suite, test, err = _.checkTestIdentifier(_.suites, suiteName, testName)
|
||||
if err then
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return {
|
||||
{
|
||||
suiteName = suiteName,
|
||||
suite = suite,
|
||||
testName = testName,
|
||||
testFunction = test
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
---
|
||||
-- Parse a test identifier and split it into separate suite and test names.
|
||||
--
|
||||
-- @param identifier
|
||||
-- A test identifier, which may be nil or an empty string, a test suite
|
||||
-- name, or a suite and test with the format "suiteName.testName".
|
||||
-- @return
|
||||
-- Two values: the suite name and the test name, or nil if not included
|
||||
-- in the identifier.
|
||||
---
|
||||
|
||||
function m.parseTestIdentifier(identifier)
|
||||
local suiteName, testName
|
||||
if identifier then
|
||||
local parts = string.explode(identifier, ".", true)
|
||||
suiteName = iif(parts[1] ~= "", parts[1], nil)
|
||||
testName = iif(parts[2] ~= "", parts[2], nil)
|
||||
end
|
||||
return suiteName, testName
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.checkTestIdentifier(suites, suiteName, testName)
|
||||
local suite, test
|
||||
|
||||
if suiteName then
|
||||
suite = suites[suiteName]
|
||||
if not suite then
|
||||
return nil, nil, "No such test suite '" .. suiteName .. "'"
|
||||
end
|
||||
|
||||
if testName then
|
||||
test = suite[testName]
|
||||
if not _.isValidTestPair(testName, test) then
|
||||
return nil, nil, "No such test '" .. suiteName .. "." .. testName .. "'"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return suite, test
|
||||
end
|
||||
|
||||
|
||||
function _.isValidTestPair(testName, testFunc)
|
||||
if type(testFunc) ~= "function" then
|
||||
return false
|
||||
end
|
||||
|
||||
if testName == "setup" or testName == "teardown" then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
87
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_helpers.lua
vendored
Normal file
87
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_helpers.lua
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
---
|
||||
-- test_helpers.lua
|
||||
--
|
||||
-- Helper functions for setting up workspaces and projects, etc.
|
||||
--
|
||||
-- Author Jason Perkins
|
||||
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
|
||||
---
|
||||
|
||||
local p = premake
|
||||
|
||||
local m = p.modules.self_test
|
||||
|
||||
|
||||
|
||||
function m.createWorkspace()
|
||||
local wks = workspace("MyWorkspace")
|
||||
configurations { "Debug", "Release" }
|
||||
local prj = m.createProject(wks)
|
||||
return wks, prj
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- Eventually we'll want to deprecate this one and move everyone
|
||||
-- over to createWorkspace() instead (4 Sep 2015).
|
||||
|
||||
function m.createsolution()
|
||||
local wks = workspace("MySolution")
|
||||
configurations { "Debug", "Release" }
|
||||
local prj = m.createproject(wks)
|
||||
return wks, prj
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.createProject(wks)
|
||||
local n = #wks.projects + 1
|
||||
if n == 1 then n = "" end
|
||||
|
||||
local prj = project ("MyProject" .. n)
|
||||
language "C++"
|
||||
kind "ConsoleApp"
|
||||
return prj
|
||||
end
|
||||
|
||||
function m.createGroup(wks)
|
||||
local prj = group ("MyGroup" .. (#wks.groups + 1))
|
||||
return prj
|
||||
end
|
||||
|
||||
|
||||
function m.getWorkspace(wks)
|
||||
p.oven.bake()
|
||||
return p.global.getWorkspace(wks.name)
|
||||
end
|
||||
|
||||
|
||||
function m.getRule(name)
|
||||
p.oven.bake()
|
||||
return p.global.getRule(name)
|
||||
end
|
||||
|
||||
|
||||
function m.getProject(wks, i)
|
||||
wks = m.getWorkspace(wks)
|
||||
return p.workspace.getproject(wks, i or 1)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function m.getConfig(prj, buildcfg, platform)
|
||||
local wks = m.getWorkspace(prj.workspace)
|
||||
prj = p.workspace.getproject(wks, prj.name)
|
||||
return p.project.getconfig(prj, buildcfg, platform)
|
||||
end
|
||||
|
||||
|
||||
|
||||
m.print = print
|
||||
|
||||
|
||||
|
||||
p.alias(m, "createProject", "createproject")
|
||||
p.alias(m, "getConfig", "getconfig")
|
||||
p.alias(m, "getProject", "getproject")
|
||||
p.alias(m, "getWorkspace", "getsolution")
|
337
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_runner.lua
vendored
Normal file
337
Src/external_dependencies/openmpt-trunk/include/premake/modules/self-test/test_runner.lua
vendored
Normal file
|
@ -0,0 +1,337 @@
|
|||
---
|
||||
-- self-test/test_runner.lua
|
||||
--
|
||||
-- Execute unit tests and test suites.
|
||||
--
|
||||
-- Author Jason Perkins
|
||||
-- Copyright (c) 2008-2016 Jason Perkins and the Premake project.
|
||||
---
|
||||
|
||||
local p = premake
|
||||
|
||||
local m = p.modules.self_test
|
||||
|
||||
local _ = {}
|
||||
|
||||
|
||||
|
||||
function m.runTest(tests)
|
||||
local failed = 0
|
||||
local failedTests = {}
|
||||
|
||||
local suites = m.getSuites()
|
||||
local suitesKeys, suiteTestsKeys, totalTestCount = _.preprocessTests(suites, tests)
|
||||
|
||||
_.log(term.lightGreen, "[==========]", string.format(" Running %d tests from %d test suites.", totalTestCount, #suitesKeys))
|
||||
local startTime = os.clock()
|
||||
|
||||
for index, suiteName in ipairs(suitesKeys) do
|
||||
suite = suites[suiteName]
|
||||
if not m.isSuppressed(suiteName) then
|
||||
local test = {
|
||||
suiteName = suiteName,
|
||||
suite = suite
|
||||
}
|
||||
|
||||
local suiteFailed, suiteFailedTests = _.runTestSuite(test, suiteTestsKeys[suiteName])
|
||||
|
||||
failed = failed + suiteFailed
|
||||
failedTests = table.join(failedTests, suiteFailedTests)
|
||||
end
|
||||
end
|
||||
|
||||
_.log(term.lightGreen, "[==========]", string.format(" %d tests from %d test suites ran. (%.0f ms total)", totalTestCount, #suitesKeys, (os.clock() - startTime) * 1000))
|
||||
_.log(term.lightGreen, "[ PASSED ]", string.format(" %d tests.", totalTestCount - failed))
|
||||
if failed > 0 then
|
||||
_.log(term.lightRed, "[ FAILED ]", string.format(" %d tests, listed below:", failed))
|
||||
for index, testName in ipairs(failedTests) do
|
||||
_.log(term.lightRed, "[ FAILED ]", " " .. testName)
|
||||
end
|
||||
end
|
||||
|
||||
return (totalTestCount - failed), failed
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.runTestSuite(test, keys)
|
||||
local failed = 0
|
||||
local failedTests = {}
|
||||
_.log(term.lightGreen, "[----------]", string.format(" %d tests from %s", #keys, test.suiteName))
|
||||
local startTime = os.clock()
|
||||
|
||||
if test.suite ~= nil then
|
||||
for index, testName in ipairs(keys) do
|
||||
testFunction = test.suite[testName]
|
||||
test.testName = testName
|
||||
test.testFunction = testFunction
|
||||
|
||||
if m.isValid(test) and not m.isSuppressed(test.suiteName .. "." .. test.testName) then
|
||||
local err = _.runTest(test)
|
||||
if err then
|
||||
failed = failed + 1
|
||||
table.insert(failedTests, test.suiteName .. "." .. test.testName .. "\n" .. err)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
_.log(term.lightGreen, "[----------]", string.format(" %d tests from %s (%.0f ms total)\n", #keys, test.suiteName, (os.clock() - startTime) * 1000))
|
||||
return failed, failedTests
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.runTest(test)
|
||||
_.log(term.lightGreen, "[ RUN ]", string.format(" %s.%s", test.suiteName, test.testName))
|
||||
local startTime = os.clock()
|
||||
local cwd = os.getcwd()
|
||||
local hooks = _.installTestingHooks()
|
||||
|
||||
_TESTS_DIR = test.suite._TESTS_DIR
|
||||
_SCRIPT_DIR = test.suite._SCRIPT_DIR
|
||||
|
||||
m.suiteName = test.suiteName
|
||||
m.testName = test.testName
|
||||
|
||||
local ok, err = _.setupTest(test)
|
||||
|
||||
if ok then
|
||||
ok, err = _.executeTest(test)
|
||||
end
|
||||
|
||||
local tok, terr = _.teardownTest(test)
|
||||
ok = ok and tok
|
||||
err = err or terr
|
||||
|
||||
_.removeTestingHooks(hooks)
|
||||
os.chdir(cwd)
|
||||
|
||||
if ok then
|
||||
_.log(term.lightGreen, "[ OK ]", string.format(" %s.%s (%.0f ms)", test.suiteName, test.testName, (os.clock() - startTime) * 1000))
|
||||
return nil
|
||||
else
|
||||
_.log(term.lightRed, "[ FAILED ]", string.format(" %s.%s (%.0f ms)", test.suiteName, test.testName, (os.clock() - startTime) * 1000))
|
||||
m.print(string.format("%s", err))
|
||||
return err
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.log(color, left, right)
|
||||
term.pushColor(color)
|
||||
io.write(left)
|
||||
term.popColor()
|
||||
m.print(right)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.preprocessTests(suites, filters)
|
||||
local suitesKeys = {}
|
||||
local suiteTestsKeys = {}
|
||||
local totalTestCount = 0
|
||||
|
||||
for i, filter in ipairs(filters) do
|
||||
for suiteName, suite in pairs(suites) do
|
||||
if not m.isSuppressed(suiteName) and suite ~= nil and (not filter.suiteName or filter.suiteName == suiteName) then
|
||||
local test = {}
|
||||
|
||||
test.suiteName = suiteName
|
||||
test.suite = suite
|
||||
|
||||
if not table.contains(suitesKeys, suiteName) then
|
||||
table.insertsorted(suitesKeys, suiteName)
|
||||
suiteTestsKeys[suiteName] = {}
|
||||
end
|
||||
|
||||
for testName, testFunction in pairs(suite) do
|
||||
test.testName = testName
|
||||
test.testFunction = testFunction
|
||||
|
||||
if m.isValid(test) and not m.isSuppressed(test.suiteName .. "." .. test.testName) and (not filter.testName or filter.testName == testName) then
|
||||
if not table.contains(suiteTestsKeys[suiteName], testName) then
|
||||
table.insertsorted(suiteTestsKeys[suiteName], testName)
|
||||
totalTestCount = totalTestCount + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return suitesKeys, suiteTestsKeys, totalTestCount
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.installTestingHooks()
|
||||
local hooks = {}
|
||||
|
||||
hooks.action = _ACTION
|
||||
hooks.options = _OPTIONS
|
||||
hooks.targetOs = _TARGET_OS
|
||||
|
||||
hooks.io_open = io.open
|
||||
hooks.io_output = io.output
|
||||
hooks.os_writefile_ifnotequal = os.writefile_ifnotequal
|
||||
hooks.p_utf8 = p.utf8
|
||||
hooks.print = print
|
||||
hooks.setTextColor = term.setTextColor
|
||||
|
||||
local mt = getmetatable(io.stderr)
|
||||
_.builtin_write = mt.write
|
||||
mt.write = _.stub_stderr_write
|
||||
|
||||
_OPTIONS = table.shallowcopy(_OPTIONS) or {}
|
||||
setmetatable(_OPTIONS, getmetatable(hooks.options))
|
||||
|
||||
io.open = _.stub_io_open
|
||||
io.output = _.stub_io_output
|
||||
os.writefile_ifnotequal = _.stub_os_writefile_ifnotequal
|
||||
print = _.stub_print
|
||||
p.utf8 = _.stub_utf8
|
||||
term.setTextColor = _.stub_setTextColor
|
||||
|
||||
stderr_capture = nil
|
||||
|
||||
p.clearWarnings()
|
||||
p.eol("\n")
|
||||
p.escaper(nil)
|
||||
p.indent("\t")
|
||||
p.api.reset()
|
||||
|
||||
m.stderr_capture = nil
|
||||
m.value_openedfilename = nil
|
||||
m.value_openedfilemode = nil
|
||||
m.value_closedfile = false
|
||||
|
||||
return hooks
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function _.removeTestingHooks(hooks)
|
||||
p.action.set(hooks.action)
|
||||
_OPTIONS = hooks.options
|
||||
_TARGET_OS = hooks.targetOs
|
||||
|
||||
io.open = hooks.io_open
|
||||
io.output = hooks.io_output
|
||||
os.writefile_ifnotequal = hooks.os_writefile_ifnotequal
|
||||
p.utf8 = hooks.p_utf8
|
||||
print = hooks.print
|
||||
term.setTextColor = hooks.setTextColor
|
||||
|
||||
local mt = getmetatable(io.stderr)
|
||||
mt.write = _.builtin_write
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.setupTest(test)
|
||||
if type(test.suite.setup) == "function" then
|
||||
return xpcall(test.suite.setup, _.errorHandler)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.executeTest(test)
|
||||
local result, err
|
||||
p.capture(function()
|
||||
result, err = xpcall(test.testFunction, _.errorHandler)
|
||||
end)
|
||||
return result, err
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.teardownTest(test)
|
||||
if type(test.suite.teardown) == "function" then
|
||||
return xpcall(test.suite.teardown, _.errorHandler)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.errorHandler(err)
|
||||
local msg = err
|
||||
|
||||
-- if the error doesn't include a stack trace, add one
|
||||
if not msg:find("stack traceback:", 1, true) then
|
||||
msg = debug.traceback(err, 2)
|
||||
end
|
||||
|
||||
-- trim of the trailing context of the originating xpcall
|
||||
local i = msg:find("[C]: in function 'xpcall'", 1, true)
|
||||
if i then
|
||||
msg = msg:sub(1, i - 3)
|
||||
end
|
||||
|
||||
-- if the resulting stack trace is only one level deep, ignore it
|
||||
local n = select(2, msg:gsub('\n', '\n'))
|
||||
if n == 2 then
|
||||
msg = msg:sub(1, msg:find('\n', 1, true) - 1)
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.stub_io_open(fname, mode)
|
||||
m.value_openedfilename = fname
|
||||
m.value_openedfilemode = mode
|
||||
return {
|
||||
read = function()
|
||||
end,
|
||||
close = function()
|
||||
m.value_closedfile = true
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.stub_io_output(f)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.stub_os_writefile_ifnotequal(content, fname)
|
||||
m.value_openedfilename = fname
|
||||
m.value_closedfile = true
|
||||
return 0
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.stub_print(s)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function _.stub_stderr_write(...)
|
||||
if select(1, ...) == io.stderr then
|
||||
m.stderr_capture = (m.stderr_capture or "") .. select(2, ...)
|
||||
else
|
||||
return _.builtin_write(...)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
function _.stub_utf8()
|
||||
end
|
||||
|
||||
|
||||
function _.stub_setTextColor()
|
||||
end
|
Loading…
Add table
Add a link
Reference in a new issue