The following piece of code:
using Base.Dates
using Base.Test
@testset "blah" begin
a = Date(2013)
@show a, "before"
function testlengths(n)
a = Dates.Date(2000)
for i = 1:n
@test length(range(a,i)) == i
end
return a+Dates.Day(n)
end
testlengths(100000)
@show a, "after"
end
gives the output:
(a,"before") = (2013-01-01,"before")
(a,"after") = (2000-01-01,"after")
Notice that a has changed and shouldn't.
Nice MCVE.
AFAIK, this is the expected behavior in a local scope. So should @testset be changed to not introduce a new scope?
Test sets introduce a new scope by design since, like try/catch they introduce rollback points. In other words, if a test in a test set fails, the tests will continue after the test set. This allows us to get much more complete testing information even when some tests fail – since the tests can continue after a failure.
In another word this is a won't fix or dup of https://github.com/JuliaLang/julia/issues/14948 ?
I'm not sure how this is a dup of #14948 since there are no threads involved, but I do think we need to decide if this is the right behavior for test sets and it does perhaps shed some light on one of the more potentially confusing corners of Julia's scoping rules. @JeffBezanson may be interested.
Chalk up another point for requiring outer (or similar keyword) to assign a variable in an outer scope, I'd have to say.
That seems like it may well make the scoping rules simpler and clearer.
X-refs: #5331, #10559, #14959, #16727, #14959
I also encountered the problem. This case may be much harder to notice:
using Base.Test
@testset begin
@testset "foo" begin
sum = 1
end
@testset "bar" begin
mktemp() do path, io
@test sum([1,2,3]) == 6
end
end
end
Original example now warns and the second one works.
Most helpful comment
Chalk up another point for requiring
outer(or similar keyword) to assign a variable in an outer scope, I'd have to say.