From 07b67d6bb4a3d0b5a57af45d29f182c551ada617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20F=C3=A9votte?= Date: Tue, 18 Apr 2023 15:17:37 +0200 Subject: [PATCH] Organize testitems in a tree according to file structure --- src/TestItemRunner.jl | 80 ++++++++++++++++++++++++++++++++++--------- test/runtests.jl | 8 ++++- test/testitemtree.jl | 29 ++++++++++++++++ 3 files changed, 99 insertions(+), 18 deletions(-) create mode 100644 test/testitemtree.jl diff --git a/src/TestItemRunner.jl b/src/TestItemRunner.jl index 9274c36..0cfc3aa 100644 --- a/src/TestItemRunner.jl +++ b/src/TestItemRunner.jl @@ -103,6 +103,40 @@ function run_testitem(filepath, use_default_usings, setups, package_name, origin end end +mutable struct TestItemTree + name :: String + path :: String + nodes :: Dict{String, TestItemTree} +end + +TestItemTree(name, path) = TestItemTree(name, normpath(path), Dict()) + +function insert_node!(tree::TestItemTree, path::Vector{String}) + isempty(path) && return + name = popfirst!(path) + subtree = get!(()->TestItemTree(name, joinpath(tree.path, name)), tree.nodes, name) + insert_node!(subtree, path) +end + +insert_node!(tree::TestItemTree, path::String) = insert_node!(tree, splitpath(relpath(path, tree.path))) + +function Base.show(io::IO, mime::MIME"text/plain", tree::TestItemTree; indent="") + println(io, "$indent- $(tree.name) ($(tree.path))") + foreach(values(tree.nodes)) do subtree + show(io, mime, subtree; indent=indent*" ") + end +end + +function simplify!(tree::TestItemTree) + foreach(simplify!, values(tree.nodes)) + if length(tree.nodes) == 1 + node = first(values(tree.nodes)) + tree.name = tree.name == "" ? node.name : "$(tree.name)/$(node.name)" + tree.path = node.path + tree.nodes = node.nodes + end +end + function run_tests(path; filter=nothing, verbose=false) # Find package name package_name = "" @@ -163,32 +197,44 @@ function run_tests(path; filter=nothing, verbose=false) end end + # Populate the TestItemTree + tree = TestItemTree(!isempty(package_name) ? package_name : path, path) + for path in keys(testitems) + insert_node!(tree, path) + end + simplify!(tree) + # Run testitems test_setup_module = Core.eval(Main, :(module $(gensym()) end)) test_setup_module_set = TestSetupModuleSet(test_setup_module, Set{Symbol}()) - Test.push_testset(testset("Package"; verbose=verbose)) - for (file, testitems) in pairs(testitems) - Test.push_testset(testset(relpath(file, path); verbose=verbose)) - for testitem in testitems - if !isempty(testitem.option_setup) - for setup in testitem.option_setup - key = String(setup) - if haskey(testsetups, key) - testsetup = testsetups[key] - ensure_evaled(test_setup_module_set, testsetup.filename, testsetup.code, testsetup.name, testsetup.line, testsetup.column) - else - error("Test setup $(setup) is not defined.") + + function run_tree(tree) + Test.push_testset(testset(tree.name; verbose=verbose)) + if isempty(tree.nodes) + for testitem in testitems[tree.path] + if !isempty(testitem.option_setup) + for setup in testitem.option_setup + key = String(setup) + if haskey(testsetups, key) + testsetup = testsetups[key] + ensure_evaled(test_setup_module_set, testsetup.filename, testsetup.code, testsetup.name, testsetup.line, testsetup.column) + else + error("Test setup $(setup) is not defined.") + end end end + Test.push_testset(testset(testitem.name; verbose=verbose)) + run_testitem(testitem.filename, testitem.option_default_imports, testitem.option_setup, package_name, testitem.code, testitem.line, testitem.column, test_setup_module_set) + Test.finish(Test.pop_testset()) + end + else + foreach(sort!(collect(keys(tree.nodes)))) do key + run_tree(tree.nodes[key]) end - Test.push_testset(testset(testitem.name; verbose=verbose)) - run_testitem(testitem.filename, testitem.option_default_imports, testitem.option_setup, package_name, testitem.code, testitem.line, testitem.column, test_setup_module_set) - Test.finish(Test.pop_testset()) end Test.finish(Test.pop_testset()) end - ts = Test.pop_testset() - Test.finish(ts) + run_tree(tree) end macro run_package_tests(ex...) diff --git a/test/runtests.jl b/test/runtests.jl index cc03caa..7e67ad1 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -15,4 +15,10 @@ end @test TestSetup.getfloat() isa Float64 end -@run_package_tests filter=i->endswith(i.filename, "TestItemRunner.jl") || endswith(i.filename, "runtests.jl") verbose=true \ No newline at end of file +function myfilter(i) + for fname in ("TestItemRunner.jl", "runtests.jl", "testitemtree.jl") + endswith(i.filename, fname) && return true + end + return false +end +@run_package_tests filter=myfilter verbose=true diff --git a/test/testitemtree.jl b/test/testitemtree.jl new file mode 100644 index 0000000..2d17366 --- /dev/null +++ b/test/testitemtree.jl @@ -0,0 +1,29 @@ + +@testitem "insert_node!" begin + using TestItemRunner: TestItemTree, insert_node! + tree = TestItemTree("ROOT", pwd()) + + # Relative path + insert_node!(tree, joinpath("a", "b", "file1.jl")) + @test tree.nodes["a"].nodes["b"].nodes["file1.jl"].path == joinpath(pwd(), "a", "b", "file1.jl") + + # Absolute path + insert_node!(tree, joinpath(pwd(), "a", "b", "file2.jl")) + @test tree.nodes["a"].nodes["b"].nodes["file2.jl"].path == joinpath(pwd(), "a", "b", "file2.jl") +end + +@testitem "simplify!" begin + using TestItemRunner: TestItemTree, insert_node!, simplify! + + tree = TestItemTree("ROOT", pwd()) + insert_node!(tree, joinpath("a", "file1.jl")) + insert_node!(tree, joinpath("a", "file2.jl")) + insert_node!(tree, joinpath("b", "file.jl")) + + @test tree.nodes["a"].nodes["file1.jl"].path == joinpath(pwd(), "a", "file1.jl") + @test tree.nodes["b"].nodes["file.jl"].path == joinpath(pwd(), "b", "file.jl") + + simplify!(tree) + @test tree.nodes["b"].path == joinpath(pwd(), "b", "file.jl") + @test tree.nodes["b"].name == "b/file.jl" +end