Skip to content

test(pacquet): coverage#11710

Merged
zkochan merged 7 commits into
mainfrom
claude/analyze-rust-test-coverage-ZXlQQ
May 18, 2026
Merged

test(pacquet): coverage#11710
zkochan merged 7 commits into
mainfrom
claude/analyze-rust-test-coverage-ZXlQQ

Conversation

@KSXGitHub

@KSXGitHub KSXGitHub commented May 18, 2026

Copy link
Copy Markdown
Contributor

Adds 44 unit + integration tests to close the easier targets from a cargo llvm-cov pass over the pacquet/ workspace, lifting line coverage on the touched files without refactoring any production code.

What's covered now

  • Pure logiclockfile::resolved_dependency (From / Display / Serialize / TryFrom<Cow> arms), lockfile::{freshness, pkg_name, snapshot_dep_ref}, registry::package (PartialEq / latest / pinned_version), graph-hasher::{engine_name, object_hasher} (Node-version detection + null / bool / array dispatch), package-manifest (engines-runtime conversion edge cases), fs::file_mode, executor::execute_shell.
  • I/O error classifications via real fixtureslockfile::save_lockfile, workspace-state, patching::apply, and package-manifest::safe_read_package_json_from_dir get coverage for their typed CreateDir / RemoveFile / RenameFile / ReadFile / ParseJson arms by planting a regular file or directory where the writer expects something else. No DI fakes needed — these branches are reachable through real filesystem state, which matches the "prefer real fixtures" rule the new style guide added in refactor(pacquet): optional DI pattern + documentation #11708.
  • New integration testspacquet run <script> (happy path, extra-arg forwarding, missing-script with and without --if-present).

Out of scope

The bigger gaps that do need the Sys: <FsCapability + …> seam from the DI section of CODE_STYLE_GUIDE.mdfs::ensure_file rename retry / exhausted temp paths, install_package_by_snapshot.rs binary / git / directory resolution, cmd-shim::link_bins remaining error arms — are left for follow-ups. They need new Fs* capabilities on Host or fetcher fakes, which is more invasive than a tests-only PR should be.

Drive-by

  • Bumped hex_decode in graph-hasher::tests to is_multiple_of so test-time clippy stays clean on Rust 1.95.
  • Dropped a trailing comma in a single-line assert! in package-manifest/src/tests.rs to satisfy Dylint's perfectionist::macro-trailing-comma.
  • Merged main to pick up refactor(pacquet): optional DI pattern + documentation #11708.

Test plan

  • cargo nextest run on every touched crate after merging main — 321 tests pass, including all the new ones.
  • cargo clippy --locked --tests on touched crates passes with --deny warnings.
  • cargo fmt --check clean.

Written by an agent (Claude Code, claude-opus-4-7).

Summary by CodeRabbit

  • Tests

    • Added many unit and integration tests across the project: CLI script execution and argument forwarding, Unix-gated shell/engine detection checks, file-mode and filesystem edge cases, hash/serialization/manifest/lockfile behaviors, patch-application error cases, package/version selection, and workspace state error handling.
  • Chores

    • Added a development dependency for test utilities.

Review Change Stack

…friends

Adds ~44 unit and integration tests to close the easier targets in the
coverage analysis at #339-style boundaries. Touches:

- `lockfile::resolved_dependency`: cover `as_alias` / `ver_peer` for
  non-matching variants, alias / parse error variants, `TryFrom<Cow>`,
  serialize-alias / serialize-link, `From<PkgVerPeer> / From<PkgNameVerPeer>`,
  and a Display vs. `String` round-trip.
- `lockfile::freshness`: cover the plural arms of `SpecDiff::Display`
  and the comma separator inside the removed/modified loops.
- `lockfile::pkg_name`: cover `TryFrom<String>` and `TryFrom<Cow>` happy
  and empty-input paths.
- `lockfile::snapshot_dep_ref`: cover `ver_peer` and `From<PkgVerPeer>`.
- `lockfile::save_lockfile`: cover the `CreateDir` / `RemoveFile` /
  `RenameFile` error classifications by planting a regular file or
  directory where the writer expects a file or a writable path.
- `registry::package`: cover `PartialEq`, `latest`, and `pinned_version`
  happy and no-match paths.
- `graph-hasher::engine_name`: cover `detect_node_version` /
  `detect_node_major` when `node` is on PATH; skip cleanly otherwise.
