summaryrefslogtreecommitdiff
path: root/helix-stdx/tests/path.rs
blob: cc3c15cba65c79c13e8d2ab6b3dbc54d0eb407f6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
#![cfg(windows)]

use std::{
    env::set_current_dir,
    error::Error,
    path::{Component, Path, PathBuf},
};

use helix_stdx::path;
use tempfile::Builder;

// Paths on Windows are almost always case-insensitive.
// Normalization should return the original path.
// E.g. mkdir `CaSe`, normalize(`case`) = `CaSe`.
#[test]
fn test_case_folding_windows() -> Result<(), Box<dyn Error>> {
    // tmp/root/case
    let tmp_prefix = std::env::temp_dir();
    set_current_dir(&tmp_prefix)?;

    let root = Builder::new().prefix("root-").tempdir()?;
    let case = Builder::new().prefix("CaSe-").tempdir_in(&root)?;

    let root_without_prefix = root.path().strip_prefix(&tmp_prefix)?;

    let lowercase_case = format!(
        "case-{}",
        case.path()
            .file_name()
            .unwrap()
            .to_string_lossy()
            .split_at(5)
            .1
    );
    let test_path = root_without_prefix.join(lowercase_case);
    assert_eq!(
        path::normalize(&test_path),
        case.path().strip_prefix(&tmp_prefix)?
    );

    Ok(())
}

#[test]
fn test_normalize_path() -> Result<(), Box<dyn Error>> {
    /*
    tmp/root/
    ├── link -> dir1/orig_file
    ├── dir1/
    │   └── orig_file
    └── dir2/
        └── dir_link -> ../dir1/
    */

    let tmp_prefix = std::env::temp_dir();
    set_current_dir(&tmp_prefix)?;

    // Create a tree structure as shown above
    let root = Builder::new().prefix("root-").tempdir()?;
    let dir1 = Builder::new().prefix("dir1-").tempdir_in(&root)?;
    let orig_file = Builder::new().prefix("orig_file-").tempfile_in(&dir1)?;
    let dir2 = Builder::new().prefix("dir2-").tempdir_in(&root)?;

    // Create path and delete existing file
    let dir_link = Builder::new()
        .prefix("dir_link-")
        .tempfile_in(&dir2)?
        .path()
        .to_owned();
    let link = Builder::new()
        .prefix("link-")
        .tempfile_in(&root)?
        .path()
        .to_owned();

    use std::os::windows;
    windows::fs::symlink_dir(&dir1, &dir_link)?;
    windows::fs::symlink_file(&orig_file, &link)?;

    // root/link
    let path = link.strip_prefix(&tmp_prefix)?;
    assert_eq!(
        path::normalize(path),
        path,
        "input {:?} and symlink last component shouldn't be resolved",
        path
    );

    // root/dir2/dir_link/orig_file/../..
    let path = dir_link
        .strip_prefix(&tmp_prefix)
        .unwrap()
        .join(orig_file.path().file_name().unwrap())
        .join(Component::ParentDir)
        .join(Component::ParentDir);
    let expected = dir_link
        .strip_prefix(&tmp_prefix)
        .unwrap()
        .join(Component::ParentDir);
    assert_eq!(
        path::normalize(&path),
        expected,
        "input {:?} and \"..\" should not erase the simlink that goes ahead",
        &path
    );

    // root/link/.././../dir2/../
    let path = link
        .strip_prefix(&tmp_prefix)
        .unwrap()
        .join(Component::ParentDir)
        .join(Component::CurDir)
        .join(Component::ParentDir)
        .join(dir2.path().file_name().unwrap())
        .join(Component::ParentDir);
    let expected = link
        .strip_prefix(&tmp_prefix)
        .unwrap()
        .join(Component::ParentDir)
        .join(Component::ParentDir);
    assert_eq!(path::normalize(&path), expected, "input {:?}", &path);

    Ok(())
}