diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d5ed66b..c7a50697 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Version [v0.9.0] - unreleased + +### Changed + +- Add `test_undocumented_names` to verify that all public symbols have docstrings (including the module itself). ([#313]) + ## Version [v0.8.9] - 2024-10-15 diff --git a/Project.toml b/Project.toml index 69e7850a..357bf268 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Aqua" uuid = "4c88cf16-eb10-579e-8560-4a9242c79595" authors = ["Takafumi Arakaki and contributors"] -version = "0.8.9" +version = "0.9.0" [deps] Compat = "34da2185-b29b-5c13-b0c7-acf172513d20" diff --git a/docs/make.jl b/docs/make.jl index 07de9cf2..d681a5d0 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -29,6 +29,7 @@ makedocs(; "deps_compat.md", "piracies.md", "persistent_tasks.md", + "undocumented_names.md", ], "release-notes.md", ], diff --git a/docs/src/undocumented_names.md b/docs/src/undocumented_names.md new file mode 100644 index 00000000..fa6ce36b --- /dev/null +++ b/docs/src/undocumented_names.md @@ -0,0 +1,7 @@ +# Undocumented names + +## [Test function](@id test_undocumented_names) + +```@docs +Aqua.test_undocumented_names +``` diff --git a/src/Aqua.jl b/src/Aqua.jl index bc4f00df..14996685 100644 --- a/src/Aqua.jl +++ b/src/Aqua.jl @@ -1,6 +1,6 @@ module Aqua -using Base: PkgId, UUID +using Base: Docs, PkgId, UUID using Pkg: Pkg, TOML, PackageSpec using Test @@ -23,6 +23,7 @@ include("stale_deps.jl") include("deps_compat.jl") include("piracies.jl") include("persistent_tasks.jl") +include("undocumented_names.jl") """ test_all(testtarget::Module) @@ -37,6 +38,7 @@ Run the following tests: * [`test_deps_compat(testtarget)`](@ref test_deps_compat) * [`test_piracies(testtarget)`](@ref test_piracies) * [`test_persistent_tasks(testtarget)`](@ref test_persistent_tasks) +* [`test_undocumented_names(testtarget)`](@ref test_undocumented_names) The keyword argument `\$x` (e.g., `ambiguities`) can be used to control whether or not to run `test_\$x` (e.g., `test_ambiguities`). @@ -52,6 +54,7 @@ passed to `\$x` to specify the keyword arguments for `test_\$x`. - `deps_compat = true` - `piracies = true` - `persistent_tasks = true` +- `undocumented_names = true` """ function test_all( testtarget::Module; @@ -63,6 +66,7 @@ function test_all( deps_compat = true, piracies = true, persistent_tasks = true, + undocumented_names = true, ) @testset "Method ambiguity" begin if ambiguities !== false @@ -105,6 +109,13 @@ function test_all( test_persistent_tasks(testtarget; askwargs(persistent_tasks)...) end end + @testset "Undocumented names" begin + if undocumented_names !== false + isempty(askwargs(undocumented_names)) || + error("Keyword arguments not supported") + test_undocumented_names(testtarget; askwargs(undocumented_names)...) + end + end end end # module diff --git a/src/undocumented_names.jl b/src/undocumented_names.jl new file mode 100644 index 00000000..5d28a50b --- /dev/null +++ b/src/undocumented_names.jl @@ -0,0 +1,26 @@ +""" + test_undocumented_names(module::Module) + +Test that all public names in `module` have a docstring (not including the module itself). + +!!! warning + For Julia versions before 1.11, this does not test anything. +""" +function test_undocumented_names(m::Module) + @static if VERSION >= v"1.11" + undocumented_names = filter(n -> n != nameof(m), Docs.undocumented_names(m)) + @test isempty(undocumented_names) + else + undocumented_names = Symbol[] + end + if !isempty(undocumented_names) + printstyled( + stderr, + "Undocumented names detected:\n"; + bold = true, + color = Base.error_color(), + ) + show(stderr, MIME"text/plain"(), undocumented_names) + println(stderr) + end +end diff --git a/test/pkgs/PkgWithUndocumentedNames.jl b/test/pkgs/PkgWithUndocumentedNames.jl new file mode 100644 index 00000000..45a56a98 --- /dev/null +++ b/test/pkgs/PkgWithUndocumentedNames.jl @@ -0,0 +1,20 @@ +module PkgWithUndocumentedNames + +""" + documented_function +""" +function documented_function end + +function undocumented_function end + +""" + DocumentedStruct +""" +struct DocumentedStruct end + +struct UndocumentedStruct end + +export documented_function, DocumentedStruct +export undocumented_function, UndocumentedStruct + +end # module diff --git a/test/pkgs/PkgWithoutUndocumentedNames.jl b/test/pkgs/PkgWithoutUndocumentedNames.jl new file mode 100644 index 00000000..46b8b5a5 --- /dev/null +++ b/test/pkgs/PkgWithoutUndocumentedNames.jl @@ -0,0 +1,18 @@ +""" + PkgWithoutUndocumentedNames +""" +module PkgWithoutUndocumentedNames + +""" + documented_function +""" +function documented_function end + +""" + DocumentedStruct +""" +struct DocumentedStruct end + +export documented_function, DocumentedStruct + +end # module diff --git a/test/test_undocumented_names.jl b/test/test_undocumented_names.jl new file mode 100644 index 00000000..83f2f1f5 --- /dev/null +++ b/test/test_undocumented_names.jl @@ -0,0 +1,31 @@ +module TestUndocumentedNames + +include("preamble.jl") + +import PkgWithUndocumentedNames +import PkgWithoutUndocumentedNames + +# Pass +results = @testtestset begin + Aqua.test_undocumented_names(PkgWithoutUndocumentedNames) +end +if VERSION >= v"1.11" + @test length(results) == 1 + @test results[1] isa Test.Pass +else + @test length(results) == 0 +end +# Fail +println("### Expected output START ###") +results = @testtestset begin + Aqua.test_undocumented_names(PkgWithUndocumentedNames) +end +println("### Expected output END ###") +if VERSION >= v"1.11" + @test length(results) == 1 + @test results[1] isa Test.Fail +else + @test length(results) == 0 +end + +end # module