123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- ---
- -- 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
|