From a7df3ffbe0ed6d10cc952e47f4e92a69403363dc Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Sun, 12 Apr 2015 12:59:56 +0800 Subject: Ignore EvError in `asyncdispatch.poll(...)` for non-windows systems, so that exceptions can be raised from `send(...)` and `recv(...)` --- lib/pure/asyncdispatch.nim | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib') diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 27f77cef2..6ed782545 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -882,9 +882,9 @@ else: let data = PData(info.key.data) assert data.fd == info.key.fd.TAsyncFD #echo("In poll ", data.fd.cint) - if EvError in info.events: - closeSocket(data.fd) - continue + # There may be EvError here, but we handle them in callbacks, + # so that exceptions can be raised from `send(...)` and + # `recv(...)` routines. if EvRead in info.events: # Callback may add items to ``data.readCBs`` which causes issues if -- cgit 1.4.1-2-gfad0 From a11a2f0fdb3ecdd995e4fc1a6cb41de4e7fc12f2 Mon Sep 17 00:00:00 2001 From: Kay Zheng Date: Sat, 18 Apr 2015 10:27:35 +0800 Subject: Check for async errors in --- lib/pure/asyncdispatch.nim | 14 +++++++++++--- tests/async/tasyncconnect.nim | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) create mode 100644 tests/async/tasyncconnect.nim (limited to 'lib') diff --git a/lib/pure/asyncdispatch.nim b/lib/pure/asyncdispatch.nim index 6ed782545..ca5b13c78 100644 --- a/lib/pure/asyncdispatch.nim +++ b/lib/pure/asyncdispatch.nim @@ -923,9 +923,17 @@ else: var retFuture = newFuture[void]("connect") proc cb(fd: TAsyncFD): bool = - # We have connected. - retFuture.complete() - return true + var ret = SocketHandle(fd).getSockOptInt(cint(SOL_SOCKET), cint(SO_ERROR)) + if ret == 0: + # We have connected. + retFuture.complete() + return true + elif ret == EINTR: + # interrupted, keep waiting + return false + else: + retFuture.fail(newException(OSError, osErrorMsg(OSErrorCode(ret)))) + return true var aiList = getAddrInfo(address, port, af) var success = false diff --git a/tests/async/tasyncconnect.nim b/tests/async/tasyncconnect.nim new file mode 100644 index 000000000..bc63b8e82 --- /dev/null +++ b/tests/async/tasyncconnect.nim @@ -0,0 +1,33 @@ +discard """ + file: "tasyncconnect.nim" + exitcode: 1 + outputsub: "Error: unhandled exception: Connection refused [Exception]" +""" + +import + asyncdispatch, + posix + + +const + testHost = "127.0.0.1" + testPort = Port(17357) + + +when defined(windows) or defined(nimdoc): + discard +else: + proc testAsyncConnect() {.async.} = + var s = newAsyncRawSocket() + + await s.connect(testHost, testPort) + + var peerAddr: SockAddr + var addrSize = Socklen(sizeof(peerAddr)) + var ret = SocketHandle(s).getpeername(addr(peerAddr), addr(addrSize)) + + if ret < 0: + echo("`connect(...)` failed but no exception was raised.") + quit(2) + + waitFor(testAsyncConnect()) -- cgit 1.4.1-2-gfad0 From 464ec61e9c11deb1a52df431a266ba50bf132304 Mon Sep 17 00:00:00 2001 From: fenekku Date: Thu, 9 Jul 2015 13:22:26 -0400 Subject: document unittest.nim + code agreement --- lib/pure/unittest.nim | 144 +++++++++++++++++++++++++++++++++++++++++---- tests/stdlib/tunittest.nim | 14 +++++ 2 files changed, 145 insertions(+), 13 deletions(-) (limited to 'lib') diff --git a/lib/pure/unittest.nim b/lib/pure/unittest.nim index 407db0a51..70b314e63 100644 --- a/lib/pure/unittest.nim +++ b/lib/pure/unittest.nim @@ -9,7 +9,7 @@ ## :Author: Zahary Karadjov ## -## This module implements boilerplate to make testing easy. +## This module implements boilerplate to make unit testing easy. ## ## Example: ## @@ -41,27 +41,69 @@ when not defined(ECMAScript): import terminal type - TestStatus* = enum OK, FAILED - OutputLevel* = enum PRINT_ALL, PRINT_FAILURES, PRINT_NONE + TestStatus* = enum OK, FAILED ## The status of a test when it is done. + OutputLevel* = enum ## The output verbosity of the tests. + PRINT_ALL, ## Print as much as possible. + PRINT_FAILURES, ## Print only the failed tests. + PRINT_NONE ## Print nothing. {.deprecated: [TTestStatus: TestStatus, TOutputLevel: OutputLevel]} -var - abortOnError* {.threadvar.}: bool - outputLevel* {.threadvar.}: OutputLevel - colorOutput* {.threadvar.}: bool +var ## Global unittest settings! + + abortOnError* {.threadvar.}: bool ## Set to true in order to quit + ## immediately on fail. Default is false, + ## unless the ``NIMTEST_ABORT_ON_ERROR`` + ## environment variable is set for + ## the non-js target. + outputLevel* {.threadvar.}: OutputLevel ## Set the verbosity of test results. + ## Default is ``PRINT_ALL``, unless + ## the ``NIMTEST_OUTPUT_LVL`` environment + ## variable is set for the non-js target. + + colorOutput* {.threadvar.}: bool ## Have test results printed in color. + ## Default is true for the non-js target + ## unless, the environment variable + ## ``NIMTEST_NO_COLOR`` is set. checkpoints {.threadvar.}: seq[string] checkpoints = @[] -template testSetupIMPL*: stmt {.immediate, dirty.} = discard +template testSetupIMPL*: stmt {.immediate, dirty.} = discard #Should this be public or even exist? template testTeardownIMPL*: stmt {.immediate, dirty.} = discard proc shouldRun(testName: string): bool = result = true template suite*(name: expr, body: stmt): stmt {.immediate, dirty.} = + ## Declare a test suite identified by `name` with optional ``setup`` + ## and/or ``teardown`` section. + ## + ## A test suite is a series of one or more related tests sharing a + ## common fixture (``setup``, ``teardown``). The fixture is executed + ## for EACH test. + ## + ## .. code-block:: nim + ## suite "test suite for addition": + ## setup: + ## let result = 4 + ## + ## test "2 + 2 = 4": + ## check(2+2 == result) + ## + ## test "2 + -2 != 4": + ## check(2+2 != result) + ## + ## # No teardown needed + ## + ## The suite will run the individual test cases in the order in which + ## they were listed. With default global settings the above code prints: + ## + ## .. code-block:: + ## + ## [OK] 2 + 2 = 4 + ## [OK] (2 + -2) != 4 block: template setup*(setupBody: stmt): stmt {.immediate, dirty.} = template testSetupIMPL: stmt {.immediate, dirty.} = setupBody @@ -87,6 +129,19 @@ proc testDone(name: string, s: TestStatus) = rawPrint() template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = + ## Define a single test case identified by `name`. + ## + ## .. code-block:: nim + ## + ## test "roses are red": + ## let roses = "red" + ## check(roses == "red") + ## + ## The above code outputs: + ## + ## .. code-block:: + ## + ## [OK] roses are red bind shouldRun, checkpoints, testDone if shouldRun(name): @@ -108,10 +163,32 @@ template test*(name: expr, body: stmt): stmt {.immediate, dirty.} = testDone name, testStatusIMPL proc checkpoint*(msg: string) = + ## Set a checkpoint identified by `msg`. Upon test failure all + ## checkpoints encountered so far are printed out. Example: + ## + ## .. code-block:: nim + ## + ## checkpoint("Checkpoint A") + ## check((42, "the Answer to life and everything") == (1, "a")) + ## checkpoint("Checkpoint B") + ## + ## outputs "Checkpoint A" once it fails. checkpoints.add(msg) # TODO: add support for something like SCOPED_TRACE from Google Test template fail* = + ## Print out the checkpoints encountered so far and quit if ``abortOnError`` + ## is true. Otherwise, erase the checkpoints and indicate the test has + ## failed (change exit code and test status). This template is useful + ## for debugging, but is otherwise mostly used internally. Example: + ## + ## .. code-block:: nim + ## + ## checkpoint("Checkpoint A") + ## complicatedProcInThread() + ## fail() + ## + ## outputs "Checkpoint A" before quitting. bind checkpoints for msg in items(checkpoints): echo msg @@ -127,8 +204,23 @@ template fail* = checkpoints = @[] macro check*(conditions: stmt): stmt {.immediate.} = + ## 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``). + ## Example: + ## + ## .. code-block:: nim + ## + ## import strutils + ## + ## check("AKB48".toLower() == "akb48") + ## + ## let teams = {'A', 'K', 'B', '4', '8'} + ## + ## check: + ## "AKB48".toLower() == "akb48" + ## 'C' in teams let checked = callsite()[1] - var argsAsgns = newNimNode(nnkStmtList) argsPrintOuts = newNimNode(nnkStmtList) @@ -143,7 +235,7 @@ macro check*(conditions: stmt): stmt {.immediate.} = checkpoint(name & " was " & $value) proc inspectArgs(exp: NimNode) = - for i in 1 .. Date: Fri, 24 Jul 2015 18:08:05 +0200 Subject: Fix times' parse with literal strings --- lib/pure/times.nim | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pure/times.nim b/lib/pure/times.nim index e4d3f7494..fd5eb7ba4 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -1020,10 +1020,10 @@ proc parse*(value, layout: string): TimeInfo = # These are literals in both the layout and the value string if layout[i] == '\'': inc(i) - inc(j) while layout[i] != '\'' and layout.len-1 > i: inc(i) inc(j) + inc(i) else: inc(i) inc(j) @@ -1112,6 +1112,8 @@ when isMainModule: s = "2006-01-12T15:04:05Z-07:00" f = "yyyy-MM-ddTHH:mm:ssZzzz" assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") + f = "yyyy-MM-dd'T'HH:mm:ss'Z'zzz" + assert($s.parse(f) == "Thu Jan 12 15:04:05 2006") # RFC3339Nano = "2006-01-02T15:04:05.999999999Z07:00" s = "2006-01-12T15:04:05.999999999Z-07:00" f = "yyyy-MM-ddTHH:mm:ss.999999999Zzzz" -- cgit 1.4.1-2-gfad0 From a88131ed4a660d6eba543a11c2df66c04cdd3908 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Fri, 24 Jul 2015 22:46:24 +0100 Subject: Improved errors in times.parse. --- lib/pure/times.nim | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) (limited to 'lib') diff --git a/lib/pure/times.nim b/lib/pure/times.nim index fd5eb7ba4..f1315a9fd 100644 --- a/lib/pure/times.nim +++ b/lib/pure/times.nim @@ -789,7 +789,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "sat": info.weekday = dSat else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (ddd), got: " & value[j..j+2]) j += 3 of "dddd": if value.len >= j+6 and value[j..j+5].cmpIgnoreCase("sunday") == 0: @@ -814,7 +815,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.weekday = dSat j += 8 else: - raise newException(ValueError, "invalid day of week ") + raise newException(ValueError, + "Couldn't parse day of week (dddd), got: " & value) of "h", "H": var pd = parseInt(value[j..j+1], sv) info.hour = sv @@ -865,7 +867,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = of "dec": info.month = mDec else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMM), got: " & value) j += 3 of "MMMM": if value.len >= j+7 and value[j..j+6].cmpIgnoreCase("january") == 0: @@ -905,7 +908,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = info.month = mDec j += 8 else: - raise newException(ValueError, "invalid month") + raise newException(ValueError, + "Couldn't parse month (MMMM), got: " & value) of "s": var pd = parseInt(value[j..j+1], sv) info.second = sv @@ -936,7 +940,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-parseInt($value[j+1]) else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (z), got: " & value[j]) j += 2 of "zz": if value[j] == '+': @@ -944,7 +949,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zz), got: " & value[j]) j += 3 of "zzz": if value[j] == '+': @@ -952,7 +958,8 @@ proc parseToken(info: var TimeInfo; token, value: string; j: var int) = elif value[j] == '-': info.timezone = 0-value[j+1..j+2].parseInt() else: - raise newException(ValueError, "Sign for timezone " & value[j]) + raise newException(ValueError, + "Couldn't parse timezone offset (zzz), got: " & value[j]) j += 6 of "ZZZ": info.tzname = value[j..j+2].toUpper() -- cgit 1.4.1-2-gfad0 From ce4e877702d361acd511b14364c26956c06a63d7 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 26 Jul 2015 18:15:19 +0100 Subject: `$` for tuples/objects now handles a nil value correctly. Fixes #3149. --- lib/system.nim | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/system.nim b/lib/system.nim index c5b0e0cc7..91495f31a 100644 --- a/lib/system.nim +++ b/lib/system.nim @@ -2173,7 +2173,11 @@ proc `$`*[T: tuple|object](x: T): string = if not firstElement: result.add(", ") result.add(name) result.add(": ") - result.add($value) + when compiles(value.isNil): + if value.isNil: result.add "nil" + else: result.add($value) + else: + result.add($value) firstElement = false result.add(")") -- cgit 1.4.1-2-gfad0 From 94ad731964af518745647f15ce56d1c65e155847 Mon Sep 17 00:00:00 2001 From: Dominik Picheta Date: Sun, 26 Jul 2015 18:21:14 +0100 Subject: Fixes example code in marshal module. --- lib/pure/marshal.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib') diff --git a/lib/pure/marshal.nim b/lib/pure/marshal.nim index 49f049e46..173cd1e81 100644 --- a/lib/pure/marshal.nim +++ b/lib/pure/marshal.nim @@ -17,7 +17,7 @@ ## .. code-block:: nim ## ## type -## A = object +## A = object of RootObj ## B = object of A ## f: int ## -- cgit 1.4.1-2-gfad0 From 8913e82f4505cb542c06545696ef687a52cd080c Mon Sep 17 00:00:00 2001 From: Araq Date: Tue, 28 Jul 2015 02:54:07 +0200 Subject: removed macros.high as it never worked outside of macros.nim --- lib/core/macros.nim | 18 ++++++++---------- web/news.txt | 2 ++ 2 files changed, 10 insertions(+), 10 deletions(-) (limited to 'lib') diff --git a/lib/core/macros.nim b/lib/core/macros.nim index 7d1c15610..c89fa354a 100644 --- a/lib/core/macros.nim +++ b/lib/core/macros.nim @@ -592,10 +592,8 @@ proc newNilLit*(): NimNode {.compileTime.} = ## New nil literal shortcut result = newNimNode(nnkNilLit) -proc high*(node: NimNode): int {.compileTime.} = len(node) - 1 - ## Return the highest index available for a node -proc last*(node: NimNode): NimNode {.compileTime.} = node[node.high] - ## Return the last item in nodes children. Same as `node[node.high()]` +proc last*(node: NimNode): NimNode {.compileTime.} = node[