Skip to content

Cli matrix testing#276

Merged
leynos merged 24 commits intomainfrom
cli-matrix-testing
Apr 27, 2026
Merged

Cli matrix testing#276
leynos merged 24 commits intomainfrom
cli-matrix-testing

Conversation

@leynos
Copy link
Copy Markdown
Owner

@leynos leynos commented Apr 25, 2026

Summary by Sourcery

Introduce a CLI option matrix integration test harness with snapshot-based verification and supporting documentation, plus a small refactor to satisfy linting in the wrapping postprocessor.

New Features:

  • Add a CLI matrix integration test harness that exercises curated combinations of transform flags in both stdout and --in-place modes using the real mdtablefix binary.
  • Introduce data-driven fixtures and insta snapshots to capture CLI behaviour across wrapped and unwrapped variants.

Enhancements:

  • Refactor inline wrapping postprocessing by extracting a helper to carry inline-code tails, addressing excessive nesting lints and improving readability.

Build:

  • Add insta as a dev-dependency for snapshot-based testing.

Documentation:

  • Document the CLI matrix harness, fixtures, and snapshot update workflow in the developer guide and an accompanying execution plan document.

Tests:

  • Add cli_matrix integration tests, shared support code, fixtures, and insta snapshot files to validate option interactions, pairwise transform coverage, and equivalence between stdout and --in-place output.

leynos added 2 commits April 25, 2026 15:25
Add an ExecPlan for the requested CLI option matrix test harness.
Capture the intended `assert_cmd` and `insta` structure, `.dat`
fixture convention, harness self-tests, developer-guide update, and
validation path before implementation begins.
Require every logical option combination to run through both
file-to-stdout formatting and `--in-place` formatting. Treat `--wrap`
as an explicit expansion over each selected non-wrap combination so the
harness guards the wrapped and unwrapped regression surface directly.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

Note

Reviews paused

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Add a deterministic CLI matrix integration test harness with self‑tests and insta snapshot envelopes, document an ExecPlan and developer guidance, add insta as a dev‑dependency, and refactor private inline‑code whitespace carry logic in wrap postprocess.

Changes

