Skip to content

test: expand insta snapshot coverage across pre-existing tests - #171

Merged
tinovyatkin merged 2 commits into
mainfrom
test/expand-insta-snapshots
Jul 23, 2026
Merged

test: expand insta snapshot coverage across pre-existing tests#171
tinovyatkin merged 2 commits into
mainfrom
test/expand-insta-snapshots

Conversation

@tinovyatkin

@tinovyatkin tinovyatkin commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Summary

insta was introduced as a dev-dependency in #141 but only used in new codegen tests. This PR expands snapshot coverage into pre-existing tests where a snapshot is a better regression target than manual assertions — 8 snapshot sites → 47 (39 conversions across 10 modules).

Snapshots are more observable: they capture whole structures (so counts are implied) and subsume negative !contains(...) guards by rendering the full output. Net −235 source lines.

Scope & method

Candidates were surfaced by a survey pass over every test-bearing module, then each was adversarially verified for determinism and invariant-loss before conversion. Only genuine value checks were converted:

  • multi-field struct/enum equality (e.g. ParserAtnPrediction, compiled GeneratedParserStep trees, PortableLocalData)
  • collection contents (buffered-token streams, recorded diagnostics, vocabulary tables)
  • formatted diagnostics / error messages / generated-code strings (sliced context-impl blocks, rendered decisions/loops)

Property checks are deliberately left as explicit assertions — boolean predicates, bounds, round-trip/algebraic invariants, ordering — with a snapshot layered alongside where both the value and the invariant matter (e.g. the predicate-hoisting ordering check).

Notable correctness guards

  • #[allow(clippy::disallowed_methods)] on each converted test module / #[test] fn: .clippy.toml bans .unwrap() and the insta macros unwrap internal I/O, so CI clippy fails without it (matches the existing semantics.rs site).
  • Determinism: snapshot targets are BTreeMap/BTreeSet-backed (generator data) or explicitly ordered; no PredictionFxHasher/HashMap iteration order is snapshotted. The lexer byte-span tests snapshot an explicit (start, stop, text, byte_span) tuple because TokenView's Debug omits byte_span — a naive token snapshot would silently drop the field those tests exist to pin.

Docs

Adds a "Snapshot tests (insta)" section to CLAUDE.md and AGENTS.md (kept in sync) directing contributors to prefer snapshots for value checks, keep assertions for properties, and documenting the project-specific traps above plus the cargo insta test/accept workflow.

Verification

  • cargo test --locked --all-features888 pass, 0 fail
  • cargo clippy --locked --all-targets --all-features -- -D warnings — clean
  • cargo fmt --check clean on all touched files (a pre-existing src/prediction.rs drift is left untouched, per repo convention)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Tests

    • Expanded snapshot-based testing across parser, lexer, grammar, recognizer, vocabulary, and code-generation tests.
    • Improved coverage of diagnostics, generated output, token details, grammar structures, and parser behavior.
    • Standardized validation of complex and multi-field results for easier review and maintenance.
  • Documentation

    • Added guidance on creating, reviewing, and updating snapshot tests.

Convert 39 value-asserting test sites (across 10 modules) from
hand-transcribed struct literals and substring-probe clusters to `insta`
snapshots, growing snapshot coverage from 8 sites to 47. Snapshots are more
observable regression targets: they capture whole structures (so counts are
implied), and subsume negative `!contains(...)` guards by rendering the full
output.

Scope was limited to genuine *value* checks — multi-field struct/enum
equality, collection contents, formatted diagnostics/error messages,
generated-code strings, and token/ATN dumps. Property checks (boolean
predicates, bounds, round-trip/algebraic invariants, ordering) are kept as
explicit assertions, with a snapshot layered alongside where both the value
and the invariant matter.

Notes:
- Each converted test module (or bare `#[test]` fn) carries
  `#[allow(clippy::disallowed_methods)]` because `.clippy.toml` bans
  `.unwrap()` and the insta macros unwrap internal I/O — matching the existing
  `semantics.rs` site.
- Snapshot targets are deterministic: generator data is `BTreeMap`/`BTreeSet`
  backed, and the lexer byte-span tests snapshot an explicit tuple because
  `TokenView`'s `Debug` omits `byte_span`.
- Net -235 source lines; all 888 tests pass and clippy is clean with
  `--all-targets --all-features -- -D warnings`.
Add a "Snapshot tests (insta)" section to CLAUDE.md and AGENTS.md (kept in
sync) directing contributors to reach for snapshots on value checks and keep
explicit assertions for properties. Documents the project-specific traps:
the mandatory `#[allow(clippy::disallowed_methods)]` on test modules,
`default-features = false` (no serde macros), the HashMap-order vs
BTreeMap-safe determinism rule and the TokenView/byte_span gotcha, and the
`cargo insta test`/`accept` workflow.
Copilot AI review requested due to automatic review settings July 23, 2026 10:32

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@github-actions

Copy link
Copy Markdown

Copy/Paste Detection

Found 19 duplication(s) across 10 changed Rust file(s) (threshold: 100 tokens).

Show duplications

Found a 14 line (150 tokens) duplication in the following files:

  • Starting at line 2401 of src/atn/parser.rs
  • Starting at line 2526 of src/atn/parser.rs
        let mut atn = ParserAtnBuilder::new(3);
        add_state(&mut atn, 0, AtnStateKind::RuleStart);
        add_state(&mut atn, 1, AtnStateKind::BlockStart);
        add_state(&mut atn, 2, AtnStateKind::Basic);
        add_state(&mut atn, 3, AtnStateKind::Basic);
        add_state(&mut atn, 4, AtnStateKind::Basic);
        add_state(&mut atn, 5, AtnStateKind::Basic);
        add_state(&mut atn, 6, AtnStateKind::BlockEnd);
        add_state(&mut atn, 7, AtnStateKind::RuleStop);
        atn.set_rule_to_start_state(vec![0])
            .expect("rule start states");
        atn.set_rule_to_stop_state(vec![7])
            .expect("rule stop states");
        atn.add_decision_state(1).expect("decision state");
```rust

---

Found a 27 line (145 tokens) duplication in the following files:
* Starting at line 15152 of src/parser.rs
* Starting at line 15285 of src/parser.rs

```rust
    fn generated_match_token_recovers_missing_token_from_context_follow() {
        let atn = generated_match_recovery_atn();
        let data = RecognizerData::new(
            "Mini.g4",
            Vocabulary::new(
                [None, Some("'X'"), Some("'Y'")],
                [None, Some("X"), Some("Y")],
                [None::<&str>, None, None],
            ),
        );
        let mut parser = BaseParser::new(
            CommonTokenStream::new(Source {
                tokens: vec![TestToken::eof("parser-test", 3, 1, 3)],
                index: 0,
            }),
            data,
        );
        parser.rule_context_stack = vec![
            RuleContextFrame {
                rule_index: 0,
                invoking_state: 0,
            },
            RuleContextFrame {
                rule_index: 1,
                invoking_state: 1,
            },
        ];

Found a 34 line (134 tokens) duplication in the following files:

  • Starting at line 8629 of src/parser.rs
  • Starting at line 8668 of src/parser.rs
                    if self.fast_parser_predicate_matches(predicate_context, transition, index) {
                        let boundary = left_recursive_boundary(atn, state, target);
                        outcomes.extend(
                            self.recognize_state_fast(
                                atn,
                                FastRecognizeRequest {
                                    state_number: target,
                                    stop_state,
                                    index,
                                    rule_start_index,
                                    decision_start_index: next_decision_start_index,
                                    precedence,
                                    depth: depth + 1,
                                    recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
                                    recovery_state: epsilon_recovery_state,
                                },
                                FastRecognizeScratch {
                                    predicate_context,
                                    visiting,
                                    memo,
                                    expected,
                                    native_depth: native_depth + 1,
                                },
                            )
                            .into_iter()
                            .map(|mut outcome| {
                                if let Some(rule_index) = boundary {
                                    let boundary = self.arena_boundary_node(rule_index, 0);
                                    self.defer_fast_outcome_node(&mut outcome, boundary);
                                }
                                outcome
                            }),
                        );
                    } else {
```rust

---

Found a 33 line (133 tokens) duplication in the following files:
* Starting at line 8593 of src/parser.rs
* Starting at line 8630 of src/parser.rs
* Starting at line 8669 of src/parser.rs

```rust
                    let boundary = left_recursive_boundary(atn, state, target);
                    outcomes.extend(
                        self.recognize_state_fast(
                            atn,
                            FastRecognizeRequest {
                                state_number: target,
                                stop_state,
                                index,
                                rule_start_index,
                                decision_start_index: next_decision_start_index,
                                precedence,
                                depth: depth + 1,
                                recovery_symbols: Rc::clone(&epsilon_recovery_symbols),
                                recovery_state: epsilon_recovery_state,
                            },
                            FastRecognizeScratch {
                                predicate_context,
                                visiting,
                                memo,
                                expected,
                                native_depth: native_depth + 1,
                            },
                        )
                        .into_iter()
                        .map(|mut outcome| {
                            if let Some(rule_index) = boundary {
                                let boundary = self.arena_boundary_node(rule_index, 0);
                                self.defer_fast_outcome_node(&mut outcome, boundary);
                            }
                            outcome
                        }),
                    );
                }

Found a 27 line (127 tokens) duplication in the following files:

  • Starting at line 14110 of src/parser.rs
  • Starting at line 14182 of src/parser.rs
        let mut atn = ParserAtnBuilder::new(2);
        assert_eq!(
            atn.add_state(AtnStateKind::RuleStart, Some(0))
                .expect("state")
                .index(),
            0
        );
        assert_eq!(
            atn.add_state(AtnStateKind::BlockStart, Some(0))
                .expect("state")
                .index(),
            1
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            2
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            3
        );
        assert_eq!(
            atn.add_state(AtnStateKind::BlockEnd, Some(0))
```rust

---

Found a 22 line (125 tokens) duplication in the following files:
* Starting at line 14136 of src/parser.rs
* Starting at line 14208 of src/parser.rs

```rust
            atn.add_state(AtnStateKind::BlockEnd, Some(0))
                .expect("state")
                .index(),
            4
        );
        assert_eq!(
            atn.add_state(AtnStateKind::RuleStop, Some(0))
                .expect("state")
                .index(),
            5
        );
        atn.set_rule_to_start_state(vec![0])
            .expect("rule start states");
        atn.set_rule_to_stop_state(vec![5])
            .expect("rule stop states");
        atn.add_decision_state(1).expect("decision state");
        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
            .expect("transition");
        atn.add_transition(
            1,
            ParserTransitionSpec::Atom {
                target: 2,

Found a 18 line (122 tokens) duplication in the following files:

  • Starting at line 2537 of src/atn/parser.rs
  • Starting at line 2622 of src/atn/parser.rs
        atn.set_rule_to_stop_state(vec![7])
            .expect("rule stop states");
        atn.add_decision_state(1).expect("decision state");
        atn.add_transition(0, ParserTransitionSpec::Epsilon { target: 1 })
            .expect("transition");
        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 2 })
            .expect("transition");
        atn.add_transition(1, ParserTransitionSpec::Epsilon { target: 4 })
            .expect("transition");
        atn.add_transition(
            2,
            ParserTransitionSpec::Atom {
                target: 3,
                label: 1,
            },
        )
        .expect("transition");
        atn.add_transition(3, ParserTransitionSpec::Epsilon { target: 6 })
```rust

---

Found a 34 line (119 tokens) duplication in the following files:
* Starting at line 9585 of src/parser.rs
* Starting at line 9660 of src/parser.rs

```rust
                        outcomes.extend(
                            self.recognize_state(
                                atn,
                                RecognizeRequest {
                                    state_number: *target,
                                    stop_state,
                                    index,
                                    rule_start_index,
                                    decision_start_index: next_decision_start_index,
                                    init_action_rules,
                                    predicates,
                                    semantics,
                                    rule_args,
                                    member_actions,
                                    return_actions,
                                    local_int_arg,
                                    member_values: member_values.clone(),
                                    return_values: return_values.clone(),
                                    rule_alt_number: next_alt_number,
                                    track_alt_numbers,
                                    consumed_eof,
                                    committed_decision: transition_committed,
                                    precedence,
                                    depth: depth + 1,
                                    recovery_symbols: epsilon_recovery_symbols.clone(),
                                    recovery_state: epsilon_recovery_state,
                                },
                                visiting,
                                memo,
                                expected,
                            )
                            .into_iter()
                            .map(|mut outcome| {
                                prepend_decision(&mut outcome, decision);

Found a 24 line (113 tokens) duplication in the following files:

  • Starting at line 244 of src/atn/parser.rs
  • Starting at line 2732 of src/atn/parser.rs
impl IntStream for LookaheadIntStream {
    fn consume(&mut self) {
        if self.la(1) != TOKEN_EOF {
            self.index += 1;
        }
    }

    fn la(&mut self, offset: isize) -> i32 {
        if offset <= 0 {
            return 0;
        }
        let offset = offset.cast_unsigned() - 1;
        self.symbols
            .get(self.index + offset)
            .copied()
            .unwrap_or(TOKEN_EOF)
    }

    fn index(&self) -> usize {
        self.index
    }

    fn seek(&mut self, index: usize) {
        self.index = index.min(self.symbols.len());
```rust

---

Found a 15 line (113 tokens) duplication in the following files:
* Starting at line 15210 of src/parser.rs
* Starting at line 15486 of src/parser.rs

```rust
    fn generated_match_token_counts_single_token_deletion_recovery() {
        let atn = generated_match_recovery_atn();
        let data = RecognizerData::new(
            "Mini.g4",
            Vocabulary::new(
                [None, Some("'X'"), Some("'Y'"), Some("'Z'")],
                [None, Some("X"), Some("Y"), Some("Z")],
                [None::<&str>, None, None, None],
            ),
        );
        let mut parser = BaseParser::new(
            CommonTokenStream::new(Source {
                tokens: vec![
                    TestToken::new(3).with_text("z"),
                    TestToken::new(2).with_text("y"),

Found a 12 line (112 tokens) duplication in the following files:

  • Starting at line 13091 of src/parser.rs
  • Starting at line 13174 of src/parser.rs
        let mut atn = ParserAtnBuilder::new(1);
        for (state, kind, rule) in [
            (0, AtnStateKind::RuleStart, 0),
            (1, AtnStateKind::StarLoopEntry, 0),
            (2, AtnStateKind::Basic, 0), // ops hub
            (3, AtnStateKind::Basic, 0), // shift prec
            (4, AtnStateKind::Basic, 0), // shift first >
            (5, AtnStateKind::Basic, 0), // shift second >
            (6, AtnStateKind::Basic, 0), // rel prec
            (7, AtnStateKind::Basic, 0), // rel >
            (8, AtnStateKind::LoopEnd, 0),
            (9, AtnStateKind::RuleStop, 0),
```rust

---

Found a 22 line (112 tokens) duplication in the following files:
* Starting at line 14547 of src/parser.rs
* Starting at line 14748 of src/parser.rs

```rust
    fn predicate_after_token_atn() -> Atn {
        let mut atn = ParserAtnBuilder::new(2);
        assert_eq!(
            atn.add_state(AtnStateKind::RuleStart, Some(0))
                .expect("state")
                .index(),
            0
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            1
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            2
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))

Found a 22 line (111 tokens) duplication in the following files:

  • Starting at line 12956 of src/parser.rs
  • Starting at line 14547 of src/parser.rs
  • Starting at line 14748 of src/parser.rs
    fn left_recursive_loop_with_caller_follow_atn(caller_symbol: i32) -> Atn {
        let mut atn = ParserAtnBuilder::new(2);
        assert_eq!(
            atn.add_state(AtnStateKind::RuleStart, Some(0))
                .expect("state")
                .index(),
            0
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            1
        );
        assert_eq!(
            atn.add_state(AtnStateKind::Basic, Some(0))
                .expect("state")
                .index(),
            2
        );
        assert_eq!(
            atn.add_state(AtnStateKind::RuleStart, Some(1))
```rust

---

Found a 14 line (110 tokens) duplication in the following files:
* Starting at line 14881 of src/parser.rs
* Starting at line 17523 of src/parser.rs

```rust
    fn parser_matches_token_and_reports_mismatch() {
        let source = Source {
            tokens: vec![
                TestToken::new(1).with_text("x"),
                TestToken::eof("parser-test", 1, 1, 1),
            ],
            index: 0,
        };
        let data = RecognizerData::new(
            "Mini.g4",
            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
        );
        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
        let matched = parser.match_token(1).expect("token 1 should match");

Found a 13 line (109 tokens) duplication in the following files:

  • Starting at line 14881 of src/parser.rs
  • Starting at line 17548 of src/parser.rs
    fn parser_matches_token_and_reports_mismatch() {
        let source = Source {
            tokens: vec![
                TestToken::new(1).with_text("x"),
                TestToken::eof("parser-test", 1, 1, 1),
            ],
            index: 0,
        };
        let data = RecognizerData::new(
            "Mini.g4",
            Vocabulary::new([None, Some("'x'")], [None, Some("X")], [None::<&str>, None]),
        );
        let mut parser = BaseParser::new(CommonTokenStream::new(source), data);
```rust

---

Found a 22 line (108 tokens) duplication in the following files:
* Starting at line 7462 of src/parser.rs
* Starting at line 7853 of src/parser.rs

```rust
    ) -> Option<RecognizeOutcome> {
        let (error_index, message) = self.expected_error_message(rule_index, start_index, expected);
        let diagnostic = diagnostic_for_token(self.token_at(error_index), message);
        let mut next_index = error_index;
        loop {
            let symbol = self.token_type_at(next_index);
            if sync_symbols.contains(&symbol) {
                if next_index == error_index {
                    return None;
                }
                break;
            }
            if symbol == TOKEN_EOF {
                break;
            }
            let after = self.consume_index(next_index, symbol);
            if after == next_index {
                break;
            }
            next_index = after;
        }
        let mut nodes = NodeSeqId::EMPTY;

Found a 15 line (108 tokens) duplication in the following files:

  • Starting at line 17814 of src/parser.rs
  • Starting at line 17838 of src/parser.rs
    fn outcome_ties_keep_later_non_recursive_alternative() {
        let arena = RecognitionArena::default();
        let first = RecognizeOutcome {
            index: 1,
            consumed_eof: false,
            alt_number: 0,
            member_values: BTreeMap::new(),
            return_values: BTreeMap::new(),
            diagnostics: DiagnosticSeqId::EMPTY,
            decisions: Vec::new(),
            actions: vec![ParserAction::new(1, 0, 0, None)],
            nodes: NodeSeqId::EMPTY,
        };
        let second = RecognizeOutcome {
            actions: vec![ParserAction::new(2, 0, 0, None)],
```rust

---

Found a 16 line (105 tokens) duplication in the following files:
* Starting at line 6637 of src/parser.rs
* Starting at line 7221 of src/parser.rs

```rust
        let start_state = atn.rule_to_start_state().get(rule_index).ok_or_else(|| {
            AntlrError::Unsupported(format!("rule {rule_index} has no start state"))
        })?;
        let stop_state = atn
            .rule_to_stop_state()
            .get(rule_index)
            .filter(|state| *state != usize::MAX)
            .ok_or_else(|| {
                AntlrError::Unsupported(format!("rule {rule_index} has no stop state"))
            })?;

        let start_index = self.current_visible_index();
        self.clear_prediction_diagnostics();
        self.reset_per_parse_caches();
        self.reset_recognition_arena();
        let caller_follow_state = self.pending_invoking_follow_state(atn);

Found a 13 line (100 tokens) duplication in the following files:

  • Starting at line 6372 of src/parser.rs
  • Starting at line 6396 of src/parser.rs
        let mut expected = BTreeSet::new();
        for index in (1..self.rule_context_stack.len()).rev() {
            let invoking_state = self.rule_context_stack[index].invoking_state;
            let Ok(state_number) = usize::try_from(invoking_state) else {
                continue;
            };
            let Some(Transition::Rule { follow_state, .. }) = atn
                .state(state_number)
                .and_then(|state| state.transitions().first())
                .map(ParserTransition::data)
            else {
                continue;
            };
```rust

</details>

@claude

claude Bot commented Jul 23, 2026

Copy link
Copy Markdown

Claude finished @tinovyatkin's task in 14m 50s —— View job


Code review — no blocking issues ✅

This is a clean, well-scoped test refactor (assertions → insta snapshots, net −235 source lines). I read every non-snapshot diff and verified the two things that actually matter for a snapshot PR — determinism (flakiness) and invariant preservation — at the type level, plus CLAUDE.md compliance and mechanical consistency. Everything holds up.

What I verified

Determinism (the flakiness risk) — clean. The four whole-struct assert_debug_snapshot! targets bottom out in Vec/BTreeMap/BTreeSet/scalars/enums only; no HashMap/HashSet is reachable from any of them, so no per-run iteration-order flake:

  • unitGrammarUnit (src/bin_support/grammar/model.rs) — the only maps in the reachable graph are BTreeMap (e.g. LeftRecursionInfo).
  • portablePortableLocalDatainline_actions/predicates are BTreeMap, required_generated_rules is BTreeSet.
  • body.stepsVec<GeneratedParserStep> and predictionParserAtnPrediction — scalars/Vec/enums throughout.

Invariant preservation — the two load-bearing claims check out:

  • reads_small_parser_atn: the dropped states().len() == 2 is preserved because atn.stats().states == state_count() == states().len(), and the committed snapshot shows states: 2.
  • converts_parser_rules_and_nested_elements: the dropped unit.syntax.source() == SourceId::new(2) is observable — the snapshot carries a top-level source: SourceId(2) (and SyntaxId(8589934592) >> 32 == 2).
  • Every converted negative !contains(...) guard is genuinely absent from its whole-string snapshot (verified per-case: __sync_error = Some(...), let __semantic_alt, parser_semantic_ir_predicate_matches, pub fn s(&self, _all(&self), …). The lexer byte-span tests correctly snapshot the explicit (start, stop, text, byte_span) tuple since TokenView's Debug omits byte_span.

CLAUDE.md compliance — clean. #[allow(clippy::disallowed_methods)] is present on all 9 newly-insta modules/fns (antlr4-rust-gen.rs already had it); the new "Snapshot tests (insta)" section is byte-for-byte identical in CLAUDE.md and AGENTS.md; cargo fmt --check is clean on all touched files (only the pre-existing, untouched src/prediction.rs drift remains); no unrelated reformatting and the #[rustfmt::skip] fixtures in atn/lexer_dfa.rs are untouched.

Mechanical consistency — clean. Removed helpers ms/mns have no remaining references (no dead_code); the DEFAULT_CHANNEL import was dropped cleanly (0 remaining uses) while HIDDEN_CHANNEL is retained (still used at 7 sites in parser.rs).

Optional (non-blocking) — one observation

In translates_portable_boolean_local_semantics (src/bin/antlr4-rust-gen.rs), the conversion also removed the structural_actions(&data) call that independently derived the inline_actions key; the test now pins state 2 via the snapshot literal. All asserted values are still captured, but the cross-check that structural_actions and build_structural_portable_local_data agree on which state the action lives at is gone. If that coupling is worth keeping, a one-line assertion alongside the snapshot would restore it. Purely optional — not a defect.

Note on the duplication bot

The 19 flagged duplications are in pre-existing production recursion (recognize_state_fast / recognize_state) and long-standing test ATN-builder fixtures — none are introduced by this diff (which only rewrites assertion blocks and is net-negative on source lines). Out of scope for this PR.


Checks completed:

  • Gather context (diff, CLAUDE.md rules)
  • Review source changes for bugs / logic errors
  • Review CLAUDE.md compliance
  • Verify snapshot determinism & invariant preservation
  • Validate candidate findings (none survived — no blocking issues)
  • Post consolidated review

Verdict: LGTM. No bugs, no CLAUDE.md violations, no determinism hazards found.
· branch test/expand-insta-snapshots

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 62712d75-cc97-478c-b215-d15cbb2b5ce4

📥 Commits

Reviewing files that changed from the base of the PR and between a8227cf and fb104b1.

⛔ Files ignored due to path filters (33)
  • src/atn/snapshots/antlr4_runtime__atn__parser__tests__adaptive_predict_marks_sll_conflict_for_full_context.snap is excluded by !**/*.snap
  • src/atn/snapshots/antlr4_runtime__atn__parser__tests__adaptive_predict_stream_retries_full_context_conflict.snap is excluded by !**/*.snap
  • src/atn/snapshots/antlr4_runtime__atn__parser__tests__context_prediction_reports_context_sensitivity_for_dfa_conflict.snap is excluded by !**/*.snap
  • src/atn/snapshots/antlr4_runtime__atn__serialized__tests__reads_small_parser_atn.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_block_decision_with_adaptive_prediction.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_left_recursive_parser_rule.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_plus_block_body_decision_with_adaptive_prediction.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_plus_loop_back_with_adaptive_prediction.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_star_loop_with_adaptive_prediction.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__compiles_token_set_transitions.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_decision_does_not_hoist_portable_predicate_past_local_action.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_decision_filters_semantic_predicate_alts.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_loop_filters_failed_leading_predicate_to_exit_alt.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_loop_filters_first_nested_predicated_decision.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_loop_filters_portable_local_predicate.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__generated_semantic_decision_reports_filtered_ambiguity_diagnostics.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__parses_supported_predicate_helpers.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__renders_fail_option_parser_predicate_error.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__translates_portable_boolean_local_semantics.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__typed_context_accessors_e_context.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__typed_context_accessors_latest_context.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__typed_context_accessors_many_context.snap is excluded by !**/*.snap
  • src/bin/snapshots/antlr4_rust_gen__tests__typed_context_accessors_s_context.snap is excluded by !**/*.snap
  • src/bin_support/grammar/snapshots/antlr4_rust_gen__grammar__ported_tests__frontend_tool_syntax_cases_match_upstream_outcomes.snap is excluded by !**/*.snap
  • src/bin_support/grammar/snapshots/antlr4_rust_gen__grammar__syntax__tests__converts_lexer_modes_sets_and_commands.snap is excluded by !**/*.snap
  • src/bin_support/grammar/snapshots/antlr4_rust_gen__grammar__syntax__tests__converts_parser_rules_and_nested_elements.snap is excluded by !**/*.snap
  • src/bin_support/grammar/snapshots/antlr4_rust_gen__grammar__syntax__tests__nested_actions_match_upstream.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__folds_left_recursive_boundary_into_rule_node.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__generated_prediction_diagnostics_use_adaptive_context.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__parsed_file_exposes_all_buffered_tokens.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__parser__tests__parser_dispatches_recovery_diagnostics_through_registered_listeners.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__recognizer__tests__recognizers_replace_the_default_console_error_listener.snap is excluded by !**/*.snap
  • src/snapshots/antlr4_runtime__vocabulary__tests__upstream_vocabulary__vocabulary_from_token_names_matches_java.snap is excluded by !**/*.snap
📒 Files selected for processing (12)
  • AGENTS.md
  • CLAUDE.md
  • src/atn/parser.rs
  • src/atn/serialized.rs
  • src/bin/antlr4-rust-gen.rs
  • src/bin_support/grammar/escape_sequence.rs
  • src/bin_support/grammar/ported_tests.rs
  • src/bin_support/grammar/syntax.rs
  • src/lexer.rs
  • src/parser.rs
  • src/recognizer.rs
  • src/vocabulary.rs

📝 Walkthrough

Walkthrough

The PR documents insta snapshot conventions and converts runtime, grammar, parser, lexer, vocabulary, recognizer, and code-generator tests from manual assertions to structured or rendered snapshot assertions. No public declarations or production behavior are changed.

Changes

Snapshot testing migration

Layer / File(s) Summary
Insta testing conventions
AGENTS.md, CLAUDE.md
Documents insta macro constraints, snapshot placement, lint allowances, deterministic data preparation, and snapshot workflows.
Runtime behavior snapshots
src/atn/*, src/parser.rs, src/lexer.rs, src/recognizer.rs, src/vocabulary.rs
Replaces detailed runtime result, token, diagnostic, ATN, and vocabulary assertions with insta snapshots and scoped Clippy allowances.
Grammar conversion snapshots
src/bin_support/grammar/*
Snapshots converted grammar structures, action bodies, escape-sequence properties, lexer units, and complete diagnostic collections.
Code generator snapshots
src/bin/antlr4-rust-gen.rs
Snapshots generated parser steps, token transitions, rendered code fragments, predicate handling, helper templates, and portable semantic data.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 78.95% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: expanding insta snapshot coverage across existing tests.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/expand-insta-snapshots

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions

Copy link
Copy Markdown

📊 Source Code Metrics (this PR vs main)

File Cyclomatic Cognitive Functions LLOC MI
src/parser.rs 2067 ⚪ 1367 ⚪ 645 ⚪ 4482 (main: 4486) 🟢 0 ⚪
src/bin/antlr4-rust-gen.rs 2226 ⚪ 1409 ⚪ 489 (main: 491) 🟢 3889 (main: 3936) 🟢 0 ⚪
src/lexer.rs 272 ⚪ 66 ⚪ 162 ⚪ 430 (main: 440) 🟢 0 ⚪
src/bin_support/grammar/syntax.rs 226 ⚪ 105 ⚪ 59 ⚪ 322 (main: 350) 🟢 0 ⚪
src/atn/serialized.rs 298 ⚪ 217 ⚪ 36 ⚪ 304 (main: 309) 🟢 0 ⚪
src/recognizer.rs 41 ⚪ 1 ⚪ 33 ⚪ 47 ⚪ 12.04 (main: 11.92) 🟢
src/bin_support/grammar/escape_sequence.rs 52 ⚪ 16 ⚪ 25 ⚪ 71 (main: 73) 🟢 12.76 (main: 13.39) 🔴
src/vocabulary.rs 27 (main: 29) 🟢 1 (main: 6) 🟢 10 ⚪ 28 (main: 34) 🟢 22.17 (main: 22.32) 🔴
src/bin_support/grammar/ported_tests.rs 5 ⚪ 2 ⚪ 1 ⚪ 10 (main: 7) 🔴 29.72 (main: 30.93) 🔴

Generated by mehen v1.6.0 — the code quality watcher.

@tinovyatkin
tinovyatkin merged commit 4eb9551 into main Jul 23, 2026
13 checks passed
@tinovyatkin
tinovyatkin deleted the test/expand-insta-snapshots branch July 23, 2026 10:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants