chore: added more @spec

This commit is contained in:
2026-05-01 17:49:50 +02:00
parent abcae1dad7
commit 881056eb61
157 changed files with 6223 additions and 1647 deletions

View File

@@ -0,0 +1,82 @@
defmodule BDS.SpecCoverageTest do
use ExUnit.Case, async: true
@section_10_files [
"lib/bds/tags.ex",
"lib/bds/templates.ex",
"lib/bds/scripts.ex",
"lib/bds/post_links.ex"
]
@section_10_editor_globs [
"lib/bds/desktop/shell_live/*editor.ex",
"lib/bds/desktop/shell_live/*_editor/*.ex"
]
describe "CODESMELL Section 10" do
test "smaller contexts have specs for all public functions" do
root = File.cwd!()
offenders =
section_10_files(root)
|> Enum.flat_map(fn relative_path ->
relative_path
|> Path.join("")
|> then(&Path.join(root, &1))
|> public_functions_without_specs(relative_path)
end)
assert offenders == []
end
end
defp section_10_files(root) do
editor_files =
@section_10_editor_globs
|> Enum.flat_map(fn pattern -> Path.wildcard(Path.join(root, pattern)) end)
|> Enum.map(&Path.relative_to(&1, root))
(@section_10_files ++ editor_files)
|> Enum.uniq()
|> Enum.sort()
end
defp public_functions_without_specs(path, relative_path) do
source = File.read!(path)
{:ok, ast} = Code.string_to_quoted(source)
specs = spec_names(source)
ast
|> public_defs()
|> Enum.uniq_by(fn {_line, name, arity} -> {name, arity} end)
|> Enum.reject(fn {_line, name, _arity} -> MapSet.member?(specs, name) end)
|> Enum.map(fn {line, name, arity} -> "#{relative_path}:#{line}:#{name}/#{arity}" end)
end
defp spec_names(source) do
~r/^\s*@spec\s+([a-zA-Z_][a-zA-Z0-9_?!]*)\s*\(/m
|> Regex.scan(source)
|> Enum.map(fn [_match, name] -> String.to_atom(name) end)
|> MapSet.new()
end
defp public_defs(ast) do
{_ast, defs} =
Macro.prewalk(ast, [], fn
{:def, meta, [head | _]} = node, acc ->
{name, arity} = public_def_name_arity(head)
{node, [{Keyword.fetch!(meta, :line), name, arity} | acc]}
node, acc ->
{node, acc}
end)
Enum.reverse(defs)
end
defp public_def_name_arity({:when, _meta, [head | _guards]}), do: public_def_name_arity(head)
defp public_def_name_arity({name, _meta, args}) when is_atom(name),
do: {name, length(args || [])}
end