summary refs log tree commit diff stats
path: root/lib/pure
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2011-10-07 10:07:18 -0700
committerAraq <rumpf_a@web.de>2011-10-07 10:07:18 -0700
commitfae8ea0cee55cf85a7d30d63d06c73ed3874fa89 (patch)
tree660df418fce1076c16cd7ab97574d0c6c12c6605 /lib/pure
parent130316751d88a93169304a19caf92308f115808c (diff)
parent4a444bf6dbf973faea020b1e82650e50eccf7d54 (diff)
downloadNim-fae8ea0cee55cf85a7d30d63d06c73ed3874fa89.tar.gz
Merge pull request #58 from zah/getast-unittests
getAst operational. Unit testing library based on it.
Diffstat (limited to 'lib/pure')
-rwxr-xr-xlib/pure/terminal.nim38
-rw-r--r--lib/pure/unittest.nim150
2 files changed, 183 insertions, 5 deletions
diff --git a/lib/pure/terminal.nim b/lib/pure/terminal.nim
index 232601640..ab9c31c8f 100755
--- a/lib/pure/terminal.nim
+++ b/lib/pure/terminal.nim
@@ -14,6 +14,8 @@
 ## Changing the style is permanent even after program termination! Use the

 ## code ``system.addQuitProc(resetAttributes)`` to restore the defaults.

 

+import macros

+

 when defined(windows):

   import windows, os

 

@@ -210,24 +212,32 @@ type
 

 when not defined(windows):

   var

+    # XXX: These better be thread-local

     gFG = 0

     gBG = 0

 

-proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =

-  ## writes the text `txt` in a given `style`.

+proc setStyle*(style: set[TStyle]) =

+  ## sets the terminal style

   when defined(windows):

     var a = 0'i16

     if styleBright in style: a = a or int16(FOREGROUND_INTENSITY)

     if styleBlink in style: a = a or int16(BACKGROUND_INTENSITY)

     if styleReverse in style: a = a or 0x4000'i16 # COMMON_LVB_REVERSE_VIDEO

     if styleUnderscore in style: a = a or 0x8000'i16 # COMMON_LVB_UNDERSCORE

-    var old = getAttributes()

     discard SetConsoleTextAttribute(conHandle, old or a)

-    stdout.write(txt)

-    discard SetConsoleTextAttribute(conHandle, old)

   else:

     for s in items(style):

       stdout.write("\e[" & $ord(s) & 'm')

+

+proc WriteStyled*(txt: string, style: set[TStyle] = {styleBright}) =

+  ## writes the text `txt` in a given `style`.

+  when defined(windows):

+    var old = getAttributes()

+    setStyle(style)

+    stdout.write(txt)

+    discard SetConsoleTextAttribute(conHandle, old)

+  else:

+    setStyle(style)

     stdout.write(txt)

     resetAttributes()

     if gFG != 0:

@@ -298,6 +308,24 @@ proc setBackgroundColor*(bg: TBackgroundColor, bright=false) =
     if bright: inc(gBG, 60)

     stdout.write("\e[" & $gBG & 'm')

 

+# XXX: 

+# These should be private, but there is no yet 

+# facility for binding local symbols within macros

+proc styledEchoProcessArg*(s: string)               = write stdout, s

+proc styledEchoProcessArg*(style: TStyle)           = setStyle {style}

+proc styledEchoProcessArg*(style: set[TStyle])      = setStyle style

+proc styledEchoProcessArg*(color: TForegroundColor) = setForeGroundColor color

+proc styledEchoProcessArg*(color: TBackgroundColor) = setBackGroundColor color

+

+macro styledEcho*(m: stmt): stmt =

+  result = newNimNode(nnkStmtList)

+

+  for i in countup(1, m.len - 1):

+    result.add(newCall(!"styledEchoProcessArg", m[i]))

+

+  result.add(newCall(!"write", newIdentNode("stdout"), newStrLitNode("\n")))

+  result.add(newCall(!"resetAttributes"))

+

 when isMainModule:

   system.addQuitProc(resetAttributes)

   write(stdout, "never mind")

diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
new file mode 100644
index 000000000..db3e5a1db
--- /dev/null
+++ b/lib/pure/unittest.nim
@@ -0,0 +1,150 @@
+#

+#

+#            Nimrod's Runtime Library

+#        (c) Copyright 2011 Nimrod Contributors

+#

+#    See the file "copying.txt", included in this

+#    distribution, for details about the copyright.

+#

+

+## This module implements the standard unit testing facilities such as

