@@ -58,6 +58,7 @@ Base.@kwdef mutable struct Options
58
58
verbose:: Bool = false # annotated verbosity
59
59
transient_verbose:: Bool = false # verbosity for next run
60
60
static_include:: Bool = false # whether to execute include at `replace_ts` time
61
+ include_functions:: Vector{Symbol} = [:include ] # functions to treat like include
61
62
end
62
63
63
64
mutable struct TestsetExpr
@@ -121,12 +122,14 @@ function extract_testsets(dest)
121
122
end
122
123
123
124
# replace unqualified `@testset` by TestsetExpr
124
- function replace_ts (source, mod, x:: Expr , parent; static_include:: Bool )
125
+ function replace_ts (source, mod, x:: Expr , parent; static_include:: Bool ,
126
+ include_functions:: Vector{Symbol} )
125
127
if x. head === :macrocall
126
128
name = x. args[1 ]
127
129
if name === Symbol (" @testset" )
128
130
@assert x. args[2 ] isa LineNumberNode
129
131
ts, hasbroken = parse_ts (x. args[2 ], mod, Tuple (x. args[3 : end ]), parent;
132
+ include_functions= include_functions,
130
133
static_include= static_include)
131
134
ts != = invalid && parent != = nothing && push! (parent. children, ts)
132
135
ts, false # hasbroken counts only "proper" @test_broken, not recursive ones
@@ -136,16 +139,17 @@ function replace_ts(source, mod, x::Expr, parent; static_include::Bool)
136
139
# `@test` is generally called a lot, so it's probably worth it to skip
137
140
# the containment test in this case
138
141
x = macroexpand (mod, x, recursive= false )
139
- replace_ts (source, mod, x, parent; static_include= static_include)
142
+ replace_ts (source, mod, x, parent; static_include= static_include,
143
+ include_functions= include_functions)
140
144
else
141
145
@goto default
142
146
end
143
- elseif x. head == :call && x. args[1 ] == :include
147
+ elseif x. head == :call && x. args[1 ] ∈ include_functions
144
148
path = x. args[end ]
145
149
sourcepath = dirname (string (source. file))
146
150
x. args[end ] = path isa AbstractString ?
147
- joinpath (sourcepath, path) :
148
- :(joinpath ($ sourcepath, $ path))
151
+ joinpath (sourcepath, path) :
152
+ :(joinpath ($ sourcepath, $ path))
149
153
if static_include
150
154
news = InlineTest. get_tests (mod). news
151
155
newslen = length (news)
@@ -166,26 +170,30 @@ function replace_ts(source, mod, x::Expr, parent; static_include::Bool)
166
170
# below; it's currently not very important
167
171
tsi. source, tsi. ts... )
168
172
for tsi in newstmp). .. )
169
- replace_ts (source, mod, included_ts, parent; static_include= static_include)
173
+ replace_ts (source, mod, included_ts, parent;
174
+ static_include= static_include, include_functions= include_functions)
170
175
else
171
176
nothing , false
172
177
end
173
178
else
174
179
x, false
175
180
end
176
181
else @label default
177
- body_br = map (z -> replace_ts (source, mod, z, parent; static_include= static_include),
182
+ body_br = map (z -> replace_ts (source, mod, z, parent; static_include= static_include,
183
+ include_functions= include_functions),
178
184
x. args)
179
185
filter! (x -> first (x) != = invalid, body_br)
180
186
Expr (x. head, first .(body_br)... ), any (last .(body_br))
181
187
end
182
188
end
183
189
184
- replace_ts (source, mod, x, _1; static_include:: Bool ) = x, false
190
+ replace_ts (source, mod, x, _1; static_include:: Bool ,
191
+ include_functions) = x, false
185
192
186
193
# create a TestsetExpr from @testset's args
187
194
function parse_ts (source:: LineNumberNode , mod:: Module , args:: Tuple , parent= nothing ;
188
- static_include:: Bool = false )
195
+ static_include:: Bool = false , include_functions:: Vector{Symbol} = [:include ])
196
+
189
197
function tserror (msg)
190
198
@error msg _file= String (source. file) _line= source. line _module= mod
191
199
invalid, false
@@ -195,14 +203,15 @@ function parse_ts(source::LineNumberNode, mod::Module, args::Tuple, parent=nothi
195
203
return tserror (" expected begin/end block or for loop as argument to @testset" )
196
204
197
205
local desc
198
- options = Options ()
206
+ options = Options (include_functions = include_functions )
199
207
marks = Marks ()
200
208
if parent != = nothing
201
209
append! (marks. hard, parent. marks. hard) # copy! not available in Julia 1.0
202
210
options. static_include = parent. options. static_include
203
211
# if static_include was set in parent, it should have been forwarded also
204
212
# through the parse_ts/replace_ts call chains:
205
213
@assert static_include == parent. options. static_include
214
+ @assert include_functions === parent. options. include_functions
206
215
end
207
216
for arg in args[1 : end - 1 ]
208
217
if arg isa String || Meta. isexpr (arg, :string )
@@ -211,10 +220,22 @@ function parse_ts(source::LineNumberNode, mod::Module, args::Tuple, parent=nothi
211
220
# TODO : support non-literal symbols?
212
221
push! (marks. hard, arg. value)
213
222
elseif Meta. isexpr (arg, :(= ))
214
- arg. args[1 ] in fieldnames (Options) ||
215
- return tserror (" unsupported @testset option" )
216
- # TODO : make that work with non-literals:
217
- setfield! (options, arg. args[1 ], arg. args[2 ])
223
+ optname = arg. args[1 ]
224
+ optname in fieldnames (Options) ||
225
+ return tserror (" unsupported @testset option: $optname " )
226
+ if optname == :include_functions
227
+ @assert Meta. isexpr (arg. args[2 ], :vect )
228
+ if parent != = nothing
229
+ options. include_functions = Symbol[] # make it non-shared
230
+ end
231
+ for ifn in arg. args[2 ]. args
232
+ @assert ifn isa QuoteNode
233
+ push! (options. include_functions, ifn. value)
234
+ end
235
+ else
236
+ # TODO : make that work with non-literals:
237
+ setfield! (options, optname, arg. args[2 ])
238
+ end
218
239
else
219
240
return tserror (" unsupported @testset" )
220
241
end
@@ -253,7 +274,8 @@ function parse_ts(source::LineNumberNode, mod::Module, args::Tuple, parent=nothi
253
274
254
275
ts = TestsetExpr (source, mod, desc, options, marks, loops, parent)
255
276
ts. body, ts. hasbroken = replace_ts (source, mod, tsbody, ts;
256
- static_include= options. static_include)
277
+ static_include= options. static_include,
278
+ include_functions= options. include_functions)
257
279
ts, false # hasbroken counts only "proper" @test_broken, not recursive ones
258
280
end
259
281
0 commit comments