Skip to main content

git_su/
user_file.rs

1// UserFile: ~/.git-su storage, TOML format
2
3use std::fs;
4use std::path::Path;
5
6use crate::user::User;
7
8#[derive(Debug, serde::Serialize, serde::Deserialize)]
9struct UserEntry {
10    name: String,
11    email: String,
12}
13
14#[derive(Debug, serde::Serialize, serde::Deserialize)]
15struct Config {
16    user: Vec<UserEntry>,
17}
18
19pub struct UserFile {
20    path: std::path::PathBuf,
21}
22
23impl UserFile {
24    pub fn new(path: impl AsRef<Path>) -> Self {
25        let path = path.as_ref().to_path_buf();
26        if !path.exists() {
27            let _ = fs::write(&path, "");
28        }
29        UserFile { path }
30    }
31
32    pub fn write(&self, user: &User) -> std::io::Result<()> {
33        let mut config = self.read_config();
34        config.user.push(UserEntry {
35            name: user.name(),
36            email: user.email(),
37        });
38        self.write_config(&config)
39    }
40
41    pub fn read(&self) -> Vec<User> {
42        self.read_config()
43            .user
44            .into_iter()
45            .map(|e| User::new(e.name, e.email))
46            .collect()
47    }
48
49    fn read_config(&self) -> Config {
50        let s = match fs::read_to_string(&self.path) {
51            Ok(s) => s,
52            Err(_) => return Config { user: vec![] },
53        };
54        toml::from_str(&s).unwrap_or(Config { user: vec![] })
55    }
56
57    fn write_config(&self, config: &Config) -> std::io::Result<()> {
58        let s = toml::to_string_pretty(config).unwrap_or_default();
59        fs::write(&self.path, s)
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use super::*;
66
67    #[test]
68    fn read_empty_file() {
69        let dir = tempfile::tempdir().unwrap();
70        let path = dir.path().join(".git-su");
71        fs::write(&path, "").unwrap();
72        let uf = UserFile::new(&path);
73        assert!(uf.read().is_empty());
74    }
75
76    #[test]
77    fn write_and_read_toml() {
78        let dir = tempfile::tempdir().unwrap();
79        let path = dir.path().join(".git-su");
80        let uf = UserFile::new(&path);
81        let u = User::new("Jane Doe", "jane@example.com");
82        uf.write(&u).unwrap();
83        let list = uf.read();
84        assert_eq!(list.len(), 1);
85        assert_eq!(list[0].name(), "Jane Doe");
86        assert_eq!(list[0].email(), "jane@example.com");
87    }
88
89    #[test]
90    fn read_valid_toml() {
91        let dir = tempfile::tempdir().unwrap();
92        let path = dir.path().join(".git-su");
93        let toml = r#"[[user]]
94name = "Bob"
95email = "bob@example.com"
96"#;
97        fs::write(&path, toml).unwrap();
98        let uf = UserFile::new(&path);
99        let list = uf.read();
100        assert_eq!(list.len(), 1);
101        assert_eq!(list[0].name(), "Bob");
102        assert_eq!(list[0].email(), "bob@example.com");
103    }
104}