1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
import std/private/miscdollars
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
## altogether so that at least the parts that are working are kept being
## tested. This also avoids making CI fail periodically for tests known to
## be flaky. Finally, for known failures, passing `notifySuccess = true` will
## log that the test succeeded, which may indicate that a bug was fixed
## "by accident" and should be looked into.
const info = instantiationInfo(-1, true)
const expr = astToStr(cond)
if cond and not notifySuccess:
discard # silent success
else:
var msg2 = ""
toLocation(msg2, info.filename, info.line, info.column)
if cond:
# a flaky test is failing, we still report it but we don't fail CI
msg2.add " FLAKY_SUCCESS "
else:
# a previously failing test is now passing, a pre-existing bug might've been
# fixed by accidend
msg2.add " FLAKY_FAILURE "
msg2.add $expr & " " & msg
echo msg2
when not defined(js):
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 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)
|