Skip to content

test: cover the documented command surface and the relation invariant - #59

Merged
imakecodes merged 1 commit into
mainfrom
test/cover-library-behavior
Sep 11, 2026
Merged

imakecodes merged 1 commit into
mainfrom
test/cover-library-behavior

Conversation

@imakecodes

@imakecodes imakecodes commented Sep 11, 2026 •

Copy link
Copy Markdown
Member

Closes #12.

Bottom of stack #61. Merge this first; #60 sits on top.

Why

Coverage was 89%, but the gap was not evenly spread. Three of the seven options the README documents had no test at all.

Untested before What it does
--table_names switches every table identifier to the physical DB name
--group_by_app emits TableGroup blocks
--color_by_app emits headercolor per table

Also unverified: selecting a whole app by label, the error on an unknown label, the default update timestamp, explicit through models, the database-engine mapping, router-aware table notes, and choices_to_markdown_table.

The part that is not about a percentage

Issue #38 was a schema dbdiagram rejected outright, because a ref named a column its table never declared. test_every_relation_endpoint_references_a_declared_column encodes that rule rather than any single column name, so it catches the whole class of failure instead of the one instance that was reported. It runs over both naming modes, since --table_names rewrites every table identifier and every relation endpoint with it.

How the assertions work

Through tests/dbml_parser.py, which reads generated DBML back into tables, columns, relations and groups. Substring matching cannot express "this ref points at a column that exists", and it passes silently when output moves. The parser is an assertion aid scoped to what the renderer emits, not a DBML implementation.

Fixture models gain the shape reported in #38 (explicit AutoField pk plus a custom db_table), a one-to-one alongside a foreign key to the same model, and an explicit through model, which is the branch where no join table should be synthesized.

Result

Before After
Tests 4 47
Coverage 89% 99%
selection.py 87% 100%
renderer.py 84% 100%
utils.py 71% 100%

The four remaining statements are the defensive dedup return in _build_many_to_many_table and the base_field.choices branch, which needs django.contrib.postgres. Both are documented in CLAUDE.md as deliberate so nobody chases them for the number.

pytest-cov and a make coverage target keep this measurable. No threshold is enforced in CI; that is a maintainer call, and a floor that fails unrelated PRs is worse than none.

Verification

make ci clean. 47 tests pass on both ends of the support matrix, Python 3.11 with Django 4.2 and Python 3.14 with Django 6.1.

No source changes in this PR.

🤖 Generated with Claude Code

Closes #12.

Coverage was 89%, but the gap was not evenly spread: three of the seven
options the README documents had no test at all. --table_names,
--group_by_app and --color_by_app were entirely unverified, as were
selecting a whole app by label, the error on an unknown label, the
default update timestamp, explicit through models, the database-engine
mapping, router-aware table notes, and choices_to_markdown_table.

The important addition is not a percentage. Issue #38 was a schema that
dbdiagram rejected outright because a ref named a column its table never
declared. test_every_relation_endpoint_references_a_declared_column
encodes that rule instead of any single column name, so it catches the
whole class of failure rather than the one instance that was reported.
It runs over both table-naming modes, since --table_names rewrites every
table identifier and every relation endpoint with it.

Assertions go through tests/dbml_parser.py, which reads the generated
DBML back into tables, columns, relations and groups. Substring matching
cannot express "this ref points at a column that exists", and it silently
passes when output moves. The parser is an assertion aid scoped to what
the renderer emits, not a DBML implementation.

Fixture models gain the shape reported in #38 (explicit AutoField pk plus
a custom db_table), a one-to-one alongside a foreign key to the same
model, and an explicit through model, which is the branch where no join
table should be synthesized.

Coverage is now 99%. The four remaining statements are the defensive
dedup return in _build_many_to_many_table and the base_field.choices
branch, which needs django.contrib.postgres. Both are documented in
CLAUDE.md as deliberate, so nobody chases them for the number.

Add pytest-cov and a make coverage target so this stays measurable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@imakecodes
imakecodes added this pull request to stack #61 September 11, 2026 15:08
@imakecodes
imakecodes merged commit 97bd996 into main Sep 11, 2026
21 checks passed
@imakecodes imakecodes mentioned this pull request Sep 11, 2026
imakecodes added a commit that referenced this pull request Sep 11, 2026
Minor rather than patch: #60 changes the generated output for every user.
A relation column is now typed by the column it points at, so a foreign
key to a BigAutoField primary key renders as `big_auto` where it used to
render as `foreign_key`. No API or CLI break, but anyone versioning a
.dbml file will see a diff.

Shipping since 1.1.2:

- #57 CLAUDE.md and shared .claude configuration
- #58 CI covers the full declared support matrix, Django 4.2 to 6.1 on
      Python 3.11 to 3.14, plus Framework :: Django classifiers so the
      tested range is visible on PyPI
- #59 command surface and relation invariants under test, 89% to 99%
- #60 relation columns typed by their target (closes #38)

Regenerate uv.lock alongside the version. The package is a member of its
own workspace, so uv.lock records project.version and `uv sync --locked`
fails without it. That would have broken the release workflow at the
sync step, before it built anything.

Drop the hardcoded version from the release example in CONTRIBUTING.md;
it went stale on every release.

Co-authored-by: Michel Wilhelm <michel@revealhealth.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Testing

1 participant