- `graph-hasher::object_hasher`: cover the null / bool / array arms of
  the bytestream serializer.
- `patching::apply`: cover non-NotFound read-patch error, partial-delete
  non-empty result, unsupported rename/copy operation, and `Create`
  with an unwritable parent.
- `workspace-state`: cover the `CreateDir` / `ReadFile` / `ParseJson`
  error variants.
- `package-manifest`: cover `from_path` ENOENT, `add_dependency` on a
  non-object field, `safe_read_package_json_from_dir` non-NotFound IO
  error, and `convert_engines_runtime_to_dependencies` for unsupported
  shapes.
- `fs::file_mode`: cover `EXEC_MASK` / `EXEC_MODE` constants,
  `is_executable` for all positions, and `make_file_executable` on Unix.
- `executor`: cover `execute_shell` happy and non-zero-exit paths.
- `cli/tests/run.rs`: new integration tests for `pacquet run`,
  including argument forwarding and `--if-present`.

Also bumps `hex_decode` in `graph-hasher::tests` to use
`is_multiple_of` so test-time clippy stays clean under Rust 1.95.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
@coderabbitai

coderabbitai Bot commented May 18, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6d7bbd9a-55b9-488a-80c1-da47ac422f29

📥 Commits

Reviewing files that changed from the base of the PR and between 1dc4930 and 50c39ca.

📒 Files selected for processing (5)
  • pacquet/crates/cli/tests/run.rs
  • pacquet/crates/executor/src/lib.rs
  • pacquet/crates/executor/src/tests.rs
  • pacquet/crates/fs/src/file_mode.rs
  • pacquet/crates/fs/src/file_mode/tests.rs
✅ Files skipped from review due to trivial changes (1)
  • pacquet/crates/executor/src/lib.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • pacquet/crates/cli/tests/run.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). (7)
  • GitHub Check: Lint and Test (ubuntu-latest)
  • GitHub Check: Lint and Test (macos-latest)
  • GitHub Check: Lint and Test (windows-latest)
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Run benchmark on ubuntu-latest
  • GitHub Check: Code Coverage
  • GitHub Check: Compile & Lint
🧰 Additional context used
📓 Path-based instructions (2)
pacquet/**/*.rs

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

