testutils.nim 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. import std/private/miscdollars
  2. when defined(nimscript):
  3. import std/os # xxx investigate why needed
  4. else:
  5. from std/os import getEnv
  6. import std/[macros, genasts]
  7. template flakyAssert*(cond: untyped, msg = "", notifySuccess = true) =
  8. ## API to deal with flaky or failing tests. This avoids disabling entire tests
  9. ## altogether so that at least the parts that are working are kept being
  10. ## tested. This also avoids making CI fail periodically for tests known to
  11. ## be flaky. Finally, for known failures, passing `notifySuccess = true` will
  12. ## log that the test succeeded, which may indicate that a bug was fixed
  13. ## "by accident" and should be looked into.
  14. const info = instantiationInfo(-1, true)
  15. const expr = astToStr(cond)
  16. if cond and not notifySuccess:
  17. discard # silent success
  18. else:
  19. var msg2 = ""
  20. toLocation(msg2, info.filename, info.line, info.column)
  21. if cond:
  22. # a flaky test is failing, we still report it but we don't fail CI
  23. msg2.add " FLAKY_SUCCESS "
  24. else:
  25. # a previously failing test is now passing, a pre-existing bug might've been
  26. # fixed by accidend
  27. msg2.add " FLAKY_FAILURE "
  28. msg2.add $expr & " " & msg
  29. echo msg2
  30. when not defined(js) and not defined(nimscript):
  31. import std/strutils
  32. proc greedyOrderedSubsetLines*(lhs, rhs: string, allowPrefixMatch = false): bool =
  33. ## Returns true if each stripped line in `lhs` appears in rhs, using a greedy matching.
  34. # xxx improve error reporting by showing the last matched pair
  35. iterator splitLinesClosure(): string {.closure.} =
  36. for line in splitLines(rhs.strip):
  37. yield line
  38. template isMatch(lhsi, rhsi): bool =
  39. if allowPrefixMatch:
  40. startsWith(rhsi, lhsi)
  41. else:
  42. lhsi == rhsi
  43. var rhsIter = splitLinesClosure
  44. var currentLine = strip(rhsIter())
  45. for line in lhs.strip.splitLines:
  46. let line = line.strip
  47. if line.len != 0:
  48. while not isMatch(line, currentLine):
  49. currentLine = strip(rhsIter())
  50. if rhsIter.finished:
  51. return false
  52. if rhsIter.finished:
  53. return false
  54. return true
  55. template enableRemoteNetworking*: bool =
  56. ## Allows contolling whether to run some test at a statement-level granularity.
  57. ## Using environment variables simplifies propagating this all the way across
  58. ## process calls, e.g. `testament all` calls itself, which in turns invokes
  59. ## a `nim` invocation (possibly via additional intermediate processes).
  60. getEnv("NIM_TESTAMENT_REMOTE_NETWORKING") == "1"
  61. template disableSSLTesting*: bool =
  62. ## TODO: workaround for GitHub Action gcc 14 matrix; remove this
  63. ## matrix and the flag after Azure agent supports ubuntu 24.04
  64. getEnv("NIM_TESTAMENT_DISABLE_SSL") == "1"
  65. template whenRuntimeJs*(bodyIf, bodyElse) =
  66. ##[
  67. Behaves as `when defined(js) and not nimvm` (which isn't legal yet).
  68. pending improvements to `nimvm`, this sugar helps; use as follows:
  69. whenRuntimeJs:
  70. doAssert defined(js)
  71. when nimvm: doAssert false
  72. else: discard
  73. do:
  74. discard
  75. ]##
  76. when nimvm: bodyElse
  77. else:
  78. when defined(js): bodyIf
  79. else: bodyElse
  80. template whenVMorJs*(bodyIf, bodyElse) =
  81. ## Behaves as: `when defined(js) or nimvm`
  82. when nimvm: bodyIf
  83. else:
  84. when defined(js): bodyIf
  85. else: bodyElse
  86. template accept*(a) =
  87. doAssert compiles(a)
  88. template reject*(a) =
  89. doAssert not compiles(a)
  90. template disableVm*(body) =
  91. when nimvm: discard
  92. else: body
  93. macro assertAll*(body) =
  94. ## works in VM, unlike `check`, `require`
  95. runnableExamples:
  96. assertAll:
  97. 1+1 == 2
  98. var a = @[1, 2] # statements work
  99. a.len == 2
  100. # remove this once these support VM, pending #10129 (closed but not yet fixed)
  101. result = newStmtList()
  102. for a in body:
  103. result.add genAst(a, a2 = a.repr, info = lineInfo(a)) do:
  104. # D20210421T014713:here
  105. # xxx pending https://github.com/nim-lang/Nim/issues/12030,
  106. # `typeof` should introduce its own scope, so that this
  107. # is sufficient: `typeof(a)` instead of `typeof(block: a)`
  108. when typeof(block: a) is void: a
  109. else:
  110. if not a:
  111. raise newException(AssertionDefect, info & " " & a2)