summary refs log tree commit diff stats
path: root/lib/pure/unittest.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/pure/unittest.nim')
-rw-r--r--lib/pure/unittest.nim100
1 files changed, 63 insertions, 37 deletions
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index aca9d51e2..92ddc3e75 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -41,7 +41,11 @@ when not defined(ECMAScript):
   import terminal
 
 type
-  TestStatus* = enum OK, FAILED ## The status of a test when it is done.
+  TestStatus* = enum ## The status of a test when it is done.
+    OK,
+    FAILED,
+    SKIPPED
+
   OutputLevel* = enum  ## The output verbosity of the tests.
     PRINT_ALL,         ## Print as much as possible.
     PRINT_FAILURES,    ## Print only the failed tests.
@@ -73,7 +77,7 @@ checkpoints = @[]
 proc shouldRun(testName: string): bool =
   result = true
 
-template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+template suite*(name, body) {.dirty.} =
   ## Declare a test suite identified by `name` with optional ``setup``
   ## and/or ``teardown`` section.
   ##
@@ -102,13 +106,13 @@ template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
   ##  [OK] 2 + 2 = 4
   ##  [OK] (2 + -2) != 4
   block:
-    template setup(setupBody: stmt): stmt {.immediate, dirty.} =
+    template setup(setupBody: untyped) {.dirty.} =
       var testSetupIMPLFlag = true
-      template testSetupIMPL: stmt {.immediate, dirty.} = setupBody
+      template testSetupIMPL: untyped {.dirty.} = setupBody
 
-    template teardown(teardownBody: stmt): stmt {.immediate, dirty.} =
+    template teardown(teardownBody: untyped) {.dirty.} =
       var testTeardownIMPLFlag = true
-      template testTeardownIMPL: stmt {.immediate, dirty.} = teardownBody
+      template testTeardownIMPL: untyped {.dirty.} = teardownBody
 
     body
 
@@ -120,14 +124,18 @@ proc testDone(name: string, s: TestStatus) =
     template rawPrint() = echo("[", $s, "] ", name)
     when not defined(ECMAScript):
       if colorOutput and not defined(ECMAScript):
-        var color = (if s == OK: fgGreen else: fgRed)
+        var color = case s
+                    of OK: fgGreen
+                    of FAILED: fgRed
+                    of SKIPPED: fgYellow
+                    else: fgWhite
         styledEcho styleBright, color, "[", $s, "] ", fgWhite, name
       else:
         rawPrint()
     else:
       rawPrint()
 
-template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+template test*(name, body) {.dirty.} =
   ## Define a single test case identified by `name`.
   ##
   ## .. code-block:: nim
@@ -203,7 +211,22 @@ template fail* =
 
   checkpoints = @[]
 
-macro check*(conditions: stmt): stmt {.immediate.} =
+template skip* =
+  ## Makes test to be skipped. Should be used directly
+  ## in case when it is not possible to perform test
+  ## for reasons depending on outer environment,
+  ## or certain application logic conditions or configurations.
+  ##
+  ## .. code-block:: nim
+  ##
+  ##  if not isGLConextCreated():
+  ##    skip()
+  bind checkpoints
+
+  testStatusIMPL = SKIPPED
+  checkpoints = @[]
+
+macro check*(conditions: untyped): untyped =
   ## Verify if a statement or a list of statements is true.
   ## A helpful error message and set checkpoints are printed out on
   ## failure (if ``outputLevel`` is not ``PRINT_NONE``).
@@ -236,31 +259,34 @@ macro check*(conditions: stmt): stmt {.immediate.} =
 
   proc inspectArgs(exp: NimNode): NimNode =
     result = copyNimTree(exp)
-    for i in countup(1, exp.len - 1):
-      if exp[i].kind notin nnkLiterals:
-        inc counter
-        var arg = newIdentNode(":p" & $counter)
-        var argStr = exp[i].toStrLit
-        var paramAst = exp[i]
-        if exp[i].kind == nnkIdent:
-          argsPrintOuts.add getAst(print(argStr, paramAst))
-        if exp[i].kind in nnkCallKinds:
-          var callVar = newIdentNode(":c" & $counter)
-          argsAsgns.add getAst(asgn(callVar, paramAst))
-          result[i] = callVar
-          argsPrintOuts.add getAst(print(argStr, callVar))
-        if exp[i].kind == nnkExprEqExpr:
-          # ExprEqExpr
-          #   Ident !"v"
-          #   IntLit 2
-          result[i] = exp[i][1]
-        if exp[i].typekind notin {ntyTypeDesc}:
-          argsAsgns.add getAst(asgn(arg, paramAst))
-          argsPrintOuts.add getAst(print(argStr, arg))
-          if exp[i].kind != nnkExprEqExpr:
-            result[i] = arg
-          else:
-            result[i][1] = arg
+    if exp[0].kind == nnkIdent and
+        $exp[0] in ["and", "or", "not", "in", "notin", "==", "<=",
+                    ">=", "<", ">", "!=", "is", "isnot"]:
+      for i in countup(1, exp.len - 1):
+        if exp[i].kind notin nnkLiterals:
+          inc counter
+          var arg = newIdentNode(":p" & $counter)
+          var argStr = exp[i].toStrLit
+          var paramAst = exp[i]
+          if exp[i].kind == nnkIdent:
+            argsPrintOuts.add getAst(print(argStr, paramAst))
+          if exp[i].kind in nnkCallKinds:
+            var callVar = newIdentNode(":c" & $counter)
+            argsAsgns.add getAst(asgn(callVar, paramAst))
+            result[i] = callVar
+            argsPrintOuts.add getAst(print(argStr, callVar))
+          if exp[i].kind == nnkExprEqExpr:
+            # ExprEqExpr
+            #   Ident !"v"
+            #   IntLit 2
+            result[i] = exp[i][1]
+          if exp[i].typekind notin {ntyTypeDesc}:
+            argsAsgns.add getAst(asgn(arg, paramAst))
+            argsPrintOuts.add getAst(print(argStr, arg))
+            if exp[i].kind != nnkExprEqExpr:
+              result[i] = arg
+            else:
+              result[i][1] = arg
 
   case checked.kind
   of nnkCallKinds:
@@ -292,7 +318,7 @@ macro check*(conditions: stmt): stmt {.immediate.} =
 
     result = getAst(rewrite(checked, checked.lineinfo, checked.toStrLit))
 
-template require*(conditions: stmt): stmt {.immediate.} =
+template require*(conditions: untyped) =
   ## Same as `check` except any failed test causes the program to quit
   ## immediately. Any teardown statements are not executed and the failed
   ## test output is not generated.
@@ -302,7 +328,7 @@ template require*(conditions: stmt): stmt {.immediate.} =
     check conditions
   abortOnError = savedAbortOnError
 
-macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
+macro expect*(exceptions: varargs[typed], body: untyped): untyped =
   ## Test if `body` raises an exception found in the passed `exceptions`.
   ## The test passes if the raised exception is part of the acceptable
   ## exceptions. Otherwise, it fails.
@@ -310,7 +336,7 @@ macro expect*(exceptions: varargs[expr], body: stmt): stmt {.immediate.} =
   ##
   ## .. code-block:: nim
   ##
-  ##  import math
+  ##  import math, random
   ##  proc defectiveRobot() =
   ##    randomize()
   ##    case random(1..4)