Skip to content

Commit 406ed1a

Browse files
branchseerclaude
andcommitted
test: add tests for Windows PATH case-insensitivity fix
Add comprehensive tests for the Windows PATH case-insensitivity handling: - test_windows_path_case_insensitive_mixed_case: Verifies mixed case "Path" is preserved and modified correctly - test_windows_path_case_insensitive_uppercase: Tests uppercase "PATH" baseline case - test_windows_path_created_when_missing: Ensures new "PATH" is created when missing - test_unix_path_case_sensitive: Regression test to ensure Unix maintains case-sensitive PATH behavior All tests verify exact PATH values using OsStr comparisons. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent e0b9137 commit 406ed1a

File tree

1 file changed

+186
-0
lines changed

1 file changed

+186
-0
lines changed

crates/vite_task/src/execute.rs

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -901,4 +901,190 @@ mod tests {
901901
assert!(all_envs.contains_key("app1_name"));
902902
assert!(all_envs.contains_key("app2_name"));
903903
}
904+
905+
#[test]
906+
#[cfg(windows)]
907+
fn test_windows_path_case_insensitive_mixed_case() {
908+
use crate::{
909+
collections::HashSet,
910+
config::{ResolvedTaskConfig, TaskCommand, TaskConfig},
911+
};
912+
913+
let task_config = TaskConfig {
914+
command: TaskCommand::ShellScript("echo test".into()),
915+
cwd: RelativePathBuf::default(),
916+
cacheable: true,
917+
inputs: HashSet::new(),
918+
envs: HashSet::new(),
919+
pass_through_envs: HashSet::new(),
920+
fingerprint_ignores: None,
921+
};
922+
let resolved =
923+
ResolvedTaskConfig { config_dir: RelativePathBuf::default(), config: task_config };
924+
925+
// Mock environment with mixed case "Path" (common on Windows)
926+
let mock_envs = vec![
927+
(OsString::from("Path"), OsString::from("C:\\existing\\path")),
928+
(OsString::from("OTHER_VAR"), OsString::from("value")),
929+
];
930+
931+
let base_dir = AbsolutePath::new("C:\\workspace\\packages\\app").unwrap();
932+
933+
let result = TaskEnvs::resolve(mock_envs.into_iter(), &base_dir, &resolved).unwrap();
934+
935+
let all_envs = result.all_envs;
936+
937+
// Verify that the original "Path" casing is preserved, not "PATH"
938+
assert!(all_envs.contains_key("Path"));
939+
assert!(!all_envs.contains_key("PATH"));
940+
941+
// Verify the complete PATH value matches expected
942+
let path_value = all_envs.get("Path").unwrap();
943+
assert_eq!(
944+
path_value.as_ref(),
945+
OsStr::new(
946+
"C:\\workspace\\packages\\app\\node_modules\\.bin;C:\\workspace\\packages\\app\\node_modules\\.bin;C:\\existing\\path"
947+
)
948+
);
949+
950+
// Verify no duplicate PATH entry was created
951+
let path_like_keys: Vec<_> =
952+
all_envs.keys().filter(|k| k.eq_ignore_ascii_case("path")).collect();
953+
assert_eq!(path_like_keys.len(), 1);
954+
}
955+
956+
#[test]
957+
#[cfg(windows)]
958+
fn test_windows_path_case_insensitive_uppercase() {
959+
use crate::{
960+
collections::HashSet,
961+
config::{ResolvedTaskConfig, TaskCommand, TaskConfig},
962+
};
963+
964+
let task_config = TaskConfig {
965+
command: TaskCommand::ShellScript("echo test".into()),
966+
cwd: RelativePathBuf::default(),
967+
cacheable: true,
968+
inputs: HashSet::new(),
969+
envs: HashSet::new(),
970+
pass_through_envs: HashSet::new(),
971+
fingerprint_ignores: None,
972+
};
973+
let resolved =
974+
ResolvedTaskConfig { config_dir: RelativePathBuf::default(), config: task_config };
975+
976+
// Mock environment with uppercase "PATH"
977+
let mock_envs = vec![
978+
(OsString::from("PATH"), OsString::from("C:\\existing\\path")),
979+
(OsString::from("OTHER_VAR"), OsString::from("value")),
980+
];
981+
982+
let base_dir = AbsolutePath::new("C:\\workspace\\packages\\app").unwrap();
983+
984+
let result = TaskEnvs::resolve(mock_envs.into_iter(), &base_dir, &resolved).unwrap();
985+
986+
let all_envs = result.all_envs;
987+
988+
// Verify that "PATH" is preserved
989+
assert!(all_envs.contains_key("PATH"));
990+
991+
// Verify the complete PATH value matches expected
992+
let path_value = all_envs.get("PATH").unwrap();
993+
assert_eq!(
994+
path_value.as_ref(),
995+
OsStr::new(
996+
"C:\\workspace\\packages\\app\\node_modules\\.bin;C:\\workspace\\packages\\app\\node_modules\\.bin;C:\\existing\\path"
997+
)
998+
);
999+
}
1000+
1001+
#[test]
1002+
#[cfg(windows)]
1003+
fn test_windows_path_created_when_missing() {
1004+
use crate::{
1005+
collections::HashSet,
1006+
config::{ResolvedTaskConfig, TaskCommand, TaskConfig},
1007+
};
1008+
1009+
let task_config = TaskConfig {
1010+
command: TaskCommand::ShellScript("echo test".into()),
1011+
cwd: RelativePathBuf::default(),
1012+
cacheable: true,
1013+
inputs: HashSet::new(),
1014+
envs: HashSet::new(),
1015+
pass_through_envs: HashSet::new(),
1016+
fingerprint_ignores: None,
1017+
};
1018+
let resolved =
1019+
ResolvedTaskConfig { config_dir: RelativePathBuf::default(), config: task_config };
1020+
1021+
// Mock environment without any PATH variable
1022+
let mock_envs = vec![(OsString::from("OTHER_VAR"), OsString::from("value"))];
1023+
1024+
let base_dir = AbsolutePath::new("C:\\workspace\\packages\\app").unwrap();
1025+
1026+
let result = TaskEnvs::resolve(mock_envs.into_iter(), &base_dir, &resolved).unwrap();
1027+
1028+
let all_envs = result.all_envs;
1029+
1030+
// Verify that "PATH" is created when missing
1031+
assert!(all_envs.contains_key("PATH"));
1032+
1033+
// Verify the complete PATH value matches expected (only node_modules/.bin paths, no existing path)
1034+
let path_value = all_envs.get("PATH").unwrap();
1035+
assert_eq!(
1036+
path_value.as_ref(),
1037+
OsStr::new(
1038+
"C:\\workspace\\packages\\app\\node_modules\\.bin;C:\\workspace\\packages\\app\\node_modules\\.bin"
1039+
)
1040+
);
1041+
}
1042+
1043+
#[test]
1044+
#[cfg(unix)]
1045+
fn test_unix_path_case_sensitive() {
1046+
use crate::{
1047+
collections::HashSet,
1048+
config::{ResolvedTaskConfig, TaskCommand, TaskConfig},
1049+
};
1050+
1051+
let task_config = TaskConfig {
1052+
command: TaskCommand::ShellScript("echo test".into()),
1053+
cwd: RelativePathBuf::default(),
1054+
cacheable: true,
1055+
inputs: HashSet::new(),
1056+
envs: HashSet::new(),
1057+
pass_through_envs: HashSet::new(),
1058+
fingerprint_ignores: None,
1059+
};
1060+
let resolved =
1061+
ResolvedTaskConfig { config_dir: RelativePathBuf::default(), config: task_config };
1062+
1063+
// Mock environment with "PATH" in uppercase (standard on Unix)
1064+
let mock_envs = vec![
1065+
(OsString::from("PATH"), OsString::from("/existing/path")),
1066+
(OsString::from("OTHER_VAR"), OsString::from("value")),
1067+
];
1068+
1069+
let base_dir = AbsolutePath::new("/workspace/packages/app").unwrap();
1070+
1071+
let result = TaskEnvs::resolve(mock_envs.into_iter(), &base_dir, &resolved).unwrap();
1072+
1073+
let all_envs = result.all_envs;
1074+
1075+
// Verify "PATH" exists and the complete value matches expected
1076+
assert!(all_envs.contains_key("PATH"));
1077+
let path_value = all_envs.get("PATH").unwrap();
1078+
assert_eq!(
1079+
path_value.as_ref(),
1080+
OsStr::new(
1081+
"/workspace/packages/app/node_modules/.bin:/workspace/packages/app/node_modules/.bin:/existing/path"
1082+
)
1083+
);
1084+
1085+
// Verify that on Unix, the code uses exact "PATH" match (case-sensitive)
1086+
// This is a regression test to ensure Windows case-insensitive logic doesn't affect Unix
1087+
assert!(!all_envs.contains_key("Path"));
1088+
assert!(!all_envs.contains_key("path"));
1089+
}
9041090
}

0 commit comments

Comments
 (0)