1use 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}