@@ -104,7 +104,7 @@ const loaded_testmodules = Dict{Module,Vector{Module}}()
104
104
105
105
"""
106
106
ReTest.hijack(source, [modname];
107
- parentmodule::Module=Main, lazy=false, testset::Bool=false ,
107
+ parentmodule::Module=Main, lazy=false, [include::Symbol] ,
108
108
[revise::Bool])
109
109
110
110
Given test files defined in `source` using the `Test` package, try to load
@@ -143,11 +143,10 @@ The `lazy` keyword specifies whether some toplevel expressions should be skipped
143
143
* `:brutal` means toplevel `@test*` macros are removed, as well as toplevel
144
144
`begin`, `let`, `for` or `if` blocks.
145
145
146
- #### `testset ` keyword
146
+ #### `include ` keyword
147
147
148
- The `testset` keyword can help to handle the case where `@testset`s contain
149
- `include` expressions (at the "toplevel" of the testset), like in the
150
- following example:
148
+ The `include` keyword can help to handle the case where `@testset`s contain
149
+ `include` expressions, like in the following example:
151
150
```julia
152
151
@testset "parent" begin
153
152
@test true
@@ -161,11 +160,28 @@ of the testset which include them. With `ReTest`, the `include` expressions
161
160
would be evaluated only when the parent testsets are run, so that included
162
161
testsets are not run themselves, but only "declared".
163
162
164
- It the `testset` keyword
165
- is `true`, `hijack` inspects `@testset` expressions and puts `include`
166
- expressions outside of the testset. This is not ideal, but at least allows
167
- `ReTest` to know about all the testsets right after the call to `hijack`, and
168
- to not declare new testsets when parent testsets are run.
163
+ If the `include` keyword is set to `:static`, `include(...)` expressions are
164
+ evaluated when `@testset` expressions containing them are parsed, before
165
+ filtering and before testsets are run. Testsets which are declared (within the
166
+ same module) as a side effect of `include(...)` are then inserted in place of
167
+ the call to `include(...)`.
168
+
169
+ If the `include` keyword is set to `:outline`, `hijack` inspects topelevel
170
+ `@testset` expressions and puts toplevel `include(...)` expressions outside of
171
+ the containing testset, and should therefore be evaluated immediately. This is
172
+ not ideal, but at least allows `ReTest` to know about all the testsets right
173
+ after the call to `hijack`, and to not declare new testsets when parent
174
+ testsets are run.
175
+
176
+ The `:outline` option might be deprecated in the future, and `include=:static`
177
+ should generally be preferred. One case where `:outline` might work better is
178
+ when the included file defines a submodule: `ReTest` doesn't have the concept
179
+ of a nested testset belonging to a different module than the parent testset,
180
+ so the best that can be done here is to "outline" such nested testsets; with
181
+ `include=:outline`, `hijack` will "process" the content of such submodules
182
+ (replace `using Test` by `using ReTest`, etc.), whereas with
183
+ `include=:static`, the subdmodules will get defined after `hijack` has
184
+ returned (on the first call to `retest` thereafter), so won't be "processed".
169
185
170
186
#### `revise` keyword
171
187
@@ -180,8 +196,12 @@ and to `false` otherwise.
180
196
"""
181
197
function hijack end
182
198
199
+ # TODO 0.4: remove `testset` kwarg
200
+ # TODO : maybe deprecate `include=:outline`?
201
+
183
202
function hijack (path:: AbstractString , modname= nothing ; parentmodule:: Module = Main,
184
- lazy= false , testset:: Bool = false , revise:: Maybe{Bool} = nothing )
203
+ lazy= false , revise:: Maybe{Bool} = nothing ,
204
+ include:: Maybe{Symbol} = nothing , testset:: Bool = false )
185
205
186
206
# do first, to error early if necessary
187
207
Revise = get_revise (revise)
@@ -192,22 +212,34 @@ function hijack(path::AbstractString, modname=nothing; parentmodule::Module=Main
192
212
modname = Symbol (modname)
193
213
194
214
newmod = @eval parentmodule module $ modname end
195
- populate_mod! (newmod, path; lazy= lazy, testset= testset, Revise= Revise)
215
+ populate_mod! (newmod, path; lazy= lazy, include= setinclude (include, testset),
216
+ Revise= Revise)
196
217
newmod
197
218
end
198
219
220
+ function setinclude (include, testset)
221
+ if testset
222
+ include === nothing || error (" cannot specify both `testset` and `include` arguments" )
223
+ :outline
224
+ else
225
+ include === nothing || include === :static || include === :outline ||
226
+ error (" `include` keyword only accepts `:static` or `:outline` as value" )
227
+ include
228
+ end
229
+ end
230
+
199
231
# this is just a work-around for v"1.5", where @__MODULE__ can't be used in
200
232
# expressions; root_module[] is set equal to @__MODULE__ within modules
201
233
const root_module = Ref {Symbol} ()
202
234
203
235
__init__ () = root_module[] = gensym (" MODULE" )
204
236
205
- function populate_mod! (mod:: Module , path; lazy, Revise, testset )
237
+ function populate_mod! (mod:: Module , path; lazy, Revise, include )
206
238
lazy ∈ (true , false , :brutal ) ||
207
239
throw (ArgumentError (" the `lazy` keyword must be `true`, `false` or `:brutal`" ))
208
240
209
241
files = Revise === nothing ? nothing : Dict (path => mod)
210
- substitute! (x) = substitute_retest! (x, lazy, testset , files)
242
+ substitute! (x) = substitute_retest! (x, lazy, include , files)
211
243
212
244
@eval mod begin
213
245
using ReTest # for files which don't have `using Test`
@@ -235,7 +267,8 @@ function revise_track(Revise, files)
235
267
end
236
268
237
269
function hijack (packagemod:: Module , modname= nothing ; parentmodule:: Module = Main,
238
- lazy= false , testset:: Bool = false , revise:: Maybe{Bool} = nothing )
270
+ lazy= false , revise:: Maybe{Bool} = nothing ,
271
+ include:: Maybe{Symbol} = nothing , testset:: Bool = false )
239
272
packagepath = pathof (packagemod)
240
273
packagepath === nothing && packagemod != = Base &&
241
274
throw (ArgumentError (" $packagemod is not a package" ))
@@ -253,13 +286,13 @@ function hijack(packagemod::Module, modname=nothing; parentmodule::Module=Main,
253
286
else
254
287
path = joinpath (dirname (dirname (packagepath)), " test" , " runtests.jl" )
255
288
hijack (path, modname, parentmodule= parentmodule,
256
- lazy= lazy, testset= testset, revise= revise)
289
+ lazy= lazy, testset= testset, include = include, revise= revise)
257
290
end
258
291
end
259
292
260
- function substitute_retest! (ex, lazy, testset , files= nothing ;
293
+ function substitute_retest! (ex, lazy, include_ , files= nothing ;
261
294
ishijack:: Bool = true )
262
- substitute! (x) = substitute_retest! (x, lazy, testset , files, ishijack= ishijack)
295
+ substitute! (x) = substitute_retest! (x, lazy, include_ , files, ishijack= ishijack)
263
296
264
297
if Meta. isexpr (ex, :using )
265
298
ishijack || return ex
@@ -309,19 +342,24 @@ function substitute_retest!(ex, lazy, testset, files=nothing;
309
342
ishijack || return ex
310
343
if lazy != false && ex. args[1 ] ∈ TEST_MACROS
311
344
empty_expr! (ex)
312
- elseif testset && ex. args[1 ] == Symbol (" @testset" )
313
- # we remove `include` expressions and put them out of the `@testset`
314
- body = ex. args[end ]
315
- if body. head == :for
316
- body = body. args[end ]
345
+ elseif include_ != = nothing && ex. args[1 ] == Symbol (" @testset" )
346
+ if include_ === :outline
347
+ # we remove `include` expressions and put them out of the `@testset`
348
+ body = ex. args[end ]
349
+ if body. head == :for
350
+ body = body. args[end ]
351
+ end
352
+ includes = splice! (body. args, findall (body. args) do x
353
+ Meta. isexpr (x, :call ) && x. args[1 ] == :include
354
+ end )
355
+ map! (substitute!, includes, includes)
356
+ ex. head = :block
357
+ newts = Expr (:macrocall , ex. args... )
358
+ push! (empty! (ex. args), newts, includes... )
359
+ else # :static
360
+ pos = ex. args[2 ] isa LineNumberNode ? 3 : 2
361
+ insert! (ex. args, pos, :(static_include= true ))
317
362
end
318
- includes = splice! (body. args, findall (body. args) do x
319
- Meta. isexpr (x, :call ) && x. args[1 ] == :include
320
- end )
321
- map! (substitute!, includes, includes)
322
- ex. head = :block
323
- newts = Expr (:macrocall , ex. args... )
324
- push! (empty! (ex. args), newts, includes... )
325
363
end
326
364
elseif ex isa Expr && ex. head ∈ (:block , :let , :for , :while , :if , :try )
327
365
if lazy == :brutal
0 commit comments