diff options
author | Araq <rumpf_a@web.de> | 2012-09-13 18:48:14 +0200 |
---|---|---|
committer | Araq <rumpf_a@web.de> | 2012-09-13 18:48:14 +0200 |
commit | 4a435a8fb4551b03bdcbbbd9b074a51fa46928dd (patch) | |
tree | 5d83bf8195b6706c70da921d199d9a04ebc539ee /lib | |
parent | d336cb4957c6b223ce7e8d717718217cb0665b56 (diff) | |
parent | 36155a6813cb414666753f6b66e04e1044954f85 (diff) | |
download | Nim-4a435a8fb4551b03bdcbbbd9b074a51fa46928dd.tar.gz |
Merge branch 'master' of github.com:Araq/Nimrod
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pure/asyncio.nim | 17 | ||||
-rw-r--r-- | lib/pure/irc.nim | 79 | ||||
-rw-r--r-- | lib/pure/unittest.nim | 394 |
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") |