diff --git a/crates/socket-patch-cli/tests/hosted_memory_engine.rs b/crates/socket-patch-cli/tests/hosted_memory_engine.rs index cc00ffc4f..af468e149 100644 --- a/crates/socket-patch-cli/tests/hosted_memory_engine.rs +++ b/crates/socket-patch-cli/tests/hosted_memory_engine.rs @@ -2281,7 +2281,9 @@ async fn user_patched_npm_packages_are_never_pinned() { .unwrap_or_else(|| panic!("{fixture} {file}: {:?}", project.skipped)); assert_eq!(skip.purl, "pkg:npm/left-pad@1.3.0"); assert!( - skip.detail.as_deref().is_some_and(|d| d.contains(file)), + skip.detail + .as_deref() + .is_some_and(|d| d.replace('\\', "/").contains(file)), "{fixture}: {:?}", skip.detail ); diff --git a/crates/socket-patch-core/src/patch/user_patches.rs b/crates/socket-patch-core/src/patch/user_patches.rs index 5e17d12b9..700b05b2b 100644 --- a/crates/socket-patch-core/src/patch/user_patches.rs +++ b/crates/socket-patch-core/src/patch/user_patches.rs @@ -1232,7 +1232,12 @@ impl Bound { ) } Bound::Disk { root, repo } => { - !normalize_lexically_keeping_escapes(&root.join(rel)).starts_with(repo) + // `repo` is canonical (`\\?\C:\...` on Windows) while a + // script names a directory as users type it (`C:\...`), and + // `starts_with` treats the two prefixes as different. + use crate::utils::pnpm_workspace::without_verbatim_prefix; + !without_verbatim_prefix(normalize_lexically_keeping_escapes(&root.join(rel))) + .starts_with(without_verbatim_prefix(repo.clone())) } } } @@ -2058,14 +2063,14 @@ mod tests { assert!( left_pad .iter() - .any(|s| s.ends_with("fixes/left-pad+1.3.0.patch")), + .any(|s| s.replace('\\', "/").ends_with("fixes/left-pad+1.3.0.patch")), "{left_pad:?}" ); let is_number = global.conflicts("pkg:npm/is-number@7.0.0"); assert!( - is_number - .iter() - .any(|s| s.ends_with("shared/a/patches/is-number+7.0.0.patch")), + is_number.iter().any(|s| s + .replace('\\', "/") + .ends_with("shared/a/patches/is-number+7.0.0.patch")), "{is_number:?}" ); assert!(global.conflicts("pkg:npm/right-pad@1.3.0").is_empty()); @@ -2115,15 +2120,17 @@ mod tests { let tmp = tempfile::tempdir().unwrap(); let repo = std::fs::canonicalize(tmp.path()).unwrap(); write(&repo, ".git/HEAD", "ref: refs/heads/main\n"); - let fixes = repo.join("fixes"); - write( - &repo, - "package.json", - &format!( - r#"{{"scripts":{{"postinstall":"patch-package --patch-dir {}"}}}}"#, - fixes.display() - ), - ); + // Spelled as a user types it: on Windows without the `\\?\` prefix + // `canonicalize` adds to `repo`, quoted in case the temp dir has a + // space, and built as JSON so its backslashes are escaped. + let fixes = + crate::utils::pnpm_workspace::without_verbatim_prefix(repo.clone()).join("fixes"); + let manifest = serde_json::json!({ + "scripts": { + "postinstall": format!("patch-package --patch-dir \"{}\"", fixes.display()) + } + }); + write(&repo, "package.json", &manifest.to_string()); write(&repo, "fixes/left-pad+1.3.0.patch", "diff\n"); let index = UserPatchIndex::discover(&repo).await; assert!( diff --git a/crates/socket-patch-core/src/utils/cargo_build_cache.rs b/crates/socket-patch-core/src/utils/cargo_build_cache.rs index 116888c1b..bcbd3bcab 100644 --- a/crates/socket-patch-core/src/utils/cargo_build_cache.rs +++ b/crates/socket-patch-core/src/utils/cargo_build_cache.rs @@ -437,7 +437,13 @@ mod tests { .unwrap(); let warnings = invalidate_project(ReadScope::Workspace, &app, purls); assert_eq!(warnings.len(), 1, "{warnings:?}"); - assert!(warnings[0].1.contains(".cargo/config.toml"), "{warnings:?}"); + assert!( + warnings[0] + .1 + .replace('\\', "/") + .contains(".cargo/config.toml"), + "{warnings:?}" + ); // A global run reads it as before. assert!(invalidate_project(ReadScope::Global, &app, purls).is_empty()); } diff --git a/crates/socket-patch-core/src/utils/repo_root_upward_tests.rs b/crates/socket-patch-core/src/utils/repo_root_upward_tests.rs index f7f22b82c..fc4571069 100644 --- a/crates/socket-patch-core/src/utils/repo_root_upward_tests.rs +++ b/crates/socket-patch-core/src/utils/repo_root_upward_tests.rs @@ -135,7 +135,8 @@ fn pnpm_workspace_file_above_the_repository_fails_closed() { write(&file, "packages:\n - other\n"); assert_eq!( crate::utils::pnpm_workspace::governing_workspace_file(&l.app), - Some(file) + // Reported without Windows' `\\?\` prefix, which `layout` keeps. + Some(crate::utils::pnpm_workspace::without_verbatim_prefix(file)) ); let plain = layout(false); write( diff --git a/crates/socket-patch-core/src/vex/discover/user_patched.rs b/crates/socket-patch-core/src/vex/discover/user_patched.rs index 7fd7fcede..7258c233d 100644 --- a/crates/socket-patch-core/src/vex/discover/user_patched.rs +++ b/crates/socket-patch-core/src/vex/discover/user_patched.rs @@ -328,6 +328,7 @@ mod tests { assert!( out.unattested[0] .detail + .replace('\\', "/") .contains("patches/left-pad+1.3.0.patch"), "{}", out.unattested[0].detail @@ -420,7 +421,7 @@ mod tests { all_marked(&out, what); let member = files[files.len() - 1].0.rsplit_once('/').unwrap().0; assert!( - out.unattested[0].detail.contains(member), + out.unattested[0].detail.replace('\\', "/").contains(member), "{what}: {}", out.unattested[0].detail );