From d909724d70acd680965b8f2963c79cee4d7fc23f Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 02:32:09 +0300 Subject: tests: Use our own output handler on travis Reasoning: 1. gtest is better then something like utfTerminal, yet it is way too verbose. 2. gtest cannot be configured to show colors always. 3. Actually I am going to add a CMake target which will allow running tests (especially, functional tests) in parallel, but this is not going to work well with any of the default output handlers. Build in this case must be more or less silent, yet debuggable. New handler does not support this in this commit though. --- .travis.yml | 2 +- busted/outputHandlers/neovim.lua | 301 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 302 insertions(+), 1 deletion(-) create mode 100644 busted/outputHandlers/neovim.lua diff --git a/.travis.yml b/.travis.yml index b8c4c0172f..60ee35a8f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ env: - CMAKE_FLAGS="-DTRAVIS_CI_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX - -DBUSTED_OUTPUT_TYPE=gtest + -DBUSTED_OUTPUT_TYPE=neovim -DDEPS_PREFIX=$DEPS_BUILD_DIR/usr -DMIN_LOG_LEVEL=2" - DEPS_CMAKE_FLAGS="-DDEPS_DOWNLOAD_DIR:PATH=$DEPS_DOWNLOAD_DIR" diff --git a/busted/outputHandlers/neovim.lua b/busted/outputHandlers/neovim.lua new file mode 100644 index 0000000000..3c77f57c0f --- /dev/null +++ b/busted/outputHandlers/neovim.lua @@ -0,0 +1,301 @@ +local s = require 'say' +local pretty = require 'pl.pretty' +local term = require 'term' + +local colors + +local isWindows = package.config:sub(1,1) == '\\' + +if isWindows then + colors = setmetatable({}, {__index = function() return function(s) return s end end}) +else + colors = require 'term.colors' +end + +return function(options) + local busted = require 'busted' + local handler = require 'busted.outputHandlers.base'() + + local c = { + succ = function(s) return colors.bright(colors.green(s)) end, + skip = function(s) return colors.bright(colors.yellow(s)) end, + fail = function(s) return colors.bright(colors.magenta(s)) end, + errr = function(s) return colors.bright(colors.red(s)) end, + test = tostring, + file = colors.cyan, + time = colors.dim, + note = colors.yellow, + sect = function(s) return colors.green(colors.dim(s)) end, + nmbr = colors.bright, + } + + local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n' + local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n') + local globalSetup = c.sect('[----------]') .. ' Global test environment setup.\n' + local fileStartString = c.sect('[----------]') .. ' Running tests from ' .. c.file('%s') .. '\n' + local runString = c.sect('[ RUN ]') .. ' ' .. c.test('%s') .. ': ' + local successString = c.time('%.2f ms') .. ' ' .. c.succ('OK') .. '\n' + local skippedString = c.time('%.2f ms') .. ' ' .. c.skip('SKIP') .. '\n' + local failureString = c.fail('FAIL') .. '\n' + local errorString = c.errr('ERR') .. '\n' + local fileEndString = c.sect('[----------]') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n' + local globalTeardown = c.sect('[----------]') .. ' Global test environment teardown.\n' + local suiteEndString = c.sect('[==========]') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n' + local successStatus = c.succ('[ PASSED ]') .. ' ' .. c.nmbr('%d') .. ' %s.\n' + + local summaryStrings = { + skipped = { + header = c.skip('[ SKIPPED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.skip('[ SKIPPED ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' SKIPPED %s\n', + }, + + failure = { + header = c.fail('[ FAILED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.fail('[ FAILED ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' FAILED %s\n', + }, + + error = { + header = c.errr('[ ERROR ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.errr('[ ERROR ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' %s\n', + }, + } + + c = nil + + local fileCount = 0 + local fileTestCount = 0 + local testCount = 0 + local successCount = 0 + local skippedCount = 0 + local failureCount = 0 + local errorCount = 0 + + local pendingDescription = function(pending) + local name = pending.name + local string = '' + + if type(pending.message) == 'string' then + string = string .. pending.message .. '\n' + elseif pending.message ~= nil then + string = string .. pretty.write(pending.message) .. '\n' + end + + return string + end + + local failureDescription = function(failure) + local string = failure.randomseed and ('Random seed: ' .. failure.randomseed .. '\n') or '' + if type(failure.message) == 'string' then + string = string .. failure.message + elseif failure.message == nil then + string = string .. 'Nil error' + else + string = string .. pretty.write(failure.message) + end + + string = string .. '\n' + + if options.verbose and failure.trace and failure.trace.traceback then + string = string .. failure.trace.traceback .. '\n' + end + + return string + end + + local getFileLine = function(element) + local fileline = '' + if element.trace or element.trace.short_src then + fileline = colors.cyan(element.trace.short_src) .. ' @ ' .. + colors.cyan(element.trace.currentline) .. ': ' + end + return fileline + end + + local getTestList = function(status, count, list, getDescription) + local string = '' + local header = summaryStrings[status].header + if count > 0 and header then + local tests = (count == 1 and 'test' or 'tests') + local errors = (count == 1 and 'error' or 'errors') + string = header:format(count, status == 'error' and errors or tests) + + local testString = summaryStrings[status].test + if testString then + for _, t in ipairs(list) do + local fullname = getFileLine(t.element) .. colors.bright(t.name) + string = string .. testString:format(fullname) + if options.deferPrint then + string = string .. getDescription(t) + end + end + end + end + return string + end + + local getSummary = function(status, count) + local string = '' + local footer = summaryStrings[status].footer + if count > 0 and footer then + local tests = (count == 1 and 'TEST' or 'TESTS') + local errors = (count == 1 and 'ERROR' or 'ERRORS') + string = footer:format(count, status == 'error' and errors or tests) + end + return string + end + + local getSummaryString = function() + local tests = (successCount == 1 and 'test' or 'tests') + local string = successStatus:format(successCount, tests) + + string = string .. getTestList('skipped', skippedCount, handler.pendings, pendingDescription) + string = string .. getTestList('failure', failureCount, handler.failures, failureDescription) + string = string .. getTestList('error', errorCount, handler.errors, failureDescription) + + string = string .. ((skippedCount + failureCount + errorCount) > 0 and '\n' or '') + string = string .. getSummary('skipped', skippedCount) + string = string .. getSummary('failure', failureCount) + string = string .. getSummary('error', errorCount) + + return string + end + + handler.suiteReset = function() + fileCount = 0 + fileTestCount = 0 + testCount = 0 + successCount = 0 + skippedCount = 0 + failureCount = 0 + errorCount = 0 + + return nil, true + end + + handler.suiteStart = function(suite, count, total, randomseed) + if total > 1 then + io.write(repeatSuiteString:format(count, total)) + end + if randomseed then + io.write(randomizeString:format(randomseed)) + end + io.write(globalSetup) + io.flush() + + return nil, true + end + + handler.suiteEnd = function(suite, count, total) + local elapsedTime_ms = suite.duration * 1000 + local tests = (testCount == 1 and 'test' or 'tests') + local files = (fileCount == 1 and 'file' or 'files') + io.write(globalTeardown) + io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms)) + io.write(getSummaryString()) + io.flush() + + return nil, true + end + + handler.fileStart = function(file) + fileTestCount = 0 + io.write(fileStartString:format(file.name)) + io.flush() + return nil, true + end + + handler.fileEnd = function(file) + local elapsedTime_ms = file.duration * 1000 + local tests = (fileTestCount == 1 and 'test' or 'tests') + fileCount = fileCount + 1 + io.write(fileEndString:format(fileTestCount, tests, file.name, elapsedTime_ms)) + io.flush() + return nil, true + end + + handler.testStart = function(element, parent) + io.write(runString:format(handler.getFullName(element))) + io.flush() + + return nil, true + end + + handler.testEnd = function(element, parent, status, debug) + local elapsedTime_ms = element.duration * 1000 + local string + + fileTestCount = fileTestCount + 1 + testCount = testCount + 1 + if status == 'success' then + successCount = successCount + 1 + string = successString + elseif status == 'pending' then + skippedCount = skippedCount + 1 + string = skippedString + elseif status == 'failure' then + failureCount = failureCount + 1 + string = nil + elseif status == 'error' then + errorCount = errorCount + 1 + string = nil + end + + if string ~= nil then + io.write(string:format(elapsedTime_ms)) + io.flush() + end + + return nil, true + end + + handler.testFailure = function(element, parent, message, debug) + io.write(failureString) + io.flush() + + if not options.deferPrint then + io.write(failureDescription(handler.failures[#handler.failures])) + io.flush() + end + return nil, true + end + + handler.testError = function(element, parent, message, debug) + io.write(errorString) + io.flush() + + if not options.deferPrint then + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() + end + return nil, true + end + + handler.error = function(element, parent, message, debug) + if element.descriptor ~= 'it' then + if not options.deferPrint then + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() + end + errorCount = errorCount + 1 + end + + return nil, true + end + + busted.subscribe({ 'suite', 'reset' }, handler.suiteReset) + busted.subscribe({ 'suite', 'start' }, handler.suiteStart) + busted.subscribe({ 'suite', 'end' }, handler.suiteEnd) + busted.subscribe({ 'file', 'start' }, handler.fileStart) + busted.subscribe({ 'file', 'end' }, handler.fileEnd) + busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending }) + busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending }) + busted.subscribe({ 'failure', 'it' }, handler.testFailure) + busted.subscribe({ 'error', 'it' }, handler.testError) + busted.subscribe({ 'failure' }, handler.error) + busted.subscribe({ 'error' }, handler.error) + + return handler +end -- cgit From bc61058dd89b45b77074dc72fbb71003a3961bfd Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 02:51:27 +0300 Subject: tests: Print description also at the end of the suite --- busted/outputHandlers/neovim.lua | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/busted/outputHandlers/neovim.lua b/busted/outputHandlers/neovim.lua index 3c77f57c0f..2e74e612a9 100644 --- a/busted/outputHandlers/neovim.lua +++ b/busted/outputHandlers/neovim.lua @@ -127,9 +127,7 @@ return function(options) for _, t in ipairs(list) do local fullname = getFileLine(t.element) .. colors.bright(t.name) string = string .. testString:format(fullname) - if options.deferPrint then - string = string .. getDescription(t) - end + string = string .. getDescription(t) end end end @@ -255,10 +253,8 @@ return function(options) io.write(failureString) io.flush() - if not options.deferPrint then - io.write(failureDescription(handler.failures[#handler.failures])) - io.flush() - end + io.write(failureDescription(handler.failures[#handler.failures])) + io.flush() return nil, true end @@ -266,19 +262,15 @@ return function(options) io.write(errorString) io.flush() - if not options.deferPrint then - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() - end + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() return nil, true end handler.error = function(element, parent, message, debug) if element.descriptor ~= 'it' then - if not options.deferPrint then - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() - end + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() errorCount = errorCount + 1 end -- cgit From accc7a0b6cf1d2c036181be18a512b791f3ceb79 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 03:16:56 +0300 Subject: tests: Skip dumping elapsed times when not available Should provide some compatibility with old busted. And also removes duplicate parts from successString and skippedString, making them more like failureString and errorString which do not have times for technical reasons (busted for some reason did not yet compute duration before running the relevant handlers). --- busted/outputHandlers/neovim.lua | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/busted/outputHandlers/neovim.lua b/busted/outputHandlers/neovim.lua index 2e74e612a9..b612ead070 100644 --- a/busted/outputHandlers/neovim.lua +++ b/busted/outputHandlers/neovim.lua @@ -34,14 +34,15 @@ return function(options) local globalSetup = c.sect('[----------]') .. ' Global test environment setup.\n' local fileStartString = c.sect('[----------]') .. ' Running tests from ' .. c.file('%s') .. '\n' local runString = c.sect('[ RUN ]') .. ' ' .. c.test('%s') .. ': ' - local successString = c.time('%.2f ms') .. ' ' .. c.succ('OK') .. '\n' - local skippedString = c.time('%.2f ms') .. ' ' .. c.skip('SKIP') .. '\n' - local failureString = c.fail('FAIL') .. '\n' - local errorString = c.errr('ERR') .. '\n' + local successString = c.succ('OK') .. '\n' + local skippedString = c.skip('SKIP') .. '\n' + local failureString = c.fail('FAIL') .. '\n' + local errorString = c.errr('ERR') .. '\n' local fileEndString = c.sect('[----------]') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n' local globalTeardown = c.sect('[----------]') .. ' Global test environment teardown.\n' local suiteEndString = c.sect('[==========]') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n' local successStatus = c.succ('[ PASSED ]') .. ' ' .. c.nmbr('%d') .. ' %s.\n' + local timeString = c.time('%.2f ms') local summaryStrings = { skipped = { @@ -186,8 +187,16 @@ return function(options) return nil, true end + local function getElapsedTime(tbl) + if tbl.duration then + return tbl.duration * 1000 + else + return tonumber('nan') + end + end + handler.suiteEnd = function(suite, count, total) - local elapsedTime_ms = suite.duration * 1000 + local elapsedTime_ms = getElapsedTime(suite) local tests = (testCount == 1 and 'test' or 'tests') local files = (fileCount == 1 and 'file' or 'files') io.write(globalTeardown) @@ -206,7 +215,7 @@ return function(options) end handler.fileEnd = function(file) - local elapsedTime_ms = file.duration * 1000 + local elapsedTime_ms = getElapsedTime(file) local tests = (fileTestCount == 1 and 'test' or 'tests') fileCount = fileCount + 1 io.write(fileEndString:format(fileTestCount, tests, file.name, elapsedTime_ms)) @@ -222,7 +231,7 @@ return function(options) end handler.testEnd = function(element, parent, status, debug) - local elapsedTime_ms = element.duration * 1000 + local elapsedTime_ms = getElapsedTime(element) local string fileTestCount = fileTestCount + 1 @@ -242,7 +251,10 @@ return function(options) end if string ~= nil then - io.write(string:format(elapsedTime_ms)) + if elapsedTime_ms == elapsedTime_ms then + string = timeString:format(elapsedTime_ms) .. ' ' .. string + end + io.write(string) io.flush() end -- cgit From 40dee9744233ea0f14aaa16e9ef0395b57604806 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 03:17:14 +0300 Subject: third-party: Update busted version --- third-party/cmake/BuildLuarocks.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third-party/cmake/BuildLuarocks.cmake b/third-party/cmake/BuildLuarocks.cmake index 9ea96b7cc5..7312b6f91b 100644 --- a/third-party/cmake/BuildLuarocks.cmake +++ b/third-party/cmake/BuildLuarocks.cmake @@ -137,7 +137,7 @@ if(USE_BUNDLED_BUSTED) endif() add_custom_command(OUTPUT ${BUSTED_EXE} COMMAND ${LUAROCKS_BINARY} - ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc11-0/busted-2.0.rc11-0.rockspec ${LUAROCKS_BUILDARGS} + ARGS build https://raw.githubusercontent.com/Olivine-Labs/busted/v2.0.rc12-1/busted-2.0.rc12-1.rockspec ${LUAROCKS_BUILDARGS} DEPENDS penlight) add_custom_target(busted DEPENDS ${BUSTED_EXE}) -- cgit From 6f5e87e4aac59e3d24c1547d3a9163fb3cc50c00 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 03:33:00 +0300 Subject: tests: Rename neovim output handler to nvim --- .travis.yml | 2 +- busted/outputHandlers/neovim.lua | 305 --------------------------------------- busted/outputHandlers/nvim.lua | 305 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 306 deletions(-) delete mode 100644 busted/outputHandlers/neovim.lua create mode 100644 busted/outputHandlers/nvim.lua diff --git a/.travis.yml b/.travis.yml index 60ee35a8f7..62d9ebebda 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,7 @@ env: - CMAKE_FLAGS="-DTRAVIS_CI_BUILD=ON -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX:PATH=$INSTALL_PREFIX - -DBUSTED_OUTPUT_TYPE=neovim + -DBUSTED_OUTPUT_TYPE=nvim -DDEPS_PREFIX=$DEPS_BUILD_DIR/usr -DMIN_LOG_LEVEL=2" - DEPS_CMAKE_FLAGS="-DDEPS_DOWNLOAD_DIR:PATH=$DEPS_DOWNLOAD_DIR" diff --git a/busted/outputHandlers/neovim.lua b/busted/outputHandlers/neovim.lua deleted file mode 100644 index b612ead070..0000000000 --- a/busted/outputHandlers/neovim.lua +++ /dev/null @@ -1,305 +0,0 @@ -local s = require 'say' -local pretty = require 'pl.pretty' -local term = require 'term' - -local colors - -local isWindows = package.config:sub(1,1) == '\\' - -if isWindows then - colors = setmetatable({}, {__index = function() return function(s) return s end end}) -else - colors = require 'term.colors' -end - -return function(options) - local busted = require 'busted' - local handler = require 'busted.outputHandlers.base'() - - local c = { - succ = function(s) return colors.bright(colors.green(s)) end, - skip = function(s) return colors.bright(colors.yellow(s)) end, - fail = function(s) return colors.bright(colors.magenta(s)) end, - errr = function(s) return colors.bright(colors.red(s)) end, - test = tostring, - file = colors.cyan, - time = colors.dim, - note = colors.yellow, - sect = function(s) return colors.green(colors.dim(s)) end, - nmbr = colors.bright, - } - - local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n' - local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n') - local globalSetup = c.sect('[----------]') .. ' Global test environment setup.\n' - local fileStartString = c.sect('[----------]') .. ' Running tests from ' .. c.file('%s') .. '\n' - local runString = c.sect('[ RUN ]') .. ' ' .. c.test('%s') .. ': ' - local successString = c.succ('OK') .. '\n' - local skippedString = c.skip('SKIP') .. '\n' - local failureString = c.fail('FAIL') .. '\n' - local errorString = c.errr('ERR') .. '\n' - local fileEndString = c.sect('[----------]') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n' - local globalTeardown = c.sect('[----------]') .. ' Global test environment teardown.\n' - local suiteEndString = c.sect('[==========]') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n' - local successStatus = c.succ('[ PASSED ]') .. ' ' .. c.nmbr('%d') .. ' %s.\n' - local timeString = c.time('%.2f ms') - - local summaryStrings = { - skipped = { - header = c.skip('[ SKIPPED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', - test = c.skip('[ SKIPPED ]') .. ' %s\n', - footer = ' ' .. c.nmbr('%d') .. ' SKIPPED %s\n', - }, - - failure = { - header = c.fail('[ FAILED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', - test = c.fail('[ FAILED ]') .. ' %s\n', - footer = ' ' .. c.nmbr('%d') .. ' FAILED %s\n', - }, - - error = { - header = c.errr('[ ERROR ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', - test = c.errr('[ ERROR ]') .. ' %s\n', - footer = ' ' .. c.nmbr('%d') .. ' %s\n', - }, - } - - c = nil - - local fileCount = 0 - local fileTestCount = 0 - local testCount = 0 - local successCount = 0 - local skippedCount = 0 - local failureCount = 0 - local errorCount = 0 - - local pendingDescription = function(pending) - local name = pending.name - local string = '' - - if type(pending.message) == 'string' then - string = string .. pending.message .. '\n' - elseif pending.message ~= nil then - string = string .. pretty.write(pending.message) .. '\n' - end - - return string - end - - local failureDescription = function(failure) - local string = failure.randomseed and ('Random seed: ' .. failure.randomseed .. '\n') or '' - if type(failure.message) == 'string' then - string = string .. failure.message - elseif failure.message == nil then - string = string .. 'Nil error' - else - string = string .. pretty.write(failure.message) - end - - string = string .. '\n' - - if options.verbose and failure.trace and failure.trace.traceback then - string = string .. failure.trace.traceback .. '\n' - end - - return string - end - - local getFileLine = function(element) - local fileline = '' - if element.trace or element.trace.short_src then - fileline = colors.cyan(element.trace.short_src) .. ' @ ' .. - colors.cyan(element.trace.currentline) .. ': ' - end - return fileline - end - - local getTestList = function(status, count, list, getDescription) - local string = '' - local header = summaryStrings[status].header - if count > 0 and header then - local tests = (count == 1 and 'test' or 'tests') - local errors = (count == 1 and 'error' or 'errors') - string = header:format(count, status == 'error' and errors or tests) - - local testString = summaryStrings[status].test - if testString then - for _, t in ipairs(list) do - local fullname = getFileLine(t.element) .. colors.bright(t.name) - string = string .. testString:format(fullname) - string = string .. getDescription(t) - end - end - end - return string - end - - local getSummary = function(status, count) - local string = '' - local footer = summaryStrings[status].footer - if count > 0 and footer then - local tests = (count == 1 and 'TEST' or 'TESTS') - local errors = (count == 1 and 'ERROR' or 'ERRORS') - string = footer:format(count, status == 'error' and errors or tests) - end - return string - end - - local getSummaryString = function() - local tests = (successCount == 1 and 'test' or 'tests') - local string = successStatus:format(successCount, tests) - - string = string .. getTestList('skipped', skippedCount, handler.pendings, pendingDescription) - string = string .. getTestList('failure', failureCount, handler.failures, failureDescription) - string = string .. getTestList('error', errorCount, handler.errors, failureDescription) - - string = string .. ((skippedCount + failureCount + errorCount) > 0 and '\n' or '') - string = string .. getSummary('skipped', skippedCount) - string = string .. getSummary('failure', failureCount) - string = string .. getSummary('error', errorCount) - - return string - end - - handler.suiteReset = function() - fileCount = 0 - fileTestCount = 0 - testCount = 0 - successCount = 0 - skippedCount = 0 - failureCount = 0 - errorCount = 0 - - return nil, true - end - - handler.suiteStart = function(suite, count, total, randomseed) - if total > 1 then - io.write(repeatSuiteString:format(count, total)) - end - if randomseed then - io.write(randomizeString:format(randomseed)) - end - io.write(globalSetup) - io.flush() - - return nil, true - end - - local function getElapsedTime(tbl) - if tbl.duration then - return tbl.duration * 1000 - else - return tonumber('nan') - end - end - - handler.suiteEnd = function(suite, count, total) - local elapsedTime_ms = getElapsedTime(suite) - local tests = (testCount == 1 and 'test' or 'tests') - local files = (fileCount == 1 and 'file' or 'files') - io.write(globalTeardown) - io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms)) - io.write(getSummaryString()) - io.flush() - - return nil, true - end - - handler.fileStart = function(file) - fileTestCount = 0 - io.write(fileStartString:format(file.name)) - io.flush() - return nil, true - end - - handler.fileEnd = function(file) - local elapsedTime_ms = getElapsedTime(file) - local tests = (fileTestCount == 1 and 'test' or 'tests') - fileCount = fileCount + 1 - io.write(fileEndString:format(fileTestCount, tests, file.name, elapsedTime_ms)) - io.flush() - return nil, true - end - - handler.testStart = function(element, parent) - io.write(runString:format(handler.getFullName(element))) - io.flush() - - return nil, true - end - - handler.testEnd = function(element, parent, status, debug) - local elapsedTime_ms = getElapsedTime(element) - local string - - fileTestCount = fileTestCount + 1 - testCount = testCount + 1 - if status == 'success' then - successCount = successCount + 1 - string = successString - elseif status == 'pending' then - skippedCount = skippedCount + 1 - string = skippedString - elseif status == 'failure' then - failureCount = failureCount + 1 - string = nil - elseif status == 'error' then - errorCount = errorCount + 1 - string = nil - end - - if string ~= nil then - if elapsedTime_ms == elapsedTime_ms then - string = timeString:format(elapsedTime_ms) .. ' ' .. string - end - io.write(string) - io.flush() - end - - return nil, true - end - - handler.testFailure = function(element, parent, message, debug) - io.write(failureString) - io.flush() - - io.write(failureDescription(handler.failures[#handler.failures])) - io.flush() - return nil, true - end - - handler.testError = function(element, parent, message, debug) - io.write(errorString) - io.flush() - - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() - return nil, true - end - - handler.error = function(element, parent, message, debug) - if element.descriptor ~= 'it' then - io.write(failureDescription(handler.errors[#handler.errors])) - io.flush() - errorCount = errorCount + 1 - end - - return nil, true - end - - busted.subscribe({ 'suite', 'reset' }, handler.suiteReset) - busted.subscribe({ 'suite', 'start' }, handler.suiteStart) - busted.subscribe({ 'suite', 'end' }, handler.suiteEnd) - busted.subscribe({ 'file', 'start' }, handler.fileStart) - busted.subscribe({ 'file', 'end' }, handler.fileEnd) - busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending }) - busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending }) - busted.subscribe({ 'failure', 'it' }, handler.testFailure) - busted.subscribe({ 'error', 'it' }, handler.testError) - busted.subscribe({ 'failure' }, handler.error) - busted.subscribe({ 'error' }, handler.error) - - return handler -end diff --git a/busted/outputHandlers/nvim.lua b/busted/outputHandlers/nvim.lua new file mode 100644 index 0000000000..b612ead070 --- /dev/null +++ b/busted/outputHandlers/nvim.lua @@ -0,0 +1,305 @@ +local s = require 'say' +local pretty = require 'pl.pretty' +local term = require 'term' + +local colors + +local isWindows = package.config:sub(1,1) == '\\' + +if isWindows then + colors = setmetatable({}, {__index = function() return function(s) return s end end}) +else + colors = require 'term.colors' +end + +return function(options) + local busted = require 'busted' + local handler = require 'busted.outputHandlers.base'() + + local c = { + succ = function(s) return colors.bright(colors.green(s)) end, + skip = function(s) return colors.bright(colors.yellow(s)) end, + fail = function(s) return colors.bright(colors.magenta(s)) end, + errr = function(s) return colors.bright(colors.red(s)) end, + test = tostring, + file = colors.cyan, + time = colors.dim, + note = colors.yellow, + sect = function(s) return colors.green(colors.dim(s)) end, + nmbr = colors.bright, + } + + local repeatSuiteString = '\nRepeating all tests (run %d of %d) . . .\n\n' + local randomizeString = c.note('Note: Randomizing test order with a seed of %d.\n') + local globalSetup = c.sect('[----------]') .. ' Global test environment setup.\n' + local fileStartString = c.sect('[----------]') .. ' Running tests from ' .. c.file('%s') .. '\n' + local runString = c.sect('[ RUN ]') .. ' ' .. c.test('%s') .. ': ' + local successString = c.succ('OK') .. '\n' + local skippedString = c.skip('SKIP') .. '\n' + local failureString = c.fail('FAIL') .. '\n' + local errorString = c.errr('ERR') .. '\n' + local fileEndString = c.sect('[----------]') .. ' '.. c.nmbr('%d') .. ' %s from ' .. c.file('%s') .. ' ' .. c.time('(%.2f ms total)') .. '\n\n' + local globalTeardown = c.sect('[----------]') .. ' Global test environment teardown.\n' + local suiteEndString = c.sect('[==========]') .. ' ' .. c.nmbr('%d') .. ' %s from ' .. c.nmbr('%d') .. ' test %s ran. ' .. c.time('(%.2f ms total)') .. '\n' + local successStatus = c.succ('[ PASSED ]') .. ' ' .. c.nmbr('%d') .. ' %s.\n' + local timeString = c.time('%.2f ms') + + local summaryStrings = { + skipped = { + header = c.skip('[ SKIPPED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.skip('[ SKIPPED ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' SKIPPED %s\n', + }, + + failure = { + header = c.fail('[ FAILED ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.fail('[ FAILED ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' FAILED %s\n', + }, + + error = { + header = c.errr('[ ERROR ]') .. ' ' .. c.nmbr('%d') .. ' %s, listed below:\n', + test = c.errr('[ ERROR ]') .. ' %s\n', + footer = ' ' .. c.nmbr('%d') .. ' %s\n', + }, + } + + c = nil + + local fileCount = 0 + local fileTestCount = 0 + local testCount = 0 + local successCount = 0 + local skippedCount = 0 + local failureCount = 0 + local errorCount = 0 + + local pendingDescription = function(pending) + local name = pending.name + local string = '' + + if type(pending.message) == 'string' then + string = string .. pending.message .. '\n' + elseif pending.message ~= nil then + string = string .. pretty.write(pending.message) .. '\n' + end + + return string + end + + local failureDescription = function(failure) + local string = failure.randomseed and ('Random seed: ' .. failure.randomseed .. '\n') or '' + if type(failure.message) == 'string' then + string = string .. failure.message + elseif failure.message == nil then + string = string .. 'Nil error' + else + string = string .. pretty.write(failure.message) + end + + string = string .. '\n' + + if options.verbose and failure.trace and failure.trace.traceback then + string = string .. failure.trace.traceback .. '\n' + end + + return string + end + + local getFileLine = function(element) + local fileline = '' + if element.trace or element.trace.short_src then + fileline = colors.cyan(element.trace.short_src) .. ' @ ' .. + colors.cyan(element.trace.currentline) .. ': ' + end + return fileline + end + + local getTestList = function(status, count, list, getDescription) + local string = '' + local header = summaryStrings[status].header + if count > 0 and header then + local tests = (count == 1 and 'test' or 'tests') + local errors = (count == 1 and 'error' or 'errors') + string = header:format(count, status == 'error' and errors or tests) + + local testString = summaryStrings[status].test + if testString then + for _, t in ipairs(list) do + local fullname = getFileLine(t.element) .. colors.bright(t.name) + string = string .. testString:format(fullname) + string = string .. getDescription(t) + end + end + end + return string + end + + local getSummary = function(status, count) + local string = '' + local footer = summaryStrings[status].footer + if count > 0 and footer then + local tests = (count == 1 and 'TEST' or 'TESTS') + local errors = (count == 1 and 'ERROR' or 'ERRORS') + string = footer:format(count, status == 'error' and errors or tests) + end + return string + end + + local getSummaryString = function() + local tests = (successCount == 1 and 'test' or 'tests') + local string = successStatus:format(successCount, tests) + + string = string .. getTestList('skipped', skippedCount, handler.pendings, pendingDescription) + string = string .. getTestList('failure', failureCount, handler.failures, failureDescription) + string = string .. getTestList('error', errorCount, handler.errors, failureDescription) + + string = string .. ((skippedCount + failureCount + errorCount) > 0 and '\n' or '') + string = string .. getSummary('skipped', skippedCount) + string = string .. getSummary('failure', failureCount) + string = string .. getSummary('error', errorCount) + + return string + end + + handler.suiteReset = function() + fileCount = 0 + fileTestCount = 0 + testCount = 0 + successCount = 0 + skippedCount = 0 + failureCount = 0 + errorCount = 0 + + return nil, true + end + + handler.suiteStart = function(suite, count, total, randomseed) + if total > 1 then + io.write(repeatSuiteString:format(count, total)) + end + if randomseed then + io.write(randomizeString:format(randomseed)) + end + io.write(globalSetup) + io.flush() + + return nil, true + end + + local function getElapsedTime(tbl) + if tbl.duration then + return tbl.duration * 1000 + else + return tonumber('nan') + end + end + + handler.suiteEnd = function(suite, count, total) + local elapsedTime_ms = getElapsedTime(suite) + local tests = (testCount == 1 and 'test' or 'tests') + local files = (fileCount == 1 and 'file' or 'files') + io.write(globalTeardown) + io.write(suiteEndString:format(testCount, tests, fileCount, files, elapsedTime_ms)) + io.write(getSummaryString()) + io.flush() + + return nil, true + end + + handler.fileStart = function(file) + fileTestCount = 0 + io.write(fileStartString:format(file.name)) + io.flush() + return nil, true + end + + handler.fileEnd = function(file) + local elapsedTime_ms = getElapsedTime(file) + local tests = (fileTestCount == 1 and 'test' or 'tests') + fileCount = fileCount + 1 + io.write(fileEndString:format(fileTestCount, tests, file.name, elapsedTime_ms)) + io.flush() + return nil, true + end + + handler.testStart = function(element, parent) + io.write(runString:format(handler.getFullName(element))) + io.flush() + + return nil, true + end + + handler.testEnd = function(element, parent, status, debug) + local elapsedTime_ms = getElapsedTime(element) + local string + + fileTestCount = fileTestCount + 1 + testCount = testCount + 1 + if status == 'success' then + successCount = successCount + 1 + string = successString + elseif status == 'pending' then + skippedCount = skippedCount + 1 + string = skippedString + elseif status == 'failure' then + failureCount = failureCount + 1 + string = nil + elseif status == 'error' then + errorCount = errorCount + 1 + string = nil + end + + if string ~= nil then + if elapsedTime_ms == elapsedTime_ms then + string = timeString:format(elapsedTime_ms) .. ' ' .. string + end + io.write(string) + io.flush() + end + + return nil, true + end + + handler.testFailure = function(element, parent, message, debug) + io.write(failureString) + io.flush() + + io.write(failureDescription(handler.failures[#handler.failures])) + io.flush() + return nil, true + end + + handler.testError = function(element, parent, message, debug) + io.write(errorString) + io.flush() + + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() + return nil, true + end + + handler.error = function(element, parent, message, debug) + if element.descriptor ~= 'it' then + io.write(failureDescription(handler.errors[#handler.errors])) + io.flush() + errorCount = errorCount + 1 + end + + return nil, true + end + + busted.subscribe({ 'suite', 'reset' }, handler.suiteReset) + busted.subscribe({ 'suite', 'start' }, handler.suiteStart) + busted.subscribe({ 'suite', 'end' }, handler.suiteEnd) + busted.subscribe({ 'file', 'start' }, handler.fileStart) + busted.subscribe({ 'file', 'end' }, handler.fileEnd) + busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending }) + busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending }) + busted.subscribe({ 'failure', 'it' }, handler.testFailure) + busted.subscribe({ 'error', 'it' }, handler.testError) + busted.subscribe({ 'failure' }, handler.error) + busted.subscribe({ 'error' }, handler.error) + + return handler +end -- cgit From 2a8055a8d9b904739bdea0b0a9f5d3e635798d13 Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 15:11:27 +0300 Subject: ci: Make appveyor use new output handler as well --- ci/build.bat | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/build.bat b/ci/build.bat index 87a171b994..9071c0864e 100644 --- a/ci/build.bat +++ b/ci/build.bat @@ -38,7 +38,7 @@ cd .. :: Build Neovim mkdir build cd build -cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUSTED_OUTPUT_TYPE=gtest -DGPERF_PRG="C:\msys64\usr\bin\gperf.exe" .. || goto :error +cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DBUSTED_OUTPUT_TYPE=nvim -DGPERF_PRG="C:\msys64\usr\bin\gperf.exe" .. || goto :error mingw32-make VERBOSE=1 || goto :error bin\nvim --version || goto :error -- cgit From 60ee50ce4b1fe9d678dcca7944903dcd2673cd5b Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 10 Apr 2017 16:17:02 +0300 Subject: appveyor: Widen .deps cache dependency --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 091e86583a..8027aee166 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -7,7 +7,7 @@ build_script: - call ci\build.bat cache: - C:\msys64\var\cache\pacman\pkg -> ci\build.bat -- .deps -> third-party/CMakeLists.txt +- .deps -> third-party/** artifacts: - path: build/Neovim.zip - path: build/bin/nvim.exe -- cgit