summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAraq <rumpf_a@web.de>2012-09-13 18:48:14 +0200
committerAraq <rumpf_a@web.de>2012-09-13 18:48:14 +0200
commit4a435a8fb4551b03bdcbbbd9b074a51fa46928dd (patch)
tree5d83bf8195b6706c70da921d199d9a04ebc539ee /lib
parentd336cb4957c6b223ce7e8d717718217cb0665b56 (diff)
parent36155a6813cb414666753f6b66e04e1044954f85 (diff)
downloadNim-4a435a8fb4551b03bdcbbbd9b074a51fa46928dd.tar.gz
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/asyncio.nim17
-rw-r--r--lib/pure/irc.nim79
-rw-r--r--lib/pure/unittest.nim394
3 files changed, 272 insertions, 218 deletions
diff --git a/lib/pure/asyncio.nim b/lib/pure/asyncio.nim
index 6b384b1a7..bcaa85827 100644
--- a/lib/pure/asyncio.nim
+++ b/lib/pure/asyncio.nim
@@ -119,6 +119,8 @@ type
 
     handleAccept*: proc (s:  PAsyncSocket) {.closure.}
 
+    handleTask*: proc (s: PAsyncSocket) {.closure.}
+
     lineBuffer: TaintedString ## Temporary storage for ``recvLine``
     sslNeedAccept: bool
     proto: TProtocol
@@ -145,6 +147,7 @@ proc newAsyncSocket(): PAsyncSocket =
   result.handleRead = (proc (s: PAsyncSocket) = nil)
   result.handleConnect = (proc (s: PAsyncSocket) = nil)
   result.handleAccept = (proc (s: PAsyncSocket) = nil)
+  result.handleTask = (proc (s: PAsyncSocket) = nil)
 
   result.lineBuffer = "".TaintedString
 
@@ -196,6 +199,13 @@ when defined(ssl):
         # handshake will set socket's ``sslNoHandshake`` field.
         discard PAsyncSocket(h).socket.handshake()
         
+
+proc asyncSockTask(h: PObject) =
+  when defined(ssl):
+    h.asyncSockDoHandshake()
+
+  PAsyncSocket(h).handleTask(PAsyncSocket(h))
+
 proc toDelegate(sock: PAsyncSocket): PDelegate =
   result = newDelegate()
   result.deleVal = sock
@@ -204,6 +214,7 @@ proc toDelegate(sock: PAsyncSocket): PDelegate =
   result.mode = fmReadWrite
   result.handleRead = asyncSockHandleRead
   result.handleWrite = asyncSockHandleWrite
+  result.task = asyncSockTask
   # TODO: Errors?
   #result.handleError = (proc (h: PObject) = assert(false))
 
@@ -215,10 +226,7 @@ proc toDelegate(sock: PAsyncSocket): PDelegate =
   if sock.info notin {SockIdle, SockClosed}:
     sock.deleg.open = true
   else:
-    sock.deleg.open = false 
-
-  when defined(ssl):
-    result.task = asyncSockDoHandshake
+    sock.deleg.open = false
 
 proc connect*(sock: PAsyncSocket, name: string, port = TPort(0),
                    af: TDomain = AF_INET) =
@@ -257,6 +265,7 @@ proc acceptAddr*(server: PAsyncSocket, client: var PAsyncSocket,
   ##
   ## **Note**: ``client`` needs to be initialised.
   assert(client != nil)
+  client = newAsyncSocket()
   var c: TSocket
   new(c)
   when defined(ssl):
diff --git a/lib/pure/irc.nim b/lib/pure/irc.nim
index cc9157053..60a86f2f1 100644
--- a/lib/pure/irc.nim
+++ b/lib/pure/irc.nim
@@ -44,10 +44,8 @@ type
 
   PAsyncIRC* = ref TAsyncIRC
   TAsyncIRC* = object of TIRC
-    userArg: PObject
-    handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent, 
-                       userArg: PObject) {.nimcall.}
-    lineBuffer: TaintedString
+    handleEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
+    asyncSock: PAsyncSocket
 
   TIRCMType* = enum
     MUnknown,
@@ -320,12 +318,16 @@ proc connect*(irc: PAsyncIRC) =
   assert(irc.address != "")
   assert(irc.port != TPort(0))
   
-  irc.sock = socket()
-  irc.sock.setBlocking(false)
-  irc.sock.connectAsync(irc.address, irc.port)
-  irc.status = SockConnecting
+  irc.asyncSock = AsyncSocket()
+  irc.asyncSock.connect(irc.address, irc.port)
 
-proc handleConnect(h: PObject) =
+proc handleConnect(s: PAsyncSocket, irc: PAsyncIRC) =  
+  # Greet the server :)
+  if irc.serverPass != "": irc[].send("PASS " & irc.serverPass, true)
+  irc[].send("NICK " & irc.nick, true)
+  irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
+
+discard """proc handleConnect(h: PObject) =
   var irc = PAsyncIRC(h)
   
   # Greet the server :)
@@ -334,8 +336,22 @@ proc handleConnect(h: PObject) =
   irc[].send("USER $1 * 0 :$2" % [irc.user, irc.realname], true)
 
   irc.status = SockConnected
+"""
+
+proc handleRead(s: PAsyncSocket, irc: PAsyncIRC) =
+  var line = "".TaintedString
+  var ret = s.recvLine(line)
+  if ret:
+    if line == "":
+      var ev: TIRCEvent
+      irc[].close()
+      ev.typ = EvDisconnected
+      irc.handleEvent(irc[], ev)
+    else:
+      var ev = irc[].processLine(line.string)
+      irc.handleEvent(irc[], ev)
 
-proc handleRead(h: PObject) =
+discard """proc handleRead(h: PObject) =
   var irc = PAsyncIRC(h)
   var line = "".TaintedString
   var ret = irc.sock.recvLineAsync(line)
@@ -352,13 +368,18 @@ proc handleRead(h: PObject) =
     irc[].close()
     ev.typ = EvDisconnected
     irc.handleEvent(irc[], ev, irc.userArg)
-  of RecvFail: nil
+  of RecvFail: nil"""
+  
+proc handleTask(s: PAsyncSocket, irc: PAsyncIRC) =
+  var ev: TIRCEvent
+  if irc[].processOther(ev):
+    irc.handleEvent(irc[], ev)
   
-proc handleTask(h: PObject) =
+discard """proc handleTask(h: PObject) =
   var irc = PAsyncIRC(h)
   var ev: TIRCEvent
   if PAsyncIRC(h)[].processOther(ev):
-    irc.handleEvent(irc[], ev, irc.userArg)
+    irc.handleEvent(irc[], ev, irc.userArg)"""
 
 proc asyncIRC*(address: string, port: TPort = 6667.TPort,
               nick = "NimrodBot",
@@ -366,9 +387,8 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
               realname = "NimrodBot", serverPass = "",
               joinChans: seq[string] = @[],
               msgLimit: bool = true,
-              ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent,
-                  userArg: PObject) {.nimcall.},
-              userArg: PObject = nil): PAsyncIRC =
+              ircEvent: proc (irc: var TAsyncIRC, ev: TIRCEvent) {.closure.}
+              ): PAsyncIRC =
   ## Use this function if you want to use asyncio's dispatcher.
   ## 
   ## **Note:** Do **NOT** use this if you're writing a simple IRC bot which only
@@ -389,28 +409,25 @@ proc asyncIRC*(address: string, port: TPort = 6667.TPort,
   result.msgLimit = msgLimit
   result.messageBuffer = @[]
   result.handleEvent = ircEvent
-  result.userArg = userArg
-  result.lineBuffer = ""
 
 proc register*(d: PDispatcher, irc: PAsyncIRC) =
   ## Registers ``irc`` with dispatcher ``d``.
-  var dele = newDelegate()
-  dele.deleVal = irc
-  dele.getSocket = (proc (h: PObject): tuple[info: TInfo, sock: TSocket] =
-                      if PAsyncIRC(h).status == SockConnecting or
-                            PAsyncIRC(h).status == SockConnected:
-                        return (PAsyncIRC(h).status, PAsyncIRC(h).sock)
-                      else: return (SockIdle, PAsyncIRC(h).sock))
-  dele.handleConnect = handleConnect
-  dele.handleRead = handleRead
-  dele.task = handleTask
-  d.register(dele)
+  irc.asyncSock.handleConnect =
+    proc (s: PAsyncSocket) =
+      handleConnect(s, irc)
+  irc.asyncSock.handleRead =
+    proc (s: PAsyncSocket) =
+      handleRead(s, irc)
+  irc.asyncSock.handleTask =
+    proc (s: PAsyncSocket) =
+      handleTask(s, irc)
+  d.register(irc.asyncSock)
   
 when isMainModule:
   #var m = parseMessage("ERROR :Closing Link: dom96.co.cc (Ping timeout: 252 seconds)")
   #echo(repr(m))
 
-  #discard """
+
   
   var client = irc("amber.tenthbit.net", nick="TestBot1234",
                    joinChans = @["#flood"])
@@ -431,5 +448,5 @@ when isMainModule:
 
         #echo( repr(event) )
       #echo("Lag: ", formatFloat(client.getLag()))
-  #"""
+  
     
diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim
index be5e19c23..fff84ee29 100644
--- a/lib/pure/unittest.nim
+++ b/lib/pure/unittest.nim
@@ -1,187 +1,215 @@
-#

-#

-#            Nimrod's Runtime Library

-#        (c) Copyright 2012 Nimrod Contributors

-#

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

-#    distribution, for details about the copyright.

-#

-

-## :Author: Zahary Karadjov (zah@github)

-##

-## 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

-

-import

-  macros, terminal, os

-

-type

-  TTestStatus* = enum OK, FAILED

-  TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE

-

-var 

-  # XXX: These better be thread-local

-  AbortOnError*: bool

-  OutputLevel*: TOutputLevel

-  ColorOutput*: bool

-  

-  checkpoints: seq[string] = @[]

-

-template TestSetupIMPL*: stmt {.immediate, dirty.} = nil

-template TestTeardownIMPL*: stmt {.immediate, dirty.} = nil

-

-proc shouldRun(testName: string): bool =

-  result = true

-

-template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =

-  block:

-    template setup*(setupBody: stmt): stmt {.immediate, dirty.} =

-      template TestSetupIMPL: stmt {.immediate, dirty.} = setupBody

-

-    template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} =

-      template TestTeardownIMPL: stmt {.immediate, dirty.} = teardownBody

-

-    body

-

-proc testDone(name: string, s: TTestStatus) =

-  if s == FAILED:

-    program_result += 1

-

-  if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED):

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

-    

-    if ColorOutput:

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

-    else:

-      echo "[", $s, "] ", name, "\n"

-  

-template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =

-  bind shouldRun, checkpoints, testDone

-

-  if shouldRun(name):

-    checkpoints = @[]

-    var TestStatusIMPL {.inject.} = OK

-    

-    try:

-      TestSetupIMPL()

-      body

-

-    except:

-      checkpoint("Unhandled exception: " & getCurrentExceptionMsg())

-      fail()

-

-    finally:

-      TestTeardownIMPL()

-      testDone name, TestStatusIMPL

-

-proc checkpoint*(msg: string) =

-  checkpoints.add(msg)

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

-

-template fail* =

-  bind checkpoints

-  for msg in items(checkpoints):

-    echo msg

-

-  if AbortOnError: quit(1)

-  

-  TestStatusIMPL = FAILED

-  checkpoints = @[]

-

+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2012 Nimrod Contributors
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+## :Author: Zahary Karadjov
+##
+## 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
+
+import
+  macros, terminal, os
+
+type
+  TTestStatus* = enum OK, FAILED
+  TOutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE
+
+var 
+  # XXX: These better be thread-local
+  AbortOnError*: bool
+  OutputLevel*: TOutputLevel
+  ColorOutput*: bool
+  
+  checkpoints: seq[string] = @[]
+
+template TestSetupIMPL*: stmt {.immediate, dirty.} = nil
+template TestTeardownIMPL*: stmt {.immediate, dirty.} = nil
+
+proc shouldRun(testName: string): bool =
+  result = true
+
+template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+  block:
+    template setup*(setupBody: stmt): stmt {.immediate, dirty.} =
+      template TestSetupIMPL: stmt {.immediate, dirty.} = setupBody
+
+    template teardown*(teardownBody: stmt): stmt {.immediate, dirty.} =
+      template TestTeardownIMPL: stmt {.immediate, dirty.} = teardownBody
+
+    body
+
+proc testDone(name: string, s: TTestStatus) =
+  if s == FAILED:
+    program_result += 1
+
+  if OutputLevel != PRINT_NONE and (OutputLevel == PRINT_ALL or s == FAILED):
+    var color = (if s == OK: fgGreen else: fgRed)
+    
+    if ColorOutput:
+      styledEcho styleBright, color, "[", $s, "] ", fgWhite, name, "\n"
+    else:
+      echo "[", $s, "] ", name, "\n"
+  
+template test*(name: expr, body: stmt): stmt {.immediate, dirty.} =
+  bind shouldRun, checkpoints, testDone
+
+  if shouldRun(name):
+    checkpoints = @[]
+    var TestStatusIMPL {.inject.} = OK
+    
+    try:
+      TestSetupIMPL()
+      body
+
+    except:
+      checkpoint("Unhandled exception: " & getCurrentExceptionMsg())
+      fail()
+
+    finally:
+      TestTeardownIMPL()
+      testDone name, TestStatusIMPL
+
+proc checkpoint*(msg: string) =
+  checkpoints.add(msg)
+  # TODO: add support for something like SCOPED_TRACE from Google Test
+
+template fail* =
+  bind checkpoints
+  for msg in items(checkpoints):
+    echo msg
+
+  if AbortOnError: quit(1)
+  
+  TestStatusIMPL = FAILED
+  checkpoints = @[]
+
 macro check*(conditions: stmt): stmt {.immediate.} =
-  let conditions = callsite()

+  let conditions = callsite()
   
-  proc standardRewrite(e: PNimrodNode): PNimrodNode =

-    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: PNimrodNode): PNimrodNode =

-        template rewrite(op, left, right, lineInfoLit: expr, opLit,

-          leftLit, rightLit: string, printLhs, printRhs: bool): stmt =

-          block:

-            var 

-              lhs = left

-              rhs = right

-

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

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

-              when printLhs: checkpoint("  " & leftLit & " was " & $lhs)

-              when printRhs: checkpoint("  " & rightLit & " was " & $rhs)

-              fail()

-

-        result = getAst(rewrite(

-          op[0], op[1], op[2],

-          op.lineinfo,

-          op.toStrLit,

-          op[1].toStrLit,

-          op[2].toStrLit,

-          op[1].kind notin nnkLiterals,

-          op[2].kind notin nnkLiterals))

-        

-      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:

-    var ast = conditions.treeRepr

-    error conditions.lineinfo & ": Malformed check statement:\n" & ast

-

-template require*(conditions: stmt): stmt {.immediate, dirty.} =

-  block:

-    const AbortOnError {.inject.} = true

-    check conditions

-

-macro expect*(exp: stmt): stmt {.immediate.} =

