summary refs log tree commit diff stats
path: root/testament/lib
diff options
context:
space:
mode:
Diffstat (limited to 'testament/lib')
-rw-r--r--testament/lib/stdtest/netutils.nim3
-rw-r--r--testament/lib/stdtest/specialpaths.nim23
-rw-r--r--testament/lib/stdtest/testutils.nim101
-rw-r--r--testament/lib/stdtest/unittest_light.nim17
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