Files
sporel-lib-core.api-discove…/init.lua
Axel Meyer 44314774ee test: cover new Badges/Topology MUST-Sections (S2 iter)
User-feedback iteration on S2 PoC template:
- Update validate_readme_structure test-data ('complete' + 'missing_api')
  to use new bold-list Badges + ## Topology H2 heading.
- Add 'missing_topology' case: README without ## Topology heading must
  report Topology as missing MUST-Section.
- Add 'missing_badges' case: README without **Lib-ID:** bold-line must
  report Badges as missing MUST-Section.

Assertion-count: 32 -> 35 (+3 new). README Coverage-Statement updated.
2026-05-16 15:26:36 +02:00

241 lines
8.2 KiB
Lua

-- lib-core.api-discovery-test — Test-lib for lib-core.api-discovery
local api = require("lib-core.api-discovery")
local M = {}
function M.run_tests(ctx)
-- Assertions added in plan tasks 2-7.
-- ===== parse_lua_surface =====
do
local src = [[
local M = {}
M.foo = function(x) return x end
M.bar = function() end
M._private = function() end
local function not_in_M() end
return M
]]
local surface = api.parse_lua_surface(src)
engine.test.equals(#surface.public, 2, "parse_lua_surface: 2 public functions")
engine.test.equals(surface.public[1], "foo", "parse_lua_surface: first public is foo")
engine.test.equals(surface.public[2], "bar", "parse_lua_surface: second public is bar")
engine.test.equals(#surface.private, 1, "parse_lua_surface: 1 private function")
engine.test.equals(surface.private[1], "_private", "parse_lua_surface: private name = _private")
-- Edge: empty source
local empty = api.parse_lua_surface("local M = {}\nreturn M")
engine.test.equals(#empty.public, 0, "parse_lua_surface: empty source = no public")
engine.test.equals(#empty.private, 0, "parse_lua_surface: empty source = no private")
end
-- ===== parse_readme_api =====
do
local md = [[
# lib-core.input
Some abstract.
## API
### `input.bind(action_name, keys)`
**Syntax:** `input.bind(action_name: string, keys: string[]) → void`
### `input.is_action_down(action) → bool`
Description.
## Conventions
Stuff.
]]
local doc = api.parse_readme_api(md)
engine.test.equals(#doc.documented, 2, "parse_readme_api: 2 documented functions")
engine.test.equals(doc.documented[1], "bind", "parse_readme_api: first = bind")
engine.test.equals(doc.documented[2], "is_action_down", "parse_readme_api: second = is_action_down")
-- Edge: no API section
local no_api = api.parse_readme_api("# Just abstract\nNothing else.")
engine.test.equals(#no_api.documented, 0, "parse_readme_api: no API-section = empty")
end
-- ===== diff_surface =====
do
-- Happy: surface == documented
local surface = { public = {"foo","bar"}, private = {"_x"} }
local readme = { documented = {"foo","bar"} }
local diff = api.diff_surface(surface, readme)
engine.test.equals(#diff.missing_docs, 0, "diff_surface: equal -> no missing")
engine.test.equals(#diff.stale_docs, 0, "diff_surface: equal -> no stale")
-- Surface > Doc -> missing
local surface2 = { public = {"foo","bar","baz"}, private = {} }
local readme2 = { documented = {"foo"} }
local diff2 = api.diff_surface(surface2, readme2)
engine.test.equals(#diff2.missing_docs, 2, "diff_surface: 2 missing docs")
engine.test.assert(diff2.missing_docs[1] == "bar" or diff2.missing_docs[1] == "baz", "diff_surface: missing contains bar/baz")
-- Doc > Surface -> stale
local surface3 = { public = {"foo"}, private = {} }
local readme3 = { documented = {"foo","gone","also_gone"} }
local diff3 = api.diff_surface(surface3, readme3)
engine.test.equals(#diff3.stale_docs, 2, "diff_surface: 2 stale docs")
end
-- ===== grep_engine_calls =====
do
local src = [[
local input = require("lib-core.input")
function update(ctx, dt)
if engine.input.is_action_down("foo") then
engine.render.text("hi")
end
engine.window.size()
end
]]
local calls = api.grep_engine_calls(src)
-- Order not guaranteed; check set membership
local set = {}
for _, c in ipairs(calls) do set[c] = true end
engine.test.assert(set["engine.input.is_action_down"], "grep_engine_calls: engine.input.is_action_down")
engine.test.assert(set["engine.render.text"], "grep_engine_calls: engine.render.text")
engine.test.assert(set["engine.window.size"], "grep_engine_calls: engine.window.size")
engine.test.equals(#calls, 3, "grep_engine_calls: 3 unique calls")
-- Edge: no engine calls
local empty = api.grep_engine_calls("local M = {}\nreturn M")
engine.test.equals(#empty, 0, "grep_engine_calls: empty -> 0")
end
-- ===== generate_topology_block =====
do
-- Standard: lib with 1 dep + engine-calls
local manifest = {
id = "lib-core.foo",
deps = { {id="lib-core.bar"} }
}
local engine_calls = {"engine.input.is_action_down"}
local mermaid = api.generate_topology_block(manifest, engine_calls)
engine.test.assert(string.find(mermaid, "graph LR") or string.find(mermaid, "graph TD"),
"generate_topology_block: starts with graph directive")
engine.test.assert(string.find(mermaid, "lib%-core%.foo", 1, false), "generate_topology_block: self-node present")
engine.test.assert(string.find(mermaid, "lib%-core%.bar", 1, false), "generate_topology_block: dep-node present")
engine.test.assert(string.find(mermaid, "engine%.%*", 1, false), "generate_topology_block: engine-node present")
-- Asset-Lib: no deps, no engine-calls
local asset = { id = "lib-asset.sprites", deps = {} }
local asset_mermaid = api.generate_topology_block(asset, {})
engine.test.assert(string.find(asset_mermaid, "lib%-asset%.sprites", 1, false), "generate_topology_block: asset-lib has self-node")
engine.test.assert(not string.find(asset_mermaid, "engine%.%*", 1, false), "generate_topology_block: asset-lib has no engine-node")
end
-- ===== validate_readme_structure =====
do
local complete = [[
# lib-core.foo
Abstract.
**Version:** 0.1.0
**Lib-ID:** lib-core.foo
**Requires:** (none)
## Topology
<!-- topology:start -->
<!-- topology:end -->
## API
### `foo.bar()`
Sig.
## References
- spec
]]
local r = api.validate_readme_structure(complete, "core")
engine.test.equals(#r.missing_sections, 0, "validate: complete README -> no missing")
engine.test.assert(r.section_order_ok, "validate: complete README -> order ok")
local missing_api = [[
# lib-core.foo
Abstract.
**Version:** 0.1.0
**Lib-ID:** lib-core.foo
## Topology
<!-- topology:start -->
<!-- topology:end -->
## References
- spec
]]
local r2 = api.validate_readme_structure(missing_api, "core")
engine.test.assert(#r2.missing_sections > 0, "validate: missing API -> reports missing")
local has_api_missing = false
for _, s in ipairs(r2.missing_sections) do
if s == "API" then has_api_missing = true end
end
engine.test.assert(has_api_missing, "validate: missing-sections list contains 'API'")
-- Missing Topology heading: should detect Topology as missing MUST-section
local missing_topology = [[
# lib-core.foo
Abstract.
**Version:** 0.1.0
**Lib-ID:** lib-core.foo
<!-- topology:start -->
<!-- topology:end -->
## API
### `foo.bar()`
Sig.
## References
- spec
]]
local r_topo = api.validate_readme_structure(missing_topology, "core")
engine.test.assert(#r_topo.missing_sections > 0, "validate: missing Topology heading -> reports missing")
local has_topology_missing = false
for _, s in ipairs(r_topo.missing_sections) do
if s == "Topology" then has_topology_missing = true end
end
engine.test.assert(has_topology_missing, "validate: missing-sections list contains 'Topology'")
-- Missing Badges (no **Lib-ID:** bold line): should detect Badges as missing
local missing_badges = [[
# lib-core.foo
Abstract.
## Topology
<!-- topology:start -->
<!-- topology:end -->
## API
### `foo.bar()`
Sig.
## References
- spec
]]
local r_badges = api.validate_readme_structure(missing_badges, "core")
local has_badges_missing = false
for _, s in ipairs(r_badges.missing_sections) do
if s == "Badges" then has_badges_missing = true end
end
engine.test.assert(has_badges_missing, "validate: missing-sections list contains 'Badges'")
-- Tier community: lockerer
local r3 = api.validate_readme_structure(missing_api, "community")
engine.test.equals(#r3.missing_sections, 0, "validate: tier=community -> no enforcement")
end
engine.exit(engine.test.failures())
end
return M