pacquet/**/*.rs: Mirror log emissions from pnpm code: when porting a function that fires events through globalLogger, logger.debug(), or streamParser.write(), match the call site, payload, and ordering so @pnpm/cli.default-reporter parses pacquet's NDJSON the same way it parses pnpm's
Prefer real fixtures (tempfile::TempDir, mocked registry, or integration tests) for testing; reach for the dependency-injection seam (capability traits on the Host provider, threaded as Sys: ) only when fixtures cannot cover the branch
Use the DI seam only for branches that real fixtures cannot reach: filesystem error kinds (PermissionDenied, ENOSPC, …), deterministic time, or external-service happy paths in features like pnpm login (2FA) and pnpm publish (OIDC / provenance)
Declare a newtype wrapper for branded string types (not a plain String or &str); give the type its own struct so misuse is a type error
If upstream always validates before construction of a branded string type, validate too; use only TryFrom and/or FromStr construction, not an infallible public constructor
If upstream never validates a branded string type, just brand for type-safety; expose an infallible From (and From<&str> when convenient) constructor
If upstream occasionally constructs a branded string type without validation, expose from_str_unchecked (or similarly named) constructor alongside the validating constructor
Match upstream serde behavior for branded types that cross JSON/YAML/INI boundaries: use #[serde(try_from = "String")] for deserialization and #[serde(into = "String")] for serialization
Derive simple conversions with derive_more (e.g., #[derive(derive_more::From)] and #[derive(derive_more::Into)]) for mechanical type conversions; use manual impl only when conversion needs custom logic like validation or normalization
String-literal unions (e.g., 'auto' | 'always' | 'never' from TypeScript) should be modeled as Rust enums, not newtype wrappers, because the set o...

Files:

  • pacquet/crates/executor/src/tests.rs
  • pacquet/crates/fs/src/file_mode.rs
  • pacquet/crates/fs/src/file_mode/tests.rs
pacquet/{**/*.rs,**/*.md}

📄 CodeRabbit inference engine (pacquet/AGENTS.md)

When citing code in comments, doc comments, Markdown docs, PR descriptions, or commit messages, link to a specific commit SHA (first 10 hex characters), not a branch name, to preserve reference permanence

Files:

  • pacquet/crates/executor/src/tests.rs
  • pacquet/crates/fs/src/file_mode.rs
  • pacquet/crates/fs/src/file_mode/tests.rs
🔇 Additional comments (3)
pacquet/crates/executor/src/tests.rs (1)

1-11: LGTM!

pacquet/crates/fs/src/file_mode.rs (1)

38-40: LGTM!

pacquet/crates/fs/src/file_mode/tests.rs (1)

1-38: LGTM!


📝 Walkthrough

Walkthrough

Adds comprehensive test coverage across crates for CLI/script execution, shell helpers, file-mode semantics, graph hashing, lockfile behaviors, manifest edge cases, patch application errors, registry version selection, and workspace-state error classification. All edits are tests or test wiring; no public APIs changed.

Changes

Test Coverage Expansion

Layer / File(s) Summary
CLI command and shell execution tests
pacquet/crates/cli/tests/run.rs, pacquet/crates/executor/src/lib.rs, pacquet/crates/executor/src/tests.rs
Integration tests for pacquet run verify script execution, argument forwarding, --if-present semantics, and missing-script errors. Unit test for execute_shell verifies successful command completion on Unix.
File system and permissions tests
pacquet/crates/fs/src/file_mode.rs, pacquet/crates/fs/src/file_mode/tests.rs
Tests assert exec-bit constants, is_executable semantics (any exec bit implies executable), and that make_file_executable sets exec bits on Unix.
Node detection and hash object tests
pacquet/crates/graph-hasher/src/engine_name.rs, pacquet/crates/graph-hasher/src/tests.rs
Tests validate detect_node_version strips leading v, detect_node_major matches major component, and hash_object emits stable, distinct hashes across null/boolean/array variants with element-order sensitivity.
Lockfile module core data structure tests
pacquet/crates/lockfile/src/freshness/tests.rs, pacquet/crates/lockfile/src/pkg_name/tests.rs, pacquet/crates/lockfile/src/snapshot_dep_ref/tests.rs
Tests cover SpecDiff pluralized display/formatting, PkgName::try_from parity for String/Cow<str>, and SnapshotDepRef::ver_peer() behavior for Plain/Alias variants.
Lockfile dependency resolution tests
pacquet/crates/lockfile/src/resolved_dependency/tests.rs
Tests validate ImporterDepVersion helpers (as_alias, ver_peer), parse-error classifications, TryFrom<Cow<str>> parity, serde serialization for Alias/Link, typed conversions from peer types, and Display/string conversion consistency.
Lockfile save and atomic write tests
pacquet/crates/lockfile/src/save_lockfile/tests.rs
Integration tests validate error mapping for failed create_dir_all, remove-step failures when target is a directory, and rename failures when target is a non-empty directory without leaving temp files.
Package manifest parsing and error handling tests
pacquet/crates/package-manifest/src/tests.rs
Tests assert typed errors for missing manifest, add_dependency rejects non-object fields, safe_read_package_json_from_dir surfaces non-ENOENT IO on Unix, and convert_engines_runtime_to_dependencies ignores unsupported shapes.
Patch application error scenario tests
pacquet/crates/patching/Cargo.toml, pacquet/crates/patching/src/apply/tests.rs
Tests ensure directory-as-patch yields ReadPatchFile, partial-delete fails with PatchFailed without unlinking, rename/copy headers are rejected, and file creation fails when parent path is blocked. Adds text-block-macros dev-dependency for test helpers.
Package registry version selection tests
pacquet/crates/registry/src/package/tests.rs
Adds package_with_versions helper and tests for equality-by-name, latest() dist-tag resolution, pinned_version() semver selection, and None when no versions match.
Workspace state error classification tests
pacquet/crates/workspace-state/src/tests.rs
Tests validate update_workspace_state and load_workspace_state surface CreateDir, ReadFile, and ParseJson errors in the corresponding failure modes.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • pnpm/pnpm#11665: Related workspace-state read/write implementation and tests that these new workspace-state error classification tests complement.
  • pnpm/pnpm#11693: Related to node-detection tests and engine-resolution behavior touched by graph-hasher tests.

Suggested reviewers

  • zkochan

Poem

🐰 I hopped through tests in moonlit rows,
Where edge-case thorns and odd paths grow,
I penned assertions, crisp and bright,
So pacquet runs behave just right,
A tiny hop for safer code.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'test(pacquet): coverage' is vague and generic, using non-descriptive terms that don't convey meaningful information about the specific changes made. Consider a more descriptive title that highlights the primary focus, such as 'test(pacquet): add unit and integration tests for coverage increase' or similar.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ 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 claude/analyze-rust-test-coverage-ZXlQQ

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.

@codecov-commenter

codecov-commenter commented May 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 89.68%. Comparing base (02f8138) to head (50c39ca).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #11710      +/-   ##
==========================================
+ Coverage   88.92%   89.68%   +0.76%     
==========================================
  Files         129      129              
  Lines       14845    14858      +13     
==========================================
+ Hits        13201    13326     +125     
+ Misses       1644     1532     -112     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Micro-Benchmark Results

Linux

group                          main                                   pr
-----                          ----                                   --
tarball/download_dependency    1.03      7.7±0.30ms   561.9 KB/sec    1.00      7.5±0.30ms   576.2 KB/sec

Dylint's perfectionist::macro-trailing-comma rule rejected the single-
line `assert!` formatting I'd accidentally inherited from the multi-
line shape — remove the trailing comma so the lint clears.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
@github-actions

github-actions Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Integrated-Benchmark Report (Linux)

Scenario: Frozen Lockfile

Command Mean [s] Min [s] Max [s] Relative
pacquet@HEAD 2.010 ± 0.060 1.881 2.102 1.02 ± 0.04
pacquet@main 1.966 ± 0.055 1.896 2.084 1.00
pnpm 4.200 ± 0.062 4.121 4.277 2.14 ± 0.07
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 2.0100859038400003,
      "stddev": 0.06004223045597236,
      "median": 2.01422144374,
      "user": 2.8184472599999997,
      "system": 2.2121591799999996,
      "min": 1.88147232124,
      "max": 2.10210939724,
      "times": [
        2.01724755424,
        2.00530829824,
        2.10210939724,
        1.98902079924,
        2.01119533324,
        1.95631765224,
        2.03660937124,
        1.88147232124,
        2.04869928424,
        2.05287902724
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 1.9663229356400003,
      "stddev": 0.05485434752336871,
      "median": 1.95505900274,
      "user": 2.8870892599999998,
      "system": 2.2106699799999996,
      "min": 1.89641118224,
      "max": 2.08373155224,
      "times": [
        1.95545242124,
        1.9763053512400002,
        1.89641118224,
        2.00871130624,
        1.90580935424,
        2.08373155224,
        1.95466558424,
        1.93498997324,
        1.94610630624,
        2.00104632524
      ]
    },
    {
      "command": "pnpm",
      "mean": 4.20045113994,
      "stddev": 0.06207072591916954,
      "median": 4.19779768824,
      "user": 8.052286059999998,
      "system": 2.56517238,
      "min": 4.12061781324,
      "max": 4.27743916424,
      "times": [
        4.12061781324,
        4.27743916424,
        4.25511461124,
        4.195088773239999,
        4.26876372824,
        4.261643009239999,
        4.20050660324,
        4.128285539239999,
        4.13536831324,
        4.16168384424
      ]
    }
  ]
}

