summary refs log tree commit diff stats
path: root/lib/pure/unittest.nim
diff options
context:
space:
mode:
authorFederico Ceratto <federico.ceratto@gmail.com>2017-11-11 16:59:42 +0000
committerFederico Ceratto <federico.ceratto@gmail.com>2017-11-28 13:12:23 +0000
commit25831a83d799a0400fbd086ea9a6f704d4d6b216 (patch)
treed796eb47d1f49898c37cf5670871ab87cde52a9d /lib/pure/unittest.nim
parente758b9408e8fe935117f7f793164f1c9b74cec06 (diff)
downloadNim-25831a83d799a0400fbd086ea9a6f704d4d6b216.tar.gz
Add unittest suite/test name filters
Support simple globbing
Diffstat (limited to 'lib/pure/unittest.nim')
-rw-r--r--lib/pure/unittest.nim91
1 files changed, 80 insertions, 11 deletions
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index 7a8d1dad0..fbce087ff 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -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