Skip to content
This repository was archived by the owner on May 14, 2026. It is now read-only.

refactor: extract all inline test modules into dedicated files#369

Merged
zkochan merged 3 commits into
pnpm:mainfrom
Saturate:docs/test-file-threshold
May 2, 2026
Merged

refactor: extract all inline test modules into dedicated files#369
zkochan merged 3 commits into
pnpm:mainfrom
Saturate:docs/test-file-threshold

Conversation

@Saturate

@Saturate Saturate commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Moves every inline #[cfg(test)] mod tests { ... } block across the workspace into external tests.rs files
  • Updates CODE_STYLE_GUIDE.md to require external test files unconditionally (no threshold)
  • 28 files extracted across 8 crates: store-dir, package-manager, fs, package-manifest, lockfile, npmrc, cli, registry
  • No behavioral change

Closes #358.

Test plan

  • cargo check --locked - clean
  • cargo clippy --locked -- --deny warnings - clean
  • cargo fmt -- --check - clean
  • cargo test --lib - all pass (3 pre-existing mock-registry failures on main, unrelated)

Summary by CodeRabbit

  • Documentation
    • Clarified code-style guidance: prefer placing larger unit tests in dedicated external test modules, with a short-in-file declaration preserved.
  • Tests
    • Reorganized many inline test suites into external test modules and added extensive unit and integration tests across the codebase to improve coverage and robustness.

@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 99032273-a987-47eb-9488-cc02874e1982

📥 Commits

Reviewing files that changed from the base of the PR and between 869983a and af2e4ca.

