Skip to content

Refactor llm-coding-tools-core tests to use rstest parameterization#74

Merged
Sewer56 merged 5 commits into
mainfrom
rstest-cleanup-core
Mar 29, 2026
Merged

Refactor llm-coding-tools-core tests to use rstest parameterization#74
Sewer56 merged 5 commits into
mainfrom
rstest-cleanup-core

Conversation

@Sewer56
Copy link
Copy Markdown
Member

@Sewer56 Sewer56 commented Mar 29, 2026

Summary

Refactors llm-coding-tools-core test suite to use rstest parameterized tests with descriptive case names and inline documentation. Reduces test function count by ~35% while maintaining equal coverage.

Motivation

The core crate had 71 individual test functions across 10 files, many testing similar scenarios with only input variations. This created:

  • Duplicated setup code - Each test recreated the same temp directories/files
  • Poor readability - Hard to see what differs between similar tests
  • Maintenance burden - Adding new test cases required copy-pasting entire functions

By using rstest with #[case::descriptive_name(...)], we can:

  • Group related scenarios into single parameterized functions
  • Add inline comments explaining each parameter
  • Make the test matrix visible at a glance

Key Changes

Files Modified

File Before After Change
tools/glob.rs 6 tests 4 tests Parameterized pattern matching + serialization
tools/grep.rs 6 tests 5 tests Grouped search scenarios, formatting, edge cases
path/allowed.rs 8 tests 4 tests Valid paths + path traversal tests
permissions.rs 22 tests 12 tests Wildcard matching, ruleset evaluation
tools/todo.rs 7 tests 5 tests Validation + status icons
output.rs 5 tests 3 tests Creation + serialization
tools/webfetch/blocking_impl.rs 4 tests 3 tests Timeout validation
internal/hash64.rs 2 tests 1 test Hash properties
models/provider_type.rs 3 tests 2 tests Provider flags
error.rs 4 tests 0 tests Removed - testing thiserror, not our code

Test Quality Improvements

1. Descriptive Case Names

#[case::existing_file_in_root("file.txt", "file.txt")]
#[case::new_file_in_subdir("subdir/new_file.txt", "new_file.txt")]

2. Inline Parameter Comments (aligned)

#[case::single_file_no_filter(
    vec![("match.txt", "hello world")],  // files: 1 file with 1 match
    "hello",                              // pattern: matches 1 place
    None::<&str>,                         // filter: none (search all)
    1,                                    // expected: 1 file matched
    1                                     // expected: 1 total match
)]

3. Documented Rationale

/// We verify this behaviour specifically to ensure the LLM does not receive
/// unnecessary tokens for default values that provide no information.

Statistics

  • Total tests: 71 → 46 functions (~35% reduction)
  • Test cases: 46 → 90+ individual cases (more coverage)
  • Lines changed: 661 insertions, 469 deletions
  • All tests pass: 233 tests in llm-coding-tools-core

Review Notes

  • No production code changed - only test files
  • All removed tests were testing framework behavior (serde/thiserror) rather than business logic
  • Parameterized tests are ordered with the most complex/important at the top of each module
  • British English spelling used throughout (behaviour, etc.)

…ization

- Convert 71 individual tests into 46 parameterized test cases using rstest
- Add descriptive case names (#[case::name]) with inline parameter comments
- Group related test scenarios to improve readability and maintainability
- Document test rationale (e.g., token reduction for LLM outputs)
- Remove redundant tests testing serde/thiserror rather than business logic
- Add inline explanations aligned in columns for complex test parameters

Key improvements:
- glob.rs: 6→4 tests (pattern matching + serialization)
- grep.rs: 6→5 tests (search scenarios, formatting, edge cases)
- allowed.rs: 8→4 tests (path resolution scenarios)
- permissions.rs: 22→12 tests (wildcard matching, ruleset evaluation)
- error.rs: Removed thiserror display tests (testing framework, not our code)
- output.rs: Removed redundant From impl tests

Net reduction: ~35% fewer test functions while maintaining equal coverage.
@codecov
Copy link
Copy Markdown

codecov Bot commented Mar 29, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 78.36%. Comparing base (e5e172c) to head (cd1d45a).
⚠️ Report is 6 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #74      +/-   ##
==========================================
- Coverage   78.43%   78.36%   -0.08%     
==========================================
  Files         108      108              
  Lines        3942     3942              
==========================================
- Hits         3092     3089       -3     
- Misses        850      853       +3     
Flag Coverage Δ
async 77.38% <ø> (-0.08%) ⬇️
blocking 51.72% <ø> (-0.07%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
src/llm-coding-tools-core/src/error.rs 0.00% <ø> (-100.00%) ⬇️
src/llm-coding-tools-core/src/internal/hash64.rs 100.00% <ø> (ø)
.../llm-coding-tools-core/src/models/provider_type.rs 66.66% <ø> (ø)
src/llm-coding-tools-core/src/output.rs 60.00% <ø> (-20.00%) ⬇️
src/llm-coding-tools-core/src/path/allowed.rs 81.25% <ø> (ø)
src/llm-coding-tools-core/src/permissions.rs 94.11% <ø> (ø)
src/llm-coding-tools-core/src/tools/glob.rs 69.38% <ø> (ø)
src/llm-coding-tools-core/src/tools/grep.rs 92.39% <ø> (+1.08%) ⬆️
src/llm-coding-tools-core/src/tools/todo.rs 100.00% <ø> (ø)
...ing-tools-core/src/tools/webfetch/blocking_impl.rs 93.75% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 29, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a4a64240-c65c-4fb6-849a-0ed9f389d144

📥 Commits

Reviewing files that changed from the base of the PR and between 09962f9 and cd1d45a.

📒 Files selected for processing (4)
  • src/llm-coding-tools-core/src/models/provider_type.rs
  • src/llm-coding-tools-core/src/permissions.rs
  • src/llm-coding-tools-core/src/tools/glob.rs
  • src/llm-coding-tools-core/src/tools/todo.rs
✅ Files skipped from review due to trivial changes (1)
  • src/llm-coding-tools-core/src/tools/todo.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/llm-coding-tools-core/src/models/provider_type.rs
  • src/llm-coding-tools-core/src/permissions.rs
📜 Recent review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Blocking macOS
  • GitHub Check: Blocking Linux
  • GitHub Check: Async Linux
  • GitHub Check: Async Windows
  • GitHub Check: Async macOS
  • GitHub Check: Blocking Windows
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.rs

📄 CodeRabbit inference engine (src/AGENTS.md)

src/**/*.rs: Preallocate collections when size is known or estimable using String::with_capacity(estimated_len), Vec::with_capacity(count), or BufReader::with_capacity(size, reader)
Prefer &str / &[T] returns over owned types when lifetime allows
Use Cow<'_, str> for conditional ownership (e.g., String::from_utf8_lossy)
Use &'static str for compile-time constant strings
Reuse buffers by using .clear() and reusing Vec/String instead of reallocating
Use const generics for compile-time branching (e.g., <const LINE_NUMBERS: bool>)
Use #[inline] on small, hot-path functions
Prefer core over std where possible (e.g., core::mem over std::mem)
Stream data instead of loading entire files when possible
Use memchr for fast byte searching over manual iteration
Keep modules under 500 lines (excluding tests); split if larger
Place use statements inside functions only for #[cfg] conditional compilation
Document public items with /// and add examples in docs where helpful
Use //! for module-level documentation
Focus comments on 'why' not 'what'
Use [TypeName] rustdoc links in documentation, not backticks

Files:

  • src/llm-coding-tools-core/src/tools/glob.rs
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: Sewer56/llm-coding-tools PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-17T21:06:53.934Z
Learning: Applies to src/**/*.rs : Keep modules under 500 lines (excluding tests); split if larger
Learnt from: CR
Repo: Sewer56/llm-coding-tools PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-17T21:06:53.934Z
Learning: Applies to src/**/*.rs : Document public items with `///` and add examples in docs where helpful
📚 Learning: 2026-03-17T21:06:53.934Z
Learnt from: CR
Repo: Sewer56/llm-coding-tools PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-17T21:06:53.934Z
Learning: Applies to src/**/*.rs : Document public items with `///` and add examples in docs where helpful

Applied to files:

  • src/llm-coding-tools-core/src/tools/glob.rs
🔇 Additional comments (5)
src/llm-coding-tools-core/src/tools/glob.rs (5)

133-133: LGTM!

Import added appropriately for rstest parameterization.


153-175: LGTM!

Clean parameterization with descriptive case names. The test correctly verifies both positive matching (**/*.rs finding lib.rs) and gitignore exclusion (target/ being ignored).


177-227: LGTM!

Well-documented test with clear rationale for verifying serialization behavior. The test matrix correctly covers the two real-world states produced by glob_files (errors present → partial=true, no errors → partial=false).


262-262: LGTM!

Clear comment explaining the expected ordering behavior.


277-285: LGTM!

Comments clearly document the test expectations and the cross-platform importance of forward-slash normalization.


Walkthrough

This PR refactors many test modules in the llm-coding-tools-core crate by consolidating multiple standalone unit tests into parameterized rstest cases. Affected test files include error.rs, internal/hash64.rs, models/provider_type.rs, output.rs, path/allowed.rs, permissions.rs, tools/{glob.rs,grep.rs,todo.rs,webfetch/blocking_impl.rs}. No production code or public API declarations were changed; edits are confined to #[cfg(test)] test modules and test imports.

Possibly related PRs

  • Sewer56/llm-coding-tools PR 45 — Overlaps with removed tests in src/error.rs that validated ToolError display output (including TimeoutWithKillFailure).
  • Sewer56/llm-coding-tools PR 32 — Modifies tests around the internal hashing module (src/internal/hash64.rs), showing direct test-level overlap.
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the main change: refactoring tests to use rstest parameterization across the llm-coding-tools-core crate.
Description check ✅ Passed The description is comprehensive with summary, motivation, key changes, statistics, and review notes. It goes well beyond the template requirements.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 rstest-cleanup-core

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 and usage tips.

Copy link
Copy Markdown

@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.

🧹 Nitpick comments (3)
src/llm-coding-tools-core/src/models/provider_type.rs (1)

72-82: Avoid double-negation in the API key expectation.

Line 81 uses !provider.requires_api_key() against no_api_key, which makes the cases harder to scan quickly. Prefer asserting requires_api_key() directly with a positive expected value.

♻️ Proposed clarity refactor
-    #[case::azure_requires_base_url(ProviderType::Azure, true, false)]
-    #[case::ollama_no_api_key(ProviderType::Ollama, false, true)]
-    #[case::openai_requires_api_key(ProviderType::OpenAiCompletions, false, false)]
+    #[case::azure_requires_base_url(ProviderType::Azure, true, true)]
+    #[case::ollama_no_api_key(ProviderType::Ollama, false, false)]
+    #[case::openai_requires_api_key(ProviderType::OpenAiCompletions, false, true)]
     fn provider_type_flags(
         #[case] provider: ProviderType,
         #[case] requires_base_url: bool,
-        #[case] no_api_key: bool,
+        #[case] requires_api_key: bool,
     ) {
         assert_eq!(provider.requires_base_url(), requires_base_url);
-        assert_eq!(!provider.requires_api_key(), no_api_key);
+        assert_eq!(provider.requires_api_key(), requires_api_key);
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/llm-coding-tools-core/src/models/provider_type.rs` around lines 72 - 82,
The test provider_type_flags currently compares !provider.requires_api_key() to
no_api_key which uses a double-negation and is confusing; change the test
signature so the second boolean represents requires_api_key (or add a new
variable expected_requires_api_key) and assert provider.requires_api_key() ==
expected_requires_api_key, updating the case attributes (e.g.,
#[case::ollama_no_api_key(..., false)] to reflect the positive requires_api_key
value) and replace the assert_eq!(!provider.requires_api_key(), no_api_key) with
assert_eq!(provider.requires_api_key(), expected_requires_api_key) to make
expectations explicit and readable while keeping the function name
provider_type_flags and the call provider.requires_api_key() to locate the
change.
src/llm-coding-tools-core/src/tools/glob.rs (1)

177-225: Optional: derive expected key presence instead of passing duplicated booleans.

expect_partial_key and expect_errors_key are currently redundant with partial / errors. Deriving them inside the test avoids accidental mismatch in future cases.

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

In `@src/llm-coding-tools-core/src/tools/glob.rs` around lines 177 - 225, The test
glob_output_serialization_omits_default_fields currently takes redundant boolean
cases expect_partial_key and expect_errors_key; refactor it to derive expected
key presence from the inputs instead of passing duplicates: in the test body
compute expected_partial_present = partial and expected_errors_present =
!errors.is_empty(), remove the #[case] params expect_partial_key and
expect_errors_key from the signature and from the #[case::...] annotations, and
update assertions to compare json.get("partial").is_some() against
expected_partial_present and json.get("errors").is_some() against
expected_errors_present; keep references to the GlobOutput struct and existing
error_count logic unchanged.
src/llm-coding-tools-core/src/tools/todo.rs (1)

152-167: Consider passing the status variant directly as a parameter.

The current test structure is inverted—it takes the expected icon and reverse-engineers the input via a match statement, duplicating the mapping logic being tested. This makes the test harder to read and introduces an unreachable panic branch.

♻️ Suggested refactor for clarity
-    #[rstest]
-    #[case::pending("[ ]")]
-    #[case::in_progress("[>]")]
-    #[case::completed("[x]")]
-    #[case::cancelled("[-]")]
-    fn status_icons(#[case] expected: &str) {
-        let status = match expected {
-            "[ ]" => TodoStatus::Pending,
-            "[>]" => TodoStatus::InProgress,
-            "[x]" => TodoStatus::Completed,
-            "[-]" => TodoStatus::Cancelled,
-            _ => panic!("unknown icon"),
-        };
-        assert_eq!(status.icon(), expected);
-    }
+    #[rstest]
+    #[case::pending(TodoStatus::Pending, "[ ]")]
+    #[case::in_progress(TodoStatus::InProgress, "[>]")]
+    #[case::completed(TodoStatus::Completed, "[x]")]
+    #[case::cancelled(TodoStatus::Cancelled, "[-]")]
+    fn status_icons(#[case] status: TodoStatus, #[case] expected: &str) {
+        assert_eq!(status.icon(), expected);
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/llm-coding-tools-core/src/tools/todo.rs` around lines 152 - 167, The test
status_icons in the TodoStatus tests is inverted: it takes expected icon strings
and reverse-maps them to TodoStatus, duplicating the mapping under test; change
the parameterization to pass the TodoStatus variants directly (e.g.,
TodoStatus::Pending, TodoStatus::InProgress, TodoStatus::Completed,
TodoStatus::Cancelled) and the expected icon next to each case, then
assert_eq!(status.icon(), expected) without the match; update the #[case]
attributes in the status_icons test to use the enum variants and expected
strings and remove the unreachable panic branch and reverse-mapping logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/llm-coding-tools-core/src/models/provider_type.rs`:
- Around line 72-82: The test provider_type_flags currently compares
!provider.requires_api_key() to no_api_key which uses a double-negation and is
confusing; change the test signature so the second boolean represents
requires_api_key (or add a new variable expected_requires_api_key) and assert
provider.requires_api_key() == expected_requires_api_key, updating the case
attributes (e.g., #[case::ollama_no_api_key(..., false)] to reflect the positive
requires_api_key value) and replace the assert_eq!(!provider.requires_api_key(),
no_api_key) with assert_eq!(provider.requires_api_key(),
expected_requires_api_key) to make expectations explicit and readable while
keeping the function name provider_type_flags and the call
provider.requires_api_key() to locate the change.

In `@src/llm-coding-tools-core/src/tools/glob.rs`:
- Around line 177-225: The test glob_output_serialization_omits_default_fields
currently takes redundant boolean cases expect_partial_key and
expect_errors_key; refactor it to derive expected key presence from the inputs
instead of passing duplicates: in the test body compute expected_partial_present
= partial and expected_errors_present = !errors.is_empty(), remove the #[case]
params expect_partial_key and expect_errors_key from the signature and from the
#[case::...] annotations, and update assertions to compare
json.get("partial").is_some() against expected_partial_present and
json.get("errors").is_some() against expected_errors_present; keep references to
the GlobOutput struct and existing error_count logic unchanged.

In `@src/llm-coding-tools-core/src/tools/todo.rs`:
- Around line 152-167: The test status_icons in the TodoStatus tests is
inverted: it takes expected icon strings and reverse-maps them to TodoStatus,
duplicating the mapping under test; change the parameterization to pass the
TodoStatus variants directly (e.g., TodoStatus::Pending, TodoStatus::InProgress,
TodoStatus::Completed, TodoStatus::Cancelled) and the expected icon next to each
case, then assert_eq!(status.icon(), expected) without the match; update the
#[case] attributes in the status_icons test to use the enum variants and
expected strings and remove the unreachable panic branch and reverse-mapping
logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5c110ded-a08f-432c-b734-2e236c144a9d

📥 Commits

Reviewing files that changed from the base of the PR and between e5e172c and 09962f9.

📒 Files selected for processing (10)
  • src/llm-coding-tools-core/src/error.rs
  • src/llm-coding-tools-core/src/internal/hash64.rs
  • src/llm-coding-tools-core/src/models/provider_type.rs
  • src/llm-coding-tools-core/src/output.rs
  • src/llm-coding-tools-core/src/path/allowed.rs
  • src/llm-coding-tools-core/src/permissions.rs
  • src/llm-coding-tools-core/src/tools/glob.rs
  • src/llm-coding-tools-core/src/tools/grep.rs
  • src/llm-coding-tools-core/src/tools/todo.rs
  • src/llm-coding-tools-core/src/tools/webfetch/blocking_impl.rs
💤 Files with no reviewable changes (1)
  • src/llm-coding-tools-core/src/error.rs
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
  • GitHub Check: Async Windows
  • GitHub Check: Async Linux
  • GitHub Check: Async macOS
  • GitHub Check: Blocking Linux
  • GitHub Check: Blocking macOS
  • GitHub Check: Blocking Windows
🧰 Additional context used
📓 Path-based instructions (1)
src/**/*.rs

📄 CodeRabbit inference engine (src/AGENTS.md)

src/**/*.rs: Preallocate collections when size is known or estimable using String::with_capacity(estimated_len), Vec::with_capacity(count), or BufReader::with_capacity(size, reader)
Prefer &str / &[T] returns over owned types when lifetime allows
Use Cow<'_, str> for conditional ownership (e.g., String::from_utf8_lossy)
Use &'static str for compile-time constant strings
Reuse buffers by using .clear() and reusing Vec/String instead of reallocating
Use const generics for compile-time branching (e.g., <const LINE_NUMBERS: bool>)
Use #[inline] on small, hot-path functions
Prefer core over std where possible (e.g., core::mem over std::mem)
Stream data instead of loading entire files when possible
Use memchr for fast byte searching over manual iteration
Keep modules under 500 lines (excluding tests); split if larger
Place use statements inside functions only for #[cfg] conditional compilation
Document public items with /// and add examples in docs where helpful
Use //! for module-level documentation
Focus comments on 'why' not 'what'
Use [TypeName] rustdoc links in documentation, not backticks

Files:

  • src/llm-coding-tools-core/src/models/provider_type.rs
  • src/llm-coding-tools-core/src/internal/hash64.rs
  • src/llm-coding-tools-core/src/tools/webfetch/blocking_impl.rs
  • src/llm-coding-tools-core/src/path/allowed.rs
  • src/llm-coding-tools-core/src/tools/glob.rs
  • src/llm-coding-tools-core/src/tools/todo.rs
  • src/llm-coding-tools-core/src/output.rs
  • src/llm-coding-tools-core/src/permissions.rs
  • src/llm-coding-tools-core/src/tools/grep.rs
🧠 Learnings (3)
📚 Learning: 2026-03-28T02:14:00.864Z
Learnt from: Sewer56
Repo: Sewer56/llm-coding-tools PR: 69
File: src/llm-coding-tools-bubblewrap/src/profile/validation.rs:57-67
Timestamp: 2026-03-28T02:14:00.864Z
Learning: In `src/llm-coding-tools-bubblewrap/src/profile/` (Rust, llm-coding-tools-bubblewrap crate), the `Builder` API paths (workspace, synthetic_home, cache_root, mount lists, overlays, etc.) are always set by trusted application/operator code — the library consumer is the trusted party. Path normalization and `..`-component hardening in validators like `validate_absolute_path` is therefore NOT required to defend against traversal attacks. Untrusted input (LLM-generated shell commands) only enters through `wrap_command`/`execute_command_with_mode`, not through the `Builder`.

Applied to files:

  • src/llm-coding-tools-core/src/path/allowed.rs
📚 Learning: 2026-03-17T21:06:53.934Z
Learnt from: CR
Repo: Sewer56/llm-coding-tools PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-17T21:06:53.934Z
Learning: Applies to src/**/*.rs : Document public items with `///` and add examples in docs where helpful

Applied to files:

  • src/llm-coding-tools-core/src/tools/glob.rs
  • src/llm-coding-tools-core/src/tools/todo.rs
  • src/llm-coding-tools-core/src/permissions.rs
  • src/llm-coding-tools-core/src/tools/grep.rs
📚 Learning: 2026-03-17T21:06:53.934Z
Learnt from: CR
Repo: Sewer56/llm-coding-tools PR: 0
File: src/AGENTS.md:0-0
Timestamp: 2026-03-17T21:06:53.934Z
Learning: Applies to src/**/*.rs : Use `memchr` for fast byte searching over manual iteration

Applied to files:

  • src/llm-coding-tools-core/src/tools/grep.rs
🔇 Additional comments (19)
src/llm-coding-tools-core/src/tools/glob.rs (2)

133-175: Good refactor to parameterized glob behavior tests.

This consolidation is cleaner, and the case names plus assertion context make failures easier to diagnose.


260-280: Comment updates improve test intent clarity.

The revised comments around mtime ordering and forward-slash normalization make these assertions easier to understand.

src/llm-coding-tools-core/src/path/allowed.rs (3)

140-160: LGTM!

Good refactoring with clear documentation. The inline comments explaining "exists: created by setup_test_dir()" vs "does NOT exist: tests write path resolution" follow the coding guideline to focus comments on 'why' not 'what'. The descriptive case names make test failures immediately understandable.


162-177: LGTM!

The parameterized cases cover the essential traversal patterns. The error message assertion contains("not within allowed") is appropriate for validating the rejection reason without being overly brittle to exact message wording.


194-205: LGTM!

The renamed test clearly states its intent, and the explicit input subdir/../file.txt makes the normalization behavior being tested obvious. The assertion is appropriately defensive.

src/llm-coding-tools-core/src/tools/todo.rs (1)

132-150: LGTM!

The parameterized test correctly validates both empty id and blank content scenarios. The case names provide clear documentation of what each test verifies.

src/llm-coding-tools-core/src/permissions.rs (5)

299-428: Well-structured parameterized test coverage.

The wildcard matching tests are comprehensive, covering star wildcards, question marks, prefix/suffix patterns, multiple stars, and edge cases with empty inputs. The descriptive case names and inline comments improve test readability and debugging output.


430-449: LGTM!

The parameterized test correctly verifies that Rule preserves pattern casing without normalization.


470-527: Last-match-wins coverage is maintained.

The last_match_wins_allow and last_match_wins_deny cases properly test both orderings of overlapping wildcard/specific patterns. This covers the critical precedence behavior that production code in extensions.rs, runtime/task.rs, and handle.rs depends on per the relevant code snippets.


529-561: LGTM!

Good coverage of case sensitivity for both permission keys and subject patterns.


563-600: LGTM!

Clear verification that permission keys require exact match while only subject patterns support wildcards. This asymmetry is well-documented in the test case comments.

src/llm-coding-tools-core/src/internal/hash64.rs (1)

44-57: LGTM!

The parameterized test cleanly consolidates the original determinism and collision tests. The should_equal boolean effectively controls the assertion type, and the test cases cover both identical input verification and different-input collision resistance.

src/llm-coding-tools-core/src/tools/webfetch/blocking_impl.rs (1)

126-143: LGTM!

The parameterized test effectively consolidates both validation error cases. Using an intentionally unreachable URL is appropriate since validation occurs before any network request, and the doc comment clearly explains this design decision.

src/llm-coding-tools-core/src/output.rs (1)

64-95: LGTM!

Both parameterized tests are well-structured. The serialization test at line 94 cleverly validates the skip_serializing_if behavior with a single assertion, and the doc comment provides good rationale for why this behavior matters (reducing unnecessary tokens for LLM consumers).

src/llm-coding-tools-core/src/tools/grep.rs (5)

267-338: LGTM!

The parameterized test effectively covers the key grep search scenarios. The inline comments documenting each case parameter are helpful for understanding test intent.

One minor note: the glob verification logic at lines 330-337 is tightly coupled to simple *.ext patterns. This works for the current test cases but would need adjustment if more complex glob patterns are added in the future.


340-374: LGTM!

Good coverage of all four boolean combinations for partial/truncated flags. The conditional errors vector setup correctly reflects how partial is derived from !errors.is_empty() in production code.


376-411: LGTM!

The conditional file creation pattern at lines 398-400 is a pragmatic approach for testing both missing-file and binary-file edge cases within a single parameterized test.


413-468: LGTM!

The truncation test cases comprehensively cover the key boundary conditions: short truncation with/without line numbers, no truncation when content fits, and the exact-boundary case.


470-484: LGTM!

Keeping this as a standalone test makes sense—it verifies a specific walker error scenario that doesn't fit the parameterized patterns used elsewhere, and the assertions clearly validate the expected partial-but-not-truncated state.

Sewer56 added 4 commits March 29, 2026 21:03
…mantics

- Rename parameter from `no_api_key` to `requires_api_key`
- Replace `!provider.requires_api_key()` with direct assertion
- Update case values to reflect positive semantics
… to remove redundant parameters

- Remove duplicate #[case] params expect_partial_key and expect_errors_key
- Compute expected field presence from input values instead:
  - expected_partial_present = partial
  - expected_errors_present = !errors.is_empty()
- Keeps error_count logic and GlobOutput references unchanged
- Pass TodoStatus enum variants as parameters instead of icon strings
- Remove reverse mapping match statement and unreachable panic branch
- Simplify test assertion to direct comparison
@Sewer56 Sewer56 merged commit 34fb8c1 into main Mar 29, 2026
10 checks passed
@Sewer56 Sewer56 deleted the rstest-cleanup-core branch March 29, 2026 20:24
Sewer56 added a commit that referenced this pull request Mar 30, 2026
Refactor llm-coding-tools-core tests to use rstest parameterization
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.

1 participant