File: testing.rs

package info (click to toggle)
rust-breezyshim 0.7.8-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 996 kB
  • sloc: makefile: 2
file content (170 lines) | stat: -rw-r--r-- 5,782 bytes parent folder | download | duplicates (2)
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
//! Test utilities for the Breezy Rust bindings.
use pyo3::prelude::*;
use std::collections::HashMap;
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;

/// Environment for running Breezy tests.
///
/// This struct sets up a temporary environment for running Breezy tests,
/// including temporary directories and environment variables, and cleans
/// up after itself when dropped.
pub struct TestEnv {
    /// The temporary directory that contains all test files.
    pub temp_dir: TempDir,
    /// The working directory where tests will run.
    pub working_dir: PathBuf,
    /// The home directory for the test environment.
    pub home_dir: PathBuf,
    /// The original working directory before the test environment was set up.
    pub old_cwd: Option<PathBuf>,
    /// The original environment variables before the test environment was set up.
    pub old_env: HashMap<String, Option<String>>,
}

impl TestEnv {
    /// Create a new testing environment.
    ///
    /// This sets up a temporary directory structure with a working directory
    /// and home directory, and configures environment variables for Breezy.
    ///
    /// # Returns
    ///
    /// A new TestEnv instance
    pub fn new() -> Self {
        // Ensure Python and Breezy are initialized
        crate::init();
        let temp_dir = TempDir::new().unwrap();
        let working_dir = temp_dir.path().join("test");
        fs::create_dir(&working_dir).unwrap();
        let home_dir = temp_dir.path().join("home");
        fs::create_dir(&home_dir).unwrap();
        let mut old_env = HashMap::new();
        let old_cwd = std::env::current_dir().ok();
        old_env.insert("HOME".to_string(), std::env::var("HOME").ok());
        old_env.insert("BRZ_EMAIL".to_string(), std::env::var("BRZ_EMAIL").ok());
        old_env.insert("BRZ_HOME".to_string(), std::env::var("BRZ_HOME").ok());
        let brz_email = "Joe Tester <joe@example.com>";
        let breezy_home = home_dir.join(".config/breezy");
        std::env::set_current_dir(&working_dir).unwrap();
        std::env::set_var("HOME", &home_dir);
        std::env::set_var("BRZ_EMAIL", brz_email);
        std::env::set_var("BRZ_HOME", &breezy_home);
        pyo3::Python::attach(|py| {
            let os = py.import("os").unwrap();
            os.call_method1("chdir", (working_dir.to_str().unwrap(),))
                .unwrap();
            let environ = os.getattr("environ").unwrap();
            environ
                .set_item("HOME", home_dir.to_str().unwrap())
                .unwrap();
            environ.set_item("BRZ_EMAIL", brz_email).unwrap();
            environ
                .set_item("BRZ_HOME", breezy_home.to_str().unwrap())
                .unwrap();
        });
        fs::create_dir_all(&breezy_home).unwrap();
        fs::write(
            breezy_home.join("breezy.conf"),
            r#"
[DEFAULT]
email = Joe Tester <joe@example.com>
"#,
        )
        .unwrap();
        Self {
            temp_dir,
            home_dir,
            working_dir,
            old_cwd,
            old_env,
        }
    }
}

impl Drop for TestEnv {
    fn drop(&mut self) {
        for (key, value) in self.old_env.drain() {
            if let Some(value) = value.as_ref() {
                std::env::set_var(&key, value);
            } else {
                std::env::remove_var(&key);
            }
            Python::attach(|py| {
                let os = py.import("os").unwrap();
                let environ = os.getattr("environ").unwrap();
                if let Some(value) = value {
                    environ.set_item(key, value).unwrap();
                } else {
                    environ.del_item(key).unwrap();
                }
            });
        }
        if let Some(ref old_cwd) = self.old_cwd {
            let _ = std::env::set_current_dir(old_cwd);
        }
    }
}

impl Default for TestEnv {
    fn default() -> Self {
        Self::new()
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use serial_test::serial;

    #[test]
    #[serial]
    fn test_testenv() {
        let env = TestEnv::new();
        assert_eq!(env.home_dir, env.temp_dir.path().join("home"));
        assert_eq!(env.working_dir, env.temp_dir.path().join("test"));
        // On Windows, canonicalize() can add \\?\ prefix and resolve short names differently
        // So we compare the canonicalized versions of both paths
        assert_eq!(
            std::env::current_dir().unwrap().canonicalize().unwrap(),
            env.working_dir.canonicalize().unwrap()
        );
        assert_eq!(
            std::env::var("HOME").unwrap(),
            env.home_dir.to_str().unwrap()
        );
        assert_eq!(
            std::env::var("BRZ_EMAIL").unwrap(),
            "Joe Tester <joe@example.com>"
        );

        Python::attach(|py| {
            let os = py.import("os").unwrap();
            // On Windows, canonicalize both paths to handle short/long names and \\?\ prefix
            let py_cwd = os
                .call_method0("getcwd")
                .unwrap()
                .extract::<PathBuf>()
                .unwrap();
            assert_eq!(
                py_cwd.canonicalize().unwrap(),
                env.working_dir.canonicalize().unwrap(),
            );
            assert_eq!(
                os.call_method1("getenv", ("HOME",))
                    .unwrap()
                    .extract::<String>()
                    .unwrap(),
                env.home_dir.to_str().unwrap()
            );
            assert_eq!(
                os.call_method1("getenv", ("BRZ_EMAIL",))
                    .unwrap()
                    .extract::<String>()
                    .unwrap(),
                "Joe Tester <joe@example.com>"
            );
        });
    }
}