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}