Cohort / File(s) Summary
Documentation & Plan
docs/execplans/cli-matrix-testing.md, docs/developers-guide.md
Add ExecPlan and developer‑guide section describing the CLI matrix harness: snapshot envelope format, fixture rules (.dat), deterministic expansion (base cases → wrap/no‑wrap → stdout/--in-place), self‑tests, staged rollout and INSTA_UPDATE=always snapshot workflow.
Test harness & support
tests/cli_matrix.rs, tests/cli_matrix/support.rs, tests/cli_matrix/invariants.rs, tests/data/cli-matrix/*
Introduce integration tests and support modules: declare transform flags and base cases, expand logical→physical cases, validate case IDs/fixture existence/coverage (wrap & pairwise flag coverage), stage fixtures into temp dirs, run mdtablefix via assert_cmd, collect RunResult envelopes, assert transform invariants, enforce stdout vs in‑place byte equality, and record insta snapshots.
Snapshot tooling dependency
Cargo.toml
Add insta to [dev-dependencies] to enable labelled envelope snapshot testing and the INSTA_UPDATE=always update workflow.
Wrap postprocess refactor
src/wrap/inline/postprocess.rs
Extract trailing inline‑code whitespace carry logic into a new private helper that returns bool; replace inline mutation logic at call site with helper call. No public API changes.

Sequence Diagram(s)

sequenceDiagram
  participant TestHarness as "Test Harness\n(rust tests)"
  participant TempFS as "Temporary FS\n(temp dir)"
  participant Binary as "mdtablefix\n(binary via assert_cmd)"
  participant SnapStore as "insta snapshots\n(snap files)"
  participant Asserts as "Assertions\n(coverage & equality)"

  TestHarness->>TempFS: create temp dir & stage fixture file
  TestHarness->>Binary: run binary with args (flags, --in-place or stdout)
  Binary-->>TestHarness: return stdout/stderr and exit status
  Binary->>TempFS: modify input file when --in-place
  TestHarness->>TempFS: read modified input file (if in-place)
  TestHarness->>SnapStore: emit envelope (case id, mode, args, status, stdout, stderr, file bytes)
  SnapStore-->>TestHarness: compare or update snapshot
  TestHarness->>Asserts: assert stdout == in-place content for same logical case
  TestHarness->>Asserts: assert coverage rules and unique IDs
Loading

Poem

🧪 Flags align in matrix rows,
Snapshots catch how output goes,
Harness runs both wrapped and plain,
Fixtures feed the steady train,
Tests keep regressions on their toes.


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (1 error, 3 warnings, 1 inconclusive)

Check name Status Explanation Resolution
Module-Level Documentation ❌ Error Five type definitions in tests/cli_matrix/support.rs place doc comments after #[derive(...)] attributes instead of before, violating Rust documentation conventions. Reorder documentation and derive attributes so /// doc comments precede #[derive(...)] for TransformFlag, BaseCase, WrapVariant, ExecutionMode, and LogicalCase types.
Developer Documentation ⚠️ Warning ExecPlan lacks status section indicating completion of staged work phases; doc comment placement violates Rust conventions (must precede #[derive] attributes). Add completion checklist to ExecPlan documenting each phase status. Reposition all /// doc comments before #[derive(...)] attributes throughout tests/cli_matrix/support.rs.
Testing (Unit) ⚠️ Warning PR introduces three fallible functions handling critical I/O operations and command execution without unit tests for error paths and edge cases. Add unit tests for stage_fixture and collect_result verifying error contexts using filesystem stubs or mock failures; add tests for run_physical_case validating error propagation from helpers.
Observability ⚠️ Warning The new carry_previous_inline_code_tail helper introduces an invariant violation detection point using debug_assert! instead of proper observability mechanisms, providing zero production visibility into silent failures. Add structured logging at the decision boundary to record fragment state and context, enabling maintainers to diagnose production issues without source inspection or local reproduction.
Title check ❓ Inconclusive The title 'Cli matrix testing' is vague and generic, using non-descriptive terms that fail to convey the specific scope of implementing a complete CLI matrix integration test harness with snapshots, documentation, and refactoring. Clarify the title to reflect the main changes: adopt a more specific format such as 'Implement CLI matrix integration test harness with snapshots and docs' or include relevant context per title-check requirements.
✅ Passed checks (13 passed)
Check name Status Explanation
Description check ✅ Passed The description is comprehensive and directly related to the changeset, covering the CLI matrix testing harness, snapshot-based verification, documentation, fixtures, and the inline postprocessor refactor.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Testing (Overall) ✅ Passed The test suite is substantive and rigorous, exercising the real mdtablefix binary through 32 physical cases with independent semantic invariants verifying expected output transformations.
User-Facing Documentation ✅ Passed PR introduces only testing infrastructure, developer documentation, and internal refactoring of a private helper function with no user-facing functionality, CLI options, or public API changes.
Testing (Property / Proof) ✅ Passed PR introduces three semantic invariants (ellipsis UTF-8 encoding, fence normalisation, list marker sequencing) validated through explicit deterministic assertions over finite input space.
Testing (Compile-Time / Ui) ✅ Passed Snapshot testing with semantic assertions validates CLI output behaviour; invariants verify ellipsis conversion, fence normalisation, and list marker elimination.
Unit Architecture ✅ Passed PR demonstrates explicit fallibility handling via Result types, clear query/command separation, dependency injection without global state, and appropriately scoped responsibilities across tests and semantic validators.
Domain Architecture ✅ Passed The pull request maintains strict domain architecture boundaries with proper test infrastructure isolation and no domain-layer coupling to test concerns.
Security And Privacy ✅ Passed PR introduces no security or privacy risks; uses safe path construction, standard binary invocation patterns, static argument passing, secure temporary directories, and proper UTF-8 handling.
Performance And Resource Use ✅ Passed PR introduces test infrastructure and helper extraction with no performance regression; 36 bounded physical test cases with negligible I/O and linear iteration patterns.
Concurrency And State ✅ Passed PR introduces no shared mutable state, concurrency primitives, or ordering constraints. All static references are immutable string and array literals. Test isolation properly achieved through temporary directory scoping with automatic cleanup.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cli-matrix-testing

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai
Copy link
Copy Markdown
Contributor

sourcery-ai Bot commented Apr 25, 2026

Reviewer's Guide

Adds a CLI option matrix integration test harness for the mdtablefix binary using assert_cmd + insta snapshots, supported by new .dat fixtures, self-tests for matrix coverage, and a small refactor in wrap postprocessing to satisfy clippy; also documents the harness and its workflow in the developer guide and an ExecPlan.

Sequence diagram for cli_matrix_snapshots test execution

sequenceDiagram
    participant Test as cli_matrix_snapshots
    participant Runner as CliMatrixRunner
    participant Fixture as Fixture
    participant TempFile as TempFile
    participant Cmd as assert_cmd_Command
    participant Bin as mdtablefix_binary
    participant Insta as insta

    Test->>Runner: all_logical_cases()
    loop for each LogicalMatrixCase
        Runner->>Runner: expand_to_physical_cases()
        loop for each PhysicalMatrixCase
            Runner->>Fixture: get path()
            Fixture-->>Runner: fixture_path

            Runner->>TempFile: copy fixture to temp file
            TempFile-->>Runner: temp_path

            Runner->>Cmd: cargo_bin(mdtablefix)
            Runner->>Cmd: args(cli_args including temp_path)
            Cmd->>Bin: spawn process
            Bin-->>Cmd: exit_code, stdout, stderr
            Cmd-->>Runner: Output

            Runner->>TempFile: read temp file (for InPlace only)
            TempFile-->>Runner: rewritten_content or empty

            Runner->>Runner: build ResultEnvelope
            Runner-->>Test: ResultEnvelope

            Test->>Insta: assert_snapshot!(ResultEnvelope.format_for_snapshot())
        end

        Test->>Runner: assert_stdout_matches_in_place(LogicalMatrixCase)
        Runner->>Runner: compare stdout vs rewritten_file for pair
    end
Loading

Class diagram for CLI matrix harness types

classDiagram
    class NonWrapTransformFlag {
        <<enum>>
        RENumber
        BREAKS
        ELLIPSIS
        FENCES
        FOOTNOTES
        CODE_EMPHASIS
        HEADINGS
    }

    class WrapVariant {
        <<enum>>
        Nowrap
        Wrap
    }

    class ExecMode {
        <<enum>>
        Stdout
        InPlace
    }

    class Fixture {
        +String id
        +String path
        +bool exists()
        +bool has_dat_extension()
    }

    class BaseMatrixCase {
        +String id
        +Fixture fixture
        +Set~NonWrapTransformFlag~ flags
        +Vec~LogicalMatrixCase~ expand_to_logical_cases()
    }

    class LogicalMatrixCase {
        +String id
        +Fixture fixture
        +Set~NonWrapTransformFlag~ flags
        +WrapVariant wrap
        +Vec~PhysicalMatrixCase~ expand_to_physical_cases()
    }

    class PhysicalMatrixCase {
        +String id
        +Fixture fixture
        +Set~NonWrapTransformFlag~ flags
        +WrapVariant wrap
        +ExecMode exec_mode
        +Vec~String~ cli_args()
        +ResultEnvelope run()
    }

    class ResultEnvelope {
        +String case_id
        +WrapVariant wrap
        +ExecMode exec_mode
        +Vec~String~ args
        +i32 exit_code
        +String stdout
        +String stderr
        +Option~String~ rewritten_file
        +String format_for_snapshot()
    }

    class CliMatrixRunner {
        +Vec~BaseMatrixCase~ base_cases
        +Vec~LogicalMatrixCase~ all_logical_cases()
        +Vec~PhysicalMatrixCase~ all_physical_cases()
        +ResultEnvelope run_case(PhysicalMatrixCase case_)
        +void assert_stdout_matches_in_place(LogicalMatrixCase logical)
        +void assert_snapshots()
    }

    class CliMatrixSelfTests {
        +void matrix_case_ids_are_unique(CliMatrixRunner runner)
        +void matrix_cases_expand_to_stdout_and_in_place(CliMatrixRunner runner)
        +void matrix_cases_expand_to_wrapped_and_unwrapped(CliMatrixRunner runner)
        +void matrix_cases_cover_all_transform_pairs(CliMatrixRunner runner)
        +void matrix_fixtures_are_dat_and_exist(CliMatrixRunner runner)
    }

    class CarryPreviousInlineCodeTailHelper {
        +bool carry_previous_inline_code_tail(
            Vec~Vec~InlineFragment~~ merged,
            Vec~InlineFragment~ pending_whitespace
        )
    }

    class InlineFragment {
        +FragmentKind kind
        +bool is_plain()
    }

    class FragmentKind {
        <<enum>>
        InlineCode
        Other
    }

    %% Relationships
    BaseMatrixCase "1" o-- "1" Fixture
    BaseMatrixCase "1" *-- "*" LogicalMatrixCase
    LogicalMatrixCase "1" o-- "1" Fixture
    LogicalMatrixCase "1" *-- "2" PhysicalMatrixCase
    PhysicalMatrixCase "1" o-- "1" Fixture
    PhysicalMatrixCase "1" o-- "1" WrapVariant
    PhysicalMatrixCase "1" o-- "1" ExecMode
    PhysicalMatrixCase "*" o-- "*" NonWrapTransformFlag
    PhysicalMatrixCase "1" --> "1" ResultEnvelope

    CliMatrixRunner "1" *-- "*" BaseMatrixCase
    CliMatrixRunner "1" ..> ResultEnvelope
    CliMatrixSelfTests ..> CliMatrixRunner

    CarryPreviousInlineCodeTailHelper ..> InlineFragment
    InlineFragment ..> FragmentKind
Loading

Flow diagram for CLI matrix case expansion and self-tests

flowchart TD
    A[Start matrix harness] --> B[Load BASE_MATRIX_CASES]
    B --> C[Expand each BaseMatrixCase to wrapped and unwrapped LogicalMatrixCase]
    C --> D[Expand each LogicalMatrixCase to Stdout and InPlace PhysicalMatrixCase]

    D --> E[Self-test: matrix_case_ids_are_unique]
    E --> F[Self-test: matrix_fixtures_are_dat_and_exist]
    F --> G[Self-test: matrix_cases_expand_to_stdout_and_in_place]
    G --> H[Self-test: matrix_cases_expand_to_wrapped_and_unwrapped]
    H --> I[Self-test: matrix_cases_cover_all_transform_pairs]

    I --> J{All self-tests pass?}
    J -- No --> K[Fail cli_matrix harness tests]
    J -- Yes --> L[Run cli_matrix_snapshots]

    L --> M[For each PhysicalMatrixCase: run mdtablefix via assert_cmd]
    M --> N[Build ResultEnvelope and assert_snapshot via insta]
    N --> O[Assert stdout output equals InPlace rewritten file per LogicalMatrixCase]
    O --> P[cli_matrix harness complete]
Loading

File-Level Changes

Change Details Files
Introduce a reusable CLI matrix test support module and matrix catalogue to generate wrapped/unwrapped and stdout/in-place variants over selected transform-flag combinations.
  • Define TransformFlag enum and ALL_FLAGS slice for the seven non-wrap CLI transform flags and map them to CLI arguments.
  • Define BaseCase, LogicalCase, and PhysicalCase types plus expansion helpers to derive logical cases (wrap/nowrap) and physical cases (stdout/in_place) from a curated BASE_MATRIX_CASES catalogue.
  • Implement RunResult, run_physical_case, and envelope formatting to execute mdtablefix via assert_cmd against temp-file copies of fixtures and capture status/stdout/stderr/file content for snapshots.
  • Provide helpers for fixture path resolution, case-id validation, non-wrap signature computation, and per-flag membership checks.
tests/cli_matrix/support.rs
Add CLI matrix integration tests that validate matrix integrity and generate insta snapshots for each logical/mode combination.
  • Add tests to assert base case IDs are valid and unique, fixtures exist and use .dat extension, logical cases expand into both stdout and --in-place physical runs, and each non-wrap signature has both wrapped and unwrapped variants.
  • Add coverage tests to ensure each transform flag appears enabled and disabled, and that every pair of flags appears in all four enabled/disabled combinations across the base matrix.
  • Implement cli_matrix_snapshots test that runs both stdout and --in-place modes for each logical case, asserts stdout equals in-place file output, and records insta snapshots using stable snapshot names derived from case ID and mode.
tests/cli_matrix.rs
Provision input fixtures and insta snapshots for the CLI matrix harness.
  • Add four .dat fixtures under a dedicated cli-matrix data directory to exercise different content patterns (tables/prose, fences/ellipsis, footnotes, frontmatter/breaks).
  • Check in 32 insta snapshot files, one per logical+mode combination (8 base rows × wrap/nowrap × stdout/in-place), capturing labelled envelopes of each run.
tests/data/cli-matrix/fences-ellipsis.dat
tests/data/cli-matrix/footnotes.dat
tests/data/cli-matrix/frontmatter-breaks.dat
tests/data/cli-matrix/table-prose.dat
tests/snapshots/cli_matrix__row_000_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_000_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_000_wrap_in_place.snap
tests/snapshots/cli_matrix__row_000_wrap_stdout.snap
tests/snapshots/cli_matrix__row_001_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_001_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_001_wrap_in_place.snap
tests/snapshots/cli_matrix__row_001_wrap_stdout.snap
tests/snapshots/cli_matrix__row_010_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_010_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_010_wrap_in_place.snap
tests/snapshots/cli_matrix__row_010_wrap_stdout.snap
tests/snapshots/cli_matrix__row_011_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_011_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_011_wrap_in_place.snap
tests/snapshots/cli_matrix__row_011_wrap_stdout.snap
tests/snapshots/cli_matrix__row_100_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_100_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_100_wrap_in_place.snap
tests/snapshots/cli_matrix__row_100_wrap_stdout.snap
tests/snapshots/cli_matrix__row_101_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_101_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_101_wrap_in_place.snap
tests/snapshots/cli_matrix__row_101_wrap_stdout.snap
tests/snapshots/cli_matrix__row_110_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_110_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_110_wrap_in_place.snap
tests/snapshots/cli_matrix__row_110_wrap_stdout.snap
tests/snapshots/cli_matrix__row_111_nowrap_in_place.snap
tests/snapshots/cli_matrix__row_111_nowrap_stdout.snap
tests/snapshots/cli_matrix__row_111_wrap_in_place.snap
tests/snapshots/cli_matrix__row_111_wrap_stdout.snap
Document the CLI matrix harness design, workflow, and execution plan.
  • Extend the developer guide with a CLI matrix harness section describing purpose, base catalogue, wrap/in-place expansion, .dat fixture convention, self-tests, and snapshot update commands.
  • Add an ExecPlan document detailing constraints, risks, implementation stages, progress log, decisions, and acceptance criteria for the CLI matrix testing rollout.
docs/developers-guide.md
docs/execplans/cli-matrix-testing.md
Refactor inline wrap postprocessing to remove excessive nesting and clarify behaviour when merging whitespace-only lines adjacent to inline-code tails.
  • Extract carry_previous_inline_code_tail helper that moves a trailing InlineCode fragment from the previous merged line into pending whitespace handling, popping the previous line if it becomes empty.
  • Replace the inlined nested logic in merge_whitespace_only_lines with a call to the helper while preserving previous carry-whitespace behaviour.
src/wrap/inline/postprocess.rs
Add insta as a dev-dependency to support snapshot testing.
  • Declare insta = "1" under dev-dependencies so tests/cli_matrix.rs can use insta::assert_snapshot!.
  • Update Cargo.lock (not shown inline) to include insta and its transitive dependencies.
Cargo.toml
Cargo.lock

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 26, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot added the Roadmap label Apr 26, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/execplans/cli-matrix-testing.md`:
- Line 25: The phrase "required paired variant" in the wrap-coverage requirement
should be rewritten to standard grammar and en-GB-oxendict style; locate the
sentence mentioning `--wrap` (the wrap-coverage requirement) and replace
"required paired variant" with either "required pair" or "required to be paired"
(e.g., "`--wrap` is required to be paired" or "`--wrap` requires a paired
option") so the sentence is clear and grammatically correct.
- Around line 340-343: The documented Git command is invalid: replace the usage
of "git branch --show" with the correct "git branch --show-current" in the CLI
execution steps so the workflow commands (the two-line snippet containing "pwd"
and "git branch --show") run correctly; update that code block to use "git
branch --show-current" instead.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 30cf4944-9b8a-42e8-9f76-9f3fd564d301

📥 Commits

Reviewing files that changed from the base of the PR and between 2de1134 and 1f2eec7.

📒 Files selected for processing (1)
  • docs/execplans/cli-matrix-testing.md

Comment thread docs/execplans/cli-matrix-testing.md Outdated
Comment thread docs/execplans/cli-matrix-testing.md
leynos added 2 commits April 26, 2026 16:22
Address review feedback on the draft matrix ExecPlan by tightening the
`--wrap` coverage sentence and replacing the invalid branch inspection
command with `git branch --show-current`.
Implement the approved CLI matrix harness with `assert_cmd` and `insta`.
The matrix covers seven non-wrap transform flags, expands every base row
through wrapped and unwrapped variants, and runs each logical case through
both file-to-stdout and `--in-place` execution.

Add `.dat` fixtures so formatter runs do not rewrite matrix input data,
commit the initial 32 snapshots, and document the harness workflow in the
developer guide.

Extract the existing inline-code whitespace carry logic in
`postprocess.rs` into a helper so the warning-deny lint gate remains clean.
@leynos leynos marked this pull request as ready for review April 26, 2026 16:49
sourcery-ai[bot]

This comment was marked as resolved.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Cargo.toml`:
- Line 34: The dependency version for insta is too broad ("insta = \"1\"");
update the Cargo.toml entry for the insta dependency to an explicit, stable
minor version (e.g., change the insta declaration to something like insta =
"1.47" or later) so builds are reproducible and consistent with other deps such
as rayon and rstest.

In `@docs/execplans/cli-matrix-testing.md`:
- Around line 3-5: The markdown list has a stray leading space before the item
"Tolerances" which breaks list formatting; edit the line containing "Tolerances"
(the list item string `Tolerances`) and remove the leading space so it aligns
with the other list items, ensuring all bullet/list items use the same
indentation and consistent formatting.

In `@tests/cli_matrix/support.rs`:
- Around line 277-282: The is_case_id function currently forbids hyphens while
the ExecPlan permits them; update is_case_id (the function named is_case_id in
tests/cli_matrix/support.rs) to accept ASCII hyphen as well by including byte ==
b'-' in the predicate (alongside byte.is_ascii_lowercase(),
byte.is_ascii_digit(), and byte == b'_'), or alternatively amend the ExecPlan
documentation to remove hyphen from the allowed characters if hyphens are
intentionally disallowed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ebf937da-523c-4f68-8107-9b97d700380a

📥 Commits

Reviewing files that changed from the base of the PR and between 1f2eec7 and 4dd7d90.

⛔ Files ignored due to path filters (37)
  • Cargo.lock is excluded by !**/*.lock
  • tests/data/cli-matrix/fences-ellipsis.dat is excluded by !**/*.dat
  • tests/data/cli-matrix/footnotes.dat is excluded by !**/*.dat
  • tests/data/cli-matrix/frontmatter-breaks.dat is excluded by !**/*.dat
  • tests/data/cli-matrix/table-prose.dat is excluded by !**/*.dat
  • tests/snapshots/cli_matrix__row_000_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_000_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_000_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_000_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_001_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_001_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_001_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_001_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_010_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_010_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_010_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_010_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_011_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_011_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_011_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_011_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_100_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_100_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_100_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_100_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_101_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_101_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_101_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_101_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_110_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_110_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_110_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_110_wrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_111_nowrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_111_nowrap_stdout.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_111_wrap_in_place.snap is excluded by !**/*.snap
  • tests/snapshots/cli_matrix__row_111_wrap_stdout.snap is excluded by !**/*.snap
