Skip to content

Commit 171669f

Browse files
committed
tests
1 parent aea2de4 commit 171669f

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed

crates/pet-fs/src/path.rs

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,141 @@ fn get_user_home() -> Option<PathBuf> {
154154
Err(_) => None,
155155
}
156156
}
157+
158+
#[cfg(test)]
159+
mod tests {
160+
use super::*;
161+
162+
#[test]
163+
fn test_norm_case_returns_path_for_nonexistent() {
164+
// norm_case should return the original path if it doesn't exist
165+
let nonexistent = PathBuf::from("/this/path/does/not/exist/anywhere");
166+
let result = norm_case(&nonexistent);
167+
assert_eq!(result, nonexistent);
168+
}
169+
170+
#[test]
171+
fn test_norm_case_existing_path() {
172+
// norm_case should work on existing paths
173+
let temp_dir = std::env::temp_dir();
174+
let result = norm_case(&temp_dir);
175+
// On unix, should return unchanged; on Windows, should normalize case
176+
assert!(result.exists());
177+
}
178+
179+
#[test]
180+
#[cfg(unix)]
181+
fn test_norm_case_unix_noop() {
182+
// On unix, norm_case should return the path unchanged
183+
let path = PathBuf::from("/Some/Path/With/Mixed/Case");
184+
let result = norm_case(&path);
185+
assert_eq!(result, path);
186+
}
187+
188+
#[test]
189+
#[cfg(windows)]
190+
fn test_norm_case_windows_case_normalization() {
191+
// On Windows, norm_case should normalize the case of existing paths
192+
// Use the Windows directory which always exists
193+
let path = PathBuf::from("c:\\windows\\system32");
194+
let result = norm_case(&path);
195+
// The result should have proper casing (C:\Windows\System32)
196+
assert!(result.to_string_lossy().contains("Windows"));
197+
assert!(result.to_string_lossy().contains("System32"));
198+
}
199+
200+
#[test]
201+
#[cfg(windows)]
202+
fn test_norm_case_windows_preserves_junction() {
203+
// This is the key test for issue #186:
204+
// norm_case should NOT resolve junctions to their target
205+
use std::fs;
206+
use std::process::Command;
207+
208+
let temp_dir = std::env::temp_dir();
209+
let target_dir = temp_dir.join("pet_test_junction_target");
210+
let junction_dir = temp_dir.join("pet_test_junction_link");
211+
212+
// Clean up any existing test directories
213+
let _ = fs::remove_dir_all(&target_dir);
214+
let _ = fs::remove_dir_all(&junction_dir);
215+
216+
// Create target directory
217+
fs::create_dir_all(&target_dir).expect("Failed to create target directory");
218+
219+
// Create a junction using mklink /J (requires no special privileges)
220+
let output = Command::new("cmd")
221+
.args([
222+
"/C",
223+
"mklink",
224+
"/J",
225+
&junction_dir.to_string_lossy(),
226+
&target_dir.to_string_lossy(),
227+
])
228+
.output()
229+
.expect("Failed to create junction");
230+
231+
if !output.status.success() {
232+
// Clean up and skip test if junction creation failed
233+
let _ = fs::remove_dir_all(&target_dir);
234+
eprintln!(
235+
"Skipping junction test - failed to create junction: {}",
236+
String::from_utf8_lossy(&output.stderr)
237+
);
238+
return;
239+
}
240+
241+
// Verify junction was created
242+
assert!(junction_dir.exists(), "Junction should exist");
243+
244+
// The key assertion: norm_case should return the junction path, NOT the target path
245+
let result = norm_case(&junction_dir);
246+
247+
// The result should still be the junction path, not resolved to target
248+
// Compare the path names (case-insensitive on Windows)
249+
assert!(
250+
result
251+
.to_string_lossy()
252+
.to_lowercase()
253+
.contains("pet_test_junction_link"),
254+
"norm_case should preserve junction path, got: {:?}",
255+
result
256+
);
257+
assert!(
258+
!result
259+
.to_string_lossy()
260+
.to_lowercase()
261+
.contains("pet_test_junction_target"),
262+
"norm_case should NOT resolve to target path, got: {:?}",
263+
result
264+
);
265+
266+
// Clean up
267+
// Remove junction first (using rmdir, not remove_dir_all, to not follow the junction)
268+
let _ = Command::new("cmd")
269+
.args(["/C", "rmdir", &junction_dir.to_string_lossy()])
270+
.output();
271+
let _ = fs::remove_dir_all(&target_dir);
272+
}
273+
274+
#[test]
275+
#[cfg(windows)]
276+
fn test_norm_case_windows_relative_path() {
277+
// Test that relative paths are converted to absolute
278+
let relative = PathBuf::from(".");
279+
let result = norm_case(&relative);
280+
assert!(result.is_absolute(), "Result should be absolute path");
281+
}
282+
283+
#[test]
284+
#[cfg(windows)]
285+
fn test_norm_case_windows_no_unc_prefix_added() {
286+
// Ensure we don't add UNC prefix to paths that didn't have it
287+
let path = PathBuf::from("C:\\Windows");
288+
let result = norm_case(&path);
289+
assert!(
290+
!result.to_string_lossy().starts_with(r"\\?\"),
291+
"Should not add UNC prefix"
292+
);
293+
}
294+
}

0 commit comments

Comments
 (0)