1mod calendar;
2mod doing;
3mod json;
4mod timing;
5
6use std::path::Path;
7
8use doing_error::Result;
9use doing_taskpaper::Entry;
10
11use crate::{Plugin, Registry};
12
13pub trait ImportPlugin: Plugin {
18 fn import(&self, path: &Path) -> Result<Vec<Entry>>;
20}
21
22pub fn default_registry() -> Result<Registry<dyn ImportPlugin>> {
24 let mut registry: Registry<dyn ImportPlugin> = Registry::new();
25 registry.register(Box::new(calendar::CalendarImport))?;
26 registry.register(Box::new(doing::DoingImport))?;
27 registry.register(Box::new(json::JsonImport))?;
28 registry.register(Box::new(timing::TimingImport))?;
29 Ok(registry)
30}
31
32#[cfg(test)]
33mod test {
34 use std::path::Path;
35
36 use super::*;
37 use crate::PluginSettings;
38
39 struct MockPlugin {
40 name: String,
41 trigger: String,
42 }
43
44 impl MockPlugin {
45 fn new(name: &str, trigger: &str) -> Self {
46 Self {
47 name: name.into(),
48 trigger: trigger.into(),
49 }
50 }
51 }
52
53 impl Plugin for MockPlugin {
54 fn name(&self) -> &str {
55 &self.name
56 }
57
58 fn settings(&self) -> PluginSettings {
59 PluginSettings {
60 trigger: self.trigger.clone(),
61 }
62 }
63 }
64
65 impl ImportPlugin for MockPlugin {
66 fn import(&self, _path: &Path) -> Result<Vec<Entry>> {
67 Ok(Vec::new())
68 }
69 }
70
71 mod default_registry {
72 use pretty_assertions::assert_eq;
73
74 use super::*;
75
76 #[test]
77 fn it_registers_all_built_in_plugins() {
78 let registry = default_registry().unwrap();
79
80 assert_eq!(
81 registry.available_formats(),
82 vec!["calendar", "doing", "json", "timing"]
83 );
84 }
85 }
86
87 mod registry_available_formats {
88 use pretty_assertions::assert_eq;
89
90 use super::*;
91
92 #[test]
93 fn it_returns_empty_for_new_registry() {
94 let registry = Registry::<dyn ImportPlugin>::new();
95
96 assert!(registry.available_formats().is_empty());
97 }
98
99 #[test]
100 fn it_returns_sorted_format_names() {
101 let mut registry = Registry::<dyn ImportPlugin>::new();
102 registry
103 .register(Box::new(MockPlugin::new("timing", "timing")))
104 .unwrap();
105 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
106
107 let formats = registry.available_formats();
108
109 assert_eq!(formats, vec!["doing", "timing"]);
110 }
111 }
112
113 mod registry_register {
114 use pretty_assertions::assert_eq;
115
116 use super::*;
117
118 #[test]
119 fn it_adds_plugin_to_registry() {
120 let mut registry = Registry::<dyn ImportPlugin>::new();
121
122 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
123
124 assert_eq!(registry.available_formats(), vec!["doing"]);
125 }
126
127 #[test]
128 fn it_returns_error_on_invalid_trigger_pattern() {
129 let mut registry = Registry::<dyn ImportPlugin>::new();
130
131 let result = registry.register(Box::new(MockPlugin::new("bad", "(?invalid")));
132
133 assert!(result.is_err());
134 assert!(result.unwrap_err().to_string().contains("invalid trigger pattern"));
135 }
136 }
137
138 mod registry_resolve {
139 use pretty_assertions::assert_eq;
140
141 use super::*;
142
143 #[test]
144 fn it_matches_exact_format_name() {
145 let mut registry = Registry::<dyn ImportPlugin>::new();
146 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
147
148 let plugin = registry.resolve("doing").unwrap();
149
150 assert_eq!(plugin.name(), "doing");
151 }
152
153 #[test]
154 fn it_matches_case_insensitively() {
155 let mut registry = Registry::<dyn ImportPlugin>::new();
156 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
157
158 assert!(registry.resolve("DOING").is_some());
159 assert!(registry.resolve("Doing").is_some());
160 }
161
162 #[test]
163 fn it_returns_none_for_unknown_format() {
164 let mut registry = Registry::<dyn ImportPlugin>::new();
165 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
166
167 assert!(registry.resolve("csv").is_none());
168 }
169
170 #[test]
171 fn it_does_not_match_partial_strings() {
172 let mut registry = Registry::<dyn ImportPlugin>::new();
173 registry.register(Box::new(MockPlugin::new("doing", "doing"))).unwrap();
174
175 assert!(registry.resolve("doingx").is_none());
176 assert!(registry.resolve("xdoing").is_none());
177 }
178 }
179}