📒 Files selected for processing (6)
  • Cargo.toml
  • docs/developers-guide.md
  • docs/execplans/cli-matrix-testing.md
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix.rs
  • tests/cli_matrix/support.rs

Comment thread Cargo.toml Outdated
Comment thread docs/execplans/cli-matrix-testing.md
Comment thread tests/cli_matrix/support.rs
@leynos

This comment was marked as resolved.

Pin `insta` to the current minor line, fix the ExecPlan heading text
indentation, and allow hyphens in matrix case identifiers so the harness
matches the documented case-id contract.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== tests/cli_matrix/support.rs ==="
cat tests/cli_matrix/support.rs

echo ""
echo "=== tests/cli_matrix.rs ==="
cat tests/cli_matrix.rs

echo ""
echo "=== docs/execplans/cli-matrix-testing.md (is_case_id section) ==="
grep -n "hyphen\|case.id\|case_id\|identifier\|[a-z]-\|\[a-z0-9\]" docs/execplans/cli-matrix-testing.md | head -40

Length of output: 15153


🏁 Script executed:

#!/bin/bash
echo "=== ExecPlan: case identifier / grammar section ==="
grep -n -A3 -B3 "hyphen\|[a-z0-9_\-]\|regex\|character.*id\|id.*character\|grammar\|valid.*id\|id.*valid\|pattern\|alpha\|digit\|lower" \
    docs/execplans/cli-matrix-testing.md | head -80

Length of output: 4854


🏁 Script executed:

#!/bin/bash
echo "=== ExecPlan: full Stage C / is_case_id section ==="
grep -n -A5 -B2 "case_id\|is_case\|Stage C\|stage.*C\|identifier.*char\|char.*identifier\|[a-z].*digit\|ascii_lower" \
    docs/execplans/cli-matrix-testing.md

echo ""
echo "=== ExecPlan: search for hyphen keyword ==="
grep -n -i "hyphen\|b'-'\|byte.*'-'" docs/execplans/cli-matrix-testing.md

echo ""
echo "=== ExecPlan: lines mentioning id format/grammar ==="
sed -n '140,250p' docs/execplans/cli-matrix-testing.md

Length of output: 7678


@leynos: None of the five checks have been resolved. Here is the current status and an AI agent prompt for each.


Status