Scenario: Frozen Lockfile (Hot Cache)

Command Mean [ms] Min [ms] Max [ms] Relative
pacquet@HEAD 507.8 ± 59.2 474.1 672.8 1.03 ± 0.12
pacquet@main 495.1 ± 11.3 481.0 514.7 1.00
pnpm 2248.2 ± 122.7 2085.9 2544.2 4.54 ± 0.27
BENCHMARK_REPORT.json
{
  "results": [
    {
      "command": "pacquet@HEAD",
      "mean": 0.5077869803,
      "stddev": 0.05923998550880405,
      "median": 0.4879180275,
      "user": 0.38898498000000004,
      "system": 0.92126786,
      "min": 0.47410696450000006,
      "max": 0.6727930525,
      "times": [
        0.6727930525,
        0.4986193575,
        0.49535841550000004,
        0.48755333050000005,
        0.47410696450000006,
        0.5168629885,
        0.48496497450000003,
        0.47746373450000007,
        0.48186426050000003,
        0.48828272450000004
      ]
    },
    {
      "command": "pacquet@main",
      "mean": 0.49512300940000004,
      "stddev": 0.011313619461233429,
      "median": 0.4924195545000001,
      "user": 0.37465428000000006,
      "system": 0.9530475599999999,
      "min": 0.4810207355000001,
      "max": 0.5146770245,
      "times": [
        0.5146770245,
        0.48733939150000005,
        0.5073454205,
        0.48989077850000007,
        0.48200619450000004,
        0.4970298765,
        0.49220905150000005,
        0.4810207355000001,
        0.49263005750000005,
        0.5070815635
      ]
    },
    {
      "command": "pnpm",
      "mean": 2.2482425582,
      "stddev": 0.1226795518322691,
      "median": 2.209213748,
      "user": 2.9856997799999996,
      "system": 1.2813889600000001,
      "min": 2.0859454025,
      "max": 2.5441991135,
      "times": [
        2.3095257865,
        2.2058105475,
        2.1985624695,
        2.0859454025,
        2.1710465445000002,
        2.2126169485,
        2.5441991135,
        2.3063687085,
        2.2536031805000003,
        2.1947468805
      ]
    }
  ]
}

