1
use std::fs;
2
use std::io::{Error, ErrorKind};
3
use std::process::Command;
4

            
5
/// Regression test: cdup should exit gracefully (not panic) when the current
6
/// working directory no longer exists. This can happen when switching git
7
/// branches while inside a directory that only exists on the previous branch.
8
#[cfg(unix)]
9
#[test]
10
2
fn cd_in_nonexistent_directory_does_not_panic() {
11
    use std::os::unix::process::CommandExt;
12

            
13
    // GIVEN a temporary directory with a subdirectory
14
2
    let tmp = tempfile::tempdir().expect("failed to create temp dir");
15
2
    let dir = tmp.path().join("ephemeral");
16
2
    fs::create_dir(&dir).expect("failed to create dir");
17

            
18
2
    let bin = env!("CARGO_BIN_EXE_cdup");
19

            
20
    // WHEN we run cdup cd 1 in the subdirectory and remove the subdirectory
21
    // after the fork but before exec using pre_exec.
22
2
    let dir_clone = dir.clone();
23
2
    let output = unsafe {
24
2
        Command::new(bin)
25
2
            .current_dir(&dir)
26
2
            .arg("cd")
27
2
            .arg("1")
28
2
            .pre_exec(move || {
29
                fs::remove_dir(&dir_clone).map_err(|e| Error::new(ErrorKind::Other, e))
30
            })
31
2
            .output()
32
    }
33
2
    .expect("failed to execute cdup");
34

            
35
    // THEN we do not panic, even though the child process starts with a
36
    // nonexistent cwd.
37
2
    assert!(!output.status.success(), "should exit with error");
38
2
    let stderr = String::from_utf8_lossy(&output.stderr);
39
2
    assert!(!stderr.contains("panicked"), "cdup panicked: {}", stderr);
40
2
    assert!(
41
2
        stderr.contains("Could not get current working directory"),
42
        "unexpected error message: {}",
43
        stderr
44
    );
45
2
}
46

            
47
#[cfg(unix)]
48
#[test]
49
2
fn hint_in_nonexistent_directory_does_not_panic() {
50
    use std::os::unix::process::CommandExt;
51

            
52
    // GIVEN a temporary directory with a subdirectory
53
2
    let tmp = tempfile::tempdir().expect("failed to create temp dir");
54
2
    let dir = tmp.path().join("ephemeral");
55
2
    fs::create_dir(&dir).expect("failed to create dir");
56

            
57
2
    let bin = env!("CARGO_BIN_EXE_cdup");
58

            
59
    // WHEN we run cdup hint in the subdirectory and remove the subdirectory
60
    // after the fork but before exec using pre_exec.
61
2
    let dir_clone = dir.clone();
62
2
    let output = unsafe {
63
2
        Command::new(bin)
64
2
            .current_dir(&dir)
65
2
            .arg("hint")
66
2
            .pre_exec(move || {
67
                fs::remove_dir(&dir_clone).map_err(|e| Error::new(ErrorKind::Other, e))
68
            })
69
2
            .output()
70
    }
71
2
    .expect("failed to execute cdup");
72

            
73
    // THEN we do not panic, even though the child process starts with a
74
    // nonexistent cwd.
75
2
    assert!(!output.status.success(), "should exit with error");
76
2
    let stderr = String::from_utf8_lossy(&output.stderr);
77
2
    assert!(!stderr.contains("panicked"), "cdup panicked: {}", stderr);
78
2
}