Check Resolved? Evidence
Testing (Overall) ❌ No cli_matrix_snapshots still only calls insta::assert_snapshot!; no per-transformation semantic assertions exist.
Module-Level Documentation ❌ No Every public entity in tests/cli_matrix/support.rs (all enums, structs, fields, constants, and free functions) still has no /// doc comment.
Unit Architecture ❌ No run_physical_case() still returns RunResult, still uses multiple .expect() calls, and still bundles staging, execution, and collection in one function.
Docstring Coverage ❌ No Downstream of Module-Level Documentation; coverage cannot reach 80 % until the above is fixed.
Developer Documentation (is_case_id hyphen) ❌ No ExecPlan Stage C (line 362–363) specifies "lowercase letters, digits, hyphens, and underscores", but is_case_id() still contains no `

AI agent prompts

Prompt A — Fix is_case_id to accept hyphens

File: tests/cli_matrix/support.rs

The ExecPlan (docs/execplans/cli-matrix-testing.md, lines 362-363) states that
case identifiers must contain only lowercase letters, digits, hyphens, and
underscores. The current `is_case_id()` implementation accepts only
[a-z0-9_] and rejects hyphens.

Add `|| byte == b'-'` to the byte predicate so the function matches the spec:

    pub(crate) fn is_case_id(id: &str) -> bool {
        !id.is_empty()
            && id.bytes().all(|byte| {
                byte.is_ascii_lowercase()
                    || byte.is_ascii_digit()
                    || byte == b'_'
                    || byte == b'-'
            })
    }

Make no other changes to this function. Run `cargo test --test cli_matrix
matrix_case_ids_are_unique` and confirm the test still passes.

Prompt B — Add /// doc comments to all public entities in tests/cli_matrix/support.rs

File: tests/cli_matrix/support.rs

Every pub(crate) item in this file currently lacks a doc comment. Add a ///
doc comment to each of the following:

Enums and their variants (use a short sentence per variant):
- TransformFlag (describe: represents a non-wrap CLI transform flag)
- WrapVariant (describe: represents whether --wrap is active)
- ExecutionMode (describe: represents how the binary is invoked)

Structs and all their pub(crate) fields:
- BaseCase  (id, fixture, flags)
- LogicalCase  (id, fixture, is_wrapped, flags)
- PhysicalCase  (logical, mode)
- RunResult  (output, file_content)

Constants:
- ALL_FLAGS  (describe: ordered slice of every non-wrap transform flag)
- BASE_MATRIX_CASES  (describe: the curated pairwise base matrix rows)

Methods:
- TransformFlag::as_arg
- RunResult::envelope
- PhysicalCase::snapshot_name
- PhysicalCase::args

Free functions:
- logical_cases
- physical_cases
- run_physical_case
- fixture_path
- is_case_id
- non_wrap_signature
- has_flag

Keep each doc comment concise (one to three sentences). Do not alter any
function signatures or implementations. Run `cargo doc --no-deps 2>&1 | grep
"missing documentation"` to confirm no items are flagged.

Prompt C — Refactor run_physical_case for explicit fallibility and separation of concerns

File: tests/cli_matrix/support.rs

The `run_physical_case()` function currently:
- returns `RunResult` (not a `Result`), hiding I/O failures behind .expect()
- bundles fixture staging, binary execution, and output collection into one
  function, making failures hard to diagnose

Perform the following refactor:

1. Extract `stage_fixture(case: &PhysicalCase, dir: &Path)
   -> Result<PathBuf, Box<dyn std::error::Error>>` that copies the fixture to
   `dir/input.md` and returns the destination path.

2. Extract `collect_result(output: Output, file_path: &Path, mode: ExecutionMode)
   -> Result<RunResult, Box<dyn std::error::Error>>` that reads the (possibly
   rewritten) file and constructs the RunResult.

3. Change `run_physical_case` to return
   `Result<RunResult, Box<dyn std::error::Error>>`, call the two helpers, and
   propagate errors with `?` instead of `.expect()`. Remove the
   `assert!(output.status.success(), ...)` call from this function.

4. In `tests/cli_matrix.rs`, update `cli_matrix_snapshots` to call
   `run_physical_case(...).expect("run physical case")` at the call site, and
   add an explicit `assert!(result.output.status.success(), ...)` assertion
   immediately after each call so the success check is visible in the test body.

Keep the public signature of `run_physical_case` identical in name. Ensure
`cargo test --test cli_matrix` passes in full after the refactor.

Prompt D — Add semantic transformation assertions to cli_matrix_snapshots

File: tests/cli_matrix.rs  (and tests/cli_matrix/support.rs if helpers are needed)

The `cli_matrix_snapshots` test currently only captures insta snapshots. It
has no independent oracle confirming that the binary actually applied the
requested transformations.

For each physical case whose flags include specific transforms, add an explicit
assertion on stdout content before the snapshot call. At minimum:

- When TransformFlag::Ellipsis is active: assert that the stdout bytes contain
  the UTF-8 sequence for "…" (U+2026) if the fixture contains "...".
- When TransformFlag::Fences is active: assert stdout contains at least one
  fenced code block delimiter ("```") if the fixture contains indented code.
- When TransformFlag::Renumber is active: assert that the stdout does not
  contain a list item numbered out of sequence (e.g. "2." directly following
  "1." should become "2.").

Add a helper `assert_transform_invariants(logical: &LogicalCase, stdout: &[u8])`
in `tests/cli_matrix/support.rs` that contains these checks and is called from
`cli_matrix_snapshots` after obtaining `stdout_result` but before the snapshot
assertions.

Document each assertion with a comment explaining which CLI flag it validates
and what property it confirms. Keep the existing insta snapshot calls in place.
Run `cargo test --test cli_matrix cli_matrix_snapshots` and confirm all
assertions pass with the current snapshots.

Preserve the original fixture filename when copying matrix inputs into
temporary directories so failed runs are easier to inspect.

Make the inline-code tail invariant explicit with `expect` after the
preceding `last()` check, and add a focused assertion that matrix case
IDs accept the documented hyphen character.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@docs/execplans/cli-matrix-testing.md`:
- Around line 29-31: Remove the stale "This plan is draft-only until approved."
disclaimer and replace it with a short completion-state sentence that reflects
the plan is finished (e.g., "This ExecPlan is complete and approved."), ensure
the document text (the new completion statement) is consistent with the existing
`Status: COMPLETE` field and with the implemented outcomes recorded later, and
remove or update the reference to `docs/developers-guide.md` so it no longer
implies outstanding work.

In `@tests/cli_matrix/support.rs`:
- Around line 12-293: The build fails the documentation gate because many
pub(crate) items in this test harness lack Rustdoc; either add short /// doc
comments to each exposed item (e.g., TransformFlag, TransformFlag::as_arg,
BaseCase, WrapVariant, WrapVariant::id_part, ExecutionMode,
ExecutionMode::id_part, LogicalCase, PhysicalCase, RunResult, ALL_FLAGS,
BASE_MATRIX_CASES, RunResult::envelope, PhysicalCase::snapshot_name,
PhysicalCase::args, logical_cases, physical_cases, run_physical_case,
fixture_path, is_case_id, non_wrap_signature, has_flag) describing their
purpose, parameters and return where applicable, or reduce visibility from
pub(crate) to private for any item not required outside the module; update docs
for fields as well (e.g., LogicalCase.id/fixture/is_wrapped/flags) so the doc
gate passes.
- Around line 247-267: Refactor run_physical_case to stop panicking and instead
return a Result<RunResult, E>: replace all .expect() and assert!-style checks
inside run_physical_case with ?-based error propagation, split responsibilities
into small helpers (e.g., stage_fixture -> creates tempdir, copies fixture and
returns file_path; run_command -> spawns Command::cargo_bin("mdtablefix") with
args and returns Output; collect_result -> reads file_content and constructs
RunResult) and have run_physical_case call them and return Ok(RunResult). Move
the status.success() assertion out of run_physical_case into callers/tests so
the fixture layer never asserts; keep identifiers like run_physical_case,
RunResult, tempdir(), fixture_path, Command::cargo_bin("mdtablefix"), and
file_path to locate the code to change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c76454c4-d114-4383-a9fe-03a5f7757a88

📥 Commits

Reviewing files that changed from the base of the PR and between 4dd7d90 and 7656244.

📒 Files selected for processing (3)
  • Cargo.toml
  • docs/execplans/cli-matrix-testing.md
  • tests/cli_matrix/support.rs

Comment thread docs/execplans/cli-matrix-testing.md Outdated
Comment thread tests/cli_matrix/support.rs Outdated
Comment thread tests/cli_matrix/support.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
tests/cli_matrix/support.rs (2)

247-267: ⚠️ Potential issue | 🟠 Major

Propagate fixture errors with Result and remove panicking calls from shared helpers.

Refactor run_physical_case to return Result<RunResult> and replace .expect()/assert! with ? plus context. Split staging, execution, and collection into dedicated helpers. Perform status.success() assertions in the calling tests.

Proposed refactor
 use std::{
     fs,
     path::{Path, PathBuf},
     process::Output,
 };

+use anyhow::{Context, Result};
 use assert_cmd::Command;
-use tempfile::tempdir;
+use tempfile::{tempdir, TempDir};

-pub(crate) fn run_physical_case(case: &PhysicalCase) -> RunResult {
-    let dir = tempdir().expect("create temporary directory");
-    let file_path = dir.path().join(case.logical.fixture);
-    fs::copy(fixture_path(case.logical.fixture), &file_path).expect("copy matrix fixture");
-
-    let mut command = Command::cargo_bin("mdtablefix").expect("create mdtablefix command");
-    command.args(case.args()).arg(&file_path);
-    let output = command.output().expect("run mdtablefix");
-    assert!(
-        output.status.success(),
-        "{} failed with stderr:\n{}",
-        case.snapshot_name(),
-        String::from_utf8_lossy(&output.stderr),
-    );
-
-    let file_content = fs::read(&file_path).expect("read matrix output file");
-    RunResult {
-        output,
-        file_content,
-    }
+pub(crate) fn run_physical_case(case: &PhysicalCase) -> Result<RunResult> {
+    let (_dir, file_path) = stage_fixture(case)?;
+    let output = execute_case(case, &file_path)?;
+    let file_content = fs::read(&file_path)
+        .with_context(|| format!("read matrix output file {}", file_path.display()))?;
+    Ok(RunResult { output, file_content })
+}
+
+fn stage_fixture(case: &PhysicalCase) -> Result<(TempDir, PathBuf)> {
+    let dir = tempdir().context("create temporary directory")?;
+    let file_path = dir.path().join(case.logical.fixture);
+    fs::copy(fixture_path(case.logical.fixture), &file_path)
+        .with_context(|| format!("copy matrix fixture to {}", file_path.display()))?;
+    Ok((dir, file_path))
+}
+
+fn execute_case(case: &PhysicalCase, file_path: &Path) -> Result<Output> {
+    let mut command = Command::cargo_bin("mdtablefix").context("create mdtablefix command")?;
+    command.args(case.args()).arg(file_path);
+    command.output().context("run mdtablefix")
 }
#!/bin/bash
set -euo pipefail

FILE="tests/cli_matrix/support.rs"

echo "== run_physical_case signature =="
rg -nP 'pub\(crate\)\s+fn\s+run_physical_case\s*\(' "$FILE" -A20 -B2

echo
echo "== panicking calls in shared helper module =="
rg -nP '\.expect\(|assert!\(' "$FILE"

As per coding guidelines, **/*.rs: "In Rust production code and shared fixtures, avoid .expect() entirely; return Result and use ? to propagate errors instead of panicking."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix/support.rs` around lines 247 - 267, Change run_physical_case
to return a Result<RunResult, E> (propagate a suitable error type like
anyhow::Error) and stop panicking inside it: break the current body into three
helpers (e.g., stage_fixture, execute_mdtablefix, collect_output) referenced
from run_physical_case; in those helpers replace all .expect() calls with ? plus
contextual errors and return Results, and remove the
assert!(output.status.success()) from inside run_physical_case so test callers
perform the success assertion themselves; keep identifiers PhysicalCase,
RunResult, and the existing command building logic
(Command::cargo_bin("mdtablefix")) but propagate errors via ? and return
Ok(RunResult { output, file_content }) on success.