claude added 2 commits May 18, 2026 03:04
The two `detect_node_*` tests previously skipped silently when `node`
was missing from `PATH`. `node` is a documented prerequisite of the
test suite (see `pacquet/CONTRIBUTING.md`'s setup section), so a
missing binary is a test-env bug to surface, not a condition to paper
over. Switch the `let Some(...) = ... else { return }` skips to
`expect` so a missing `node` fails loudly with a clear message.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
…ame (#11708)

PR #11708 renamed the dependency-injection seam (`Api` → `Sys`,
`RealApi` → `Host`, `FsReadString` → `FsReadToString`, fakes drop
the `*Api` suffix) and documented the convention in
`pacquet/CODE_STYLE_GUIDE.md`. My tests on this branch use real
fixtures only (no DI fakes), so the rename has no source-level impact
on the tests themselves; the documentation references in the PR
description and the per-file commit message get updated separately.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
Comment thread pacquet/crates/cli/tests/run.rs Outdated
Comment thread pacquet/crates/cli/tests/run.rs Outdated
Comment thread pacquet/crates/cli/tests/run.rs Outdated
Comment thread pacquet/crates/patching/src/apply/tests.rs Outdated
Comment thread pacquet/crates/patching/src/apply/tests.rs Outdated
Comment thread pacquet/crates/patching/src/apply/tests.rs Outdated
Addresses six review comments on #11710:

- `cli/tests/run.rs`: the three `package.json` fixtures used
  `format!("{{ ... }}", marker = …)` with literal-brace escapes,
  which is awkward and brittle when path strings contain
  JSON-special characters. Switched to
  `json!({...}).to_string()` so serde handles escaping and the
  shape reads as JSON, not as a brace-escaped template.
- `patching/src/apply/tests.rs`: the three patch fixtures I
  added used `"\<newline>...\n"` raw strings. Converted them to
  `text_block_fnl!`, matching the convention the rest of the
  workspace (lockfile, package-manager, testing-utils) uses for
  multi-line fixture text. The `_fnl` variant keeps the trailing
  newline that git-diff parsers expect.

Pre-existing fixtures in the same file (`IS_POSITIVE_PATCH`,
etc.) were not touched — keeping the scope to the lines
reviewers flagged.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
Idiomatic Rust and produces a better failure message when the
assertion trips. Caught during a self-review pass over #11710.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
@KSXGitHub KSXGitHub marked this pull request as ready for review May 18, 2026 07:37
@KSXGitHub KSXGitHub requested a review from zkochan as a code owner May 18, 2026 07:37
Copilot AI review requested due to automatic review settings May 18, 2026 07:37
Comment thread pacquet/crates/executor/src/lib.rs Outdated
}

#[cfg(test)]
mod tests {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

wasn't the convention to always put tests in a separate file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right — fixed in 50c39ca. Moved the executor and fs::file_mode tests into their conventional src/<parent>/tests.rs locations as documented in CODE_STYLE_GUIDE.md ("Unit test file layout"). My mistake on the inline mod tests { ... } block.


Generated by Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds pacquet test coverage across lockfile, package manifest, patching, graph hashing, filesystem, executor, workspace-state, registry package logic, and CLI run behavior.

Changes:

  • Adds unit tests for serialization/parsing helpers, error classification paths, hashing dispatch, file modes, and shell execution.
  • Adds CLI integration tests for pacquet run.
  • Adds text-block-macros as a patching dev-dependency for multiline patch fixtures.

Reviewed changes

Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
Cargo.lock Records the new patching test dependency.
pacquet/crates/cli/tests/run.rs Adds integration tests for pacquet run.
pacquet/crates/executor/src/lib.rs Adds executor unit tests.
pacquet/crates/fs/src/file_mode.rs Adds file mode unit tests.
pacquet/crates/graph-hasher/src/engine_name.rs Adds Node version detection tests.
pacquet/crates/graph-hasher/src/tests.rs Adds object hasher variant coverage and clippy cleanup.
pacquet/crates/lockfile/src/freshness/tests.rs Adds plural diff display coverage.
pacquet/crates/lockfile/src/pkg_name/tests.rs Adds conversion-path coverage.
pacquet/crates/lockfile/src/resolved_dependency/tests.rs Adds importer dependency parsing/serialization coverage.
pacquet/crates/lockfile/src/save_lockfile/tests.rs Adds save error classification coverage.
pacquet/crates/lockfile/src/snapshot_dep_ref/tests.rs Adds snapshot dependency helper coverage.
pacquet/crates/package-manifest/src/tests.rs Adds manifest error and engines-runtime edge-case coverage.
pacquet/crates/patching/Cargo.toml Adds text-block-macros for test fixtures.
pacquet/crates/patching/src/apply/tests.rs Adds patch application failure-path coverage.
pacquet/crates/registry/src/package/tests.rs Adds package equality/latest/pinned-version coverage.
pacquet/crates/workspace-state/src/tests.rs Adds workspace-state load/update error coverage.
Comments suppressed due to low confidence (2)

pacquet/crates/cli/tests/run.rs:48

