Skip to content

Commit 693c02a

Browse files
authored
Merge pull request #63 from JuliaTesting/compat
Fix support for 1.13
2 parents f1c9b48 + dfa64a0 commit 693c02a

16 files changed

Lines changed: 368 additions & 395 deletions

File tree

.github/workflows/CI.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ jobs:
1919
fail-fast: false
2020
matrix:
2121
include:
22-
- { os: ubuntu-latest, version: '1.10', arch: x64}
2322
- { os: ubuntu-latest, version: 'nightly', arch: x64}
24-
- { os: ubuntu-latest, version: '1', arch: x86 }
25-
- { os: windows-latest, version: '1', arch: x64}
26-
- { os: macOS-latest, version: '1', arch: aarch64}
23+
- { os: ubuntu-latest, version: '1.13.0-rc1', arch: x64 }
24+
- { os: ubuntu-latest, version: '1.13.0-rc1', arch: x86 }
25+
- { os: windows-latest, version: '1.13.0-rc1', arch: x64}
26+
- { os: macOS-latest, version: '1.13.0-rc1', arch: aarch64}
2727

2828
steps:
2929
- uses: actions/checkout@v4

.github/workflows/Documentation.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@v4
1515
- uses: julia-actions/setup-julia@latest
16+
with:
17+
version: '1.13.0-rc1'
1618
- uses: julia-actions/cache@v2
1719
- name: Install dependencies
1820
run: |

InlineTest/src/InlineTest.jl

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,11 @@ const INLINE_TEST = Symbol("##InlineTest-01b48f5c342f65df7fcd07f28f0d2cacbb09f0a
3232
const TESTED_MODULES = Union{Module,Nothing}[]
3333
const TESTSET_MACROS = Symbol[]
3434

35-
get_tests(m::Module) = getfield(m, INLINE_TEST).tests
35+
function get_tests(m::Module)
36+
invokelatest() do
37+
getfield(m, INLINE_TEST).tests
38+
end
39+
end
3640

3741
function register(m::Module, macros::Vector{Symbol})
3842
push!(TESTED_MODULES, m)
@@ -111,7 +115,9 @@ function get_inline_mod!(mod)::Module
111115
@eval mod module $INLINE_TEST
112116
const tests = (tests=[], news=[], map=Dict{Union{String,Expr},Int}())
113117
const TESTSET_MACROS = Symbol[]
114-
__init__() = $register($mod, TESTSET_MACROS)
118+
# use invokelatest so TESTSET_MACROS (defined in the same world)
119+
# is visible to __init__ under Julia 1.13+ binding semantics
120+
__init__() = $register($mod, invokelatest(getglobal, @__MODULE__, :TESTSET_MACROS))
115121
end
116122
end
117123
end

Project.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ReTest"
22
uuid = "e0db7c4e-2690-44b9-bad6-7687da720f89"
3+
version = "0.4.0"
34
authors = ["Rafael Fourquet <fourquet.rafael@gmail.com>"]
4-
version = "0.3.4"
55

66
[deps]
77
Distributed = "8ba89e20-285c-5b6f-9357-94700520ee1b"
@@ -12,11 +12,14 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
1212
Sockets = "6462fe0b-24de-5631-8697-dd941f90decc"
1313
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1414

15+
[sources]
16+
InlineTest = {path = "InlineTest"}
17+
1518
[compat]
1619
InlineTest = "=0.2.0"
17-
Revise = "3.1"
1820
PrecompileTools = "1.2.1"
19-
julia = "1.10"
21+
Revise = "3.1"
22+
julia = "1.13"
2023

2124
[extras]
2225
Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@
44
[![](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaTesting.github.io/ReTest.jl/stable)
55
[![](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaTesting.github.io/ReTest.jl/dev)
66

7+
> [!NOTE]
8+
> For compatibility reasons, ReTest v0.4 requires at least Julia 1.13.
9+
710
`ReTest` is a testing framework for Julia allowing:
811

912
1. Defining tests in source files, whose execution is deferred and triggered

src/ReTest.jl

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ export Test,
1616
detect_ambiguities, detect_unbound_args,
1717
GenericString, GenericSet, GenericDict, GenericArray, GenericOrder
1818

19+
using Base.ScopedValues: @with
20+
1921
using Test: Test,
2022
@test, @test_throws, @test_broken, @test_skip,
2123
@test_warn, @test_nowarn,
@@ -179,11 +181,17 @@ function replace_ts(source, mod, x::Expr, parent; static_include::Bool,
179181
x, false
180182
end
181183
else @label default
182-
body_br = map(z -> replace_ts(source, mod, z, parent; static_include=static_include,
183-
include_functions=include_functions),
184-
x.args)
185-
filter!(x -> first(x) !== invalid, body_br)
186-
Expr(x.head, first.(body_br)...), any(last.(body_br))
184+
new_args = Any[]
185+
hasbroken = false
186+
for z in x.args
187+
nz, br = replace_ts(source, mod, z, parent;
188+
static_include=static_include,
189+
include_functions=include_functions)
190+
nz === invalid && continue
191+
push!(new_args, nz)
192+
hasbroken |= br
193+
end
194+
Expr(x.head, new_args...), hasbroken
187195
end
188196
end
189197

@@ -776,8 +784,9 @@ function retest(@nospecialize(args::ArgType...);
776784
root = Testset.ReTestSet(Main, "Overall", overall=true)
777785

778786
maxidw = Ref{Int}(0) # visual width for showing IDs (Ref for mutability in hack below)
779-
tests_descs_hasbrokens = fetchtests.(modules, verbose, module_header, Ref(maxidw);
787+
tests_descs_hasbrokens = [fetchtests(m, verbose, module_header, maxidw;
780788
strict=strict, dup=dup, static=static)
789+
for m in modules]
781790
isempty(tests_descs_hasbrokens) &&
782791
throw(ArgumentError("no modules using ReTest could be found"))
783792

@@ -888,19 +897,14 @@ function retest(@nospecialize(args::ArgType...);
888897

889898
printlock = ReentrantLock()
890899
previewchan =
891-
if spin && stdout isa Base.TTY && (nthreads() > 1 && VERSION >= v"1.3" ||
892-
nprocs() > 1)
900+
if spin && stdout isa Base.TTY && (nthreads() > 1 || nprocs() > 1)
893901
RemoteChannel(() -> Channel{Maybe{Tuple{Int64,String}}}(Inf))
894902
# needs to be "remote" in the case nprocs() == 2, as then nworkers() == 1,
895903
# which means the one remote worker will put descriptions on previewchan
896904
# (if nworkers() > 1, descriptions are not put because we can't predict
897905
# the order in which they complete, and then the previewer will
898906
# not show the descriptions, just the spinning wheel)
899907

900-
# on VERSION < v"1.3" : we can't call `thread_pin` (see below), and in this
901-
# case previewing doesn't work well, as the worker and previewer tasks
902-
# can end up in the same thread, and the previewer is not responsive
903-
904908
# channel size: if nworkers() == 1, then 2 would suffice (one for
905909
# the "compilation step", one for @testset execution step, and then
906910
# the printer would empty the channel; but for two workers and more,
@@ -1151,7 +1155,13 @@ function retest(@nospecialize(args::ArgType...);
11511155
resp = remotecall_fetch(wrkr, mod, ts, pat, chan
11521156
) do mod, ts, pat, chan
11531157
mts = make_ts(ts, pat, format.stats, chan)
1154-
Core.eval(mod, mts)
1158+
# Run in a fresh dynamic scope so a surrounding
1159+
# Test.@testset (whose CURRENT_TESTSET is now a
1160+
# ScopedValue on Julia 1.13+) doesn't make our
1161+
# top-level testset look nested.
1162+
@with(Test.CURRENT_TESTSET => Test.FallbackTestSet(),
1163+
Test.TESTSET_DEPTH => 0,
1164+
Core.eval(mod, mts))
11551165
end
11561166
if resp isa Vector
11571167
ntests += length(resp)
@@ -1174,7 +1184,7 @@ function retest(@nospecialize(args::ArgType...);
11741184
end # worker = @task begin ...
11751185

11761186
try
1177-
if previewchan !== nothing && nthreads() > 1 && VERSION >= v"1.3"
1187+
if previewchan !== nothing && nthreads() > 1
11781188
# we try to keep thread #1 free of heavy work, so that the previewer stays
11791189
# responsive
11801190
tid = rand(2:nthreads())
@@ -1276,8 +1286,8 @@ function process_args(@nospecialize(args);
12761286
stestmod = Symbol(mod, :Tests)
12771287

12781288
testmods = get(loaded_testmodules, mod, nothing)
1279-
if testmods === nothing && isdefined(Main, stestmod)
1280-
testmod = getfield(Main, stestmod)
1289+
if testmods === nothing && invokelatest(isdefined, Main, stestmod)
1290+
testmod = invokelatest(getglobal, Main, stestmod)
12811291
# TODO: test this branch
12821292
if testmod isa Module
12831293
testmods = [testmod]
@@ -1405,7 +1415,7 @@ function process_args(@nospecialize(args);
14051415

14061416
# remove modules which don't have tests, which can happen when a parent module without
14071417
# tests is passed to retest in order to run tests in its submodules
1408-
filter!(m -> isdefined(m, INLINE_TEST), modules)
1418+
filter!(m -> invokelatest(isdefined, m, INLINE_TEST), modules)
14091419

14101420
# Remove the precompilation module if we're not precompiling
14111421
if ccall(:jl_generating_output, Cint, ()) == 0
@@ -1460,7 +1470,7 @@ function update_TESTED_MODULES!(double_check::Bool=false)
14601470
for sub in recsubmodules(mod)
14611471
# new version: just check the assumption
14621472
nameof(sub) == INLINE_TEST && continue
1463-
if isdefined(sub, INLINE_TEST)
1473+
if invokelatest(isdefined, sub, INLINE_TEST)
14641474
@assert sub in TESTED_MODULES
14651475
end
14661476
# old effective version:

src/hijack.jl

Lines changed: 10 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
Include file `testpath` into `parentmodule`. If `revise` is `true`, `Revise`,
66
which must be loaded beforehand in your Julia session, is used to track all
77
recursively included files (in particular testsets). The `revise` keyword
8-
defaults to `true` when `Revise` is loaded and `VERSION >= v"1.5"`, and to
9-
`false` otherwise.
8+
defaults to `true` when `Revise` is loaded, and to `false` otherwise.
109
1110
The point of using this function is when `revise` is `true` and in particular
1211
when files are included recursively.
@@ -15,16 +14,12 @@ and if there are no recursively included files, this should be equivalent
1514
to `Revise.includet(testpath)`, provided `parentmodule == Main` and
1615
all `@testset`s defined in `testpath` are in a module defining
1716
`__revise_mode__ = :eval`.
18-
19-
!!! compat "Julia 1.5"
20-
This function requires at least Julia 1.5 when `revise` is `true`.
2117
"""
2218
function load(testpath::AbstractString;
2319
parentmodule::Module=Main, revise::Maybe{Bool}=nothing)
2420

25-
revise === true && VERSION < v"1.5" &&
26-
error("the `revise` keyword requires at least Julia 1.5")
2721
Revise = get_revise(revise)
22+
testpath = normpath(abspath(testpath))
2823

2924
if Revise === nothing
3025
Base.include(parentmodule, testpath)
@@ -53,10 +48,7 @@ If `revise` is `true`, `Revise`, which must be loaded beforehand in your Julia
5348
session, is used to track the test files (in particular testsets). Note that
5449
this might be brittle, and it's recommended instead to load your test module
5550
via `using ModTests`. The `revise` keyword defaults to `true` when `Revise` is
56-
loaded and `VERSION >= v"1.5"`, and to `false` otherwise.
57-
58-
!!! compat "Julia 1.5"
59-
This function requires at least Julia 1.5 when `revise` is `true`.
51+
loaded, and to `false` otherwise.
6052
"""
6153
function load(packagemod::Module, testfile::Maybe{AbstractString}=nothing;
6254
parentmodule::Module=Main, revise::Maybe{Bool}=nothing,
@@ -200,8 +192,6 @@ be loaded beforehand in your Julia session. Note that this might be brittle
200192
and not work in all cases. `revise` defaults to `true` when `Revise` is loaded,
201193
and to `false` otherwise.
202194
203-
!!! compat "Julia 1.5"
204-
This function requires at least Julia 1.5.
205195
"""
206196
function hijack end
207197

@@ -215,14 +205,15 @@ function hijack(path::AbstractString, modname=nothing; parentmodule::Module=Main
215205

216206
# do first, to error early if necessary
217207
Revise = get_revise(revise)
208+
include = setinclude(include, testset)
218209

219210
if modname === nothing
220211
modname = replace(splitext(basename(path))[1], ['-', '.'] => '_')
221212
end
222213
modname = Symbol(modname)
223214

224215
newmod = @eval parentmodule module $modname end
225-
populate_mod!(newmod, path; lazy=lazy, include=setinclude(include, testset),
216+
populate_mod!(newmod, path; lazy=lazy, include=include,
226217
include_functions=include_functions,
227218
Revise=Revise)
228219
newmod
@@ -250,6 +241,7 @@ function populate_mod!(mod::Module, path; lazy, Revise, include::Maybe{Symbol}=n
250241
lazy (true, false, :brutal) ||
251242
throw(ArgumentError("the `lazy` keyword must be `true`, `false` or `:brutal`"))
252243

244+
path = normpath(abspath(path))
253245
files = Revise === nothing ? nothing : Dict(path => mod)
254246
substitute!(x) = substitute_retest!(x, lazy, include, files;
255247
include_functions=include_functions)
@@ -269,8 +261,6 @@ function populate_mod!(mod::Module, path; lazy, Revise, include::Maybe{Symbol}=n
269261
end
270262

271263
function revise_track(Revise, files)
272-
# uniquemod serves in v1.5 to make hijack w/ revise still work in many cases,
273-
# when there aren't nested submodules/includes
274264
for (filepath, mod) in files
275265
if isfile(filepath) # some files might not exist when they are conditionally
276266
# included
@@ -332,11 +322,7 @@ function substitute_retest!(ex, lazy, include_::Maybe{Symbol}, files=nothing;
332322
include($substitute!, $newfile)
333323
$files[newfile] = $(root_module[])
334324
end)
335-
if VERSION >= v"1.6"
336-
# v1.5 doesn't play well with @__MODULE__, the let expression
337-
# simply... vanishes; so we have to use root_module instead
338-
push!(ex2.args[2].args, :(@assert $(root_module[]) == @__MODULE__))
339-
end
325+
push!(ex2.args[2].args, :(@assert $(root_module[]) == @__MODULE__))
340326
# TODO: add `copy!(::Expr, ::Expr)` to Base
341327
ex.head = ex2.head
342328
copy!(ex.args, ex2.args)
@@ -456,9 +442,6 @@ and not enclosed within `BaseTests` or `StdLibTests`.
456442
The `lazy` and `revise` keywords have the same meaning as in [`ReTest.hijack`](@ref).
457443
Depending on the value of `lazy`, some test files are skipped when they
458444
are known to fail.
459-
460-
!!! compat "Julia 1.5"
461-
This function requires at least Julia 1.5.
462445
"""
463446
function hijack_base(tests, modname=nothing; parentmodule::Module=Main, lazy=false,
464447
base=:BaseTests, stdlib=:StdLibTests, revise::Maybe{Bool}=nothing)
@@ -511,9 +494,9 @@ function hijack_base(tests, modname=nothing; parentmodule::Module=Main, lazy=fal
511494
# e.g. `tuple`, collision betwen the tuple function and test/tuple.jl
512495
comp = Symbol(comp, :_)
513496
end
514-
if isdefined(mod, comp) && ith != length(components) ||
497+
if invokelatest(isdefined, mod, comp) && ith != length(components) ||
515498
modname !== nothing && ith == 1 # module already freshly created
516-
mod = getfield(mod, comp)
499+
mod = invokelatest(getglobal, mod, comp)
517500
else
518501
# we always re-eval leaf-modules
519502
mod = @eval mod module $comp end
@@ -528,7 +511,7 @@ function hijack_base(tests, modname=nothing; parentmodule::Module=Main, lazy=fal
528511
end
529512

530513
get_revise(revise) =
531-
if revise === true || revise === nothing && VERSION >= v"1.5"
514+
if revise === true || revise === nothing
532515
Revise = get(Base.loaded_modules, revise_pkgid(), nothing)
533516
Revise === nothing && revise === true &&
534517
error("Revise is not loaded")
@@ -573,34 +556,6 @@ function test_path(test)
573556
end
574557
end
575558

576-
if VERSION < v"1.8.0-DEV.34"
577-
const TESTNAMES = [
578-
"subarray", "core", "compiler", "worlds",
579-
"keywordargs", "numbers", "subtype",
580-
"char", "strings", "triplequote", "unicode", "intrinsics",
581-
"dict", "hashing", "iobuffer", "staged", "offsetarray",
582-
"arrayops", "tuple", "reduce", "reducedim", "abstractarray",
583-
"intfuncs", "simdloop", "vecelement", "rational",
584-
"bitarray", "copy", "math", "fastmath", "functional", "iterators",
585-
"operators", "ordering", "path", "ccall", "parse", "loading", "gmp",
586-
"sorting", "spawn", "backtrace", "exceptions",
587-
"file", "read", "version", "namedtuple",
588-
"mpfr", "broadcast", "complex",
589-
"floatapprox", "stdlib", "reflection", "regex", "float16",
590-
"combinatorics", "sysinfo", "env", "rounding", "ranges", "mod2pi",
591-
"euler", "show", "client",
592-
"errorshow", "sets", "goto", "llvmcall", "llvmcall2", "ryu",
593-
"some", "meta", "stacktraces", "docs",
594-
"misc", "threads", "stress", "binaryplatforms", "atexit",
595-
"enums", "cmdlineargs", "int", "interpreter",
596-
"checked", "bitset", "floatfuncs", "precompile",
597-
"boundscheck", "error", "ambiguous", "cartesian", "osutils",
598-
"channels", "iostream", "secretbuffer", "specificity",
599-
"reinterpretarray", "syntax", "corelogging", "missing", "asyncmap",
600-
"smallarrayshrink", "opaque_closure"
601-
]
602-
end
603-
604559
const BLACKLIST = [
605560
# failing at load time (in hijack_base)
606561
"backtrace", "misc", "threads", "cmdlineargs","boundscheck",

src/patterns.jl

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,8 @@ function make_pattern(str::AbstractString)
182182
rx =
183183
if isempty(str)
184184
r"" # in order to know to match unconditionally
185-
elseif VERSION >= v"1.3"
186-
r""i * str
187185
else
188-
Regex(str, "i")
186+
r""i * str
189187
end
190188
neg ? not(rx) : rx
191189
end
@@ -462,14 +460,8 @@ julia> retest(Fail, reachable("a"), verbose=9, dry=true, static=true)
462460
1| a
463461
```
464462
465-
!!! compat "Julia 1.3"
466-
This function requires at least Julia 1.3.
467463
"""
468-
function reachable end
469-
470-
if VERSION >= v"1.3"
471-
reachable(x) = Reachable(make_pattern(x))
472-
end
464+
reachable(x) = Reachable(make_pattern(x))
473465

474466
"""
475467
depth(d::Integer)

0 commit comments

Comments
 (0)