12-293: ⚠️ Potential issue | 🟠 Major

Document exposed harness APIs or reduce visibility immediately.

Add /// Rustdoc comments for all pub(crate) enums, structs, public fields, constants, methods, and free functions in this module, or make non-shared items private now.

#!/bin/bash
set -euo pipefail

python - <<'PY'
from pathlib import Path

path = Path("tests/cli_matrix/support.rs")
lines = path.read_text().splitlines()

for idx, line in enumerate(lines, start=1):
    s = line.strip()
    if "pub(crate)" in s and not s.startswith("//"):
        j = idx - 1
        while j > 0 and lines[j-1].strip() == "":
            j -= 1
        prev = lines[j-1].strip() if j > 0 else ""
        if not prev.startswith("///"):
            print(f"Line {idx}: missing Rustdoc -> {s}")
PY

As per coding guidelines, **/*.rs: "Document public APIs in Rust using Rustdoc comments (///) so documentation can be generated with cargo doc."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix/support.rs` around lines 12 - 293, Many items in this module
are exported with pub(crate) but lack Rustdoc; either add brief /// comments for
each exported symbol (at minimum a one-line description) or reduce their
visibility to private if they are not intended to be shared: apply this to enums
and methods TransformFlag and TransformFlag::as_arg, BaseCase, WrapVariant and
WrapVariant::id_part, ExecutionMode and ExecutionMode::id_part, LogicalCase,
PhysicalCase and PhysicalCase::snapshot_name/PhysicalCase::args, RunResult and
RunResult::envelope, constants ALL_FLAGS and BASE_MATRIX_CASES, and free
functions logical_cases, physical_cases, run_physical_case, fixture_path,
is_case_id, non_wrap_signature, has_flag; ensure each pub(crate) item receives a
/// doc comment placed immediately above its declaration or change the
visibility to remove pub(crate).
tests/cli_matrix.rs (1)

127-155: ⚠️ Potential issue | 🟠 Major

Add behavioural assertions and stop using snapshots as the sole oracle.

Assert transform semantics explicitly in cli_matrix_snapshots before snapshotting. Validate concrete enabled/disabled outcomes per transform on focused cases, then keep snapshots for regression visibility only.

Based on learnings, "Create or update CLI matrix snapshots only when the behaviour change is intentional; review generated tests/snapshots/cli_matrix__*.snap files before committing and inspect snapshot churn to detect if a fixture is too broad or a shared transform changed behaviour."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix.rs` around lines 127 - 155, In cli_matrix_snapshots, add
explicit behavioral assertions before the insta snapshots: for a few focused
logical cases (from logical_cases()) call run_physical_case (as done for
stdout_result and in_place_result) and assert concrete transform outcomes (e.g.,
enabled/disabled flags, expected output fragments or presence/absence of
transforms) by inspecting stdout_result.output and in_place_result.file_content
or the structures returned by envelope(&stdout_case); then keep the existing
insta::assert_snapshot! calls only for regression visibility. Target the same
symbols used here (cli_matrix_snapshots, logical_cases, PhysicalCase,
ExecutionMode::Stdout/InPlace, run_physical_case, snapshot_name, envelope) so
the new assertions live adjacent to the snapshotting and validate semantics
before snapshot updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/wrap/inline/postprocess.rs`:
- Around line 34-57: The helper carry_previous_inline_code_tail currently uses
.expect(...) which can panic; change the pop() call on previous_line to a
non-panicking pattern (e.g., match or let Some(previous_atomic) =
previous_line.pop() else { return false; }) so the function returns false
instead of panicking when no element is present, then push previous_atomic into
pending_whitespace and keep the existing logic that pops merged if previous_line
becomes empty; ensure you reference the same symbols (merged,
pending_whitespace, previous_line, previous_atomic, InlineFragment,
FragmentKind) and preserve the function's boolean return contract.

---

Duplicate comments:
In `@tests/cli_matrix.rs`:
- Around line 127-155: In cli_matrix_snapshots, add explicit behavioral
assertions before the insta snapshots: for a few focused logical cases (from
logical_cases()) call run_physical_case (as done for stdout_result and
in_place_result) and assert concrete transform outcomes (e.g., enabled/disabled
flags, expected output fragments or presence/absence of transforms) by
inspecting stdout_result.output and in_place_result.file_content or the
structures returned by envelope(&stdout_case); then keep the existing
insta::assert_snapshot! calls only for regression visibility. Target the same
symbols used here (cli_matrix_snapshots, logical_cases, PhysicalCase,
ExecutionMode::Stdout/InPlace, run_physical_case, snapshot_name, envelope) so
the new assertions live adjacent to the snapshotting and validate semantics
before snapshot updates.

In `@tests/cli_matrix/support.rs`:
- Around line 247-267: Change run_physical_case to return a Result<RunResult, E>
(propagate a suitable error type like anyhow::Error) and stop panicking inside
it: break the current body into three helpers (e.g., stage_fixture,
execute_mdtablefix, collect_output) referenced from run_physical_case; in those
helpers replace all .expect() calls with ? plus contextual errors and return
Results, and remove the assert!(output.status.success()) from inside
run_physical_case so test callers perform the success assertion themselves; keep
identifiers PhysicalCase, RunResult, and the existing command building logic
(Command::cargo_bin("mdtablefix")) but propagate errors via ? and return
Ok(RunResult { output, file_content }) on success.
- Around line 12-293: Many items in this module are exported with pub(crate) but
lack Rustdoc; either add brief /// comments for each exported symbol (at minimum
a one-line description) or reduce their visibility to private if they are not
intended to be shared: apply this to enums and methods TransformFlag and
TransformFlag::as_arg, BaseCase, WrapVariant and WrapVariant::id_part,
ExecutionMode and ExecutionMode::id_part, LogicalCase, PhysicalCase and
PhysicalCase::snapshot_name/PhysicalCase::args, RunResult and
RunResult::envelope, constants ALL_FLAGS and BASE_MATRIX_CASES, and free
functions logical_cases, physical_cases, run_physical_case, fixture_path,
is_case_id, non_wrap_signature, has_flag; ensure each pub(crate) item receives a
/// doc comment placed immediately above its declaration or change the
visibility to remove pub(crate).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 2d6cd945-a299-420a-ab7f-0de0039a6579

📥 Commits

Reviewing files that changed from the base of the PR and between 7656244 and a522e7e.

📒 Files selected for processing (3)
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix.rs
  • tests/cli_matrix/support.rs

Comment thread src/wrap/inline/postprocess.rs
leynos added 2 commits April 26, 2026 18:38
Add concise Rustdoc comments for the matrix support types, fields,
constants, methods, and helper functions so the test harness support
module has explicit internal documentation.
Split fixture staging and result collection out of the matrix
runner so I/O and command construction failures propagate as errors.

Keep process success assertions in the snapshot test body where each
stdout and in-place invocation is visible beside its snapshots.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
tests/cli_matrix/support.rs (1)

285-305: ⚠️ Potential issue | 🟠 Major

Refactor run_physical_case to propagate errors and stop panicking.

Split this helper into staging/execution/collection steps and return Result<RunResult, _>. Remove .expect() at Line 286, Line 288, Line 290, Line 292, and Line 300. Remove assert! at Line 293-298 and assert status.success() in the test caller.

🔧 Proposed refactor
 use std::{
     fs,
     path::{Path, PathBuf},
     process::Output,
 };

 use assert_cmd::Command;
-use tempfile::tempdir;
+use tempfile::{tempdir, TempDir};

+type HarnessResult<T> = Result<T, Box<dyn std::error::Error + Send + Sync>>;

 /// Runs a physical matrix case through the real `mdtablefix` binary.
-pub(crate) fn run_physical_case(case: &PhysicalCase) -> RunResult {
-    let dir = tempdir().expect("create temporary directory");
-    let file_path = dir.path().join(case.logical.fixture);
-    fs::copy(fixture_path(case.logical.fixture), &file_path).expect("copy matrix fixture");
-
-    let mut command = Command::cargo_bin("mdtablefix").expect("create mdtablefix command");
-    command.args(case.args()).arg(&file_path);
-    let output = command.output().expect("run mdtablefix");
-    assert!(
-        output.status.success(),
-        "{} failed with stderr:\n{}",
-        case.snapshot_name(),
-        String::from_utf8_lossy(&output.stderr),
-    );
-
-    let file_content = fs::read(&file_path).expect("read matrix output file");
-    RunResult {
-        output,
-        file_content,
-    }
+pub(crate) fn run_physical_case(case: &PhysicalCase) -> HarnessResult<RunResult> {
+    let (_dir, file_path) = stage_fixture(case)?;
+    let output = run_command(case, &file_path)?;
+    let file_content = collect_result(&file_path)?;
+    Ok(RunResult { output, file_content })
 }
+
+fn stage_fixture(case: &PhysicalCase) -> HarnessResult<(TempDir, PathBuf)> {
+    let dir = tempdir()?;
+    let file_path = dir.path().join(case.logical.fixture);
+    fs::copy(fixture_path(case.logical.fixture), &file_path)?;
+    Ok((dir, file_path))
+}
+
+fn run_command(case: &PhysicalCase, file_path: &Path) -> HarnessResult<Output> {
+    let mut command = Command::cargo_bin("mdtablefix")?;
+    command.args(case.args()).arg(file_path);
+    Ok(command.output()?)
+}
+
+fn collect_result(file_path: &Path) -> HarnessResult<Vec<u8>> {
+    Ok(fs::read(file_path)?)
+}

As per coding guidelines, **/*.rs: “In Rust production code and shared fixtures, avoid .expect() entirely; return Result and use ? to propagate errors instead of panicking.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix/support.rs` around lines 285 - 305, Change run_physical_case
to return a Result<RunResult, E> (e.g., Result<RunResult, Box<dyn
std::error::Error>> or a crate Result type) and stop panicking: replace
tempdir().expect(...), fs::copy(...).expect(...),
Command::cargo_bin(...).expect(...), command.output().expect(...), and
fs::read(...).expect(...) with ? to propagate errors; remove the assert! block
that checks output.status.success() so this helper only stages (create temp
file), executes (run Command via Command::cargo_bin and command.output()), and
collects (read file) and then return Ok(RunResult { output, file_content });
update the test caller to call run_physical_case(...)?.output.status.success()
(or otherwise assert status.success() there). Reference: function
run_physical_case, types PhysicalCase and RunResult, tempdir(), fixture_path(),
Command::cargo_bin(), command.output(), and fs::read().
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tests/cli_matrix/support.rs`:
- Around line 285-305: Change run_physical_case to return a Result<RunResult, E>
(e.g., Result<RunResult, Box<dyn std::error::Error>> or a crate Result type) and
stop panicking: replace tempdir().expect(...), fs::copy(...).expect(...),
Command::cargo_bin(...).expect(...), command.output().expect(...), and
fs::read(...).expect(...) with ? to propagate errors; remove the assert! block
that checks output.status.success() so this helper only stages (create temp
file), executes (run Command via Command::cargo_bin and command.output()), and
collects (read file) and then return Ok(RunResult { output, file_content });
update the test caller to call run_physical_case(...)?.output.status.success()
(or otherwise assert status.success() there). Reference: function
run_physical_case, types PhysicalCase and RunResult, tempdir(), fixture_path(),
Command::cargo_bin(), command.output(), and fs::read().

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ef586867-a052-47f4-8e77-6590db97657f

📥 Commits

Reviewing files that changed from the base of the PR and between a522e7e and e23e2b0.

📒 Files selected for processing (1)
  • tests/cli_matrix/support.rs

Add explicit stdout assertions for matrix rows that exercise
ellipsis, fence, and list-renumber transforms before the insta
snapshots are recorded.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/cli_matrix.rs`:
- Around line 127-170: In cli_matrix_snapshots, before the
insta::assert_snapshot! calls add explicit semantic assertions that verify
transform-specific invariants on stdout_result and in_place_result (e.g., that
fence delimiters are normalized, that expected headers/footers or exit-code
semantics are present, and that stdout_result.output.stdout equals
in_place_result.file_content) so snapshots aren’t the sole oracle; place these
checks immediately after the assert_eq! comparing stdout and file_content and
before the two insta::assert_snapshot! calls, referencing cli_matrix_snapshots,
stdout_result, in_place_result, stdout_case, and in_place_case to locate where
to insert the assertions.

In `@tests/cli_matrix/support.rs`:
- Around line 286-316: Change the three fixture helper signatures from
Result<..., Box<dyn Error>> to anyhow::Result and add contextual .context(...)
calls for each fallible op: in stage_fixture add context to fs::copy (including
the source fixture and target path) and to any fixture_path resolution; in
collect_result add context to fs::read (including the file_path and
ExecutionMode); and in run_physical_case add context to tempdir creation,
Command::cargo_bin("mdtablefix") creation, and command.output() (including the
case.args or file_path where useful). Update uses of these functions to
propagate anyhow errors as needed and import anyhow::{Result, Context}.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 83257bac-b2c4-4e09-8fa5-f46567ae658c

📥 Commits

Reviewing files that changed from the base of the PR and between e23e2b0 and ca4c6fe.

📒 Files selected for processing (2)
  • tests/cli_matrix.rs
  • tests/cli_matrix/support.rs

Comment thread tests/cli_matrix.rs
Comment thread tests/cli_matrix/support.rs Outdated
leynos added 2 commits April 26, 2026 18:51
Replace the stale draft-only note with a completion statement that
matches the completed harness and developer-guide documentation.
Return false when the previous inline-code fragment cannot be popped,
preserving the helper contract without panicking in the wrap postprocess path.
Comment thread tests/cli_matrix/support.rs Outdated
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 26, 2026

@coderabbitai Have the following now been resolved?

Annul any requirements that violate the en-GB-oxendict spelling (-ize / -yse / -our) conventions (for example a request to replace "normalize" with "normalise" or "artefact" with "artifact"), or where the requirement unnecessarily increases cyclomatic complexity.

Please address the comments from this code review:

Overall Comments

  • In support::run_physical_case, consider preserving the original fixture extension instead of always using input.md so that failures and temporary files are easier to interpret when debugging.
  • is_case_id only allows lowercase letters, digits, and underscores, but the ExecPlan text mentions hyphens as valid; either relax the validator to accept hyphens or tighten the plan/comments so they are consistent with the enforced rule.

Individual Comments

Comment 1

+ return false; + } + + let Some(previous_atomic) = previous_line.pop() else { + return false; + }; + pending_whitespace.push(previous_atomic); **suggestion (bug_risk):** The `None` branch after checking `last().is_some_and(..)` is logically unreachable and may hide invariants breaking.

Since previous_line.last() is already verified as Some with FragmentKind::InlineCode, previous_line.pop() returning None would indicate a broken invariant, not normal control flow. Returning false here would silently mask that.

Instead, make the invariant explicit, e.g.:

let previous_atomic = previous_line
    .pop()
    .expect("inline code tail must be present after last() check");

or use a debug_assert! plus unwrap() so we fail loudly in debug builds if this invariant is ever violated.

    let previous_atomic = previous_line
        .pop()
        .expect("inline code tail must be present after last() check");

</issue_to_address>

@coderabbitai

This comment was marked as resolved.

@coderabbitai

This comment was marked as resolved.

leynos added 5 commits April 26, 2026 19:10
Run transform invariants against both stdout and in-place output,
preserve ordered-list indentation when checking renumber results, and
add contextual anyhow errors to the CLI matrix command runner.
Move the five type-level CLI matrix support comments directly above
their pub(crate) declarations so the repository doc check reports no gaps.
Stage CLI matrix fixtures as input files with their original extension
so temporary paths remain easier to interpret during debugging.
Use an explicit expect after the inline-code tail check so invariant
violations fail loudly during wrap postprocessing.
Clarify that staged CLI matrix input files preserve the source fixture
extension, matching the current debug-friendly staging behaviour.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
src/wrap/inline/postprocess.rs (1)

49-52: ⚠️ Potential issue | 🟠 Major

Remove the panic path from carry_previous_inline_code_tail.

Replace .expect(...) with a non-panicking branch so the no-panic contract remains true and lint policy remains enforced.

Proposed fix
-    let previous_atomic = previous_line
-        .pop()
-        .expect("inline code tail must be present after last() check");
+    let Some(previous_atomic) = previous_line.pop() else {
+        return false;
+    };

As per coding guidelines, **/*.rs: “.expect() and .unwrap() are forbidden outside of tests. Errors must be propagated.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/wrap/inline/postprocess.rs` around lines 49 - 52, In
carry_previous_inline_code_tail, remove the panic by replacing
previous_line.pop().expect(...) with a non-panicking branch (e.g., match or if
let) that handles the empty case and propagates an error instead of panicking;
specifically, check previous_line.pop() and on Some(previous_atomic) push it
into pending_whitespace as now, but on None return an appropriate Result::Err
(or None if the function uses Option) using the crate's existing error type or a
small sentinel error, and update the function signature to return Result/Option
as needed so no unwrap/expect remains.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/cli_matrix/invariants.rs`:
- Around line 15-17: The helper assert_transform_invariants currently panics on
fixture read with fs::read_to_string(...).expect(...); change its signature
(assert_transform_invariants) to return a Result (e.g., Result<(), Box<dyn
std::error::Error>> or a crate Result type), replace the expect call with
?-based propagation on fs::read_to_string(fixture_path(logical.fixture)), and
return Ok(()) on success; update all callers in tests to propagate or unwrap the
Result (e.g., using ? in test functions) so no shared test-support code panics.

---

Duplicate comments:
In `@src/wrap/inline/postprocess.rs`:
- Around line 49-52: In carry_previous_inline_code_tail, remove the panic by
replacing previous_line.pop().expect(...) with a non-panicking branch (e.g.,
match or if let) that handles the empty case and propagates an error instead of
panicking; specifically, check previous_line.pop() and on Some(previous_atomic)
push it into pending_whitespace as now, but on None return an appropriate
Result::Err (or None if the function uses Option) using the crate's existing
error type or a small sentinel error, and update the function signature to
return Result/Option as needed so no unwrap/expect remains.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 36cdfcaa-7ee6-41e3-abd1-5e6c67d5cbaf

📥 Commits

Reviewing files that changed from the base of the PR and between 3851d6f and 2488a1a.

📒 Files selected for processing (4)
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix.rs
  • tests/cli_matrix/invariants.rs
  • tests/cli_matrix/support.rs

Comment thread tests/cli_matrix/invariants.rs Outdated
leynos added 2 commits April 26, 2026 20:32
Use anyhow Context as an extension import and align the CLI matrix
fixture, output, and command failures with explicit context messages.
Propagate fixture-read failures from matrix invariants and keep the
inline-code tail carry helper non-panicking when an invariant is broken.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
tests/cli_matrix/support.rs (1)

288-291: ⚠️ Potential issue | 🟠 Major

Close the semantic-oracle gap for transform coverage.

Add explicit invariant assertions for Breaks, Footnotes, CodeEmphasis, and Headings. Line 288 states that enabled transforms are proven, but the delegated implementation currently validates only Ellipsis, Fences, and Renumber, leaving four flags snapshot-only.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix/support.rs` around lines 288 - 291, The current
assert_transform_invariants function delegates to
invariants::assert_transform_invariants but only validates Ellipsis, Fences, and
Renumber, leaving transform flags Breaks, Footnotes, CodeEmphasis, and Headings
unchecked; update tests/cli_matrix/support.rs (function
assert_transform_invariants) to explicitly assert invariants for those four
transforms by either calling corresponding invariants::assert_breaks_invariants
/ assert_footnotes_invariants / assert_code_emphasis_invariants /
assert_headings_invariants (or adding equivalent checks that inspect LogicalCase
and stdout) so each enabled flag in LogicalCase is validated rather than left
snapshot-only.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@tests/cli_matrix/support.rs`:
- Around line 288-291: The current assert_transform_invariants function
delegates to invariants::assert_transform_invariants but only validates
Ellipsis, Fences, and Renumber, leaving transform flags Breaks, Footnotes,
CodeEmphasis, and Headings unchecked; update tests/cli_matrix/support.rs
(function assert_transform_invariants) to explicitly assert invariants for those
four transforms by either calling corresponding
invariants::assert_breaks_invariants / assert_footnotes_invariants /
assert_code_emphasis_invariants / assert_headings_invariants (or adding
equivalent checks that inspect LogicalCase and stdout) so each enabled flag in
LogicalCase is validated rather than left snapshot-only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b87d34da-06c1-4a53-a206-d8a0772bcb79

📥 Commits

Reviewing files that changed from the base of the PR and between 2488a1a and 2e8313e.

📒 Files selected for processing (1)
  • tests/cli_matrix/support.rs

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/wrap/inline/postprocess.rs`:
- Around line 49-51: The code silently returns false when previous_line.pop()
yields None, masking what should be an invariant breach; replace the current
conditional that binds previous_atomic from previous_line.pop() and returns
false with a failing assertion/unreachable that includes a descriptive message
(e.g., using panic! or unreachable!("expected previous tail to exist for inline
code: previous_line empty")) so that functions referencing previous_line and
previous_atomic (the previous_line.pop() call and subsequent logic) fail loudly
when this impossible state occurs.

In `@tests/cli_matrix/invariants.rs`:
- Around line 62-67: The unordered_fixture_markers function currently uses a
single global expected counter for all ordered markers, which diverges from
src/lists.rs behavior; change it to reset expectations per list
scope/indentation by tracking expected counters keyed by marker.indent (or by a
stack of indentation levels) instead of the single (1..) counter: look up the
current expected for marker.indent, compare to marker.number, push a mismatch
when they differ, then increment and store the expected for that indent so each
list scope is renumbered independently.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1a0a2ee7-9101-489e-9951-4704820d56a2

📥 Commits

Reviewing files that changed from the base of the PR and between 2e8313e and 11ba988.

📒 Files selected for processing (4)
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix.rs
  • tests/cli_matrix/invariants.rs
  • tests/cli_matrix/support.rs

Comment thread src/wrap/inline/postprocess.rs
Comment thread tests/cli_matrix/invariants.rs
@leynos

This comment was marked as resolved.

Fail loudly when the inline-code tail invariant is broken and track
matrix renumber expectations independently for each list indentation.
@coderabbitai

This comment was marked as resolved.

Replace the unreachable let-else branch with the requested expect call
so the inline-code tail invariant reports the precise failure message.
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 26, 2026

@coderabbitai pause

Track CLI matrix renumber expectations by indentation length and reset
the fixture-side counters across blank-line list boundaries.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

✅ Actions performed

Reviews paused.

@coderabbitai

This comment was marked as resolved.

Add focused unit coverage for matrix invariant parsing helpers and
support predicates used by the CLI matrix harness.
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 26, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== src/wrap/inline/postprocess.rs ==="
cat src/wrap/inline/postprocess.rs

echo ""
echo "=== tests/cli_matrix/invariants.rs ==="
cat tests/cli_matrix/invariants.rs

echo ""
echo "=== tests/cli_matrix/support.rs ==="
cat tests/cli_matrix/support.rs

Length of output: 31561


@leynos: All in-scope checks are now resolved. Here is the full updated status table.


Updated status

Check Resolved? Evidence
Testing (Overall) Resolved carry_previous_inline_code_tail uses .expect(…) in place of the silent return false; unordered_fixture_markers uses BTreeMap<usize, usize> with per-indent counters and blank-line resets via expected_by_indent.clear().
Unit Architecture Resolved All three sub-issues closed: stage_fixture preserves the .dat extension; .expect(…) replaces the silent return false; BTreeMap replaces the global counter.
Title check Annulled Process convention; out of scope.
Developer Documentation Resolved Both sub-issues fixed: per-indent BTreeMap scoping in invariants.rs; .expect(…) in postprocess.rs.
Testing (Unit) Resolved invariants.rs has a #[cfg(test)] block covering ordered_marker (4 tests), fixture_has_fence_candidate (4 tests), and unordered_fixture_markers (5 tests); support.rs has a #[cfg(test)] block covering is_case_id (6 tests), non_wrap_signature (2 tests), and has_flag (2 tests).
Testing (Property / Proof) Resolved (within scope) BTreeMap fix applied; "eliminate snapshot testing in favour of proptest" sub-requirement remains annulled as scope-expanding.
Testing (Compile-Time / Ui) Resolved Both sub-issues (BTreeMap scoping; .expect(…)) fixed.
Domain Architecture Resolved Both sub-issues (per-indent counter tracking; loud invariant failure) fixed.

No further work is required.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/wrap/inline/postprocess.rs (1)

49-51: ⚠️ Potential issue | 🟠 Major

Remove the production .expect(...) branch and preserve the non-panicking contract.

Replace the panic at Line 49-51. Keep invariant visibility with debug_assert!, then return false in release builds to match the contract documented at Line 64.

Proposed fix
-    let previous_atomic = previous_line
-        .pop()
-        .expect("inline code tail must be present after last() check");
+    let Some(previous_atomic) = previous_line.pop() else {
+        debug_assert!(
+            false,
+            "inline code tail vanished after successful tail-kind check",
+        );
+        return false;
+    };
#!/bin/bash
set -euo pipefail
rg -n 'This helper never panics|carry_previous_inline_code_tail|\.expect\(' src/wrap/inline/postprocess.rs

As per coding guidelines, “In Rust production code and shared fixtures, avoid .expect() entirely; return Result and use ? to propagate errors instead of panicking.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/wrap/inline/postprocess.rs` around lines 49 - 51, The code currently uses
previous_line.pop().expect(...) which can panic; replace this with a
non-panicking pattern: match the result of previous_line.pop() as
Some(previous_atomic) and, if None, call debug_assert!(false, "...") with a
descriptive message (e.g., "inline code tail vanished after successful tail-kind
check") and return false to preserve the documented non-panicking contract;
update the block in the carry_previous_inline_code_tail / previous_line handling
to remove .expect and use the described Some/None handling so release builds
return false while debug builds assert.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/cli_matrix/support.rs`:
- Around line 332-336: The error context for executing the test command should
include the specific matrix case identity; update the call that obtains the
process output (the command.output() invocation) to attach a contextual message
using with_context or similar so it includes either case.snapshot_name() or
case.logical.id (e.g., format!("execute mdtablefix for matrix case '{}'",
case.snapshot_name())). Locate the Command construction and the subsequent
command.output() call and replace the plain .context(...) with a
.with_context(|| format!(...)) that interpolates the chosen case identifier.
- Around line 370-395: Replace the macro-generated tests in the test module with
rstest parameterised tests: remove the macro_rules! case_id_test and
has_flag_test and instead add #[rstest] parameterised functions for is_case_id
(cases for "row_001","row-001","abc123","", "Row_001","row 001") calling
is_case_id(id) and asserting equality, and for has_flag (cases
TransformFlag::Renumber -> true, TransformFlag::Fences -> false) creating a
BaseCase and asserting has_flag(&case, flag); also convert the
non_wrap_signature checks into explicit rstest cases (or simple #[test]s) that
exercise non_wrap_signature("fixture.dat", &flags) for the wrap/unwrap and
differing-flag-list scenarios; import rstest::rstest and keep references to
BaseCase, TransformFlag, has_flag, is_case_id, and non_wrap_signature.

---

Duplicate comments:
In `@src/wrap/inline/postprocess.rs`:
- Around line 49-51: The code currently uses previous_line.pop().expect(...)
which can panic; replace this with a non-panicking pattern: match the result of
previous_line.pop() as Some(previous_atomic) and, if None, call
debug_assert!(false, "...") with a descriptive message (e.g., "inline code tail
vanished after successful tail-kind check") and return false to preserve the
documented non-panicking contract; update the block in the
carry_previous_inline_code_tail / previous_line handling to remove .expect and
use the described Some/None handling so release builds return false while debug
builds assert.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 5fd7a733-d415-4b51-86eb-589d8df12baa

📥 Commits

Reviewing files that changed from the base of the PR and between 11ba988 and 608db41.

📒 Files selected for processing (3)
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix/invariants.rs
  • tests/cli_matrix/support.rs

Comment thread tests/cli_matrix/support.rs Outdated
Comment thread tests/cli_matrix/support.rs Outdated
Add case-specific command execution context, convert matrix helper tests
to rstest cases, and keep inline tail handling non-panicking in release.
@leynos
Copy link
Copy Markdown
Owner Author

leynos commented Apr 26, 2026

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 26, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
tests/cli_matrix/support.rs (1)

373-397: 🧹 Nitpick | 🔵 Trivial

Remove #[rustfmt::skip] and let the formatter normalise the test module.

The #[rustfmt::skip] directive lacks a justification. The resulting compressed style (multiple statements per line, opening brace on the module declaration line) harms readability and complicates future maintenance.

Proposed fix
 #[cfg(test)]
-#[rustfmt::skip]
-mod tests { use super::{BaseCase, TransformFlag, has_flag, is_case_id, non_wrap_signature};
+mod tests {
+    use super::{BaseCase, TransformFlag, has_flag, is_case_id, non_wrap_signature};
     use rstest::rstest;
 
     #[rstest]
-    #[case("row_001", true)] #[case("row-001", true)] #[case("abc123", true)]
-    #[case("", false)] #[case("Row_001", false)] #[case("row 001", false)]
+    #[case("row_001", true)]
+    #[case("row-001", true)]
+    #[case("abc123", true)]
+    #[case("", false)]
+    #[case("Row_001", false)]
+    #[case("row 001", false)]
     fn is_case_id_returns_expected_value(#[case] id: &str, #[case] expected: bool) {
         assert_eq!(is_case_id(id), expected);
     }
 
-    #[test] fn non_wrap_signature_ignores_wrap_variant() {
-        let flags = [TransformFlag::Renumber, TransformFlag::Fences]; let (unwrapped, wrapped) = (false, true);
-        assert_ne!(unwrapped, wrapped); assert_eq!(non_wrap_signature("fixture.dat", &flags), non_wrap_signature("fixture.dat", &flags)); }
-    #[test] fn non_wrap_signature_distinguishes_flag_lists() {
-        assert_ne!(non_wrap_signature("fixture.dat", &[TransformFlag::Renumber]), non_wrap_signature("fixture.dat", &[TransformFlag::Fences])); }
+    #[test]
+    fn non_wrap_signature_ignores_wrap_variant() {
+        let flags = [TransformFlag::Renumber, TransformFlag::Fences];
+        let (unwrapped, wrapped) = (false, true);
+        assert_ne!(unwrapped, wrapped);
+        assert_eq!(
+            non_wrap_signature("fixture.dat", &flags),
+            non_wrap_signature("fixture.dat", &flags)
+        );
+    }
+
+    #[test]
+    fn non_wrap_signature_distinguishes_flag_lists() {
+        assert_ne!(
+            non_wrap_signature("fixture.dat", &[TransformFlag::Renumber]),
+            non_wrap_signature("fixture.dat", &[TransformFlag::Fences])
+        );
+    }
 
     #[rstest]
-    #[case(TransformFlag::Renumber, true)] #[case(TransformFlag::Fences, false)]
+    #[case(TransformFlag::Renumber, true)]
+    #[case(TransformFlag::Fences, false)]
     fn has_flag_returns_expected_value(#[case] flag: TransformFlag, #[case] expected: bool) {
-        let case = BaseCase { id: "row_001", fixture: "fixture.dat", flags: &[TransformFlag::Renumber] };
+        let case = BaseCase {
+            id: "row_001",
+            fixture: "fixture.dat",
+            flags: &[TransformFlag::Renumber],
+        };
         assert_eq!(has_flag(&case, flag), expected);
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/cli_matrix/support.rs` around lines 373 - 397, Remove the
#[rustfmt::skip] attribute on the tests module so rustfmt can reflow and
normalise the formatting; edit the tests mod declaration (module named tests) to
drop the attribute and then run rustfmt (or cargo fmt) to let it expand
statements onto separate lines and standardise brace placement for functions
like is_case_id_returns_expected_value, non_wrap_signature_ignores_wrap_variant,
non_wrap_signature_distinguishes_flag_lists and has_flag_returns_expected_value
while keeping the existing test logic and imports (BaseCase, TransformFlag,
has_flag, is_case_id, non_wrap_signature).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/cli_matrix/support.rs`:
- Around line 16-18: Move the doc comment for the TransformFlag enum to precede
the #[derive(...)] attribute so documentation appears before attributes; update
the same pattern for any other enums/structs in this file that currently have a
trailing /// after a #[derive(...)] (i.e., place the /// doc comment above the
derive attribute for each such item) to follow Rust convention and tooling
expectations.

---

Duplicate comments:
In `@tests/cli_matrix/support.rs`:
- Around line 373-397: Remove the #[rustfmt::skip] attribute on the tests module
so rustfmt can reflow and normalise the formatting; edit the tests mod
declaration (module named tests) to drop the attribute and then run rustfmt (or
cargo fmt) to let it expand statements onto separate lines and standardise brace
placement for functions like is_case_id_returns_expected_value,
non_wrap_signature_ignores_wrap_variant,
non_wrap_signature_distinguishes_flag_lists and has_flag_returns_expected_value
while keeping the existing test logic and imports (BaseCase, TransformFlag,
has_flag, is_case_id, non_wrap_signature).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 66af8b09-0885-4c71-982a-e1e634eeda6a

📥 Commits

Reviewing files that changed from the base of the PR and between 608db41 and fc62f43.

📒 Files selected for processing (2)
  • src/wrap/inline/postprocess.rs
  • tests/cli_matrix/support.rs

Comment thread tests/cli_matrix/support.rs Outdated
Place the Rustdoc comment before the derive attribute for TransformFlag.
@leynos leynos merged commit a7ffcf2 into main Apr 27, 2026
3 checks passed
@leynos leynos deleted the cli-matrix-testing branch April 27, 2026 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant