mirror of
https://github.com/nim-lang/Nim.git
synced 2026-01-08 14:03:23 +00:00
Merge pull request #6725 from FedericoCeratto/unittest-5114
Add unittest suite/test name filters
This commit is contained in:
@@ -21,13 +21,41 @@
|
||||
## ``nim c -r <testfile.nim>`` exits with 0 or 1
|
||||
##
|
||||
## Running a single test
|
||||
## ---------------------
|
||||
## =====================
|
||||
##
|
||||
## Simply specify the test name as a command line argument.
|
||||
## Specify the test name as a command line argument.
|
||||
##
|
||||
## .. code::
|
||||
##
|
||||
## nim c -r test "my super awesome test name"
|
||||
## nim c -r test "my test name" "another test"
|
||||
##
|
||||
## Multiple arguments can be used.
|
||||
##
|
||||
## Running a single test suite
|
||||
## ===========================
|
||||
##
|
||||
## Specify the suite name delimited by ``"::"``.
|
||||
##
|
||||
## .. code::
|
||||
##
|
||||
## nim c -r test "my test name::"
|
||||
##
|
||||
## Selecting tests by pattern
|
||||
## ==========================
|
||||
##
|
||||
## A single ``"*"`` can be used for globbing.
|
||||
##
|
||||
## Delimit the end of a suite name with ``"::"``.
|
||||
##
|
||||
## Tests matching **any** of the arguments are executed.
|
||||
##
|
||||
## .. code::
|
||||
##
|
||||
## nim c -r test fast_suite::mytest1 fast_suite::mytest2
|
||||
## nim c -r test "fast_suite::mytest*"
|
||||
## nim c -r test "auth*::" "crypto::hashing*"
|
||||
## # Run suites starting with 'bug #' and standalone tests starting with '#'
|
||||
## nim c -r test 'bug #*::' '::#*'
|
||||
##
|
||||
## Example
|
||||
## -------
|
||||
@@ -121,7 +149,7 @@ var
|
||||
|
||||
checkpoints {.threadvar.}: seq[string]
|
||||
formatters {.threadvar.}: seq[OutputFormatter]
|
||||
testsToRun {.threadvar.}: HashSet[string]
|
||||
testsFilters {.threadvar.}: HashSet[string]
|
||||
|
||||
when declared(stdout):
|
||||
abortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
|
||||
@@ -300,22 +328,63 @@ method testEnded*(formatter: JUnitOutputFormatter, testResult: TestResult) =
|
||||
method suiteEnded*(formatter: JUnitOutputFormatter) =
|
||||
formatter.stream.writeLine("\t</testsuite>")
|
||||
|
||||
proc shouldRun(testName: string): bool =
|
||||
if testsToRun.len == 0:
|
||||
proc glob(matcher, filter: string): bool =
|
||||
## Globbing using a single `*`. Empty `filter` matches everything.
|
||||
if filter.len == 0:
|
||||
return true
|
||||
|
||||
result = testName in testsToRun
|
||||
if not filter.contains('*'):
|
||||
return matcher == filter
|
||||
|
||||
let beforeAndAfter = filter.split('*', maxsplit=1)
|
||||
if beforeAndAfter.len == 1:
|
||||
# "foo*"
|
||||
return matcher.startswith(beforeAndAfter[0])
|
||||
|
||||
if matcher.len < filter.len - 1:
|
||||
return false # "12345" should not match "123*345"
|
||||
|
||||
return matcher.startsWith(beforeAndAfter[0]) and matcher.endsWith(beforeAndAfter[1])
|
||||
|
||||
proc matchFilter(suiteName, testName, filter: string): bool =
|
||||
if filter == "":
|
||||
return true
|
||||
if testName == filter:
|
||||
# corner case for tests containing "::" in their name
|
||||
return true
|
||||
let suiteAndTestFilters = filter.split("::", maxsplit=1)
|
||||
|
||||
if suiteAndTestFilters.len == 1:
|
||||
# no suite specified
|
||||
let test_f = suiteAndTestFilters[0]
|
||||
return glob(testName, test_f)
|
||||
|
||||
return glob(suiteName, suiteAndTestFilters[0]) and glob(testName, suiteAndTestFilters[1])
|
||||
|
||||
when defined(testing): export matchFilter
|
||||
|
||||
proc shouldRun(currentSuiteName, testName: string): bool =
|
||||
## Check if a test should be run by matching suiteName and testName against
|
||||
## test filters.
|
||||
if testsFilters.len == 0:
|
||||
return true
|
||||
|
||||
for f in testsFilters:
|
||||
if matchFilter(currentSuiteName, testName, f):
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
proc ensureInitialized() =
|
||||
if formatters == nil:
|
||||
formatters = @[OutputFormatter(defaultConsoleFormatter())]
|
||||
|
||||
if not testsToRun.isValid:
|
||||
testsToRun.init()
|
||||
if not testsFilters.isValid:
|
||||
testsFilters.init()
|
||||
when declared(paramCount):
|
||||
# Read tests to run from the command line.
|
||||
for i in 1 .. paramCount():
|
||||
testsToRun.incl(paramStr(i))
|
||||
testsFilters.incl(paramStr(i))
|
||||
|
||||
# These two procs are added as workarounds for
|
||||
# https://github.com/nim-lang/Nim/issues/5549
|
||||
@@ -395,7 +464,7 @@ template test*(name, body) {.dirty.} =
|
||||
|
||||
ensureInitialized()
|
||||
|
||||
if shouldRun(name):
|
||||
if shouldRun(when declared(testSuiteName): testSuiteName else: "", name):
|
||||
checkpoints = @[]
|
||||
var testStatusIMPL {.inject.} = OK
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ discard """
|
||||
|
||||
[Suite] bug #5784
|
||||
|
||||
[Suite] test name filtering
|
||||
|
||||
'''
|
||||
"""
|
||||
|
||||
@@ -120,3 +122,39 @@ suite "bug #5784":
|
||||
field: int
|
||||
var obj: Obj
|
||||
check obj.isNil or obj.field == 0
|
||||
|
||||
when defined(testing):
|
||||
suite "test name filtering":
|
||||
test "test name":
|
||||
check matchFilter("suite1", "foo", "")
|
||||
check matchFilter("suite1", "foo", "foo")
|
||||
check matchFilter("suite1", "foo", "::")
|
||||
check matchFilter("suite1", "foo", "*")
|
||||
check matchFilter("suite1", "foo", "::foo")
|
||||
check matchFilter("suite1", "::foo", "::foo")
|
||||
|
||||
test "test name - glob":
|
||||
check matchFilter("suite1", "foo", "f*")
|
||||
check matchFilter("suite1", "foo", "*oo")
|
||||
check matchFilter("suite1", "12345", "12*345")
|
||||
check matchFilter("suite1", "q*wefoo", "q*wefoo")
|
||||
check false == matchFilter("suite1", "foo", "::x")
|
||||
check false == matchFilter("suite1", "foo", "::x*")
|
||||
check false == matchFilter("suite1", "foo", "::*x")
|
||||
# overlap
|
||||
check false == matchFilter("suite1", "12345", "123*345")
|
||||
check matchFilter("suite1", "ab*c::d*e::f", "ab*c::d*e::f")
|
||||
|
||||
test "suite name":
|
||||
check matchFilter("suite1", "foo", "suite1::")
|
||||
check false == matchFilter("suite1", "foo", "suite2::")
|
||||
check matchFilter("suite1", "qwe::foo", "qwe::foo")
|
||||
check matchFilter("suite1", "qwe::foo", "suite1::qwe::foo")
|
||||
|
||||
test "suite name - glob":
|
||||
check matchFilter("suite1", "foo", "::*")
|
||||
check matchFilter("suite1", "foo", "*::*")
|
||||
check matchFilter("suite1", "foo", "*::foo")
|
||||
check false == matchFilter("suite1", "foo", "*ite2::")
|
||||
check matchFilter("suite1", "q**we::foo", "q**we::foo")
|
||||
check matchFilter("suite1", "a::b*c::d*e", "a::b*c::d*e")
|
||||
|
||||
Reference in New Issue
Block a user