test(strings): guard that every string is re-exported from the package
strings/ is split into domain submodules whose names are re-exported from strings/__init__.py. Adding a constant to a submodule and forgetting to re-export it - or shadowing a name across two submodules - would only surface as a runtime crash in a command. This test asserts every submodule __all__ entry is reachable as strings.NAME, that no name is defined twice, and that strings.__all__ matches the union of the submodules. Submodules are auto-discovered, so a new one is covered without editing the test. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
77
tests/test_strings.py
Normal file
77
tests/test_strings.py
Normal file
@@ -0,0 +1,77 @@
|
||||
"""Guard tests for the strings/ package.
|
||||
|
||||
strings/ is split into domain submodules whose names are re-exported from
|
||||
strings/__init__.py so callers keep using `strings.NAME`. It's easy to add a
|
||||
constant to a submodule and forget to re-export it (or to shadow a name across
|
||||
two submodules) - both would only surface as a runtime crash in a command.
|
||||
These tests catch that at test time instead.
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import pkgutil
|
||||
|
||||
import strings
|
||||
|
||||
# Auto-discover submodules so a newly added one is covered without editing this.
|
||||
SUBMODULES = sorted(m.name for m in pkgutil.iter_modules(strings.__path__))
|
||||
|
||||
|
||||
def _submodule(name):
|
||||
return importlib.import_module(f"strings.{name}")
|
||||
|
||||
|
||||
class TestStringsPackage:
|
||||
def test_submodules_discovered(self):
|
||||
# Sanity: the split actually produced multiple domain modules.
|
||||
assert len(SUBMODULES) >= 2, SUBMODULES
|
||||
|
||||
def test_every_submodule_declares_all(self):
|
||||
for name in SUBMODULES:
|
||||
mod = _submodule(name)
|
||||
assert hasattr(mod, "__all__"), f"strings.{name} is missing __all__"
|
||||
|
||||
def test_all_entries_exist_in_their_submodule(self):
|
||||
for name in SUBMODULES:
|
||||
mod = _submodule(name)
|
||||
for const in mod.__all__:
|
||||
assert hasattr(mod, const), (
|
||||
f"{const} is listed in strings.{name}.__all__ "
|
||||
f"but not defined in that module"
|
||||
)
|
||||
|
||||
def test_every_name_is_reexported_from_package(self):
|
||||
for name in SUBMODULES:
|
||||
mod = _submodule(name)
|
||||
for const in mod.__all__:
|
||||
assert hasattr(strings, const), (
|
||||
f"{const} is defined in strings.{name} but not re-exported "
|
||||
f"from strings/__init__.py - add it to the imports there"
|
||||
)
|
||||
assert getattr(strings, const) is getattr(mod, const), (
|
||||
f"strings.{const} is not the same object as strings.{name}.{const}"
|
||||
)
|
||||
|
||||
def test_no_name_defined_in_two_submodules(self):
|
||||
origin = {}
|
||||
for name in SUBMODULES:
|
||||
for const in _submodule(name).__all__:
|
||||
assert const not in origin, (
|
||||
f"{const} is defined in both strings.{origin[const]} "
|
||||
f"and strings.{name}"
|
||||
)
|
||||
origin[const] = name
|
||||
|
||||
def test_package_all_matches_submodule_union(self):
|
||||
union = set()
|
||||
for name in SUBMODULES:
|
||||
union |= set(_submodule(name).__all__)
|
||||
assert set(strings.__all__) == union, {
|
||||
"missing_from_package_all": sorted(union - set(strings.__all__)),
|
||||
"extra_in_package_all": sorted(set(strings.__all__) - union),
|
||||
}
|
||||
|
||||
def test_public_constants_all_declared(self):
|
||||
# Every UPPER_CASE constant exposed on the package is accounted for in
|
||||
# __all__ (E, the emoji helper, is an implementation detail, not a string).
|
||||
public = {n for n in vars(strings) if n.isupper() and n != "E"}
|
||||
assert public == set(strings.__all__)
|
||||
Reference in New Issue
Block a user