Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
8 changed files
with
211 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
""" | ||
Aqua.test_stale_deps(package; [ignore]) | ||
Test that `package` loads all dependencies listed in `Project.toml`. | ||
!!! note "Known bug" | ||
Currently, `Aqua.test_stale_deps` does not detect stale | ||
dependencies when they are stdlib. This is considered a bug and | ||
may be fixed in the future. Such a release is considered | ||
non-breaking. | ||
# Arguments | ||
- `packages`: a top-level `Module`, a `Base.PkgId`, or a collection of | ||
them. | ||
# Keyword Arguments | ||
- `ignore::Vector{Symbol}`: names of dependent packages to be ignored. | ||
""" | ||
test_stale_deps | ||
function test_stale_deps(packages; kwargs...) | ||
@testset "$(result.label)" for result in analyze_stale_deps(packages, kwargs) | ||
@debug result.label result | ||
@test result ⊜ true | ||
end | ||
end | ||
|
||
analyze_stale_deps(packages; kwargs...) = analyze_stale_deps(packages, kwargs) | ||
analyze_stale_deps(packages, kwargs) = | ||
[_analyze_stale_deps_1(pkg; kwargs...) for pkg in aspkgids(packages)] | ||
|
||
function _analyze_stale_deps_1(pkg::PkgId; ignore::AbstractArray{Symbol} = Symbol[]) | ||
label = "$pkg" | ||
|
||
result = root_project_or_failed_lazytest(pkg) | ||
result isa LazyTestResult && return result | ||
root_project_path = result | ||
|
||
@debug "Parsing `$root_project_path`" | ||
deps = [PkgId(UUID(v), k) for (k, v) in TOML.parsefile(root_project_path)["deps"]] | ||
|
||
code = """ | ||
$(Base.load_path_setup_code()) | ||
Base.require($(reprpkgid(pkg))) | ||
for pkg in keys(Base.loaded_modules) | ||
pkg.uuid === nothing || println(pkg.uuid) | ||
end | ||
""" | ||
cmd = Base.julia_cmd() | ||
output = read(`$cmd --startup-file=no --color=no -e $code`, String) | ||
@debug("Checked modules loaded in a separate process.", cmd, Text(code), Text(output)) | ||
loaded_uuids = map(UUID, eachline(IOBuffer(output))) | ||
|
||
return _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = deps, | ||
loaded_uuids = loaded_uuids, | ||
ignore = ignore, | ||
) | ||
end | ||
|
||
# Side-effect -free part of stale dependency analysis. | ||
function _analyze_stale_deps_2(; | ||
pkg::PkgId, | ||
deps::AbstractArray{PkgId}, | ||
loaded_uuids::AbstractArray{UUID}, | ||
ignore::AbstractArray{Symbol}, | ||
) | ||
label = "$pkg" | ||
deps_uuids = [p.uuid for p in deps] | ||
pkgid_from_uuid = Dict(p.uuid => p for p in deps) | ||
|
||
stale_uuids = setdiff(deps_uuids, loaded_uuids) | ||
stale_pkgs = [pkgid_from_uuid[uuid] for uuid in stale_uuids] | ||
stale_pkgs = [p for p in stale_pkgs if !(Symbol(p.name) in ignore)] | ||
|
||
if isempty(stale_pkgs) | ||
return LazyTestResult( | ||
label, | ||
""" | ||
All packages in `deps` are loaded via `using $(pkg.name)`. | ||
""", | ||
true, | ||
) | ||
end | ||
|
||
stale_msg = join(("* $p" for p in stale_pkgs), "\n") | ||
msglines = [ | ||
"Some package(s) in `deps` of $pkg are not loaded during via" * | ||
" `using $(pkg.name)`.", | ||
stale_msg, | ||
"", | ||
"To ignore from stale dependency detection, pass the package name to" * | ||
" `ignore` keyword argument of `Aqua.test_stale_deps`", | ||
] | ||
return LazyTestResult(label, join(msglines, "\n"), false) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
module TestStaleDeps | ||
|
||
include("preamble.jl") | ||
using Aqua: PkgId, UUID, _analyze_stale_deps_2, ispass, ⊜ | ||
|
||
@testset "_analyze_stale_deps_2" begin | ||
pkg = PkgId(UUID(42), "TargetPkg") | ||
|
||
dep1 = PkgId(UUID(1), "Dep1") | ||
dep2 = PkgId(UUID(2), "Dep2") | ||
dep3 = PkgId(UUID(3), "Dep3") | ||
|
||
@testset "pass" begin | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[], | ||
loaded_uuids = UUID[], | ||
ignore = Symbol[], | ||
) ⊜ true | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[dep1], | ||
loaded_uuids = UUID[dep1.uuid, dep2.uuid, dep3.uuid], | ||
ignore = Symbol[], | ||
) ⊜ true | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[dep1], | ||
loaded_uuids = UUID[dep2.uuid, dep3.uuid], | ||
ignore = Symbol[:Dep1], | ||
) ⊜ true | ||
end | ||
@testset "failure" begin | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[dep1], | ||
loaded_uuids = UUID[], | ||
ignore = Symbol[], | ||
) ⊜ false | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[dep1], | ||
loaded_uuids = UUID[dep2.uuid, dep3.uuid], | ||
ignore = Symbol[], | ||
) ⊜ false | ||
@test _analyze_stale_deps_2(; | ||
pkg = pkg, | ||
deps = PkgId[dep1, dep2], | ||
loaded_uuids = UUID[dep3.uuid], | ||
ignore = Symbol[:Dep1], | ||
) ⊜ false | ||
end | ||
end | ||
|
||
with_sample_pkgs() do | ||
@testset "PkgWithoutProject" begin | ||
pkg = AquaTesting.SAMPLE_PKG_BY_NAME["PkgWithoutProject"] | ||
results = Aqua.analyze_stale_deps(pkg) | ||
@test length(results) == 1 | ||
r, = results | ||
@test !ispass(r) | ||
@test r ⊜ false | ||
msg = sprint(show, "text/plain", r) | ||
@test occursin("Project.toml file at project directory does not exist", msg) | ||
end | ||
end | ||
|
||
end # module |