1
1
module ReTest
2
2
3
- export retest, @testset , @testset_macro , not, interpolated, reachable, depth, pass, fail
3
+ export retest, @testset , @testset_macro , not, interpolated, reachable, depth, pass, fail, iter
4
4
5
5
using Distributed
6
6
using Base. Threads: nthreads
@@ -80,6 +80,7 @@ mutable struct TestsetExpr
80
80
loopiters:: Maybe{Expr}
81
81
hasbroken:: Bool
82
82
hasbrokenrec:: Bool # recursive hasbroken, transiently
83
+ iter:: Union{Int,UnitRange{Int}} # transient loop iteration counter
83
84
run:: Bool
84
85
descwidth:: Int # max width of self and children shown descriptions
85
86
body:: Expr
@@ -343,7 +344,8 @@ function resolve!(mod::Module, ts::TestsetExpr, pat::Pattern;
343
344
for str in parentstrs
344
345
! strict && ts. run && break
345
346
new = str * " /" * desc
346
- hasmissing && new === missing ||
347
+ # string[end] == new can happen with loops when has(pat, Iter) and desc isa String
348
+ hasmissing && new === missing || ! isempty (strings) && strings[end ] === new ||
347
349
push! (strings, new)
348
350
hasmissing |= new === missing # comes either from desc or str
349
351
ts. run = ts. run || decide (new)
@@ -352,7 +354,7 @@ function resolve!(mod::Module, ts::TestsetExpr, pat::Pattern;
352
354
end
353
355
354
356
loops = ts. loops
355
- if loops === nothing || desc isa String
357
+ if loops === nothing || desc isa String && ! has (pat, Iter)
356
358
# TODO : maybe, for testset-for and !(desc isa String), still try this branch
357
359
# in case the the interpolation can be resolved thanks to a global binding
358
360
# (i.e. the description doesn't depend on loop variables)
@@ -368,9 +370,11 @@ function resolve!(mod::Module, ts::TestsetExpr, pat::Pattern;
368
370
if shown
369
371
ts. descwidth = descwidth (desc)
370
372
end
373
+ ts. iter = 1
371
374
decide_testset! (desc, false )
372
375
373
- else # we have a testset-for with description which needs interpolation
376
+ else # we have a testset-for with description which needs interpolation, or
377
+ # the iterator must be computed to get an iterator counter
374
378
xs = ()
375
379
loopiters = Expr (:tuple , (arg. args[1 ] for arg in loops). .. )
376
380
@@ -398,17 +402,20 @@ function resolve!(mod::Module, ts::TestsetExpr, pat::Pattern;
398
402
catch
399
403
@assert xs == ()
400
404
ts. descwidth = shown ? descwidth (missing ) : 0
405
+ ts. iter = typemax (Int)
401
406
ts. run = ts. run || decide (missing )
402
407
push! (strings, missing )
403
408
end
404
409
hasmissing = false
405
- for x in xs # empty loop if eval above threw
410
+ for (iter, x) in enumerate (xs) # empty loop if eval above threw
406
411
descx = eval_desc (mod, ts, x)
412
+ ts. iter = iter
407
413
if shown
408
414
ts. descwidth = max (ts. descwidth, descwidth (descx))
409
415
end
410
- if ! strict && ts. run
411
- if ! shown # no need to compute subsequent descx to update ts.descwidth
416
+ if ts. run && (! strict || ts. desc isa String)
417
+ if ts. desc isa String || ! shown # no need to compute subsequent descx to update ts.descwidth
418
+ iter = length (xs)
412
419
break
413
420
else
414
421
continue
@@ -420,6 +427,7 @@ function resolve!(mod::Module, ts::TestsetExpr, pat::Pattern;
420
427
421
428
run = ts. run
422
429
ts. hasbrokenrec = ts. hasbroken
430
+ ts. iter = 1 : ts. iter # for children, when reachable is used, set the possible range
423
431
424
432
for tsc in ts. children
425
433
runc, id = resolve! (mod, tsc, pat, force = ! strict && ts. run,
@@ -465,7 +473,7 @@ function make_ts(ts::TestsetExpr, pat::Pattern, stats, chan)
465
473
body = make_ts (ts. body, pat, stats, chan)
466
474
end
467
475
468
- if ts . loops === nothing
476
+ if ! isfor (ts)
469
477
quote
470
478
@testset $ (ts. mod) $ (isfinal (ts)) $ pat $ (ts. id) $ (ts. desc) $ (ts. options) #=
471
479
=# $ (ts. marks) $ stats $ chan $ body
@@ -1448,7 +1456,7 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1448
1456
@assert ts. run
1449
1457
desc = ts. desc
1450
1458
1451
- if ts . loops === nothing
1459
+ if ! isfor (ts)
1452
1460
if evaldesc && ! (desc isa String)
1453
1461
try
1454
1462
desc = Core. eval (mod, desc)
@@ -1532,8 +1540,8 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1532
1540
end
1533
1541
false , false , false
1534
1542
end
1535
- else
1536
- function dryrun_beginend (descx, repeated= nothing )
1543
+ else # isfor(ts)
1544
+ function dryrun_beginend (descx; iter , repeated= nothing )
1537
1545
# avoid repeating ourselves, transform this iteration into a "begin/end" testset
1538
1546
if descx isa Expr
1539
1547
@assert descx. head == :string
@@ -1553,6 +1561,8 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1553
1561
ts. parent, ts. children)
1554
1562
beginend. run = true
1555
1563
beginend. id = ts. id
1564
+ beginend. iter = iter
1565
+ ts. iter = iter # necessary when reachable is used
1556
1566
beginend. marks = ts. marks
1557
1567
dryrun (mod, beginend, pat, align, parentsubj; evaldesc= false ,
1558
1568
repeated= repeated, maxidw= maxidw, marks= marks, clear= clear, show= show)
@@ -1564,7 +1574,11 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1564
1574
# identitical lines (caveat: if subjects of children would change randomly)
1565
1575
# but still try simply to evaluate the length of the iterator
1566
1576
repeated = - 1
1567
- if ts. desc isa String
1577
+ if ts. desc isa String && ! has (pat, Iter)
1578
+ # when has(pat, Iter), we probably weren't able to eval the forloop-iterator
1579
+ # in resolve!, so no need to re-try here; plus, we wouldn't be able in this
1580
+ # branch to tell how many iterations are matching, without going thru the
1581
+ # dryrun_beginend function in an enumerate'd loop
1568
1582
local iterlen
1569
1583
try
1570
1584
iterlen = 1
@@ -1575,7 +1589,9 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1575
1589
catch
1576
1590
end
1577
1591
end
1578
- dryrun_beginend (ts. desc, repeated)
1592
+ # if iterlen was computed, then !has(pat, Iter) so the value of the iter
1593
+ # keyword below doesn't matter
1594
+ dryrun_beginend (ts. desc, repeated= repeated, iter= 1 : typemax (Int))
1579
1595
else
1580
1596
passes, fails, unrun = false , false , false
1581
1597
for (i, x) in enumerate (loopvalues)
@@ -1587,9 +1603,10 @@ function dryrun(mod::Module, ts::TestsetExpr, pat::Pattern, align::Int=0, parent
1587
1603
# so we add the "repeated" annotation
1588
1604
# (it's certainly not worth it to bother being more precise about
1589
1605
# exactly which iterations are uninterpolated)
1590
- lp, lf, lu = dryrun_beginend (ts. desc, length (loopvalues)- i+ 1 )
1606
+ lp, lf, lu = dryrun_beginend (ts. desc, repeated= length (loopvalues)- i+ 1 ,
1607
+ iter= i: length (loopvalues))
1591
1608
else
1592
- lp, lf, lu = dryrun_beginend (descx)
1609
+ lp, lf, lu = dryrun_beginend (descx, iter = i )
1593
1610
end
1594
1611
passes |= lp
1595
1612
fails |= lf
0 commit comments