+  case conditions.kind
+  of nnkCall, nnkCommand, nnkMacroStmt:
+    case conditions[1].kind
+    of nnkInfix:
+      proc rewriteBinaryOp(op: PNimrodNode): PNimrodNode =
+        template rewrite(op, left, right, lineInfoLit: expr, opLit,
+          leftLit, rightLit: string, printLhs, printRhs: bool): stmt =
+          block:
+            var 
+              lhs = left
+              rhs = right
+
+            if not `op`(lhs, rhs):
+              checkpoint(lineInfoLit & ": Check failed: " & opLit)
+              when printLhs: checkpoint("  " & leftLit & " was " & $lhs)
+              when printRhs: checkpoint("  " & rightLit & " was " & $rhs)
+              fail()
+
+        result = getAst(rewrite(
+          op[0], op[1], op[2],
+          op.lineinfo,
+          op.toStrLit,
+          op[1].toStrLit,
+          op[2].toStrLit,
+          op[1].kind notin nnkLiterals,
+          op[2].kind notin nnkLiterals))
+        
+      result = rewriteBinaryOp(conditions[1])
+  
+    of nnkCall, nnkCommand:
+      proc rewriteCall(op: PNimrodNode): PNimrodNode =
+        template rewrite(call, lineInfoLit: expr, expLit: string,
+                         argAssgs, argPrintOuts: stmt): stmt =
+          block:
+            argAssgs
+            if not call:
+              checkpoint(lineInfoLit & ": Check failed: " & expLit)
+              argPrintOuts
+              fail()
+
+        template asgn(a, value: expr): stmt =
+          let a = value
+        
+        template print(name, value: expr): stmt =
+          checkpoint(name & " was " & $value)
+
+        var 
+          argsAsgns = newNimNode(nnkStmtList)
+          argsPrintOuts = newNimNode(nnkStmtList)
+          opStr = op.toStrLit
+        
+        for i in 1 .. <op.len:
+          if op[i].kind notin nnkLiterals:
+            # TODO: print only types that are printable
+            var arg = newIdentNode(":param" & ($i))
+            argsAsgns.add getAst(asgn(arg, op[i]))
+            argsPrintOuts.add getAst(print(op[i].toStrLit, arg))
+            op[i] = arg
+
+        result = getAst(rewrite(op, op.lineinfo, opStr, argsAsgns, argsPrintOuts))
+
+      result = rewriteCall(conditions[1])
+
+    of nnkStmtList:
+      result = newNimNode(nnkStmtList)
+      for i in countup(0, conditions[1].len - 1):
+        result.add(newCall(!"check", conditions[1][i]))
+
+    else:
+      template rewrite(Exp, lineInfoLit: expr, expLit: string): stmt =
+        if not Exp:
+          checkpoint(lineInfoLit & ": Check failed: " & expLit)
+          fail()
+
+      let e = conditions[1]
+      result = getAst(rewrite(e, e.lineinfo, e.toStrLit))
+
+  else:
+    var ast = conditions.treeRepr
+    error conditions.lineinfo & ": Malformed check statement:\n" & ast
+
+template require*(conditions: stmt): stmt {.immediate, dirty.} =
+  block:
+    const AbortOnError {.inject.} = true
+    check conditions
+
+macro expect*(exp: stmt): stmt {.immediate.} =
   let exp = callsite()
   template expectBody(errorTypes, lineInfoLit: expr,
-                      body: stmt): PNimrodNode {.dirty.} =

-    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))

-

-

-## Reading settings

-var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string

-

-if envOutLvl.len > 0:

-  for opt in countup(low(TOutputLevel), high(TOutputLevel)):

-    if $opt == envOutLvl:

-      OutputLevel = opt

-      break

-

-AbortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")

-ColorOutput  = not existsEnv("NIMTEST_NO_COLOR")

+                      body: stmt): PNimrodNode {.dirty.} =
+    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))
+
+
+## Reading settings
+var envOutLvl = os.getEnv("NIMTEST_OUTPUT_LVL").string
+
+if envOutLvl.len > 0:
+  for opt in countup(low(TOutputLevel), high(TOutputLevel)):
+    if $opt == envOutLvl:
+      OutputLevel = opt
+      break
+
+AbortOnError = existsEnv("NIMTEST_ABORT_ON_ERROR")
+ColorOutput  = not existsEnv("NIMTEST_NO_COLOR")