+## suites, fixtures and test cases as well as facilities for combinatorial 

+## and randomzied test case generation (not yet available) 

+## and object mocking (not yet available)

+##

+## It is loosely based on C++'s boost.test and Haskell's QuickTest

+##

+## Maintainer: Zahary Karadjov (zah@github)

+##

+

+import

+  macros, terminal

+

+type

+  TestStatus* = enum OK, FAILED

+  # ETestFailed* = object of ESynch

+

+var 

+  # XXX: These better be thread-local

+  AbortOnError* = false

+  checkpoints: seq[string] = @[]

+

+template TestSetupIMPL*: stmt = nil

+template TestTeardownIMPL*: stmt = nil

+

+proc shouldRun(testName: string): bool =

+  result = true

+

+template suite*(name: expr, body: stmt): stmt =

+  block:

+    template setup(setupBody: stmt): stmt =

+      template TestSetupIMPL: stmt = setupBody

+

+    template teardown(teardownBody: stmt): stmt =

+      template TestTeardownIMPL: stmt = teardownBody

+

+    body

+

+proc printStatus*(s: TestStatus, name: string) =

+  var color = (if s == OK: fgGreen else: fgRed)

+  styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n"

+  

+template test*(name: expr, body: stmt): stmt =

+  if bind shouldRun(name):

+    bind checkpoints = @[]

+    var TestStatusIMPL = OK

+    

+    try:

+      TestSetupIMPL()

+      body

+

+    finally:

+      TestTeardownIMPL()

+      printStatus(TestStatusIMPL, name)

+

+proc checkpoint*(msg: string) =

+  checkpoints.add(msg)

+  # TODO: add support for something like SCOPED_TRACE from Google Test

+

+template fail* =

+  for msg in items(bind checkpoints):

+    echo msg

+

+  if AbortOnError: quit(1)

+  

+  TestStatusIMPL = FAILED

+  checkpoints = @[]

+

+macro check*(conditions: stmt): stmt =

+  proc standardRewrite(e: expr): stmt =

+    template rewrite(Exp, lineInfoLit: expr, expLit: string): stmt =

+      if not Exp:

+        checkpoint(lineInfoLit & ": Check failed: " & expLit)

+        fail()

+ 

+    result = getAst(rewrite(e, e.lineinfo, e.toStrLit))

+  

+  case conditions.kind

+  of nnkCall, nnkCommand, nnkMacroStmt:

+    case conditions[1].kind

+    of nnkInfix:

+      proc rewriteBinaryOp(op: expr): stmt =

+        template rewrite(op, left, right, lineInfoLit: expr, opLit, leftLit, rightLit: string): stmt =

+          block:

+            var 

+              lhs = left

+              rhs = right

+

+            if not `op`(lhs, rhs):

+              checkpoint(lineInfoLit & ": Check failed: " & opLit)

+              checkpoint("  " & leftLit & " was " & $lhs)

+              checkpoint("  " & rightLit & " was " & $rhs)

+              fail()

+

+        result = getAst(rewrite(

+          op[0], op[1], op[2],

+          op.lineinfo,

+          op.toStrLit,

+          op[1].toStrLit,

+          op[2].toStrLit))

+        

+      result = rewriteBinaryOp(conditions[1])

+  

+    of nnkCall, nnkCommand:

+      # TODO: We can print out the call arguments in case of failure

+      result = standardRewrite(conditions[1])

+

+    of nnkStmtList:

+      result = newNimNode(nnkStmtList)

+      for i in countup(0, conditions[1].len - 1):

+        result.add(newCall(!"check", conditions[1][i]))

+

+    else:

+      result = standardRewrite(conditions[1])

+

+  else:

+    error conditions.lineinfo & ": Malformed check statement"

+

+template require*(conditions: stmt): stmt =

+  block:

+    const AbortOnError = true    

+    check conditions

+

+macro expect*(exp: stmt): stmt =

+  template expectBody(errorTypes, lineInfoLit: expr, body: stmt): stmt =

+    try:

+      body

+      checkpoint(lineInfoLit & ": Expect Failed, no exception was thrown.")

+      fail()

+    except errorTypes:

+      nil

+

+  var expectCall = exp[0]

+  var body = exp[1]

+  

+  var errorTypes = newNimNode(nnkBracket)

+  for i in countup(1, expectCall.len - 1):

+    errorTypes.add(expectCall[i])

+

+  result = getAst(expectBody(errorTypes, exp.lineinfo, body))

+