test: cover the documented command surface and the relation invariant - #59
Merged
Merged
Conversation
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
added this pull request to stack #61
September 11, 2026 15:08
Merged
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>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.
--table_names--group_by_appTableGroupblocks--color_by_appheadercolorper tableAlso unverified: selecting a whole app by label, the error on an unknown label, the default update timestamp, explicit
throughmodels, the database-engine mapping, router-aware table notes, andchoices_to_markdown_table.The part that is not about a percentage
Issue #38 was a schema dbdiagram rejected outright, because a
refnamed a column its table never declared.test_every_relation_endpoint_references_a_declared_columnencodes 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_namesrewrites 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
AutoFieldpk plus a customdb_table), a one-to-one alongside a foreign key to the same model, and an explicitthroughmodel, which is the branch where no join table should be synthesized.Result
selection.pyrenderer.pyutils.pyThe four remaining statements are the defensive dedup return in
_build_many_to_many_tableand thebase_field.choicesbranch, which needsdjango.contrib.postgres. Both are documented inCLAUDE.mdas deliberate so nobody chases them for the number.pytest-covand amake coveragetarget 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 ciclean. 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