Feat/test quality execution#32
Merged
Merged
Conversation
…1.3.1) has_test_attr matched only path segments test/rstest/test_case, so a #[quickcheck] property fn (segment `quickcheck`, not ending in `test`) was treated as production code and could be flagged DEAD_CODE / uncovered. Add `quickcheck` to the last-segment match. Failing-first regression test added to framework_test_attributes_recognized. Slice 0a of the test-quality-execution plan. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
syn does not expand function-like macros, so #[test] fns declared inside
proptest!{} / quickcheck!{} were opaque Item::Macro nodes — invisible to
test classification and every analyzer dimension.
Add a macro-expansion pre-pass (adapters/shared/macro_expansion.rs) run
once at the top of run_analysis: it replaces a recognised test-macro
invocation with the fn items it declares, each marked #[test] so they
route through the shared cfg_test::has_test_attr recognition. Lenient by
design — proptest's non-Rust `x in <strategy>` params are dropped (body
preserved), a leading #![proptest_config(..)] is tolerated, and any parse
failure keeps the original opaque macro (blind spot, never a regression).
Recognition lives next to cfg_test in adapters/shared (one place for all
test-recognition policy).
run_analysis now takes parsed by value so the pre-pass can rewrite in
place; the single hook covers both production entry points and all tests.
Failing-first regression tests in
src/adapters/shared/tests/macro_expansion.rs. Slice 0b of the
test-quality-execution plan.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Introduces the configuration surface for applying a curated subset of checks to test code (Phase #1, Slice 1a — scaffolding only, no behaviour change yet). TestsConfig holds Option<usize> overrides — max_function_lines (LONG_FN), file_length_baseline, file_length_ceiling, max_methods — each defaulting to None, meaning the matching production threshold is inherited. So out of the box test code is judged by the same limits as production; a project can relax them per field. The curated APPLY/KEEP split itself is fixed (not configurable). Field names mirror [complexity] / [srp]. Resolver methods that read these are added in the consuming slices (1c LONG_FN, 1d SRP) to avoid dead code. Documented in rustqual.toml and book/reference-configuration.md; tests in config/tests/sections.rs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…tests Slice 1b cleanup (gate still off — pure test refactor). The pub_fns tests each repeated the same ~13-line PubFnInputs construction (empty wrapper / promoted-attr / workspace sets) verbatim across ~39 tests. Extract a pub_fns_by_layer(&files) helper; the 3 tests that need a non-empty set still call collect_pub_fns_by_layer directly. Cuts the DRY fallout on pub_fns.rs from 988 fragment entries → 2 and 56 duplicate-fn entries → 14 (measured with DRY applied to tests). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 1 of the test-quality-execution plan: a curated subset of quality checks now runs on test code, at `[tests]`-section thresholds that default to the production values. - DRY (DRY-001/004/005) run on tests; `[duplicates] ignore_tests` removed (BREAKING config: a stale `ignore_tests` line now fails to parse). - LONG_FN runs on test fns at `[tests].max_function_lines`. - SRP file-length (SRP_MODULE) runs on test files at `[tests].file_length_baseline`/`ceiling`. The SRP cohesion (independent-cluster) check stays PRODUCTION-ONLY — a test file's many independent `#[test]` fns are its purpose, not a low-cohesion smell. `analyze_module_srp` takes a `test_length_thresholds: (usize, usize)` tuple (one param to stay within SRP_PARAMS). Remediation done as real fixes, not suppressions: - ~25 oversized test files split along behavioral seams into focused directory sub-modules (mod.rs + thematic parts). - All 20 transient LONG_FN test suppressions added during 1c were then eliminated via arrange/act separation (const-hoisted fixtures/tables, fixture builders, dead-fixture removal, imports/docs lifted out of fn bodies). The total `qual:allow(complexity)` count is back to the pre-work baseline (9, all in production code) — net zero new suppressions across the whole effort. Docs: CLAUDE.md Test-aware bullet, README, CHANGELOG [1.4.0], rustqual.toml + book/reference-configuration.md `[tests]` section. Self-analysis (`cargo run -- . --fail-on-warnings`) = 0 findings across all seven dimensions; nextest green; clippy -Dwarnings clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…4.1) Phase 2 of the test-quality effort: prove the suite actually catches defects (cargo-mutants) and close the gaps it surfaced. Mutation coverage (cargo-mutants, --no-shuffle, nextest): - shared/cfg_test*: 89/89 non-equivalent viable mutants caught. - normalize.rs + macro_expansion.rs: survivors 70 -> 4 (128/132 caught); the 4 remaining are documented semantic equivalents (jaccard ||->&&, and the Call/Block/Paren arm deletions that fall to an identical default-recurse). Tests added: - shared/tests/normalize_coverage.rs: enumeration tests pinning the exact NormalizedToken for every binary op (28), unary op (3), expr-kind (incl. an expr-position `let _ = m!();` reaching the Expr::Macro arm), pattern-kind (11), and an or-pattern pipe-count test. - shared/tests/cfg_test.rs: path x test-attribute variant matrix + two proptest properties (qualified `::test` always recognized; non-test attrs never recognized). - shared/tests/cfg_test_files.rs: nested-src/bin and inline-mod propagation mutation-killers. - macro_expansion: non_test_macro_left_untouched strengthened to carry a parseable fn so `is_test_macro -> true` is forced to surface it. Production fixes surfaced during the effort: - TQ-001: is_assertion_macro now recognizes proptest's prop_assert!/ prop_assert_eq!/prop_assert_ne! so property tests are not false-flagged as assertion-free. - F1: architecture matcher's has_cfg_test_attr delegates to the shared cfg_test::has_cfg_test, giving #[cfg(test)] detection one source of truth. proptest added as a dev-dependency. .gitignore excludes mutants.out/. Version 1.4.1, CHANGELOG updated. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Phase 3 — full mutation sweep (cargo-mutants) extended from the shared core to every dimension plus app and report. All reachable survivors killed; only documented semantic equivalents remain. Drove asserts/oracles into many existing tests and split oversized test files along behaviour seams. Phase 4 — per-dimension relevance review against book/*-quality.md: positive AND negative per-rule coverage, oracle quality, behaviour- vs implementation-coupling, redundancy, test intent. Strengthened weak oracles (dry near-duplicate threshold, srp named clusters, architecture PatternScope::accepts scoping, coupling SDP-from-source) and added missing end-to-end pins. Follow-up design + review-finding fixes: - SRP: the god-struct check (SRP-001) deliberately applies to test code (a god-fixture wiring up many concerns is a real smell); only module-cohesion (independent clusters) stays production-only. Removed the dead [tests].max_methods knob and pinned the contract. - TQ-001: no longer flags quickcheck! `-> bool` properties as assertion-free — the boolean return is the property's oracle (a plain #[test] can't return bool). - DEH: honours a function's own #[test]/#[cfg(test)] attrs, so expanded quickcheck!/proptest! property bodies (and hand-written top-level #[test] fns) are no longer falsely flagged as production downcast escape hatches. - `rustqual --init` templates now include the [tests] section. - Docs: book BTC stub forms drop Default::default(); CLAUDE.md DRY rule IDs match the emitted ones (DRY-003 fragment, DRY-004 wildcard). Four gates green: cargo fmt, 1851 nextest, self-analysis 0 findings, clippy. CHANGELOG updated under [1.4.1]; no version bump. Co-Authored-By: Claude Opus 4.8 (1M context) <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.
No description provided.