  • The redirection target is an unquoted temp path inside a shell command. This becomes invalid or redirects to the wrong location when the temp directory contains spaces or shell metacharacters, making the integration test environment-dependent.
            "echo-args": format!(r#"sh -c 'printf %s "$1" > {}' --"#, marker_path.display()),

pacquet/crates/graph-hasher/src/engine_name.rs:258

  • This test also hard-requires a host node binary even though the detection API is expected to tolerate its absence. In Rust-only environments it will fail before exercising the parser; consider using a controlled fixture or skipping when node --version cannot be spawned.
        let major = detect_node_major().expect("`node` must be on PATH for the test suite");
        let version = detect_node_version().expect("`node` must be on PATH for the test suite");

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pacquet/crates/executor/src/lib.rs Outdated
Comment on lines +57 to +58
fn execute_shell_propagates_nonzero_exit_as_ok() {
execute_shell("exit 1").expect("wait succeeds even on nonzero exit");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Dropped this test in 50c39ca. The "non-zero exit → Ok" behavior in execute_shell is indeed a bug relative to pnpm/npm's run semantics (which propagate the script's status as the CLI's exit code), and pinning it as a regression test would block the eventual fix. The fix itself belongs in its own PR — outside the scope of a tests-only change.


Generated by Claude Code

/// bug, so we `expect` rather than skip.
#[test]
fn detect_node_version_strips_leading_v() {
let version = detect_node_version().expect("`node` must be on PATH for the test suite");

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Intentionally left as-is. A human reviewer (KSXGitHub) explicitly asked in [r3255978...] for these tests to fail loudly when node is missing rather than skip silently, on grounds that node is a documented prerequisite of the test suite (see pacquet/CONTRIBUTING.md "Setup → Prerequisites"). That choice landed as 5d0987c. Reverting to a tolerant skip would undo it.


Generated by Claude Code

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. Tolerant tests are kinda pointless.

I wonder. Amongst the existing AI-generated tests, how many are mistakenly "tolerant" like the one Copilot suggested.

Comment thread pacquet/crates/cli/tests/run.rs Outdated
let manifest = json!({
"name": "test",
"version": "0.0.0",
"scripts": { "touch-marker": format!("touch {}", marker_path.display()) },

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 50c39ca. Wrapped the temp-path interpolation in "..." in both cli/tests/run.rs shell fixtures so a path with a space (the common macOS /var/folders/... shape) doesn't split the redirect/touch argument. Stopped short of a full shell-escape because tempfile::tempdir() paths can't contain ' or " in practice — quoting handles the realistic case.


Generated by Claude Code

Comment thread pacquet/crates/executor/src/lib.rs Outdated

#[cfg(test)]
mod tests {
use super::execute_shell;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in 50c39ca by gating mod tests itself on #[cfg(all(test, unix))] at the parent's declaration site. Since both tests in the module spawn sh and are Unix-only, the cleanest fix is to compile the whole module out on Windows rather than to scatter #[cfg(unix)] across each test.


Generated by Claude Code

- Move executor + fs::file_mode unit tests from inline modules
  to the project's standard `src/<parent>/tests.rs` layout. The
  convention is documented in `CODE_STYLE_GUIDE.md` under "Unit
  test file layout"; zkochan flagged the violation in the
  executor file.

- Gate `pacquet-executor::tests` on `cfg(all(test, unix))` at
  the declaration site so the `use super::execute_shell` import
  isn't dead on Windows. Copilot flagged that
  `clippy --tests --deny warnings` would fail there.

- Drop `execute_shell_propagates_nonzero_exit_as_ok`. Copilot
  flagged that it regression-pinned a behavior that *should*
  change: pnpm/npm `run` exits with the script's status, but
  pacquet's wrapper currently returns `Ok(())` regardless. A
  fix belongs in its own PR; until then we should not add tests
  that block that fix.

- Quote the temp-path redirect targets in the `cli/tests/run.rs`
  shell fixtures so a tempdir path containing a space
  (`/var/folders/...` on macOS) doesn't split the `touch` /
  redirect argument. Copilot flagged the unquoted paths.

The `fs::file_mode::make_file_executable_sets_exec_bits` test
keeps `#[cfg(unix)]` at the test site (and moves its
`make_file_executable` import inside) rather than gating the
whole `tests` module — the other two tests
(`exec_constants_pin_pnpm_layout`,
`is_executable_matches_any_exec_bit`) are platform-neutral and
should still run on Windows.

Copilot's concern about `detect_node_version`'s `expect` (in
`engine_name.rs`) is intentionally not addressed: KSXGitHub
asked for the hard-fail in 5d0987c on grounds that `node` is a
documented prerequisite of the test suite, and the human
reviewer's call wins over the bot's.

https://claude.ai/code/session_01D8WBTfQzTpsZsRknrzwNKL
@zkochan zkochan merged commit e74a6b7 into main May 18, 2026
25 checks passed
@zkochan zkochan deleted the claude/analyze-rust-test-coverage-ZXlQQ branch May 18, 2026 08:21
KSXGitHub pushed a commit that referenced this pull request May 18, 2026
… in new test fixtures

origin/main advanced with four PRs touching files this branch also changes:

- #11679 (fix: silence verify-deps auto-install output) — TS only, no conflict with pacquet/.
- #11705 (feat: tighten minimumReleaseAge) — TS only, no conflict.
- #11708 (refactor(pacquet): optional DI pattern + documentation) —
  renames the test-DI seam (`Api` generic → `Sys`, `RealApi` → `Host`,
  `FsReadString` → `FsReadToString`, fakes drop `*Api` suffix) across
  modules-yaml / cmd-shim / config / reporter / package-manager / cli,
  and adds a "Dependency injection for tests" section to
  `pacquet/CODE_STYLE_GUIDE.md` plus a corresponding rule 7 in
  `pacquet/AGENTS.md`. Most files auto-merged cleanly with this branch's
  single-letter renames; only `pacquet/crates/patching/Cargo.toml`
  needed a manual resolve where this branch added `[lints] workspace = true`
  and main added `text-block-macros` to dev-dependencies — combined.
- #11710 (test(pacquet): coverage) — adds 44 unit + integration tests.
  Two of the new closures (`|v|` in `registry/package/tests.rs:84` and
  `|e|` in `lockfile/save_lockfile/tests.rs:337`) tripped
  `perfectionist::single_letter_closure_param` because they predate this
  branch's enablement of the rule; renamed to `|version|` / `|entry|` to
  keep dylint at zero warnings post-merge.

Verified: `cargo check --workspace --tests --locked` clean,
`cargo dylint --all -- --all-targets --workspace` clean,
`cargo fmt --check` clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants