diff options
Diffstat (limited to 'testament/lib')
-rw-r--r-- | testament/lib/stdtest/netutils.nim | 3 | ||||
-rw-r--r-- | testament/lib/stdtest/specialpaths.nim | 23 | ||||
-rw-r--r-- | testament/lib/stdtest/testutils.nim | 101 | ||||
-rw-r--r-- | testament/lib/stdtest/unittest_light.nim | 17 |
4 files changed, 133 insertions, 11 deletions
diff --git a/testament/lib/stdtest/netutils.nim b/testament/lib/stdtest/netutils.nim index eb913a56a..5115390e0 100644 --- a/testament/lib/stdtest/netutils.nim +++ b/testament/lib/stdtest/netutils.nim @@ -1,6 +1,7 @@ import std/[nativesockets, asyncdispatch, os] proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = + ## See also `asynchttpserver.getPort`. block: var name: Sockaddr_in name.sin_family = typeof(name.sin_family)(toInt(AF_INET)) @@ -8,5 +9,5 @@ proc bindAvailablePort*(handle: SocketHandle, port = Port(0)): Port = name.sin_addr.s_addr = htonl(INADDR_ANY) if bindAddr(handle, cast[ptr SockAddr](addr(name)), sizeof(name).Socklen) < 0'i32: - raiseOSError(osLastError()) + raiseOSError(osLastError(), $port) result = getLocalAddr(handle, AF_INET)[1] diff --git a/testament/lib/stdtest/specialpaths.nim b/testament/lib/stdtest/specialpaths.nim index 42f656d76..e214d113d 100644 --- a/testament/lib/stdtest/specialpaths.nim +++ b/testament/lib/stdtest/specialpaths.nim @@ -1,6 +1,6 @@ #[ todo: move findNimStdLibCompileTime, findNimStdLib here -xxx: consider moving this to $nim/compiler/relpaths.nim to get relocatable paths +xxx: factor pending https://github.com/timotheecour/Nim/issues/616 ## note: $lib vs $nim note: these can resolve to 3 different paths if running via `nim c --lib:lib foo`, @@ -13,6 +13,8 @@ import compiler/nimpaths ]# import os +when defined(nimPreviewSlimSystem): + import std/assertions # Note: all the const paths defined here are known at compile time and valid # so long Nim repo isn't relocated after compilation. @@ -24,13 +26,30 @@ const # robust way to derive other paths here # We don't depend on PATH so this is robust to having multiple nim binaries nimRootDir* = sourcePath.parentDir.parentDir.parentDir.parentDir ## root of Nim repo + testsFname* = "tests" stdlibDir* = nimRootDir / "lib" systemPath* = stdlibDir / "system.nim" - testsDir* = nimRootDir / "tests" + testsDir* = nimRootDir / testsFname buildDir* = nimRootDir / "build" ## refs #10268: all testament generated files should go here to avoid ## polluting .gitignore +proc splitTestFile*(file: string): tuple[cat: string, path: string] = + ## At least one directory is required in the path, to use as a category name + runnableExamples: + doAssert splitTestFile("tests/fakedir/tfakename.nim") == ("fakedir", "tests/fakedir/tfakename.nim".unixToNativePath) + for p in file.parentDirs(inclusive = false): + let parent = p.parentDir + if parent.lastPathPart == testsFname: + result.cat = p.lastPathPart + let dir = getCurrentDir() + if file.isRelativeTo(dir): + result.path = file.relativePath(dir) + else: + result.path = file + return result + raiseAssert "file must match this pattern: '/pathto/tests/dir/**/tfile.nim', got: '" & file & "'" + static: # sanity check doAssert fileExists(systemPath) diff --git a/testament/lib/stdtest/testutils.nim b/testament/lib/stdtest/testutils.nim index 8083a63e8..a490b17c8 100644 --- a/testament/lib/stdtest/testutils.nim +++ b/testament/lib/stdtest/testutils.nim @@ -1,4 +1,9 @@ import std/private/miscdollars +when defined(nimscript): + import std/os # xxx investigate why needed +else: + from std/os import getEnv +import std/[macros, genasts] template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = ## API to deal with flaky or failing tests. This avoids disabling entire tests @@ -23,3 +28,99 @@ template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) = msg2.add " FLAKY_FAILURE " msg2.add $expr & " " & msg echo msg2 + +when not defined(js) and not defined(nimscript): + import std/strutils + + proc greedyOrderedSubsetLines*(lhs, rhs: string, allowPrefixMatch = false): bool = + ## Returns true if each stripped line in `lhs` appears in rhs, using a greedy matching. + # xxx improve error reporting by showing the last matched pair + iterator splitLinesClosure(): string {.closure.} = + for line in splitLines(rhs.strip): + yield line + template isMatch(lhsi, rhsi): bool = + if allowPrefixMatch: + startsWith(rhsi, lhsi) + else: + lhsi == rhsi + + var rhsIter = splitLinesClosure + var currentLine = strip(rhsIter()) + + for line in lhs.strip.splitLines: + let line = line.strip + if line.len != 0: + while not isMatch(line, currentLine): + currentLine = strip(rhsIter()) + if rhsIter.finished: + return false + + if rhsIter.finished: + return false + return true + +template enableRemoteNetworking*: bool = + ## Allows contolling whether to run some test at a statement-level granularity. + ## Using environment variables simplifies propagating this all the way across + ## process calls, e.g. `testament all` calls itself, which in turns invokes + ## a `nim` invocation (possibly via additional intermediate processes). + getEnv("NIM_TESTAMENT_REMOTE_NETWORKING") == "1" + +template disableSSLTesting*: bool = + ## TODO: workaround for GitHub Action gcc 14 matrix; remove this + ## matrix and the flag after Azure agent supports ubuntu 24.04 + getEnv("NIM_TESTAMENT_DISABLE_SSL") == "1" + +template whenRuntimeJs*(bodyIf, bodyElse) = + ##[ + Behaves as `when defined(js) and not nimvm` (which isn't legal yet). + pending improvements to `nimvm`, this sugar helps; use as follows: + + whenRuntimeJs: + doAssert defined(js) + when nimvm: doAssert false + else: discard + do: + discard + ]## + when nimvm: bodyElse + else: + when defined(js): bodyIf + else: bodyElse + +template whenVMorJs*(bodyIf, bodyElse) = + ## Behaves as: `when defined(js) or nimvm` + when nimvm: bodyIf + else: + when defined(js): bodyIf + else: bodyElse + +template accept*(a) = + doAssert compiles(a) + +template reject*(a) = + doAssert not compiles(a) + +template disableVm*(body) = + when nimvm: discard + else: body + +macro assertAll*(body) = + ## works in VM, unlike `check`, `require` + runnableExamples: + assertAll: + 1+1 == 2 + var a = @[1, 2] # statements work + a.len == 2 + # remove this once these support VM, pending #10129 (closed but not yet fixed) + result = newStmtList() + for a in body: + result.add genAst(a, a2 = a.repr, info = lineInfo(a)) do: + # D20210421T014713:here + # xxx pending https://github.com/nim-lang/Nim/issues/12030, + # `typeof` should introduce its own scope, so that this + # is sufficient: `typeof(a)` instead of `typeof(block: a)` + when typeof(block: a) is void: a + else: + if not a: + raise newException(AssertionDefect, info & " " & a2) diff --git a/testament/lib/stdtest/unittest_light.nim b/testament/lib/stdtest/unittest_light.nim index bf254c11f..4ab1d7543 100644 --- a/testament/lib/stdtest/unittest_light.nim +++ b/testament/lib/stdtest/unittest_light.nim @@ -1,3 +1,6 @@ +import std/assertions + + proc mismatch*[T](lhs: T, rhs: T): string = ## Simplified version of `unittest.require` that satisfies a common use case, ## while avoiding pulling too many dependencies. On failure, diagnostic @@ -11,26 +14,24 @@ proc mismatch*[T](lhs: T, rhs: T): string = proc quoted(s: string): string = result.addQuoted s - result.add "\n" + result.add '\n' result.add "lhs:{" & replaceInvisible( $lhs) & "}\nrhs:{" & replaceInvisible($rhs) & "}\n" when compiles(lhs.len): if lhs.len != rhs.len: - result.add "lhs.len: " & $lhs.len & " rhs.len: " & $rhs.len & "\n" + result.add "lhs.len: " & $lhs.len & " rhs.len: " & $rhs.len & '\n' when compiles(lhs[0]): var i = 0 while i < lhs.len and i < rhs.len: if lhs[i] != rhs[i]: break i.inc - result.add "first mismatch index: " & $i & "\n" + result.add "first mismatch index: " & $i & '\n' if i < lhs.len and i < rhs.len: result.add "lhs[i]: {" & quoted($lhs[i]) & "}\nrhs[i]: {" & quoted( $rhs[i]) & "}\n" result.add "lhs[0..<i]:{" & replaceInvisible($lhs[ - 0..<i]) & "}" + 0..<i]) & '}' proc assertEquals*[T](lhs: T, rhs: T, msg = "") = - when false: # can be useful for debugging to see all that's fed to this. - echo "----" & $lhs - if lhs!=rhs: - doAssert false, mismatch(lhs, rhs) & "\n" & msg + if lhs != rhs: + doAssert false, mismatch(lhs, rhs) & '\n' & msg |