|
| 1 | +//! Tests for paths with many components to verify SmallVec spills to heap correctly |
| 2 | +
|
| 3 | +use std::path::Path; |
| 4 | +use sugar_path::SugarPath; |
| 5 | + |
| 6 | +#[test] |
| 7 | +fn test_normalize_deep_path() { |
| 8 | + // Create a path with more than 8 components (SmallVec inline capacity) |
| 9 | + let deep_path = "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"; |
| 10 | + let normalized = deep_path.normalize(); |
| 11 | + assert_eq!(normalized, Path::new(deep_path)); |
| 12 | + |
| 13 | + // Test with dots |
| 14 | + let deep_path_with_dots = "a/b/c/./d/e/f/./g/h/i/./j/k/l/./m/n/o/p"; |
| 15 | + let normalized = deep_path_with_dots.normalize(); |
| 16 | + assert_eq!(normalized, Path::new("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p")); |
| 17 | + |
| 18 | + // Test with parent dirs |
| 19 | + let deep_path_with_parents = "a/b/c/../d/e/f/../g/h/i/../j/k/l/../m/n/o/p"; |
| 20 | + let normalized = deep_path_with_parents.normalize(); |
| 21 | + assert_eq!(normalized, Path::new("a/b/d/e/g/h/j/k/m/n/o/p")); |
| 22 | +} |
| 23 | + |
| 24 | +#[test] |
| 25 | +fn test_relative_deep_paths() { |
| 26 | + // Test relative path calculation with more than 8 components |
| 27 | + let base = "/a/b/c/d/e/f/g/h/i/j"; |
| 28 | + let target = "/a/b/c/d/e/f/g/k/l/m/n/o/p"; |
| 29 | + |
| 30 | + let relative = target.relative(base); |
| 31 | + assert_eq!(relative, Path::new("../../../k/l/m/n/o/p")); |
| 32 | + |
| 33 | + // Test with even deeper paths (15+ components) |
| 34 | + let base = |
| 35 | + "/level1/level2/level3/level4/level5/level6/level7/level8/level9/level10/level11/level12"; |
| 36 | + let target = "/level1/level2/level3/level4/level5/level6/level7/level8/different9/different10/different11/different12/different13/different14/different15"; |
| 37 | + |
| 38 | + let relative = target.relative(base); |
| 39 | + assert_eq!( |
| 40 | + relative, |
| 41 | + Path::new( |
| 42 | + "../../../../different9/different10/different11/different12/different13/different14/different15" |
| 43 | + ) |
| 44 | + ); |
| 45 | +} |
| 46 | + |
| 47 | +#[test] |
| 48 | +fn test_absolutize_deep_paths() { |
| 49 | + // Test absolutize with deep paths |
| 50 | + #[cfg(target_family = "unix")] |
| 51 | + { |
| 52 | + let base = "/root/level1/level2/level3/level4/level5/level6/level7/level8/level9"; |
| 53 | + let relative = "../../../../../../../../../../deep1/deep2/deep3/deep4/deep5"; |
| 54 | + |
| 55 | + let absolute = relative.absolutize_with(base); |
| 56 | + assert_eq!(absolute, Path::new("/deep1/deep2/deep3/deep4/deep5")); |
| 57 | + |
| 58 | + // Test with current directory dots in deep path |
| 59 | + let deep_relative = "./sub1/./sub2/./sub3/./sub4/./sub5/./sub6/./sub7/./sub8/./sub9/./sub10"; |
| 60 | + let absolute = deep_relative.absolutize_with(base); |
| 61 | + assert_eq!( |
| 62 | + absolute, |
| 63 | + Path::new( |
| 64 | + "/root/level1/level2/level3/level4/level5/level6/level7/level8/level9/sub1/sub2/sub3/sub4/sub5/sub6/sub7/sub8/sub9/sub10" |
| 65 | + ) |
| 66 | + ); |
| 67 | + } |
| 68 | + |
| 69 | + #[cfg(target_family = "windows")] |
| 70 | + { |
| 71 | + let base = "C:\\root\\level1\\level2\\level3\\level4\\level5\\level6\\level7\\level8\\level9"; |
| 72 | + let relative = "..\\..\\..\\..\\..\\..\\..\\..\\..\\..\\deep1\\deep2\\deep3\\deep4\\deep5"; |
| 73 | + |
| 74 | + let absolute = relative.absolutize_with(base); |
| 75 | + assert_eq!(absolute, Path::new("C:\\deep1\\deep2\\deep3\\deep4\\deep5")); |
| 76 | + |
| 77 | + // Test with current directory dots in deep path |
| 78 | + let deep_relative = |
| 79 | + ".\\sub1\\.\\sub2\\.\\sub3\\.\\sub4\\.\\sub5\\.\\sub6\\.\\sub7\\.\\sub8\\.\\sub9\\.\\sub10"; |
| 80 | + let absolute = deep_relative.absolutize_with(base); |
| 81 | + assert_eq!( |
| 82 | + absolute, |
| 83 | + Path::new( |
| 84 | + "C:\\root\\level1\\level2\\level3\\level4\\level5\\level6\\level7\\level8\\level9\\sub1\\sub2\\sub3\\sub4\\sub5\\sub6\\sub7\\sub8\\sub9\\sub10" |
| 85 | + ) |
| 86 | + ); |
| 87 | + } |
| 88 | +} |
| 89 | + |
| 90 | +#[test] |
| 91 | +fn test_to_slash_deep_paths() { |
| 92 | + // Test to_slash with deep paths |
| 93 | + #[cfg(target_family = "windows")] |
| 94 | + { |
| 95 | + let deep_path = Path::new("a\\b\\c\\d\\e\\f\\g\\h\\i\\j\\k\\l\\m\\n\\o\\p"); |
| 96 | + let slashed = deep_path.to_slash().unwrap(); |
| 97 | + assert_eq!(slashed, "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"); |
| 98 | + } |
| 99 | + |
| 100 | + #[cfg(target_family = "unix")] |
| 101 | + { |
| 102 | + let deep_path = Path::new("a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"); |
| 103 | + let slashed = deep_path.to_slash().unwrap(); |
| 104 | + assert_eq!(slashed, "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"); |
| 105 | + } |
| 106 | +} |
| 107 | + |
| 108 | +#[test] |
| 109 | +fn test_extreme_depth() { |
| 110 | + // Test with 20+ components |
| 111 | + let mut path_parts = Vec::new(); |
| 112 | + for i in 0..25 { |
| 113 | + path_parts.push(format!("component{}", i)); |
| 114 | + } |
| 115 | + let deep_path = path_parts.join("/"); |
| 116 | + |
| 117 | + // Test normalize |
| 118 | + let normalized = deep_path.as_str().normalize(); |
| 119 | + assert_eq!(normalized.components().count(), 25); |
| 120 | + |
| 121 | + // Add some dots and test again |
| 122 | + let mut path_with_dots = Vec::new(); |
| 123 | + for i in 0..25 { |
| 124 | + path_with_dots.push(format!("component{}", i)); |
| 125 | + if i % 3 == 0 { |
| 126 | + path_with_dots.push(".".to_string()); |
| 127 | + } |
| 128 | + } |
| 129 | + let deep_path_dots = path_with_dots.join("/"); |
| 130 | + let normalized = deep_path_dots.as_str().normalize(); |
| 131 | + assert_eq!(normalized.components().count(), 25); |
| 132 | +} |
| 133 | + |
| 134 | +#[test] |
| 135 | +fn test_stress_smallvec_spillover() { |
| 136 | + // Create paths that will definitely spill over SmallVec's inline capacity |
| 137 | + |
| 138 | + // Test 1: Exactly at boundary (8 components) |
| 139 | + let path8 = "a/b/c/d/e/f/g/h"; |
| 140 | + let normalized8 = path8.normalize(); |
| 141 | + assert_eq!(normalized8.components().count(), 8); |
| 142 | + |
| 143 | + // Test 2: Just over boundary (9 components) |
| 144 | + let path9 = "a/b/c/d/e/f/g/h/i"; |
| 145 | + let normalized9 = path9.normalize(); |
| 146 | + assert_eq!(normalized9.components().count(), 9); |
| 147 | + |
| 148 | + // Test 3: Well over boundary (16 components) |
| 149 | + let path16 = "a/b/c/d/e/f/g/h/i/j/k/l/m/n/o/p"; |
| 150 | + let normalized16 = path16.normalize(); |
| 151 | + assert_eq!(normalized16.components().count(), 16); |
| 152 | + |
| 153 | + // Test 4: Complex normalization with many components |
| 154 | + let complex = "a/./b/../c/d/./e/../f/g/./h/../i/j/./k/../l/m/./n/../o/p/./q/../r"; |
| 155 | + let normalized_complex = complex.normalize(); |
| 156 | + // This should normalize to: a/c/d/f/g/i/j/l/m/o/p/r (12 components) |
| 157 | + assert_eq!(normalized_complex, Path::new("a/c/d/f/g/i/j/l/m/o/p/r")); |
| 158 | +} |
| 159 | + |
| 160 | +#[test] |
| 161 | +fn test_windows_deep_paths() { |
| 162 | + #[cfg(target_family = "windows")] |
| 163 | + { |
| 164 | + // Test Windows-specific deep path handling |
| 165 | + let deep_win_path = "C:\\level1\\level2\\level3\\level4\\level5\\level6\\level7\\level8\\level9\\level10\\level11\\level12"; |
| 166 | + let normalized = deep_win_path.normalize(); |
| 167 | + assert!(normalized.components().count() > 8); |
| 168 | + |
| 169 | + // Test UNC paths with many components |
| 170 | + let unc_path = "\\\\server\\share\\folder1\\folder2\\folder3\\folder4\\folder5\\folder6\\folder7\\folder8\\folder9\\folder10"; |
| 171 | + let normalized_unc = unc_path.normalize(); |
| 172 | + assert!(normalized_unc.components().count() > 8); |
| 173 | + } |
| 174 | +} |
| 175 | + |
| 176 | +#[test] |
| 177 | +fn test_relative_with_common_deep_prefix() { |
| 178 | + // Test paths that share a deep common prefix |
| 179 | + let base = "/shared/path/components/that/are/very/deep/and/long/base/specific/part"; |
| 180 | + let target = "/shared/path/components/that/are/very/deep/and/long/target/different/end"; |
| 181 | + |
| 182 | + let relative = target.relative(base); |
| 183 | + assert_eq!(relative, Path::new("../../../target/different/end")); |
| 184 | + |
| 185 | + // Verify the path has the expected structure |
| 186 | + let components: Vec<_> = relative.components().collect(); |
| 187 | + assert_eq!(components.len(), 6); |
| 188 | +} |
0 commit comments