⛔ Files ignored due to path filters (1)
  • crates/package-manager/src/install/snapshots/pacquet_package_manager__install__tests__should_install_dependencies.snap is excluded by !**/*.snap
📒 Files selected for processing (9)
  • crates/lockfile/src/save_lockfile/tests.rs
  • crates/lockfile/src/snapshot_dep_ref/tests.rs
  • crates/npmrc/src/workspace_yaml/tests.rs
  • crates/package-manager/src/build_snapshot/tests.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/package-manager/src/link_file/tests.rs
  • crates/package-manifest/src/tests.rs
  • crates/store-dir/src/check_pkg_files_integrity/tests.rs
✅ Files skipped from review due to trivial changes (4)
  • crates/package-manager/src/build_snapshot/tests.rs
  • crates/lockfile/src/snapshot_dep_ref/tests.rs
  • crates/store-dir/src/check_pkg_files_integrity/tests.rs
  • crates/package-manager/src/link_file/tests.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • crates/lockfile/src/save_lockfile/tests.rs
  • crates/npmrc/src/workspace_yaml/tests.rs
  • crates/package-manager/src/install/tests.rs

📝 Walkthrough

Walkthrough

Refactors many inline Rust unit-test modules into external file-backed #[cfg(test)] mod tests; submodules and adds the corresponding tests.rs files. Also updates CODE_STYLE_GUIDE.md to prefer dedicated external tests submodules and to standardize the parent-side #[cfg(test)] mod tests; declaration.

Changes

Test organization & style-guide

Layer / File(s) Summary
Style guidance
CODE_STYLE_GUIDE.md
Updated guidance to require placing unit tests in a dedicated external tests submodule; documents using #[cfg(test)] mod tests; at the end of parent modules.
Module wiring
crates/*/.../*.rs (many files, e.g. .../ensure_file.rs, .../install.rs, .../state.rs, .../pkg_name.rs, .../store_index.rs, .../link_file.rs, etc.)
Replaced inline #[cfg(test)] mod tests { ... } blocks with #[cfg(test)] mod tests; declarations, moving test implementations to external files.
New/Relocated tests
crates/*/.../*/tests.rs, crates/*/.../tests.rs (many new files)
Added the relocated test modules (e.g., crates/fs/src/ensure_file/tests.rs, crates/package-manager/src/install/tests.rs, crates/lockfile/src/*/tests.rs, etc.) containing the former inline tests.
Test content (preserved/expanded)
crates/*/.../*/tests.rs
Tests cover parsing/serialization, filesystem semantics, store/CAS behavior, msgpackr encoding/decoding, install end-to-end and reporter sequencing, link-file import methods, and many helpers; production code and public APIs were not changed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • zkochan

Poem

🐰 I hopped through source with tidy paws,
Moved tests to burrows and straightened the laws.
Now modules end politely, “mod tests;” they say,
Neat files for each test, tucked safe away.
A quiet nose-twitch — the repo smiles today.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
CODE_STYLE_GUIDE.md (1)

500-503: ⚡ Quick win

Clarify how “~75 lines” should be counted.

The numeric threshold is a big improvement, but “roughly 75 lines” is still ambiguous: does it include blank lines, comments, #[test] attributes, doc comments, etc.? That ambiguity will cause drift (the exact thing this PR is trying to prevent).

Suggested wording change
 #### When the inline form is acceptable
- The inline form `mod tests { ... }` is acceptable when the test module is shorter than roughly 75 lines. Once it exceeds that, move the tests into an external file.
+ The inline form `mod tests { ... }` is acceptable when the test module is shorter than roughly 75 lines (counting the lines inside the `mod tests { ... }` block, excluding the surrounding braces). Once it exceeds that, move the tests into an external file—unless readability clearly suffers earlier.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CODE_STYLE_GUIDE.md` around lines 500 - 503, Clarify the ambiguity around
"roughly 75 lines" for the inline test module rule by specifying exactly what
counts toward the line limit for an inline `mod tests { ... }`: state whether
blank lines, comment lines (including doc comments like /// and //!), attribute
lines (e.g. `#[test]`, `#[cfg(...)]`), and `use`/`extern crate` statements are
included or excluded, and give a short example (e.g., "count all non-empty
lines, including attributes and doc comments, but exclude completely blank
lines") so maintainers have an unambiguous counting rule for `mod tests { ...
}`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@CODE_STYLE_GUIDE.md`:
- Around line 500-503: Clarify the ambiguity around "roughly 75 lines" for the
inline test module rule by specifying exactly what counts toward the line limit
for an inline `mod tests { ... }`: state whether blank lines, comment lines
(including doc comments like /// and //!), attribute lines (e.g. `#[test]`,
`#[cfg(...)]`), and `use`/`extern crate` statements are included or excluded,
and give a short example (e.g., "count all non-empty lines, including attributes
and doc comments, but exclude completely blank lines") so maintainers have an
unambiguous counting rule for `mod tests { ... }`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 6884d7f1-d222-4e46-b573-8895b428cfd2

📥 Commits

Reviewing files that changed from the base of the PR and between d8750cd and aff1151.

📒 Files selected for processing (1)
  • CODE_STYLE_GUIDE.md

@zkochan

zkochan commented May 1, 2026

Copy link
Copy Markdown
Member

IMO the tests should be either in separate files or in the same files. Moving the tests to separate files when they reach a threshold will just break history.

@Saturate

Saturate commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

IMO the tests should be either in separate files or in the same files. Moving the tests to separate files when they reach a threshold will just break history.

Kinda agree, just went of the issue you made. I like separate files more, makes it easy to reason about.

@zkochan

zkochan commented May 2, 2026

Copy link
Copy Markdown
Member

The issue was automatically generated by @KSXGitHub request in a previous PR.

@KSXGitHub

KSXGitHub commented May 2, 2026

Copy link
Copy Markdown
Contributor

@Saturate BTW, can you merge all your previous test reorganization PRs into this one? The docs(dev/guide): in the PR title would then be replaced with refactor: or something.

Unless @zkochan prefers multiple PRs more.

@zkochan

zkochan commented May 2, 2026

Copy link
Copy Markdown
Member

One pr sounds good

Move every inline `#[cfg(test)] mod tests { ... }` block across the
workspace into external `tests.rs` files and update CODE_STYLE_GUIDE.md
to require external test files unconditionally (no threshold).

28 files extracted across 8 crates: store-dir, package-manager, fs,
package-manifest, lockfile, npmrc, cli, registry.

Closes pnpm#358.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 12

🧹 Nitpick comments (6)
crates/package-manager/src/build_snapshot/tests.rs (1)

52-53: ⚡ Quick win

Add diagnostic logging before non-assert_eq! assertions.

Line 52, Line 53, and Line 77 use assert!/matches! without context output, which makes failures harder to diagnose.

Proposed patch
@@
-    assert!(matches!(built.metadata.resolution, LockfileResolution::Registry(_)));
-    assert!(built.snapshot.dependencies.is_none());
+    eprintln!("resolution = {:?}", built.metadata.resolution);
+    assert!(matches!(built.metadata.resolution, LockfileResolution::Registry(_)));
+    eprintln!("dependencies = {:?}", built.snapshot.dependencies);
+    assert!(built.snapshot.dependencies.is_none());
@@
-    assert!(matches!(err, BuildSnapshotError::MissingIntegrity { .. }));
+    eprintln!("error = {:?}", err);
+    assert!(matches!(err, BuildSnapshotError::MissingIntegrity { .. }));

Based on learnings: “In Rust test code, follow the repo’s CODE_STYLE_GUIDE test-logging rule: add logging for non-assert_eq! assertions so failures are diagnosable.”

Also applies to: 77-77

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

In `@crates/package-manager/src/build_snapshot/tests.rs` around lines 52 - 53, The
tests use bare assert!/matches! calls for built.metadata.resolution (matching
LockfileResolution::Registry(_)) and built.snapshot.dependencies (is_none())
without contextual output; before each non-assert_eq! assertion (e.g., the
checks referencing built.metadata.resolution, LockfileResolution::Registry, and
built.snapshot.dependencies and the similar assertion around line 77), add
diagnostic logging that prints the relevant values (for example print or
eprintln the built struct or the specific fields) so test failures show the
actual values; follow the repo test-logging rule by emitting these diagnostics
immediately before the assert so failures are diagnosable.
crates/store-dir/src/cas_file/tests.rs (1)

42-55: ⚡ Quick win

Please add test-context logging before non-assert_eq! assertions.

There are several assert! checks here without explicit diagnostic logging. Add lightweight eprintln! context (mode, generated path, shard byte, etc.) near these assertions for easier failure triage.

Based on learnings: “if you use assertions like assert!, assert_ne!, etc., ensure the test logs the relevant actual/expected values (or context)”.

Also applies to: 86-88, 101-109, 121-123

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

In `@crates/store-dir/src/cas_file/tests.rs` around lines 42 - 55, Add lightweight
test-context logging immediately before the assert! checks that verify
cas_file_path_by_mode results: print the mode (octal), hex, generated path, and
relevant shard byte info using eprintln! so failures show concrete values;
specifically, before each assert! that checks
path.to_string_lossy().ends_with("-exec") (and the inverse checks), call
eprintln! with mode, hex, path, and any shard byte used by cas_file_path_by_mode
(e.g., first byte of hex) to aid triage — do the same for the other assert!
blocks referenced (the checks around the same pattern later in the test).
crates/store-dir/src/store_index/tests.rs (1)

53-55: ⚡ Quick win

Align non-assert_eq! checks with the test-logging rule.

Please add explicit logging around these assert! checks (especially map-membership/emptiness assertions) so CI failures include enough context without reruns.

As per coding guidelines: “log before non-assert_eq! assertions…”.

Also applies to: 95-96, 141-142, 155-156, 195-199, 228-230

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

In `@crates/store-dir/src/store_index/tests.rs` around lines 53 - 55, Add explicit
logs immediately before the non-assert_eq! assertions: bind the key string
("sha512-never\tnone@0.0.0") to a local variable, call idx.get(key) and
idx.contains_key(key) into temporaries, log their values (e.g., via eprintln! or
tracing::debug!) with the key and returned Option/Result for context, then run
the existing assert!(...is_none()) and assert!(!...). Apply the same pattern to
the other occurrences that use idx.get(...) and idx.contains_key(...) (the
blocks around the other listed checks) so each non-assert_eq!
map-membership/emptiness assertion has a preceding log showing the key and
result.
crates/fs/src/ensure_file/tests.rs (1)

108-109: ⚡ Quick win

Add diagnostic logging around non-assert_eq! assertions in this test suite.

Coverage is solid, but many boolean/assertion checks still lack explicit log context. Please add targeted eprintln! values before these assertions to follow the repo’s test-failure diagnostics convention.

Based on learnings: “if you use assertions like assert!, assert_ne!, etc., ensure the test logs the relevant actual/expected values (or context)”.

Also applies to: 118-120, 141-148, 163-167, 190-194, 235-236, 249-254, 277-282

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

In `@crates/fs/src/ensure_file/tests.rs` around lines 108 - 109, Before each
non-assert_eq! boolean assertion (e.g., the assert! that checks
name.starts_with("cdefx") which uses the variable name), add an eprintln! that
prints the actual and expected values (for example: the runtime value of name
and the expected prefix) so test-failure output shows context; do the same for
the other boolean assertions mentioned (the checks in the groups at 118-120,
141-148, 163-167, 190-194, 235-236, 249-254, 277-282) by emitting concise
diagnostic lines that show the relevant variables/expected values immediately
before the assert!/assert_ne! calls (use the same variable names and
expectations found in those assertions).
crates/store-dir/src/store_dir/tests.rs (1)

35-43: ⚡ Quick win

Add explicit diagnostic logging around non-assert_eq! loop assertions.

These looped assert! checks currently rely on assertion text only. Please add eprintln! context (e.g., shard path/state) before assertions to match the repo’s test-debuggability rule.

As per coding guidelines: “Follow test-logging guidance in CODE_STYLE_GUIDE.md: log before non-assert_eq! assertions…”.

Also applies to: 79-83, 105-110

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

In `@crates/store-dir/src/store_dir/tests.rs` around lines 35 - 43, Before the
looped assert! checks, add eprintln! calls that print diagnostic context: the
shard hex name, the full shard path (files.join(&name).display()), and the
result of store.shard_already_ensured(shard) so failures show state before
panicking. Locate the loop that iterates shard (variable shard, name =
format!("{shard:02x}"), files, and store.shard_already_ensured) and insert
eprintln! lines immediately before each assert! (and repeat the same pattern for
the similar loops around the other assertions mentioned) to log shard path/state
and the boolean cache check.
crates/npmrc/src/workspace_yaml/tests.rs (1)

23-23: ⚡ Quick win

Add diagnostics around non-assert_eq! assertions in tests.

These assertions should log relevant values/context (or be converted to assert_eq! when practical) so failures are diagnosable without reruns.

As per coding guidelines, "Follow test-logging guidance in CODE_STYLE_GUIDE.md: log before non-assert_eq! assertions, dbg! complex structures, skip logging for simple scalar assert_eq!."

Also applies to: 59-59, 61-61, 122-122, 124-124, 157-157

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

In `@crates/npmrc/src/workspace_yaml/tests.rs` at line 23, The test contains a
non-descriptive assert! (assert!(matches!(settings.node_linker,
Some(NodeLinker::Hoisted)))) which should include diagnostics; update the
test(s) in workspace_yaml::tests (symbols: settings, node_linker,
NodeLinker::Hoisted and the other mentioned assertions) to either convert to
assert_eq! when comparing scalars or log the actual values just before the
assert (e.g., using dbg! or a test-specific eprintln!/log macro) so failures
show settings.node_linker and related values; apply the same pattern to the
other asserted locations referenced (lines covering the other matches/asserts)
to ensure actionable test failure output.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@crates/lockfile/src/save_lockfile/tests.rs`:
- Line 95: The test currently uses assert!(matches!(err,
SaveLockfileError::WriteFile(_))) without showing the actual error on failure;
update that assertion to include diagnostics by providing a custom message that
prints the actual err (e.g., change the assertion to assert!(matches!(err,
SaveLockfileError::WriteFile(_)), "unexpected SaveLockfileError: {:?}", err)) so
failures include the err value; refer to the SaveLockfileError value named err
and the existing matches! assertion to locate and replace the assertion.
- Around line 93-95: Replace the hardcoded absolute bad_path with a path
guaranteed to be missing inside a temp directory: create a temp dir (e.g. via
tempfile::tempdir()), build a nested non-existent path by joining a subdirectory
and "pnpm-lock.yaml" (do not create the subdirectory), call
empty_lockfile.save_to_path(the_missing_path) and expect_err, and assert it
matches SaveLockfileError::WriteFile(_); this makes the invalid-path test
deterministic across environments.

In `@crates/lockfile/src/snapshot_dep_ref/tests.rs`:
- Around line 88-97: The test looks_like_alias_rules uses bare assert! calls
which provide poor failure diagnostics; change it to a table-driven assertion
using the looks_like_alias_rules test and the looks_like_alias function: build a
list of (input, expected_bool) cases for strings like "5.1.2",
"17.0.2(react@17.0.2)", "string-width@4.2.3", "@types/react@17.0.49",
"react-dom@17.0.2(react@17.0.2)", "link:../foo", "workspace:*" and iterate
asserting assert_eq!(looks_like_alias(input), expected, "input = {}", input) so
failures show expected vs actual and the input that failed; alternatively
replace each assert! with assert_eq!(looks_like_alias("<str>"), <true|false>,
"input = <str>").

In `@crates/npmrc/src/custom_deserializer/tests.rs`:
- Around line 21-44: The first test (test_default_store_dir_with_pnpm_home)
currently mutates PNPM_HOME with an unsafe env::set_var call without using
EnvGuard; change it to snapshot the environment first like the other test by
calling let _g = EnvGuard::snapshot(["PNPM_HOME"]); then perform the env
mutation and assertion (you may keep the SAFETY comment and the unsafe block
around env::set_var if desired), so default_store_dir and display_store_dir are
exercised under EnvGuard serialization for soundness and consistency with
test_default_store_dir_with_xdg_env.

In `@crates/npmrc/src/workspace_yaml/tests.rs`:
- Line 58: Replace the platform-dependent string comparison with a direct
StoreDir value comparison: instead of asserting
npmrc.store_dir.display().to_string() == "/absolute/store", construct the
expected StoreDir (using the same constructor/pattern used at line 76) and
assert equality with npmrc.store_dir; reference the StoreDir type and the
npmrc.store_dir field to locate the assertion to change.

In `@crates/package-manager/src/install_package_from_registry/tests.rs`:
- Line 80: Before the assertion assert!(virtual_store_path.is_dir()) add
diagnostic logging that prints the path and its metadata (e.g., existence and
file type) so CI failures show context; specifically, log virtual_store_path and
results of virtual_store_path.exists() and virtual_store_path.metadata() (or use
dbg!/eprintln!/tracing::debug! as appropriate) immediately before the assert to
provide readable failure information for debugging.

In `@crates/package-manager/src/install/tests.rs`:
- Around line 55-65: The test contains plain assert! checks that lack diagnostic
context; before each assert! that verifies filesystem state (the calls using
project_root and is_symlink_or_junction, and checks on paths like
node_modules/.pacquet/@pnpm.e2e+hello-world-js-bin@1.0.0 and
node_modules/.pacquet/@pnpm+xyz@1.0.0) add brief logging (eprintln! or dbg!)
that prints the path and relevant metadata (exists(), is_dir(), and the result
of is_symlink_or_junction) so failures show current state; apply the same
pattern to any other non-assert_eq! assertions in this test file to follow the
CODE_STYLE_GUIDE.md testing guidance.
- Around line 417-469: Reset the process-global EVENTS vector before the test
run to avoid events leaking across retries: call EVENTS.lock().unwrap().clear()
(or replace the Mutex contents) at the start of the test (e.g., just before
creating RecordingReporter / before the Install.run::<RecordingReporter>()
invocation) so the static EVENTS is empty when RecordingReporter::emit pushes
new events; reference the static EVENTS and the RecordingReporter used in the
test to locate where to insert the clear call.

In `@crates/package-manager/src/link_file/tests.rs`:
- Around line 66-67: The failing tests use non-`assert_eq!` checks that lack
diagnostic output; before the `assert!(src_meta.nlink() >= 2, "hardlink should
bump nlink")` in tests.rs (and the similar checks around the other mentioned
spots), add a pre-assert diagnostic that prints the relevant values (e.g., call
dbg!/eprintln! on `src_meta.nlink()`, the full `src_meta`/`dst_meta` or symlink
metadata variables and any path variables) so CI failures show runtime values;
follow CODE_STYLE_GUIDE.md by using simple prints for scalars and `dbg!` for
complex structs and place them immediately before the `assert!`/`assert_ne!`
invocations.

In `@crates/package-manifest/src/tests.rs`:
- Around line 30-31: Before each non-assert_eq! assertion (e.g., the assertions
calling tmp.exists() and tmp.is_file(), and the other assert!/assert_ne! sites
mentioned), add a diagnostic log that prints the actual values and context so
failures are easier to debug; specifically, emit a message (using eprintln! or
the test crate's logger) showing tmp.display() and the boolean results of
tmp.exists() and tmp.is_file() immediately before the assert! calls, and do the
same pattern for the other assert!/assert_ne! checks referenced so the test
output contains the actual vs expected values when an assertion fails.
- Line 69: The test currently calls manifest.script("test", false).unwrap() but
only verifies success; change it to capture the returned value (e.g., let script
= manifest.script("test", false).unwrap();) and add an assertion that the
returned script equals the expected string (assert_eq!(script, "<expected script
string>")), replacing "<expected script string>" with the actual script you
expect for the "test" entry so regressions in the returned value are caught;
reference the manifest.script("test", false) call and the resulting variable
name when adding the assertion.

In `@crates/store-dir/src/check_pkg_files_integrity/tests.rs`:
- Around line 58-60: The tests have several assert! / assert_ne! checks that
lack runtime context, making CI failures hard to diagnose; before each
non-assert_eq! assertion (e.g., the block with result, the lookup
result.files_map.get("index.js") and the path.exists() assertion) add a
diagnostic print such as eprintln! or dbg! that prints the relevant values
(e.g., the entire result, the files_map entry, the resolved PathBuf, and any
cache/state variables used in the test) so failures will show runtime context;
apply the same pattern to the other assertion sites referenced (lines around 83,
96–97, 117–119, 134–136, 154–155, 184–186, 193–197, 214–215, 226–229, 246–248,
268–273, 285–287) by inserting a short eprintln!/dbg! immediately before each
assert! / assert_ne! that logs the symbols used in that assertion.

---

Nitpick comments:
In `@crates/fs/src/ensure_file/tests.rs`:
- Around line 108-109: Before each non-assert_eq! boolean assertion (e.g., the
assert! that checks name.starts_with("cdefx") which uses the variable name), add
an eprintln! that prints the actual and expected values (for example: the
runtime value of name and the expected prefix) so test-failure output shows
context; do the same for the other boolean assertions mentioned (the checks in
the groups at 118-120, 141-148, 163-167, 190-194, 235-236, 249-254, 277-282) by
emitting concise diagnostic lines that show the relevant variables/expected
values immediately before the assert!/assert_ne! calls (use the same variable
names and expectations found in those assertions).

In `@crates/npmrc/src/workspace_yaml/tests.rs`:
- Line 23: The test contains a non-descriptive assert!
(assert!(matches!(settings.node_linker, Some(NodeLinker::Hoisted)))) which
should include diagnostics; update the test(s) in workspace_yaml::tests
(symbols: settings, node_linker, NodeLinker::Hoisted and the other mentioned
assertions) to either convert to assert_eq! when comparing scalars or log the
actual values just before the assert (e.g., using dbg! or a test-specific
eprintln!/log macro) so failures show settings.node_linker and related values;
apply the same pattern to the other asserted locations referenced (lines
covering the other matches/asserts) to ensure actionable test failure output.

In `@crates/package-manager/src/build_snapshot/tests.rs`:
- Around line 52-53: The tests use bare assert!/matches! calls for
built.metadata.resolution (matching LockfileResolution::Registry(_)) and
built.snapshot.dependencies (is_none()) without contextual output; before each
non-assert_eq! assertion (e.g., the checks referencing
built.metadata.resolution, LockfileResolution::Registry, and
built.snapshot.dependencies and the similar assertion around line 77), add
diagnostic logging that prints the relevant values (for example print or
eprintln the built struct or the specific fields) so test failures show the
actual values; follow the repo test-logging rule by emitting these diagnostics
immediately before the assert so failures are diagnosable.

In `@crates/store-dir/src/cas_file/tests.rs`:
- Around line 42-55: Add lightweight test-context logging immediately before the
assert! checks that verify cas_file_path_by_mode results: print the mode
(octal), hex, generated path, and relevant shard byte info using eprintln! so
failures show concrete values; specifically, before each assert! that checks
path.to_string_lossy().ends_with("-exec") (and the inverse checks), call
eprintln! with mode, hex, path, and any shard byte used by cas_file_path_by_mode
(e.g., first byte of hex) to aid triage — do the same for the other assert!
blocks referenced (the checks around the same pattern later in the test).

In `@crates/store-dir/src/store_dir/tests.rs`:
- Around line 35-43: Before the looped assert! checks, add eprintln! calls that
print diagnostic context: the shard hex name, the full shard path
(files.join(&name).display()), and the result of
store.shard_already_ensured(shard) so failures show state before panicking.
Locate the loop that iterates shard (variable shard, name =
format!("{shard:02x}"), files, and store.shard_already_ensured) and insert
eprintln! lines immediately before each assert! (and repeat the same pattern for
the similar loops around the other assertions mentioned) to log shard path/state
and the boolean cache check.

In `@crates/store-dir/src/store_index/tests.rs`:
- Around line 53-55: Add explicit logs immediately before the non-assert_eq!
assertions: bind the key string ("sha512-never\tnone@0.0.0") to a local
variable, call idx.get(key) and idx.contains_key(key) into temporaries, log
their values (e.g., via eprintln! or tracing::debug!) with the key and returned
Option/Result for context, then run the existing assert!(...is_none()) and
assert!(!...). Apply the same pattern to the other occurrences that use
idx.get(...) and idx.contains_key(...) (the blocks around the other listed
checks) so each non-assert_eq! map-membership/emptiness assertion has a
preceding log showing the key and result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: cdb9d135-c0c9-4f08-8485-01f28e48d049

📥 Commits

Reviewing files that changed from the base of the PR and between aff1151 and 869983a.

📒 Files selected for processing (57)
  • CODE_STYLE_GUIDE.md
  • crates/cli/src/cli_args/add.rs
  • crates/cli/src/cli_args/add/tests.rs
  • crates/cli/src/cli_args/install.rs
  • crates/cli/src/cli_args/install/tests.rs
  • crates/cli/src/state.rs
  • crates/cli/src/state/tests.rs
  • crates/fs/src/ensure_file.rs
  • crates/fs/src/ensure_file/tests.rs
  • crates/lockfile/src/comver.rs
  • crates/lockfile/src/comver/tests.rs
  • crates/lockfile/src/lockfile_version.rs
  • crates/lockfile/src/lockfile_version/tests.rs
  • crates/lockfile/src/pkg_name.rs
  • crates/lockfile/src/pkg_name/tests.rs
  • crates/lockfile/src/pkg_name_ver.rs
  • crates/lockfile/src/pkg_name_ver/tests.rs
  • crates/lockfile/src/pkg_name_ver_peer.rs
  • crates/lockfile/src/pkg_name_ver_peer/tests.rs
  • crates/lockfile/src/pkg_ver_peer.rs
  • crates/lockfile/src/pkg_ver_peer/tests.rs
  • crates/lockfile/src/project_snapshot.rs
  • crates/lockfile/src/project_snapshot/tests.rs
  • crates/lockfile/src/resolution.rs
  • crates/lockfile/src/resolution/tests.rs
  • crates/lockfile/src/save_lockfile.rs
  • crates/lockfile/src/save_lockfile/tests.rs
  • crates/lockfile/src/snapshot_dep_ref.rs
  • crates/lockfile/src/snapshot_dep_ref/tests.rs
  • crates/npmrc/src/custom_deserializer.rs
  • crates/npmrc/src/custom_deserializer/tests.rs
  • crates/npmrc/src/npmrc_auth.rs
  • crates/npmrc/src/npmrc_auth/tests.rs
  • crates/npmrc/src/workspace_yaml.rs
  • crates/npmrc/src/workspace_yaml/tests.rs
  • crates/package-manager/src/build_snapshot.rs
  • crates/package-manager/src/build_snapshot/tests.rs
  • crates/package-manager/src/install.rs
  • crates/package-manager/src/install/tests.rs
  • crates/package-manager/src/install_package_from_registry.rs
  • crates/package-manager/src/install_package_from_registry/tests.rs
  • crates/package-manager/src/link_file.rs
  • crates/package-manager/src/link_file/tests.rs
  • crates/package-manifest/src/lib.rs
  • crates/package-manifest/src/tests.rs
  • crates/registry/src/package.rs
  • crates/registry/src/package/tests.rs
  • crates/store-dir/src/cas_file.rs
  • crates/store-dir/src/cas_file/tests.rs
  • crates/store-dir/src/check_pkg_files_integrity.rs
  • crates/store-dir/src/check_pkg_files_integrity/tests.rs
  • crates/store-dir/src/msgpackr_records.rs
  • crates/store-dir/src/msgpackr_records/tests.rs
  • crates/store-dir/src/store_dir.rs
  • crates/store-dir/src/store_dir/tests.rs
  • crates/store-dir/src/store_index.rs
  • crates/store-dir/src/store_index/tests.rs
✅ Files skipped from review due to trivial changes (30)
  • crates/lockfile/src/pkg_name_ver.rs
  • crates/cli/src/state/tests.rs
  • crates/package-manager/src/install.rs
  • crates/lockfile/src/comver.rs
  • crates/lockfile/src/comver/tests.rs
  • crates/lockfile/src/save_lockfile.rs
  • crates/npmrc/src/npmrc_auth.rs
  • crates/lockfile/src/pkg_ver_peer.rs
  • crates/lockfile/src/project_snapshot.rs
  • crates/package-manager/src/install_package_from_registry.rs
  • crates/registry/src/package/tests.rs
  • crates/cli/src/cli_args/add.rs
  • crates/lockfile/src/pkg_name_ver/tests.rs
  • crates/npmrc/src/workspace_yaml.rs
  • crates/package-manifest/src/lib.rs
  • crates/store-dir/src/store_dir.rs
  • crates/lockfile/src/snapshot_dep_ref.rs
  • crates/store-dir/src/check_pkg_files_integrity.rs
  • crates/lockfile/src/pkg_name.rs
  • crates/registry/src/package.rs
  • crates/lockfile/src/resolution.rs
  • crates/store-dir/src/cas_file.rs
  • crates/npmrc/src/custom_deserializer.rs
  • crates/store-dir/src/msgpackr_records.rs
  • crates/lockfile/src/pkg_name_ver_peer/tests.rs
  • crates/lockfile/src/lockfile_version.rs
  • crates/package-manager/src/link_file.rs
  • crates/cli/src/cli_args/install.rs
  • crates/lockfile/src/pkg_name_ver_peer.rs
  • CODE_STYLE_GUIDE.md

Comment thread crates/lockfile/src/save_lockfile/tests.rs Outdated
Comment thread crates/lockfile/src/save_lockfile/tests.rs Outdated
Comment thread crates/lockfile/src/snapshot_dep_ref/tests.rs
Comment on lines +21 to +44
unsafe {
env::set_var("PNPM_HOME", "/tmp/pnpm-home"); // TODO: change this to dependency injection
}
let store_dir = default_store_dir();
assert_eq!(display_store_dir(&store_dir), "/tmp/pnpm-home/store");
}

#[test]
fn test_default_store_dir_with_xdg_env() {
// `default_store_dir` checks `PNPM_HOME` before `XDG_DATA_HOME`,
// so a developer running the test suite with pnpm in their
// environment (very common) otherwise sees the `PNPM_HOME`
// branch win and the assertion fail. Snapshot-and-restore both
// env vars so the test is self-contained even under nextest's
// in-process parallelism. Proper fix is dependency injection —
// see the TODO — but this is enough for the failure mode this
// PR is fixing.
let _g = EnvGuard::snapshot(["PNPM_HOME", "XDG_DATA_HOME"]);
// SAFETY: EnvGuard above serializes the test against other env-mutating
// tests in this process; no other thread reads these vars concurrently.
unsafe {
env::remove_var("PNPM_HOME");
env::set_var("XDG_DATA_HOME", "/tmp/xdg_data_home");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify EnvGuard implementation and env access patterns in this crate.
# Expected: EnvGuard uses a global lock, and env reads/writes in tests are consistently guarded or isolated.

set -euo pipefail

echo "== Locate EnvGuard implementation =="
fd -i 'test_env_guard.rs'

echo
echo "== Inspect EnvGuard synchronization details =="
rg -n -C4 'struct\s+EnvGuard|impl\s+EnvGuard|fn\s+snapshot|Mutex|RwLock|OnceLock|lazy_static' crates/npmrc/src

echo
echo "== Find env access sites in npmrc crate source/tests =="
rg -n -C2 'env::(set_var|remove_var|var|vars)\(' crates/npmrc/src

Repository: pnpm/pacquet

Length of output: 7329


Make the first test use EnvGuard for consistency and soundness.

The second test (test_default_store_dir_with_xdg_env) correctly uses EnvGuard::snapshot(...) to serialize env mutations. The first test (test_default_store_dir_with_pnpm_home, line 21) should do the same instead of relying on an unsafe comment alone. EnvGuard is already implemented in this crate with a process-wide Mutex and proper snapshot/restore semantics; the inconsistency between these two adjacent tests is a maintenance hazard.

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

In `@crates/npmrc/src/custom_deserializer/tests.rs` around lines 21 - 44, The
first test (test_default_store_dir_with_pnpm_home) currently mutates PNPM_HOME
with an unsafe env::set_var call without using EnvGuard; change it to snapshot
the environment first like the other test by calling let _g =
EnvGuard::snapshot(["PNPM_HOME"]); then perform the env mutation and assertion
(you may keep the SAFETY comment and the unsafe block around env::set_var if
desired), so default_store_dir and display_store_dir are exercised under
EnvGuard serialization for soundness and consistency with
test_default_store_dir_with_xdg_env.

Comment thread crates/npmrc/src/workspace_yaml/tests.rs Outdated
Comment thread crates/package-manager/src/install/tests.rs
Comment thread crates/package-manager/src/link_file/tests.rs
Comment thread crates/package-manifest/src/tests.rs
Comment thread crates/package-manifest/src/tests.rs Outdated
Comment thread crates/store-dir/src/check_pkg_files_integrity/tests.rs
@Saturate

Saturate commented May 2, 2026

Copy link
Copy Markdown
Contributor Author

It's done.

@KSXGitHub

Copy link
Copy Markdown
Contributor

Fix the tests please.

zkochan added 2 commits May 2, 2026 20:42
When `install::tests::should_install_dependencies` moved from the
inline `mod tests` in `install.rs` to the external
`install/tests.rs`, insta's snapshot lookup directory shifted from
`crates/package-manager/src/snapshots/` to
`crates/package-manager/src/install/snapshots/`. CI failed on every
platform because no snapshot existed at the new location. Move the
existing `.snap` file to its new home.
Apply the actionable review comments on the test-extraction PR:

- save_lockfile: replace hardcoded `/nonexistent-pacquet-dir/...`
  with a tempdir-based missing path so the invalid-path test is
  deterministic across environments; add diagnostic message to the
  `matches!` assertion.
- snapshot_dep_ref: convert `looks_like_alias_rules` to a
  table-driven `assert_eq!` form with per-case logging.
- npmrc/workspace_yaml: compare `StoreDir` values directly instead
  of `display().to_string()`, which produces backslashes on Windows
  and would fail the `apply_overrides_npmrc_defaults` test there.
- package-manager/install: clear the static `EVENTS` mutex at the
  start of `install_emits_pnpm_event_sequence` so retries don't
  inherit stale events; add per-path logging before the
  `is_symlink_or_junction` / `exists` / `is_dir` assertions.
- package-manager/link_file: same `EVENTS.clear()` defense in
  `log_method_once_emits_first_call_per_method_only`; add
  diagnostics before nlink and symlink-metadata assertions.
- package-manager/build_snapshot: log the relevant fields before
  the `matches!` and `is_none` assertions.
- package-manager/install_package_from_registry: log
  `virtual_store_path` state before the `is_dir` assertion.
- package-manifest: assert the actual return value of
  `manifest.script("test", false)` (was `Some("echo")`) and
  `manifest.script("invalid", true)` (was `None`); add `dbg!` /
  `eprintln!` diagnostics around the bare `assert!` checks per
  CODE_STYLE_GUIDE.md.
- store-dir/check_pkg_files_integrity: add `dbg!(&result)` and
  path-existence logging before each non-`assert_eq!` assertion
  across all 11 tests.
@zkochan zkochan merged commit f79f7a4 into pnpm:main May 2, 2026
12 of 13 checks passed
zkochan added a commit that referenced this pull request May 2, 2026
main landed #369 ("extract all inline test modules into dedicated
files") while this PR was open, switching the workspace convention
to external `tests.rs` files for every test module. The unit tests
this PR added in `create_virtual_dir_by_snapshot.rs`,
`install_package_by_snapshot.rs`, and `create_virtual_store.rs`
were inline; move each one to its dedicated `<parent>/tests.rs`
with a `#[cfg(test)] mod tests;` declaration on the parent, matching
the rest of the package-manager crate.

No behavioral change.
@Saturate Saturate deleted the docs/test-file-threshold branch May 4, 2026 08:26
KSXGitHub pushed a commit that referenced this pull request May 5, 2026
Match the workspace convention solidified by #369: tests
in unit-test modules under `src/` carry `///` doc comments so the
intent of each case renders under `cargo doc --document-private-items`.
The integration tests at `crates/modules-yaml/tests/index.rs` follow
the same convention here.

Section preambles between tests stay as `//` because they apply to
multiple `#[test]` items rather than to a single function. A blank
line between two `///` blocks orphans the earlier block from the
following item, so collapsing them would silently drop the section
context.

No behavior change. Tests remain 18/18 passing.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Extract long inline mod tests into dedicated test files

3 participants