Conversation
- Introduce a shared `FenceTracker` in `wrap::fence` so all features reuse consistent fence semantics.\n- Replace bespoke toggles in stream processing, list renumbering, thematic break formatting, and footnote detection with the tracker.\n- Exercise the new tracker behaviour with dedicated unit tests.
Reviewer's GuideThis PR centralizes fenced code block state management by introducing a shared FenceTracker helper, refactors existing fence detection across multiple modules to use it instead of custom toggles, and adds focused unit and behavioral tests to validate its behavior. Sequence diagram for fence line processing with FenceTrackersequenceDiagram
participant ProcessStream
participant FenceTracker
participant OutputBuffer
ProcessStream->>FenceTracker: observe(line)
alt line is fence marker
FenceTracker-->>ProcessStream: true
ProcessStream->>OutputBuffer: flush_buffer()
ProcessStream->>OutputBuffer: push(line)
else line is not fence marker
FenceTracker-->>ProcessStream: false
alt FenceTracker.in_fence()
ProcessStream->>OutputBuffer: push(line)
end
end
File-Level Changes
Possibly linked issues
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
|
Note Other AI code review bot(s) detectedCodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review. Summary by CodeRabbit
WalkthroughReplace ad-hoc in-fence booleans with a shared Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant Src as Input Lines
participant Proc as process_stream_inner
participant FT as FenceTracker
participant Core as wrap/lists/breaks/footnotes
participant Out as Output
loop For each line
Src->>Proc: line
Proc->>FT: observe(line)
alt Line is fence marker
Proc->>Out: flush buffers and emit fence line
Note right of FT: Tracker records marker char & length
else Inside fence
FT-->>Proc: in_fence = true
Proc->>Out: emit line unchanged
else Normal text
Proc->>Core: apply wrapping/renumbering/footnote checks
Core-->>Proc: transformed line
Proc->>Out: emit line
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: ASSERTIVE Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used📓 Path-based instructions (1)**/*.rs📄 CodeRabbit inference engine (AGENTS.md)
Files:
⚙️ CodeRabbit configuration file
Files:
🧬 Code graph analysis (1)tests/wrap/fence_behaviour.rs (1)
🔍 Remote MCPAdditional Context for Fence Handling
These rules underline why centralizing fence state in a ⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
Comment |
There was a problem hiding this comment.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/wrap/fence.rs:66` </location>
<code_context>
+///
+/// The tracker centralises fence matching logic so that callers share the
+/// same semantics for opening and closing blocks.
+#[derive(Default)]
+pub struct FenceTracker {
+ state: Option<(char, usize)>,
</code_context>
<issue_to_address>
**issue (review_instructions):** Add behavioural and unit tests for the new FenceTracker struct and its methods.
The FenceTracker struct and its methods (new, observe, in_fence) are new features. You must provide both behavioural and unit tests to demonstrate their correctness and expected behaviour.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*`
**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.
</details>
</issue_to_address>
### Comment 2
<location> `src/wrap/fence.rs:66` </location>
<code_context>
+///
+/// The tracker centralises fence matching logic so that callers share the
+/// same semantics for opening and closing blocks.
+#[derive(Default)]
+pub struct FenceTracker {
+ state: Option<(char, usize)>,
</code_context>
<issue_to_address>
**issue (review_instructions):** The #[derive(Default)] attribute should be placed after the doc comment for FenceTracker.
Rust convention and the review instruction require that attributes like #[derive(Default)] appear after the doc comment, not before. Please move the attribute below the doc comment for FenceTracker.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*.rs`
**Instructions:**
Place function attributes **after** doc comments.
</details>
</issue_to_address>
### Comment 3
<location> `src/wrap/fence.rs:66` </location>
<code_context>
+///
+/// The tracker centralises fence matching logic so that callers share the
+/// same semantics for opening and closing blocks.
+#[derive(Default)]
+pub struct FenceTracker {
+ state: Option<(char, usize)>,
</code_context>
<issue_to_address>
**issue (review_instructions):** src/wrap/fence.rs does not begin with a //! module-level comment.
Please add a //! comment at the top of src/wrap/fence.rs to describe the module's purpose, as required by the review instructions.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*.rs`
**Instructions:**
Every module **must** begin with a `//!` comment.
</details>
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Document FenceTracker usage and cover its behaviour with new unit and integration tests.
There was a problem hiding this comment.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (4)
src/wrap/fence.rs(1 hunks)src/wrap/tests.rs(2 hunks)tests/wrap/fence_behaviour.rs(1 hunks)tests/wrap/mod.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider usingArcto reduce the amount of data returned.
Every module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessarymutbindings.
Handle errors with theResulttype instead of panicking where feasible.
Avoidunsafecode unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not usereturnin single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Preferexpectoverallow.
Prefer.expect()over.unwrap().
Useconcat!()to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums: Derivestd::error::Error(via thethiserrorcrate) for any condition the caller might inspect, retry, or map to an HTTP status.
Use an opaque error only at the app boundary: Useeyre::Reportfor human-readable logs; these should not be exposed in public APIs.
Never export the opaque type from a library: Convert to domain enums at API boundaries, and toeyreonly in the mainmain()entrypoint or top-level async task.
Files:
tests/wrap/fence_behaviour.rssrc/wrap/tests.rssrc/wrap/fence.rstests/wrap/mod.rs
⚙️ CodeRabbit configuration file
**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.
Adhere to single responsibility and CQRS
Place function attributes after doc comments.
Do not use
returnin single-line functions.Move conditionals with >2 branches into a predicate function.
Avoid
unsafeunless absolutely necessary.Every module must begin with a
//!doc comment that explains the module's purpose and utility.Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
Lints must not be silenced except as a last resort.
#[allow]is forbidden.- Only narrowly scoped
#[expect(lint, reason = "...")]is allowed.- No lint groups, no blanket or file-wide suppression.
- Include
FIXME:with link if a fix is expected.Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
Use
rstestfixtures for shared setup and to avoid repetition between tests.Replace duplicated tests with
#[rstest(...)]parameterised cases.Prefer
mockallfor mocks/stubs.Prefer
.expect()over.unwrap()Ensure that any API or behavioural changes are reflected in the documentation in
docs/Ensure that any completed roadmap steps are recorded in the appropriate roadmap in
docs/Files must not exceed 400 lines in length
- Large modules must be decomposed
- Long match statements or dispatch tables should be decomposed by domain and collocated with targets
- Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
- For testing of functionality depending upon environment variables, dependency injection and the
mockablecrate are the preferred option.- If mockable cannot be used, env mutations in...
Files:
tests/wrap/fence_behaviour.rssrc/wrap/tests.rssrc/wrap/fence.rstests/wrap/mod.rs
🧬 Code graph analysis (3)
tests/wrap/fence_behaviour.rs (1)
src/process.rs (1)
process_stream(215-223)
src/wrap/tests.rs (2)
src/wrap.rs (1)
wrap_text(327-441)src/wrap/fence.rs (3)
new(87-89)in_fence(120-122)observe(96-116)
src/wrap/fence.rs (1)
src/wrap.rs (1)
flush_paragraph(251-273)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
🔇 Additional comments (4)
tests/wrap/mod.rs (1)
18-18: Wire up the new fence behaviour test module. LGTM.The additional module import is correct and keeps the wrap integration suite cohesive.
src/wrap/fence.rs (2)
49-60: handle_fence_line now delegates detection to the tracker. LGTM.The buffer flush before emitting the fence marker avoids interleaving prose with fence lines and matches the caller’s expectations.
118-123: Expose intent with a tiny helper.Keep, but a named helper improves readability when scanning call sites.
Apply:
- pub fn in_fence(&self) -> bool { - self.state.is_some() - } + pub fn in_fence(&self) -> bool { self.state.is_some() }Likely an incorrect or invalid review comment.
src/wrap/tests.rs (1)
12-12: Confirm re-export exists; no changes needed
FenceTracker is publicly re-exported in src/wrap.rs at line 18, so the test import remains valid.
|
@sourcery-ai review |
There was a problem hiding this comment.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
Prompt for AI Agents
Please address the comments from this code review:
## Individual Comments
### Comment 1
<location> `src/breaks.rs:49-50` </location>
<code_context>
+ let mut fences = FenceTracker::default();
for line in lines {
- if is_fence(line).is_some() {
- in_code = !in_code;
+ if fences.observe(line) {
out.push(Cow::Borrowed(line.as_str()));
continue;
</code_context>
<issue_to_address>
**suggestion:** Switching to FenceTracker may change how thematic breaks are detected inside code blocks.
Please verify that FenceTracker correctly handles edge cases, such as fences opened and closed on the same line or with atypical spacing, to ensure compliance with Markdown semantics.
Suggested implementation:
```rust
for line in lines {
// Handle multiple fences on the same line and atypical spacing.
if fences.observe(line) {
out.push(Cow::Borrowed(line.as_str()));
continue;
}
```
```rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fence_tracker_edge_cases() {
let lines = vec![
"```rust code fence on one line```".to_string(),
" ``` ".to_string(),
"text outside fence".to_string(),
"```".to_string(),
"text inside fence".to_string(),
"```".to_string(),
" ```".to_string(),
"text after fence".to_string(),
];
let mut fences = FenceTracker::default();
let mut results = Vec::new();
for line in &lines {
results.push(fences.observe(line));
}
// Fence opened and closed on same line should be detected
assert!(results[0]);
// Fence with atypical spacing should be detected
assert!(results[1]);
// Text outside fence should not be detected as fence
assert!(!results[2]);
// Fence should be detected
assert!(results[3]);
// Text inside fence should not be detected as fence
assert!(!results[4]);
// Closing fence should be detected
assert!(results[5]);
// Fence with leading spaces should be detected
assert!(results[6]);
// Text after fence should not be detected as fence
assert!(!results[7]);
}
}
```
If `FenceTracker::observe` does not already handle fences with leading/trailing spaces or multiple fences on the same line, you will need to update its implementation to normalize whitespace and scan for multiple fence patterns per line. Ensure it toggles the fence state correctly for each detected fence.
</issue_to_address>
### Comment 2
<location> `src/lists.rs:94-95` </location>
<code_context>
+ let mut fences = FenceTracker::default();
for line in lines {
- if is_fence(line).is_some() {
- in_code = !in_code;
+ if fences.observe(line) {
out.push(Cow::Borrowed(line.as_str()));
continue;
</code_context>
<issue_to_address>
**suggestion:** List renumbering now respects FenceTracker, which may affect list handling inside code blocks.
Please test with nested lists and malformed fences to ensure FenceTracker handles these scenarios correctly.
Suggested implementation:
```rust
use super::*;
use std::borrow::Cow;
#[test]
fn test_nested_lists_with_fence_tracker() {
let input = vec![
"1. Outer list",
" ```",
" 1. Code block list",
" ```",
"2. Outer list continued",
" 1. Nested list",
" ```",
" - Malformed fence",
" ```",
" 2. Nested list continued",
].into_iter().map(|s| s.to_string()).collect::<Vec<_>>();
let output = renumber_lists(&input);
// Check that list renumbering is correct outside code blocks
assert_eq!(output[0], Cow::Borrowed("1. Outer list"));
assert_eq!(output[4], Cow::Borrowed("2. Outer list continued"));
assert_eq!(output[5], Cow::Borrowed(" 1. Nested list"));
assert_eq!(output[8], Cow::Borrowed(" 2. Nested list continued"));
// Check that code block lines are preserved
assert_eq!(output[1], Cow::Borrowed(" ```"));
assert_eq!(output[2], Cow::Borrowed(" 1. Code block list"));
assert_eq!(output[3], Cow::Borrowed(" ```"));
assert_eq!(output[6], Cow::Borrowed(" ```"));
assert_eq!(output[7], Cow::Borrowed(" - Malformed fence"));
}
#[test]
fn test_malformed_fences() {
let input = vec![
"1. List before fence",
" ```",
" 1. Inside code block",
" ``", // malformed fence
"2. List after fence",
].into_iter().map(|s| s.to_string()).collect::<Vec<_>>();
let output = renumber_lists(&input);
// List renumbering should not occur inside code block
assert_eq!(output[0], Cow::Borrowed("1. List before fence"));
assert_eq!(output[1], Cow::Borrowed(" ```"));
assert_eq!(output[2], Cow::Borrowed(" 1. Inside code block"));
assert_eq!(output[3], Cow::Borrowed(" ``"));
assert_eq!(output[4], Cow::Borrowed("2. List after fence"));
}
```
- If your test runner does not automatically pick up `tests/lists.rs`, ensure it is included in your test suite.
- If `renumber_lists` or `FenceTracker` are not public, you may need to adjust their visibility (`pub`) for testing.
- If your project uses a different test organization, move these tests to the appropriate location.
</issue_to_address>
### Comment 3
<location> `src/wrap/tests.rs:347` </location>
<code_context>
+#[test]
+fn fence_tracker_ignores_shorter_closing_marker() {
</code_context>
<issue_to_address>
**suggestion (testing):** Suggestion to add tests for non-standard fence markers and malformed input.
Please add tests for malformed or non-standard fence markers, such as single backticks/ tildes or mixed markers, and for lines resembling fences that should not be recognized. This will improve robustness against edge cases.
</issue_to_address>
### Comment 4
<location> `tests/wrap/fence_behaviour.rs:20-22` </location>
<code_context>
+ "fn demonstrate() { println!(\"This code line intentionally exceeds eighty characters ",
+ "to ensure the wrapping logic would normally split it if fences were not honoured.\"); }",
+ );
+ let input = lines_vec![first_paragraph, "```", code_line, "```", closing_paragraph];
+ let output = process_stream(&input);
+ assert!(!output.iter().any(|l| l.starts_with("``") && l.len() == 2), "no false 2-tick fences");
+
+ let fence_positions: Vec<usize> = output
</code_context>
<issue_to_address>
**suggestion (testing):** Suggestion to add behavioral tests for edge cases with info strings and whitespace.
Add tests for fence lines with different info strings, trailing whitespace, and indentation to verify correct handling of all Markdown fence cases.
</issue_to_address>
### Comment 5
<location> `src/wrap/fence.rs:67` </location>
<code_context>
+/// The tracker centralises fence matching logic so that callers share the
+/// same semantics for opening and closing blocks.
+///
+/// # Examples
+///
+/// ```
</code_context>
<issue_to_address>
**issue (review_instructions):** Add unit tests for FenceTracker to verify edge cases and correctness.
The FenceTracker struct is a new feature. While an example is provided in the docstring, you must add dedicated unit tests to src/wrap/tests.rs to verify its behaviour, including edge cases such as mismatched fence markers and multiple consecutive fences.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*`
**Instructions:**
For any new feature or change to an existing feature, both behavioural *and* unit tests are required.
</details>
</issue_to_address>
### Comment 6
<location> `src/wrap/fence.rs:101` </location>
<code_context>
+ /// Panics when the fence regular expression yields an empty marker, which
+ /// would indicate the regex is inconsistent with Markdown fence rules.
+ #[must_use]
+ pub fn observe(&mut self, line: &str) -> bool {
+ let Some((_indent, fence, _info)) = is_fence(line) else {
+ return false;
</code_context>
<issue_to_address>
**issue (review_instructions):** Demonstrate bug fixes in fence handling with a test.
If this refactor fixes any previously existing bugs in fence handling, you must add a test that demonstrates the bug and its resolution.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*`
**Instructions:**
Bug fixes *must* be demonstrated by a test.
</details>
</issue_to_address>
### Comment 7
<location> `src/wrap/fence.rs:62` </location>
<code_context>
- *in_code = false;
- *fence_state = None;
- }
+/// Tracks Markdown fenced code block state across lines.
+///
+/// The tracker centralises fence matching logic so that callers share the
</code_context>
<issue_to_address>
**issue (review_instructions):** The module is missing a `//!` doc comment at the top as required.
Please add a `//!` doc comment at the very top of this module to describe its purpose, as per the review instructions.
<details>
<summary>Review instructions:</summary>
**Path patterns:** `**/*.rs`
**Instructions:**
Every module **must** begin with a `//!` comment.
</details>
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Add unit coverage for inline markers, tilde fences, and malformed sequences while reinforcing list renumbering and wrap behaviour with info string and short-marker scenarios.
There was a problem hiding this comment.
Actionable comments posted: 2
📜 Review details
Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro
📒 Files selected for processing (3)
src/wrap/tests.rs(2 hunks)tests/lists.rs(1 hunks)tests/wrap/fence_behaviour.rs(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs
📄 CodeRabbit inference engine (AGENTS.md)
**/*.rs: Clippy warnings MUST be disallowed.
Fix any warnings emitted during tests in the code itself rather than silencing them.
Where a function is too long, extract meaningfully named helper functions adhering to separation of concerns and CQRS.
Where a function has too many parameters, group related parameters in meaningfully named structs.
Where a function is returning a large error consider usingArcto reduce the amount of data returned.
Every module must begin with a module level (//!) comment explaining the module's purpose and utility.
Document public APIs using Rustdoc comments (///) so documentation can be generated with cargo doc.
Prefer immutable data and avoid unnecessarymutbindings.
Handle errors with theResulttype instead of panicking where feasible.
Avoidunsafecode unless absolutely necessary and document any usage clearly.
Place function attributes after doc comments.
Do not usereturnin single-line functions.
Use predicate functions for conditional criteria with more than two branches.
Lints must not be silenced except as a last resort.
Lint rule suppressions must be tightly scoped and include a clear reason.
Preferexpectoverallow.
Prefer.expect()over.unwrap().
Useconcat!()to combine long string literals rather than escaping newlines with a backslash.
Prefer semantic error enums: Derivestd::error::Error(via thethiserrorcrate) for any condition the caller might inspect, retry, or map to an HTTP status.
Use an opaque error only at the app boundary: Useeyre::Reportfor human-readable logs; these should not be exposed in public APIs.
Never export the opaque type from a library: Convert to domain enums at API boundaries, and toeyreonly in the mainmain()entrypoint or top-level async task.
Files:
src/wrap/tests.rstests/wrap/fence_behaviour.rstests/lists.rs
⚙️ CodeRabbit configuration file
**/*.rs: * Seek to keep the cyclomatic complexity of functions no more than 12.
Adhere to single responsibility and CQRS
Place function attributes after doc comments.
Do not use
returnin single-line functions.Move conditionals with >2 branches into a predicate function.
Avoid
unsafeunless absolutely necessary.Every module must begin with a
//!doc comment that explains the module's purpose and utility.Comments and docs must follow en-GB-oxendict (-ize / -yse / -our) spelling and grammar
Lints must not be silenced except as a last resort.
#[allow]is forbidden.- Only narrowly scoped
#[expect(lint, reason = "...")]is allowed.- No lint groups, no blanket or file-wide suppression.
- Include
FIXME:with link if a fix is expected.Where code is only used by specific features, it must be conditionally compiled or a conditional expectation for unused_code applied.
Use
rstestfixtures for shared setup and to avoid repetition between tests.Replace duplicated tests with
#[rstest(...)]parameterised cases.Prefer
mockallfor mocks/stubs.Prefer
.expect()over.unwrap()Ensure that any API or behavioural changes are reflected in the documentation in
docs/Ensure that any completed roadmap steps are recorded in the appropriate roadmap in
docs/Files must not exceed 400 lines in length
- Large modules must be decomposed
- Long match statements or dispatch tables should be decomposed by domain and collocated with targets
- Large blocks of inline data (e.g., test fixtures, constants or templates) must be moved to external files and inlined at compile-time or loaded at run-time.
Environment access (env::set_var and env::remove_var) are always unsafe in Rust 2024 and MUST be marked as such
- For testing of functionality depending upon environment variables, dependency injection and the
mockablecrate are the preferred option.- If mockable cannot be used, env mutations in...
Files:
src/wrap/tests.rstests/wrap/fence_behaviour.rstests/lists.rs
🧬 Code graph analysis (3)
src/wrap/tests.rs (2)
src/wrap.rs (1)
wrap_text(327-441)src/wrap/fence.rs (3)
new(87-89)in_fence(125-127)observe(101-121)
tests/wrap/fence_behaviour.rs (1)
src/process.rs (1)
process_stream(215-223)
tests/lists.rs (1)
src/lists.rs (1)
renumber_lists(85-144)
⏰ Context from checks skipped due to timeout of 120000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Sourcery review
| #[test] | ||
| fn fence_tracker_new_starts_outside_fence() { | ||
| let tracker = FenceTracker::new(); | ||
| assert!(!tracker.in_fence()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_closes_matching_markers() { | ||
| let mut tracker = FenceTracker::default(); | ||
| assert!(!tracker.in_fence()); | ||
| assert!(tracker.observe("```rust")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("```")); | ||
| assert!(!tracker.in_fence()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_closes_with_info_string() { | ||
| let mut tracker = FenceTracker::new(); | ||
| assert!(tracker.observe("```rust")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("``` ")); | ||
| assert!(!tracker.in_fence()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_ignores_shorter_closing_marker() { | ||
| let mut tracker = FenceTracker::new(); | ||
| assert!(tracker.observe("````")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("```")); | ||
| assert!(tracker.in_fence()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_requires_matching_marker_to_close() { | ||
| let mut tracker = FenceTracker::default(); | ||
| assert!(tracker.observe("```")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("~~~")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("````")); | ||
| assert!(!tracker.in_fence()); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_handles_inline_and_indented_markers() { | ||
| let lines = [ | ||
| "```rust code fence on one line```", | ||
| " ``` ", | ||
| "text outside fence", | ||
| "```", | ||
| concat!( | ||
| "text inside fence that should remain intact even if it exceeds the usual width ", | ||
| "limit when wrapping is enabled." | ||
| ), | ||
| "``` ", | ||
| "text after fence", | ||
| ]; | ||
| let mut tracker = FenceTracker::default(); | ||
| let results: Vec<bool> = lines.iter().map(|line| tracker.observe(line)).collect(); | ||
| assert_eq!( | ||
| results, | ||
| vec![true, true, false, true, false, true, false], | ||
| "expected fences to be recognised with inline markers and atypical spacing" | ||
| ); | ||
| assert!( | ||
| !tracker.in_fence(), | ||
| "tracker should end outside of a fence after matching closures" | ||
| ); | ||
| } | ||
|
|
||
| #[test] | ||
| fn fence_tracker_handles_tilde_fences() { | ||
| let mut tracker = FenceTracker::new(); | ||
| assert!(tracker.observe("~~~~rust")); | ||
| assert!(tracker.in_fence()); | ||
| assert!(tracker.observe("~~~~")); | ||
| assert!(!tracker.in_fence()); | ||
| } | ||
|
|
||
| #[rstest] | ||
| #[case("`")] | ||
| #[case("``")] | ||
| #[case("`~~`")] | ||
| #[case("~~`")] | ||
| #[case("`` ~~")] | ||
| fn fence_tracker_rejects_short_or_mixed_markers(#[case] line: &str) { | ||
| let mut tracker = FenceTracker::default(); | ||
| assert!(!tracker.observe(line)); | ||
| assert!(!tracker.in_fence()); | ||
| } |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
Enforce the 400-line ceiling for this module. Move the new FenceTracker suite into a dedicated submodule (for example, tests::fence_tracker) so that src/wrap/tests.rs shrinks back below 400 lines; this file is now 428 lines long and violates the repository rule that test modules stay under 400 lines. As per coding guidelines.
🤖 Prompt for AI Agents
In src/wrap/tests.rs around lines 336 to 427, the new FenceTracker test suite
must be moved into its own test submodule to keep this file under the 400-line
limit; extract the entire block of FenceTracker tests into a new test file
(e.g., src/wrap/tests/fence_tracker.rs) and replace the removed block in
src/wrap/tests.rs with a mod declaration that pulls in the new tests (e.g., pub
mod fence_tracker or #[cfg(test)] mod fence_tracker as appropriate). Ensure the
new file has the same use/imports needed by the tests, preserves attributes
(#[test] / #[rstest]) and visibility, and update Cargo or module paths if
necessary so the test build still discovers and runs them.
Summary
FenceTrackerhelper inwrap::fenceand re-export it for downstream callersTesting
https://chatgpt.com/codex/tasks/task_e_68d81d0b061c832283fd3f68d4d9c09a
Summary by Sourcery
Unify fenced code block tracking across multiple modules by introducing a shared FenceTracker, updating all fence-sensitive logic to use it, and covering its behavior with dedicated tests
New Features:
Enhancements:
Tests: