mdmg/commands/
list.rs

1use crate::logger::{Logger, StdoutLogger};
2use crate::template_repository::{FSTemplateRepository, TemplateRepository};
3use crate::Result;
4use std::env::current_dir;
5use std::sync::Arc;
6
7pub trait ListCommand {
8    fn run(&self) -> Result<()>;
9}
10
11pub trait Dependencies {
12    fn template_repository(&self) -> Arc<dyn TemplateRepository>;
13    fn logger(&self) -> Arc<dyn Logger>;
14}
15
16pub struct ListCommandImpl {
17    logger_instance: Arc<dyn Logger>,
18    template_repository_instance: Arc<dyn TemplateRepository>,
19}
20
21impl Default for ListCommandImpl {
22    fn default() -> Self {
23        let current_dir = current_dir().expect("failed fetch current dir");
24        ListCommandImpl {
25            template_repository_instance: Arc::new(FSTemplateRepository::new(
26                current_dir.join(".mdmg"),
27            )),
28            logger_instance: Arc::new(StdoutLogger::new()),
29        }
30    }
31}
32
33impl Dependencies for ListCommandImpl {
34    fn template_repository(&self) -> Arc<dyn TemplateRepository> {
35        self.template_repository_instance.clone()
36    }
37    fn logger(&self) -> Arc<dyn Logger> {
38        self.logger_instance.clone()
39    }
40}
41
42impl ListCommand for ListCommandImpl {
43    fn run(&self) -> Result<()> {
44        let template_list = self.template_repository().list()?;
45        for template in template_list.iter() {
46            self.logger().info(&template.0)
47        }
48        Ok(())
49    }
50}
51
52#[cfg(not(tarpaulin_include))]
53#[cfg(test)]
54mod tests {
55    use std::sync::Mutex;
56
57    use super::*;
58    use crate::file::FileName;
59    use crate::logger::Logger;
60    use crate::template_repository::TemplateRepository;
61    use crate::Result;
62    use derive_more::Constructor;
63
64    #[test]
65    fn test_list_command_output() {
66        #[derive(Debug, Constructor, Copy, Clone)]
67        struct DummyTemplateRepository;
68
69        #[derive(Debug, Constructor)]
70        struct DummyLogger {
71            outputs: Mutex<Vec<String>>,
72        }
73
74        impl TemplateRepository for DummyTemplateRepository {
75            fn list(&self) -> Result<Vec<FileName>> {
76                Ok(vec![FileName::new("foo")])
77            }
78            fn resolve(&self, _: String) -> Result<crate::template::Template> {
79                unimplemented!()
80            }
81        }
82
83        impl Logger for DummyLogger {
84            fn info(&self, info: &str) {
85                self.outputs.lock().unwrap().push(info.to_string());
86            }
87            fn debug(&self, _log: &str) {
88                unreachable!();
89            }
90        }
91
92        let logger = Arc::new(DummyLogger::new(Mutex::new(vec![])));
93        let command = ListCommandImpl {
94            logger_instance: logger.clone(),
95            template_repository_instance: Arc::new(DummyTemplateRepository::new()),
96        };
97
98        assert!(command.run().is_ok());
99        assert_eq!(*logger.outputs.lock().unwrap(), vec!["foo".to_string()]);
100    }
101}