From 2738c48aa06493bb3b1101f89b91364d9c092684 Mon Sep 17 00:00:00 2001 From: ChrisRackauckas-Claude Date: Sun, 14 Jun 2026 05:27:20 -0400 Subject: [PATCH] Canonicalize tests to @safetestset for per-unit module isolation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Convert each independent top-level test unit in the Static.jl suite from a plain `@testset` to a `@safetestset` so it runs in its own fresh module, matching the canonical OrdinaryDiffEq structure (test isolation + world-age safety). Each converted unit carries its own `using` lines so its body is self-contained. - test/core_tests.jl: the 11 top-level `@testset` units (StaticSymbol, StaticInt, StaticBool, operators, static interface, promote_shape, tuple utilities, invperm, NDIndex, StaticFloat64, string/print/show) plus the `include("ranges.jl")` and Allocation Tests units are now `@safetestset`. Nested grouping `@testset`s inside a unit (reduce_tup, constructors, trig) stay plain `@testset` since the unit-level `@safetestset` already isolates. - The `maybe_static_length` block stays in a top-level `module` (its `@inferred` helpers must be defined at module scope, not inside a testset function, or inference degrades to `Any`). - test/ranges.jl now carries its own `using Static, Test`. - test/qa/qa.jl: Aqua and ExplicitImports are now separate `@safetestset`s. - Add SafeTestsets to root Project.toml ([extras]/[targets].test/[compat]) and test/qa/Project.toml ([deps]/[compat]). Behavior-preserving: same tests run under the same GROUP dispatch, same assertions. Verified locally with `GROUP=Core` and `GROUP=QA` Pkg.test on julia 1.11 — both pass. Co-Authored-By: Chris Rackauckas Co-Authored-By: Claude Opus 4.8 (1M context) --- Project.toml | 4 ++- test/core_tests.jl | 73 +++++++++++++++++++++++++++++++------------- test/qa/Project.toml | 2 ++ test/qa/qa.jl | 11 ++++--- test/ranges.jl | 3 ++ 5 files changed, 67 insertions(+), 26 deletions(-) diff --git a/Project.toml b/Project.toml index 904a3b7..f105c15 100644 --- a/Project.toml +++ b/Project.toml @@ -17,6 +17,7 @@ ExplicitImports = "1.9" IfElse = "0.1" Pkg = "1" PrecompileTools = "1.2.0" +SafeTestsets = "0.1, 1" SciMLPublic = "1.0.0" Test = "1" julia = "1.10" @@ -26,7 +27,8 @@ AllocCheck = "9b6a8646-10ed-4001-bbdc-1d2f46dfbb1a" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" Pkg = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" [targets] -test = ["AllocCheck", "Aqua", "ExplicitImports", "Pkg", "Test"] +test = ["AllocCheck", "Aqua", "ExplicitImports", "Pkg", "SafeTestsets", "Test"] diff --git a/test/core_tests.jl b/test/core_tests.jl index 7e49c81..41fb151 100644 --- a/test/core_tests.jl +++ b/test/core_tests.jl @@ -1,8 +1,8 @@ -using Static -using Static: Zero -using Test +using SafeTestsets -@testset "StaticSymbol" begin +@safetestset "StaticSymbol" begin + using Static + using Test x = StaticSymbol(:x) y = StaticSymbol("y") z = StaticSymbol(1) @@ -19,7 +19,10 @@ using Test @test_throws ErrorException static([]) end -@testset "StaticInt" begin +@safetestset "StaticInt" begin + using Static + using Static: Zero + using Test @test static(UInt(8)) === StaticInt(UInt(8)) === StaticInt{8}() @test iszero(StaticInt(0)) @test !iszero(StaticInt(1)) @@ -114,7 +117,9 @@ end @test_throws ArgumentError convert(StaticInt{8}, StaticInt{0}()) end -@testset "StaticBool" begin +@safetestset "StaticBool" begin + using Static + using Test t = static(static(true)) f = StaticBool(static(false)) @@ -233,7 +238,9 @@ end @test_throws ArgumentError convert(False, True()) end -@testset "operators" begin +@safetestset "operators" begin + using Static + using Test f = static(false) t = static(true) x = StaticInt(1) @@ -286,7 +293,9 @@ end @test (dm ∘ sm1) === dm end -@testset "static interface" begin +@safetestset "static interface" begin + using Static + using Test v = Val((:a, 1, true)) @test static(1) === StaticInt(1) @@ -320,7 +329,9 @@ end @test @inferred(Static.dynamic((static(:a), static(1), true))) === (:a, 1, true) end -@testset "promote_shape" begin +@safetestset "promote_shape" begin + using Static + using Test x = (static(1), 1) y = (1, static(1), 1) @test @inferred(Base.promote_shape(x, x)) === (static(1), 1) @@ -332,7 +343,9 @@ end @test_throws ErrorException Base.promote_shape((static(1),), (static(2),)) end -@testset "tuple utilities" begin +@safetestset "tuple utilities" begin + using Static + using Test x = (static(1), static(2), static(3)) y = (static(3), static(2), static(1)) z = (static(1), static(2), static(3), static(4)) @@ -373,13 +386,17 @@ end end end -@testset "invperm" begin +@safetestset "invperm" begin + using Static + using Test perm = static((10, 3, 4, 5, 6, 2, 9, 7, 8, 1)) invp = static((10, 6, 2, 3, 4, 5, 8, 9, 7, 1)) @test @inferred(invperm(perm)) === invp end -@testset "NDIndex" begin +@safetestset "NDIndex" begin + using Static + using Test x = NDIndex((1, 2, 3)) y = NDIndex((1, static(2), 3)) z = NDIndex(static(3), static(3), static(3)) @@ -427,17 +444,27 @@ end @test deleteat!(Union{}[], Union{}[]) == Union{}[] end -# for some reason this can't be inferred when in the "Static.jl" test set +module MaybeStaticLengthTests +using Static +using Test +# These helpers must be defined at module top level (not inside a `@testset`) +# so that `@inferred` sees a concretely-typed method; defining them inside a +# testset's function scope degrades the inferred return type to `Any`. known_length(x) = known_length(typeof(x)) known_length(::Type{T}) where {N, T <: Tuple{Vararg{Any, N}}} = N known_length(::Type{T}) where {T} = nothing maybe_static_length(x) = Static.maybe_static(known_length, length, x) -x = ntuple(+, 10) -y = 1:10 -@test @inferred(maybe_static_length(x)) === StaticInt(10) -@test @inferred(maybe_static_length(y)) === 10 +@testset "maybe_static_length" begin + x = ntuple(+, 10) + y = 1:10 + @test @inferred(maybe_static_length(x)) === StaticInt(10) + @test @inferred(maybe_static_length(y)) === 10 +end +end -@testset "StaticFloat64" begin +@safetestset "StaticFloat64" begin + using Static + using Test f = static(1.0) @test @inferred(dynamic(f)) === @inferred(known(f)) === 1.0 for i in -10:10 @@ -553,7 +580,9 @@ y = 1:10 @test @inferred(!isinteger(static(1.5))) end -@testset "string/print/show" begin +@safetestset "string/print/show" begin + using Static + using Test f = static(float(2)) repr(f) @test repr(static(float(1))) == "static($(float(1)))" @@ -566,8 +595,10 @@ end @test repr(static(1):static(2):static(9)) == "static(1):static(2):static(9)" end -include("ranges.jl") +@safetestset "ranges" begin + include("ranges.jl") +end -@testset "Allocation Tests" begin +@safetestset "Allocation Tests" begin include("alloc_tests.jl") end diff --git a/test/qa/Project.toml b/test/qa/Project.toml index 4fff0ee..ff46447 100644 --- a/test/qa/Project.toml +++ b/test/qa/Project.toml @@ -1,6 +1,7 @@ [deps] Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" ExplicitImports = "7d51a73a-1435-4ff3-83d9-f097790105c7" +SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" Static = "aedffcd0-7271-4cad-89d0-dc628f76c6d3" Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" @@ -10,5 +11,6 @@ Static = { path = "../.." } [compat] Aqua = "0.8.4" ExplicitImports = "1.9" +SafeTestsets = "0.1, 1" Test = "1" julia = "1.10" diff --git a/test/qa/qa.jl b/test/qa/qa.jl index 23c5c8d..66d05f3 100644 --- a/test/qa/qa.jl +++ b/test/qa/qa.jl @@ -1,7 +1,8 @@ -using Static, Aqua, ExplicitImports -using Test +using SafeTestsets -@testset "Aqua" begin +@safetestset "Aqua" begin + using Static, Aqua + using Test Aqua.find_persistent_tasks_deps(Static) Aqua.test_ambiguities(Static, recursive = false) Aqua.test_deps_compat(Static) @@ -12,7 +13,9 @@ using Test Aqua.test_undefined_exports(Static) end -@testset "ExplicitImports" begin +@safetestset "ExplicitImports" begin + using Static, ExplicitImports + using Test @test check_no_implicit_imports(Static) === nothing @test check_no_stale_explicit_imports(Static) === nothing end diff --git a/test/ranges.jl b/test/ranges.jl index dd928ed..1ca8cda 100644 --- a/test/ranges.jl +++ b/test/ranges.jl @@ -1,3 +1,6 @@ +using Static +using Test + @testset "Range Constructors" begin @test @inferred(static(1):static(10)) == 1:10 @test @inferred(Static.SUnitRange{1, 10}()) == 1:10