diff --git a/README.md b/README.md index f6645e064..9b36ea695 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,8 @@ changes in `julia`. ## Supported features +* `@include_files` is a clone of Test.jl's `@include_files` that was added in Julia 1.13. + * `@__FUNCTION__` is a macro that returns the innermost enclosing function ([#58940]) (since Compat 4.18.0). * *Note: the Compat version of this macro does not work in callable structs.* diff --git a/src/Compat.jl b/src/Compat.jl index 7971b13d7..eb5f96a27 100644 --- a/src/Compat.jl +++ b/src/Compat.jl @@ -1160,7 +1160,7 @@ if VERSION < v"1.12.0-DEV.974" # contrib/commit-name.sh 2635dea else using Base: insertdims, _insertdims end - + # https://github.com/JuliaLang/julia/pull/54653: add Fix @static if !isdefined(Base, :Fix) # VERSION < v"1.12.0-DEV.981" @static if !isdefined(Base, :_stable_typeof) @@ -1283,6 +1283,95 @@ end export @__FUNCTION__ end +# https://github.com/JuliaLang/julia/pull/59951 +@static if VERSION < v"1.13.0-0" + function filter_test_files(files::Vector, args::Vector) + # Parse args to extract file filters + filter_args = String[] + use_regex = false + + # Check for --files-regex= argument (takes precedence) + regex_idx = findfirst(arg -> startswith(arg, "--files-regex="), args) + if regex_idx !== nothing + # Extract comma-separated list from --files-regex= + pattern_str = args[regex_idx][15:end] # Skip "--files-regex=" + append!(filter_args, split(pattern_str, ',')) + use_regex = true + else + # Check for --files= argument + files_idx = findfirst(arg -> startswith(arg, "--files="), args) + if files_idx !== nothing + # Extract comma-separated list from --files= + files_str = args[files_idx][9:end] # Skip "--files=" + append!(filter_args, split(files_str, ',')) + end + end + + # Return all files if no filters + isempty(filter_args) && return files + + # Filter files based on basename matching + return filter(files) do file + name = basename(file) + if use_regex + any(arg -> occursin(Regex(arg), name), filter_args) + else + any(arg -> occursin(arg, name), filter_args) + end + end + end + + """ + @include_files(files) + + Include test files from a list, optionally filtered by command-line test arguments. + + When running tests via `Pkg.test()`, files can be filtered by passing `test_args` + with the `--files=` or `--files-regex=` flag. If no test args are provided, all files are included. + + This macro is part of `Test` in Julia 1.13+. In earlier versions, it's provided + by Compat in the `Compat` module (not re-exported into `Test`). + + # Example + ```julia + using Test + using Compat + + # Include common utilities + include("utils.jl") + + @include_files [ + "foo.jl", + "bar.jl", + "baz.jl", + ] + ``` + + ## Usage patterns: + + - `Pkg.test()` → includes all files + - `Pkg.test(test_args=["--files=foo"])` → includes only "foo.jl" + - `Pkg.test(test_args=["--files=foo,bar"])` → includes "foo.jl" and "bar.jl" + - `Pkg.test(test_args=["--files-regex=^test_.*\\.jl\$"])` → uses regex pattern matching + - `Pkg.test(test_args=["--files-regex=foo|bar"])` → includes files matching "foo" or "bar" + """ + macro include_files(files) + quote + let test_files = $(esc(files)) + # Filter files based on ARGS + filtered_files = Compat.filter_test_files(test_files, ARGS) + + # Include filtered files + for file in filtered_files + include(file) + end + end + end + end + + export @include_files +end + include("deprecated.jl") end # module Compat diff --git a/test/include_test/runtests.jl b/test/include_test/runtests.jl new file mode 100644 index 000000000..4ee2777a7 --- /dev/null +++ b/test/include_test/runtests.jl @@ -0,0 +1,3 @@ +using Compat + +@include_files ["test_foo.jl", "test_bar.jl", "test_baz.jl"] diff --git a/test/include_test/test_bar.jl b/test/include_test/test_bar.jl new file mode 100644 index 000000000..82465181a --- /dev/null +++ b/test/include_test/test_bar.jl @@ -0,0 +1 @@ +println("BAR_RAN") diff --git a/test/include_test/test_baz.jl b/test/include_test/test_baz.jl new file mode 100644 index 000000000..14f566430 --- /dev/null +++ b/test/include_test/test_baz.jl @@ -0,0 +1 @@ +println("BAZ_RAN") diff --git a/test/include_test/test_foo.jl b/test/include_test/test_foo.jl new file mode 100644 index 000000000..5275c9fbc --- /dev/null +++ b/test/include_test/test_foo.jl @@ -0,0 +1 @@ +println("FOO_RAN") diff --git a/test/runtests.jl b/test/runtests.jl index 39e24dee5..56c1668f7 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -940,7 +940,7 @@ end @test insertdims(dropdims(b; dims); dims) == b end end - + # https://github.com/JuliaLang/julia/pull/54653: add Fix @testset "Fix" begin function test_fix1(Fix1=Compat.Fix1) @@ -1260,3 +1260,72 @@ end end end end + +if VERSION < v"1.13.0-0" +# https://github.com/JuliaLang/julia/pull/59951 +@testset "@include_files" begin + files = ["test_foo.jl", "test_bar.jl", "test_baz.jl"] + + @test Compat.filter_test_files(files, String[]) == files + @test Compat.filter_test_files(files, ["--files=foo"]) == ["test_foo.jl"] + @test Compat.filter_test_files(files, ["--files=foo,bar"]) == ["test_foo.jl", "test_bar.jl"] + @test Compat.filter_test_files(files, ["--files=ba"]) == ["test_bar.jl", "test_baz.jl"] + @test Compat.filter_test_files(files, ["--files=nomatch"]) == String[] + @test Compat.filter_test_files(files, ["--files=foo", "bar"]) == ["test_foo.jl"] # Other args ignored + @test Compat.filter_test_files(files, ["foo"]) == files # No --files= means no filtering + @test Compat.filter_test_files(files, ["bar", "baz"]) == files # No --files= means no filtering + + # Test regex patterns + @test Compat.filter_test_files(files, ["--files-regex=^test_foo"]) == ["test_foo.jl"] + @test Compat.filter_test_files(files, ["--files-regex=foo|bar"]) == ["test_foo.jl", "test_bar.jl"] + @test Compat.filter_test_files(files, ["--files-regex=ba[rz]"]) == ["test_bar.jl", "test_baz.jl"] + @test Compat.filter_test_files(files, ["--files-regex=^test_.*\\.jl\$"]) == files + @test Compat.filter_test_files(files, ["--files-regex=nomatch"]) == String[] + @test Compat.filter_test_files(files, ["--files-regex=foo", "--files=bar"]) == ["test_foo.jl"] # --files-regex takes precedence + + # Test @include_files macro in subprocess + test_file = joinpath(@__DIR__, "include_test", "runtests.jl") + + # Test 1: No args - all files included + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file`, String) + @test occursin("FOO_RAN", output) + @test occursin("BAR_RAN", output) + @test occursin("BAZ_RAN", output) + + # Test 2: --files= with single filter + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file --files=foo`, String) + @test occursin("FOO_RAN", output) + @test !occursin("BAR_RAN", output) + @test !occursin("BAZ_RAN", output) + + # Test 3: --files= with multiple filters + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file --files=bar,baz`, String) + @test !occursin("FOO_RAN", output) + @test occursin("BAR_RAN", output) + @test occursin("BAZ_RAN", output) + + # Test 4: --files= with comma-separated list + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file --files=foo,bar`, String) + @test occursin("FOO_RAN", output) + @test occursin("BAR_RAN", output) + @test !occursin("BAZ_RAN", output) + + # Test 5: Bare args without --files= should include all files + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file foo bar`, String) + @test occursin("FOO_RAN", output) + @test occursin("BAR_RAN", output) + @test occursin("BAZ_RAN", output) + + # Test 6: --files-regex= with pattern + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file --files-regex=foo\|bar`, String) + @test occursin("FOO_RAN", output) + @test occursin("BAR_RAN", output) + @test !occursin("BAZ_RAN", output) + + # Test 7: --files-regex= with anchored pattern + output = read(`$(Base.julia_cmd()) --startup-file=no $test_file --files-regex=^test_foo`, String) + @test occursin("FOO_RAN", output) + @test !occursin("BAR_RAN", output) + @test !occursin("BAZ_RAN", output) +end +end