2016-05-18 19:56:04 +00:00
|
|
|
---
|
|
|
|
-- 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 = {}
|
2016-05-25 20:55:49 +00:00
|
|
|
_.suppressed = {}
|
2016-05-18 19:56:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
-- 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
|
|
|
|
|
2018-04-30 13:40:49 +00:00
|
|
|
local _suite = {}
|
|
|
|
-- Setup a metatable for the test suites to use, this will catch duplicate tests
|
|
|
|
local suite = setmetatable({}, {
|
|
|
|
__index = _suite,
|
2018-04-30 13:41:45 +00:00
|
|
|
__newindex = function (table, key, value)
|
|
|
|
if m.detectDuplicateTests and _suite[key] ~= nil then
|
|
|
|
error('Duplicate test "'.. key .. '"', 2)
|
|
|
|
end
|
|
|
|
_suite[key] = value
|
|
|
|
end,
|
2018-04-30 13:40:49 +00:00
|
|
|
__pairs = function (table) return pairs(_suite) end,
|
|
|
|
__ipairs = function (table) return ipairs(_suite) end,
|
|
|
|
})
|
2016-05-18 19:56:04 +00:00
|
|
|
|
|
|
|
suite._SCRIPT_DIR = _SCRIPT_DIR
|
|
|
|
suite._TESTS_DIR = _TESTS_DIR
|
|
|
|
|
|
|
|
_.suites[suiteName] = suite
|
|
|
|
return suite
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-25 20:55:49 +00:00
|
|
|
---
|
|
|
|
-- 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
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-21 00:13:04 +00:00
|
|
|
---
|
|
|
|
-- 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2018-06-14 14:51:36 +00:00
|
|
|
-- Fetch test objects via the string identifier.
|
2016-05-21 00:13:04 +00:00
|
|
|
--
|
|
|
|
-- @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.
|
2018-06-14 14:51:36 +00:00
|
|
|
-- Use "*" to match any part of a suite or test name
|
2016-05-21 00:13:04 +00:00
|
|
|
-- @return
|
2018-06-14 14:51:36 +00:00
|
|
|
-- On success, returns an array of test objects, which should be considered opaque.
|
2016-05-21 00:13:04 +00:00
|
|
|
-- On failure, returns `nil` and an error.
|
|
|
|
---
|
|
|
|
|
2018-06-14 14:51:36 +00:00
|
|
|
function m.getTestsWithIdentifier(identifier)
|
2016-05-21 00:13:04 +00:00
|
|
|
local suiteName, testName = m.parseTestIdentifier(identifier)
|
|
|
|
|
2018-06-14 14:51:36 +00:00
|
|
|
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
|
2016-05-21 00:13:04 +00:00
|
|
|
|
2018-06-14 14:51:36 +00:00
|
|
|
return {
|
|
|
|
{
|
|
|
|
suiteName = suiteName,
|
|
|
|
suite = suite,
|
|
|
|
testName = testName,
|
|
|
|
testFunction = test
|
|
|
|
}
|
|
|
|
}
|
|
|
|
end
|
2016-05-21 00:13:04 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
2016-05-18 19:56:04 +00:00
|
|
|
---
|
|
|
|
-- 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
|
2016-05-21 00:13:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|