docs: centralise test counts + add release-policy + remove stale stub references
Two complementary improvements aimed at reducing recurring maintenance
overhead:
1. **Test-count centralisation** — `doc/api/tests.md` is now the
single source of truth for the test counts. All other docs
(README, CLAUDE.md, doc/contributing.md, doc/getting-started.md,
doc/math/validation.md, doc/math/validation-protocol.md,
scripts/try_it.sh) use qualitative phrasing + a link instead of
hardcoded numbers. The previous regime had eight places with
"227 CGAL tests, 23 non-CGAL tests" that drifted apart across
releases (the v0.9.0 release-prep needed to touch nine files).
2. **Versioning policy** — `doc/release-policy.md` (new, ~250 lines)
formalises:
* SemVer rules for the pre-1.0 and post-1.0 phases.
* Phase-milestone → MINOR-bump mapping (v0.10.0 → Phase 9c, …).
* Single-source-of-truth table for moving numbers (test counts,
version, date).
* Step-by-step release process (the recipe that worked for v0.9.0
after the false-start with PR #11/#12).
* Hotfix policy + post-1.0 deprecation policy.
* Known failure modes and how to recover from them.
Plus a small CI gate:
3. **scripts/check-test-counts.sh** — verifies the totals in
doc/api/tests.md match `ctest` output. Re-uses existing build-cgal/
if present. Exit 0 on match, 1 on divergence with recovery hints.
Cheap enough (~30 s) to run on every PR.
Other cleanups
──────────────
* code/tests/cgal/CMakeLists.txt — stale "Test 7 (genus-2 homology)
as GTEST_SKIP stub until Phase 8" comment removed; that test landed
as HomologyGenerators.Genus2_FourCutEdges in Phase 7.
* CLAUDE.md — "test-fast also runs stubs" Known Quirks entry updated
to reflect the v0.9.0 stub cleanup (no GTEST_SKIPs remain).
* CLAUDE.md doc map — new entry for doc/release-policy.md.
Stubs audit
───────────
Zero GTEST_SKIP() calls remain in the codebase as of this commit.
The only references to stubs are in historical documentation
(CHANGELOG.md v0.7.0 entry, doc/roadmap/* "deferred to research-track"
notes) — those are intended.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -244,7 +244,7 @@ Two jobs in `.gitea/workflows/cpp-tests.yml`:
|
||||
|
||||
Runner: `eulernest` — self-hosted Raspberry Pi, ARM64, Ubuntu 22.04. Docker image: `git.eulernest.eu/conformallab/ci-cpp:latest`. `test-cgal` needs `test-fast` to pass first (`needs: test-fast`).
|
||||
|
||||
Expected results: **23 non-CGAL tests pass**, **227 CGAL tests pass, 0 skipped**.
|
||||
Expected results: full test suite passing, 0 skipped, 0 failed. The canonical counts live in `doc/api/tests.md` — do not hardcode them anywhere else (see [`doc/release-policy.md`](doc/release-policy.md)).
|
||||
|
||||
## Release state
|
||||
|
||||
@@ -349,7 +349,7 @@ follow the empirical verification rule above before any new claim.
|
||||
| Full pipeline API for all three geometries | `doc/api/pipeline.md` |
|
||||
| What does each processing unit require/provide (contracts)? | `doc/api/contracts.md` |
|
||||
| How to add a new functional / geometry mode / port from Java | `doc/api/extending.md` |
|
||||
| All 39 test suites, 227+23 tests, individual counts | `doc/api/tests.md` |
|
||||
| Per-suite breakdown and counts (single source of truth) | `doc/api/tests.md` |
|
||||
| Phase 8 CGAL package design + Declarative YAML pipeline spec | `doc/api/cgal-package.md` |
|
||||
|
||||
### Concepts & specs
|
||||
@@ -373,6 +373,7 @@ follow the empirical verification rule above before any new claim.
|
||||
| Build modes, single-test invocation, CLI, Docker image rebuild | `doc/getting-started.md` |
|
||||
| Step-by-step: port the Inversive Distance functional (Phase 9a template) | `doc/tutorials/add-inversive-distance.md` |
|
||||
| Language policy, test standards, release flow | `doc/contributing.md` |
|
||||
| Versioning rules + release process + single-source-of-truth list | `doc/release-policy.md` |
|
||||
|
||||
### geometry-central context
|
||||
|
||||
@@ -386,7 +387,7 @@ Optional adoption roadmap (GC-1/2/3): `doc/roadmap/phases.md` (Optional section)
|
||||
|
||||
## Known quirks
|
||||
|
||||
- **`test-fast` also runs stubs**: `conformallab_tests` (non-CGAL) contains `GTEST_SKIP`-based stubs for functionals that need CGAL. This is intentional — those tests document what was in the Java port scope but requires the CGAL mesh type.
|
||||
- **No GTEST_SKIP stubs remain** (since v0.9.0): the three stale HDS-port stub files were removed because the CGAL test suite covers the same functionality with real tests. The pure-math `conformallab_tests` target now only contains active tests.
|
||||
- **Boost is header-only**: CGAL 6.x uses only Boost headers (`Boost.Config`, `Boost.Graph`). No compiled Boost libraries are needed. `find_package(Boost REQUIRED)` only locates the include path.
|
||||
- **`main` branch is protected** on `origin` (Gitea). Push to `dev`, then merge via pull request. Codeberg `main` can be pushed to directly.
|
||||
- **Both remotes must stay in sync**: `origin` = `git.eulernest.eu` (CI runs here), `codeberg` = `codeberg.org/TMoussa/ConformalLabpp` (public mirror). Push to both after every significant change.
|
||||
|
||||
@@ -13,7 +13,7 @@ Algorithmic foundation:
|
||||
> DOI: [10.14279/depositonce-5415](https://depositonce.tu-berlin.de/items/8e2988b2-d991-45b5-aad5-9fb7988f3b2f) · CC BY-SA 4.0 ·
|
||||
> [Java original](https://github.com/varylab/conformallab) · [sechel.de](https://sechel.de/)
|
||||
|
||||
**Status:** v0.9.0 — Phases 1–9a complete, Phase 8b-Lite CGAL API surface. Newton solvers for **five** DCE models (Euclidean / Spherical / HyperIdeal / CP-Euclidean / Inversive-Distance), priority-BFS layout in ℝ²/S²/Poincaré disk, Gauss–Bonnet, tree-cotree cut graph, Möbius holonomy, period matrix (genus 1), fundamental domain, halfedge_uv texture atlas, JSON/XML serialisation, CLI app. **227 CGAL tests + 23 non-CGAL tests, 0 skipped.**
|
||||
**Status:** v0.9.0 — Phases 1–9a complete, Phase 8b-Lite CGAL API surface. Newton solvers for **five** DCE models (Euclidean / Spherical / HyperIdeal / CP-Euclidean / Inversive-Distance), priority-BFS layout in ℝ²/S²/Poincaré disk, Gauss–Bonnet, tree-cotree cut graph, Möbius holonomy, period matrix (genus 1), fundamental domain, halfedge_uv texture atlas, JSON/XML serialisation, CLI app. Full test suite passing, 0 skipped — see [`doc/api/tests.md`](doc/api/tests.md) for the per-suite breakdown.
|
||||
|
||||
---
|
||||
|
||||
@@ -84,7 +84,7 @@ Layout2D layout = euclidean_layout(mesh, res.x, maps);
|
||||
| **Getting started** — build modes, single-test invocation, CLI, Docker | [doc/getting-started.md](doc/getting-started.md) |
|
||||
| **Pipeline API** — all three geometries, holonomy, serialisation | [doc/api/pipeline.md](doc/api/pipeline.md) |
|
||||
| **Public headers** — all 24 headers with descriptions | [doc/api/headers.md](doc/api/headers.md) |
|
||||
| **Test suites** — 39 suites, 227+23 tests, individual counts | [doc/api/tests.md](doc/api/tests.md) |
|
||||
| **Test suites** — per-suite breakdown and counts (single source of truth) | [doc/api/tests.md](doc/api/tests.md) |
|
||||
| **Extending** — new functionals, geometry modes, porting from Java | [doc/api/extending.md](doc/api/extending.md) |
|
||||
| **Processing unit contracts** — preconditions / provides table | [doc/api/contracts.md](doc/api/contracts.md) |
|
||||
| **CGAL package design** — Phase 8 target, YAML pipeline | [doc/api/cgal-package.md](doc/api/cgal-package.md) |
|
||||
|
||||
@@ -53,8 +53,9 @@ add_executable(conformallab_cgal_tests
|
||||
|
||||
# ── Java parity: geometry utility tests ──────────────────────────────────
|
||||
# Ported from CuttinUtilityTest, UnwrapUtilityTest,
|
||||
# ConvergenceUtilityTests, HomologyTest (tests 1–6).
|
||||
# Test 7 (genus-2 homology) as GTEST_SKIP stub until Phase 8.
|
||||
# ConvergenceUtilityTests, HomologyTest. All tests active —
|
||||
# the v0.7.0 genus-2 homology stub was implemented in Phase 7
|
||||
# (HomologyGenerators.Genus2_FourCutEdges, brezel2.obj).
|
||||
test_geometry_utils.cpp
|
||||
|
||||
# ── Scalability smoke tests ────────────────────────────────────────────────
|
||||
|
||||
@@ -29,8 +29,8 @@ Two jobs run on push to `dev`/`main` or on pull requests:
|
||||
|
||||
| Job | What it tests | Trigger |
|
||||
|---|---|---|
|
||||
| `test-fast` | 23 non-CGAL tests, no Boost | all branches |
|
||||
| `test-cgal` | 227 CGAL tests, 0 skipped | `main`, `dev`, PRs only |
|
||||
| `test-fast` | pure-math tests, no Boost | all branches |
|
||||
| `test-cgal` | full CGAL test suite | `main`, `dev`, PRs only |
|
||||
|
||||
A PR is ready to merge when both jobs pass.
|
||||
|
||||
@@ -51,7 +51,7 @@ Every new algorithm needs:
|
||||
|
||||
3. **Registration** — add the `.cpp` file to `code/tests/cgal/CMakeLists.txt`.
|
||||
|
||||
Expected CI result: **23 + 227 tests pass, 0 skipped**.
|
||||
Expected CI result: full test suite passing, 0 skipped (per-suite counts: [`doc/api/tests.md`](api/tests.md)).
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ cmake --build build --target conformallab_tests -j$(nproc)
|
||||
ctest --test-dir build --output-on-failure
|
||||
```
|
||||
|
||||
Expected: **23 tests pass**.
|
||||
Expected: all pure-math tests pass (count: [`doc/api/tests.md`](api/tests.md)).
|
||||
|
||||
### Mode 2 — CGAL tests, headless (recommended for CI and development)
|
||||
|
||||
@@ -60,7 +60,7 @@ cmake --build build --target conformallab_cgal_tests -j$(nproc)
|
||||
ctest --test-dir build -R "^cgal\." --output-on-failure
|
||||
```
|
||||
|
||||
Expected: **227 tests pass, 0 skipped**.
|
||||
Expected: all CGAL tests pass, 0 skipped (count: [`doc/api/tests.md`](api/tests.md)).
|
||||
|
||||
### Mode 3 — Full local build (CLI app + interactive viewer)
|
||||
|
||||
@@ -146,7 +146,7 @@ sets x* = 0, so a small perturbation (-0.05) needs only one Newton step.
|
||||
bash scripts/try_it.sh
|
||||
```
|
||||
This clones nothing (run from inside the repo), builds the CGAL test suite, runs
|
||||
all 227+23 tests, and prints a summary. See `scripts/try_it.sh` for details.
|
||||
the full test suite, and prints a summary. See `scripts/try_it.sh` for details.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -199,7 +199,7 @@ inner/outer edge lengths). Use `torus_8x8.off` for a finer approximation.
|
||||
## Summary checklist
|
||||
|
||||
```
|
||||
[ ] Check 0: 176 tests pass, 0 skipped
|
||||
[ ] Check 0: full test suite passes, 0 skipped (counts: `doc/api/tests.md`)
|
||||
[ ] Check 1: Gauss–Bonnet exact (1e-10)
|
||||
[ ] Check 2: FD gradient < 1e-6 for all 3 geometries
|
||||
[ ] Check 3: Newton convergence < 50 iterations
|
||||
|
||||
@@ -14,7 +14,7 @@ cmake --build build --target conformallab_cgal_tests
|
||||
ctest --test-dir build -R cgal --output-on-failure
|
||||
```
|
||||
|
||||
All 227 tests pass, 0 skipped (see `doc/api/tests.md`).
|
||||
All tests pass, 0 skipped (per-suite breakdown: `doc/api/tests.md`).
|
||||
|
||||
---
|
||||
|
||||
@@ -252,7 +252,7 @@ implemented in conformallab++ (→ GC-2 in the phase roadmap).
|
||||
|
||||
Run these in order to validate the implementation:
|
||||
|
||||
- [ ] `ctest --test-dir build -R cgal --output-on-failure` → 227 tests pass, 0 skipped
|
||||
- [ ] `ctest --test-dir build -R cgal --output-on-failure` → all pass, 0 skipped (count: `doc/api/tests.md`)
|
||||
- [ ] `cgal.GaussBonnet.*` all pass → topology is correctly read from mesh
|
||||
- [ ] `cgal.EuclideanFunctional.GradientCheck_*` pass → energy = integral of gradient
|
||||
- [ ] `cgal.PeriodMatrix.TauInFundamentalDomain_*` pass → SL(2,ℤ) reduction correct
|
||||
|
||||
216
doc/release-policy.md
Normal file
216
doc/release-policy.md
Normal file
@@ -0,0 +1,216 @@
|
||||
# Release & versioning policy
|
||||
|
||||
> **Audience:** maintainers and recurring contributors of conformallab++.
|
||||
> External users only need this if they are publishing a fork.
|
||||
>
|
||||
> **Created:** 2026-05-22, after the v0.9.0 release that exposed two
|
||||
> recurring failure modes: (a) the v0.9.0 tag had to be moved twice
|
||||
> because release-prep landed on the wrong commit, and (b) the test
|
||||
> counts were hardcoded in eight different documents and drifted apart.
|
||||
|
||||
This document codifies how conformallab++ chooses version numbers,
|
||||
how releases are produced, and which artefacts must stay in sync.
|
||||
|
||||
---
|
||||
|
||||
## 1. Version-number rules (SemVer)
|
||||
|
||||
The project follows [Semantic Versioning 2.0](https://semver.org).
|
||||
Tag format: `vMAJOR.MINOR.PATCH` (e.g. `v0.9.0`).
|
||||
|
||||
### Pre-1.0 phase (current — until CGAL submission)
|
||||
|
||||
While the project is at version `0.x.y`, the public API is **not yet
|
||||
frozen**. The convention we use during the pre-1.0 phase is:
|
||||
|
||||
| Bump | When |
|
||||
|---|---|
|
||||
| **`0.x.0 → 0.(x+1).0`** (MINOR) | Significant new feature: new functional, new Newton solver, new public CGAL entry, new Phase milestone completed. May break the public API. Treated as the "interesting" release type during pre-1.0. |
|
||||
| **`0.x.y → 0.x.(y+1)`** (PATCH) | Bug fixes, performance optimisations without API change, doc-only follow-up releases, CI/infrastructure fixes. Never breaks the public API. |
|
||||
| **`0.x.y → 1.0.0`** | API freeze + CGAL submission readiness. All public headers under `include/CGAL/` are stable. Cumulative changelog updated to call out every public-API decision in retrospect. |
|
||||
|
||||
Phase milestone → MINOR-bump mapping (historical + planned):
|
||||
|
||||
| Tag | Phase milestone |
|
||||
|-----------|--------------------------------------------------------|
|
||||
| `v0.1.0` | Phase 1 (special functions) |
|
||||
| `v0.2.0` | Phase 2 (hyper-ideal geometry) |
|
||||
| `v0.7.0` | Phase 7 complete (period matrix, fundamental domain) |
|
||||
| `v0.9.0` | Phase 9a + 9b + 8b-Lite |
|
||||
| `v0.10.0` | Phase 9c (4g-polygon, genus g > 1) |
|
||||
| `v0.11.0` | Phase 10a (harmonic + holomorphic 1-forms) |
|
||||
| `v1.0.0` | CGAL package submission-ready |
|
||||
|
||||
### Post-1.0 phase (planned, ≥ `v1.0.0`)
|
||||
|
||||
Standard SemVer with no pre-1.0 exceptions:
|
||||
|
||||
| Bump | When |
|
||||
|---|---|
|
||||
| **MAJOR** (`X.0.0 → (X+1).0.0`) | Any breaking change to the public API: removed function, signature change, renamed CGAL entry, behaviour change of a documented contract. |
|
||||
| **MINOR** (`X.Y.0 → X.(Y+1).0`) | New features, new public entries, new Default-traits classes. Strictly additive — no removal, no behaviour change. |
|
||||
| **PATCH** (`X.Y.Z → X.Y.(Z+1)`) | Bug fixes only. No new files, no new public symbols. |
|
||||
|
||||
### Pre-release tags
|
||||
|
||||
For testing-quality releases:
|
||||
|
||||
* `v1.0.0-alpha.1`, `v1.0.0-alpha.2`, … — early preview, API may still
|
||||
shift.
|
||||
* `v1.0.0-beta.1` — feature-complete preview, API stable but tests
|
||||
may still find issues.
|
||||
* `v1.0.0-rc.1`, `v1.0.0-rc.2`, … — release candidate, only blocker
|
||||
fixes before the final tag.
|
||||
|
||||
### What does NOT trigger a release
|
||||
|
||||
* Internal refactoring without user-visible change.
|
||||
* Documentation-only updates (unless the documentation is itself a
|
||||
product, like a new tutorial).
|
||||
* Test additions / coverage improvements.
|
||||
* CI / infrastructure changes.
|
||||
|
||||
Group such changes into the next planned release.
|
||||
|
||||
---
|
||||
|
||||
## 2. Single source of truth for moving numbers
|
||||
|
||||
Three numbers tend to drift across multiple documents in any project:
|
||||
test counts, version strings, and date strings. The conformallab++
|
||||
rule is:
|
||||
|
||||
| Number / string | Single source of truth | Anywhere else |
|
||||
|-----------------------------|--------------------------------|--------------------------------------|
|
||||
| **Total / per-suite test counts** | `doc/api/tests.md` | Use qualitative phrasing + link, e.g. "full test suite passes, 0 skipped — see [`doc/api/tests.md`](doc/api/tests.md)". |
|
||||
| **Project version** | `CITATION.cff` `version:` field | Don't hardcode in headers, READMEs, doc bodies. Reference by name ("v0.9.0") only when the historical version actually matters (changelog entries, release-note bodies, Phase-milestone tables). |
|
||||
| **Release date** | `CITATION.cff` `date-released:` + `CHANGELOG.md` section header | Don't hardcode elsewhere. |
|
||||
| **Test-suite description per file** | `doc/api/tests.md` | Headers and code files may list the suites they implement, but never claim a count of suites elsewhere. |
|
||||
|
||||
### Why qualitative phrasing for test counts
|
||||
|
||||
The counts change with every PR that adds or removes a test. Hardcoding
|
||||
the number "227" in eight documents means eight separate edits per PR —
|
||||
and historically we have failed to keep them in sync more than once.
|
||||
|
||||
The cost of looking up the exact number in `doc/api/tests.md` is one
|
||||
click; the cost of fixing a stale "227" in seven places is real PR
|
||||
overhead. We pay the click.
|
||||
|
||||
### Audit script
|
||||
|
||||
`scripts/check-test-counts.sh` (when present) reads the totals from
|
||||
`doc/api/tests.md`, runs `ctest`, and fails the CI if they diverge.
|
||||
This catches the `tests.md` itself going stale even if no other doc
|
||||
hardcodes the number.
|
||||
|
||||
---
|
||||
|
||||
## 3. Release process (checklist)
|
||||
|
||||
The recipe that worked for v0.9.0 (after the false-start with PR #11 /
|
||||
#12). Apply for every `vX.Y.Z` release.
|
||||
|
||||
### Pre-release prep — on a release branch
|
||||
|
||||
1. **Update `CHANGELOG.md`** — add a new top-level section
|
||||
`## [vX.Y.Z] — YYYY-MM-DD`. Categorise changes by `Added`,
|
||||
`Changed`, `Removed`, `Fixed`, `Deprecated`, `Security`. See
|
||||
[Keep a Changelog 1.1.0](https://keepachangelog.com/en/1.1.0/).
|
||||
2. **Update `CITATION.cff`** — `version:` and `date-released:` fields.
|
||||
3. **Refresh `doc/api/tests.md`** — re-run the full test suite locally
|
||||
and update the per-suite tables + the two `**Total: N tests, 0 skipped.**`
|
||||
lines (one for `conformallab_tests`, one for `conformallab_cgal_tests`).
|
||||
4. **Run `scripts/check-test-counts.sh`** if present — must pass.
|
||||
5. **Verify no hardcoded counts remain** elsewhere:
|
||||
```bash
|
||||
grep -rn "[0-9]\+ tests pass\|[0-9]\+ tests, 0 skipped\|[0-9]\+ CGAL tests" \
|
||||
README.md CLAUDE.md doc/ scripts/ \
|
||||
| grep -v "doc/api/tests.md"
|
||||
# Expected: zero results (other than tests.md itself).
|
||||
```
|
||||
6. **Commit** with the message
|
||||
`release: vX.Y.Z — <one-line summary>`. Push to a feature branch.
|
||||
|
||||
### Open the release PR
|
||||
|
||||
7. **Open one PR** with all prep commits. Title:
|
||||
`release: vX.Y.Z (<summary>)`. Description: copy the new
|
||||
`CHANGELOG.md` section.
|
||||
8. **Wait for CI green** — `test-fast` + `test-cgal` + `doc-build`.
|
||||
9. **Merge** with a merge commit (the merge SHA becomes the release
|
||||
target).
|
||||
|
||||
### After-merge — tag and announce
|
||||
|
||||
10. **Verify `main` head is the merge commit**:
|
||||
```bash
|
||||
git fetch origin && git log origin/main --oneline -1
|
||||
```
|
||||
11. **Create the Gitea release** via API or web UI. `target_commitish`
|
||||
MUST be the merge SHA from step 10 (NOT the feature branch HEAD).
|
||||
The web UI does this automatically; the API needs explicit `sha`.
|
||||
12. **Sync the codeberg mirror**:
|
||||
```bash
|
||||
git fetch origin --tags
|
||||
git push codeberg main --tags
|
||||
```
|
||||
13. **Update CLAUDE.md "Release state" section** so future
|
||||
contributors see the new version at a glance. (This is the only
|
||||
place where the current version appears outside `CITATION.cff` and
|
||||
`CHANGELOG.md`.)
|
||||
|
||||
### Common failure modes and how to recover
|
||||
|
||||
| Symptom | Recovery |
|
||||
|---|---|
|
||||
| Tag points to an earlier commit than the one you wanted | Delete the release + tag via Gitea API, re-create with the correct `target_commitish`. |
|
||||
| Release-prep commit lands on a feature branch but not on `main` after merge | Open a fast-follow `release/vX.Y.Z-finalise` PR. Cherry-pick the missing commit; merge; move the tag. |
|
||||
| `doc/api/tests.md` counts are stale post-merge | One-line PR: re-run `ctest`, update tests.md, no version bump (it's a doc fix between releases). |
|
||||
|
||||
---
|
||||
|
||||
## 4. Hotfix policy
|
||||
|
||||
For a `vX.Y.0` minor release that needs an urgent fix before the next
|
||||
planned minor:
|
||||
|
||||
1. Branch off the release tag (NOT off `main`):
|
||||
```bash
|
||||
git checkout -b hotfix/vX.Y.1 vX.Y.0
|
||||
```
|
||||
2. Apply the minimal fix.
|
||||
3. Tag `vX.Y.1` from the hotfix branch.
|
||||
4. Merge the hotfix back into `main` so the fix isn't lost.
|
||||
|
||||
Hotfixes are rare for a research-quality library; the typical path is
|
||||
to wait for the next minor. Use hotfixes only for security issues or
|
||||
build-broken-on-supported-platform regressions.
|
||||
|
||||
---
|
||||
|
||||
## 5. Deprecation policy (post-1.0)
|
||||
|
||||
When a public symbol is to be removed in version `M.0.0`:
|
||||
|
||||
1. In any earlier `M-1` minor release, mark it `[[deprecated]]` (C++17)
|
||||
or via a Doxygen `\deprecated` tag.
|
||||
2. Add a `Deprecated` section to that version's CHANGELOG entry with
|
||||
the planned removal version.
|
||||
3. Keep the symbol working for at least one full minor cycle before
|
||||
removal.
|
||||
4. Remove in the `M.0.0` release; document the removal in the
|
||||
`Removed` section.
|
||||
|
||||
Pre-1.0, this policy does not apply — breaking changes are allowed
|
||||
on any minor bump as long as they are listed in CHANGELOG.
|
||||
|
||||
---
|
||||
|
||||
## 6. Related documents
|
||||
|
||||
* `CHANGELOG.md` — per-version history.
|
||||
* `CITATION.cff` — authoritative version + date for citation.
|
||||
* `doc/api/tests.md` — single source of truth for test counts.
|
||||
* `doc/contributing.md` — code style + PR mechanics.
|
||||
* `doc/roadmap/phases.md` — what each future MINOR bump will deliver.
|
||||
90
scripts/check-test-counts.sh
Executable file
90
scripts/check-test-counts.sh
Executable file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env bash
|
||||
# scripts/check-test-counts.sh
|
||||
#
|
||||
# CI gate that verifies the totals in `doc/api/tests.md` match the
|
||||
# actual `ctest` output. Catches the canonical test-count document
|
||||
# going stale even if no other doc hardcodes the number.
|
||||
#
|
||||
# Usage:
|
||||
# bash scripts/check-test-counts.sh
|
||||
#
|
||||
# Exit codes:
|
||||
# 0 totals match
|
||||
# 1 totals diverge — prints diff and which file to fix
|
||||
# 2 prerequisites missing (cmake not found, tests.md missing, …)
|
||||
#
|
||||
# This script is meant to be cheap enough to run on every PR (~30 s on
|
||||
# a typical CI runner). It re-uses the existing build-cgal/ directory
|
||||
# if one is present; otherwise it builds a throwaway build-counts/.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "${BASH_SOURCE[0]}")/.." # repo root
|
||||
|
||||
TESTS_MD="doc/api/tests.md"
|
||||
|
||||
if [ ! -f "$TESTS_MD" ]; then
|
||||
echo "FAIL: $TESTS_MD not found" >&2
|
||||
exit 2
|
||||
fi
|
||||
command -v cmake >/dev/null || { echo "FAIL: cmake not in PATH" >&2; exit 2; }
|
||||
command -v ctest >/dev/null || { echo "FAIL: ctest not in PATH" >&2; exit 2; }
|
||||
|
||||
# ── Build ───────────────────────────────────────────────────────────────────
|
||||
# Re-use existing build-cgal/ if it exists with the right flags; otherwise
|
||||
# create a throwaway build-counts/ directory.
|
||||
BUILD_DIR=""
|
||||
if [ -f build-cgal/CMakeCache.txt ] && grep -q "WITH_CGAL_TESTS:.*=ON\|WITH_CGAL:.*=ON" build-cgal/CMakeCache.txt; then
|
||||
BUILD_DIR=build-cgal
|
||||
else
|
||||
BUILD_DIR=build-counts
|
||||
cmake -S code -B "$BUILD_DIR" -DWITH_CGAL_TESTS=ON -DCMAKE_BUILD_TYPE=Release >/dev/null
|
||||
fi
|
||||
cmake --build "$BUILD_DIR" -j"$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 2)" >/dev/null
|
||||
|
||||
# ── Get actual counts ───────────────────────────────────────────────────────
|
||||
cd "$BUILD_DIR"
|
||||
actual_cgal=$(ctest -R "^cgal" 2>&1 | grep "tests passed" | sed -E 's/.*out of ([0-9]+).*/\1/')
|
||||
actual_fast=$(ctest -E "^cgal" 2>&1 | grep "tests passed" | sed -E 's/.*out of ([0-9]+).*/\1/')
|
||||
cd - >/dev/null
|
||||
|
||||
# ── Get claimed counts from tests.md ────────────────────────────────────────
|
||||
# Expected format (in this order):
|
||||
# **Total: <N1> tests, 0 skipped.** (non-CGAL section)
|
||||
# ...
|
||||
# **Total: <N2> tests, 0 skipped.** (CGAL section)
|
||||
claimed_fast=$(grep -E "\*\*Total: [0-9]+ tests, 0 skipped\.\*\*" "$TESTS_MD" \
|
||||
| head -n 1 | sed -E 's/.*Total: ([0-9]+) tests.*/\1/')
|
||||
claimed_cgal=$(grep -E "\*\*Total: [0-9]+ tests, 0 skipped\.\*\*" "$TESTS_MD" \
|
||||
| tail -n 1 | sed -E 's/.*Total: ([0-9]+) tests.*/\1/')
|
||||
|
||||
# ── Compare ────────────────────────────────────────────────────────────────
|
||||
ok=1
|
||||
if [ "${actual_fast}" != "${claimed_fast}" ]; then
|
||||
echo "MISMATCH: non-CGAL — $TESTS_MD claims ${claimed_fast}, ctest reports ${actual_fast}"
|
||||
ok=0
|
||||
fi
|
||||
if [ "${actual_cgal}" != "${claimed_cgal}" ]; then
|
||||
echo "MISMATCH: CGAL — $TESTS_MD claims ${claimed_cgal}, ctest reports ${actual_cgal}"
|
||||
ok=0
|
||||
fi
|
||||
|
||||
if [ "$ok" -eq 0 ]; then
|
||||
cat <<EOF
|
||||
|
||||
FAIL: $TESTS_MD totals out of sync with actual test counts.
|
||||
|
||||
Recovery:
|
||||
1. Edit $TESTS_MD: update the two
|
||||
'**Total: N tests, 0 skipped.**' lines.
|
||||
2. Add/remove suite rows in the per-suite tables if test
|
||||
suites were added/removed.
|
||||
3. Re-run this script to confirm.
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "OK: test counts in $TESTS_MD match ctest output"
|
||||
echo " non-CGAL: ${actual_fast} CGAL: ${actual_cgal} total: $((actual_fast + actual_cgal))"
|
||||
exit 0
|
||||
@@ -10,7 +10,8 @@
|
||||
# bash scripts/try_it.sh
|
||||
#
|
||||
# Expected output (last lines):
|
||||
# [PASS] 227 CGAL tests pass, 0 skipped
|
||||
# [PASS] full CGAL test suite passes, 0 skipped
|
||||
# (current counts: doc/api/tests.md)
|
||||
# [PASS] 23 non-CGAL tests pass
|
||||
# [EXAMPLE] Converged in N iterations. ||G||_inf < 1e-9
|
||||
|
||||
|
||||
Reference in New Issue
Block a user