hyprshell_config_lib/
check.rs

1use crate::Config;
2use anyhow::bail;
3
4pub fn check(config: &Config) -> anyhow::Result<()> {
5    if config
6        .windows
7        .as_ref()
8        .is_some_and(|w| w.scale >= 15f64 || w.scale <= 0f64)
9    {
10        bail!("Scale factor must be less than 15 and greater than 0");
11    }
12
13    if config
14        .windows
15        .as_ref()
16        .and_then(|w| w.overview.as_ref())
17        .is_some_and(|o| o.launcher.launch_modifier == o.modifier)
18    {
19        bail!(
20            "Launcher modifier cannot be the same as overview open modifier. (pressing the modifier will just close the overview instead of launching an app)"
21        );
22    }
23
24    if config
25        .windows
26        .as_ref()
27        .and_then(|w| w.overview.as_ref())
28        .is_some_and(|o| matches!(&*o.key, "super" | "alt" | "control" | "ctrl"))
29    {
30        bail!(
31            "If a modifier key is used to open it must include _l or _r at the end. (e.g. super_l, alt_r, etc)\nctrl_l / _r is NOT a valid modifier key, only control_l / _r is"
32        );
33    }
34
35    if let Some(l) = &config
36        .windows
37        .as_ref()
38        .and_then(|w| w.overview.as_ref().map(|o| &o.launcher))
39    {
40        if let Some(dt) = &l.default_terminal {
41            if dt.is_empty() {
42                bail!("Default terminal command cannot be empty");
43            }
44        }
45
46        let mut used: Vec<char> = vec![];
47        for engine in l
48            .plugins
49            .websearch
50            .as_ref()
51            .map_or(&vec![], |ws| &ws.engines)
52        {
53            if engine.url.is_empty() {
54                bail!("Search engine url cannot be empty");
55            }
56            if engine.name.is_empty() {
57                bail!("Search engine name cannot be empty");
58            }
59            if used.contains(&engine.key) {
60                bail!("Duplicate search engine key: {}", engine.key);
61            }
62            used.push(engine.key);
63        }
64        if l.plugins.calc.is_some() {
65            #[cfg(not(feature = "launcher_calc_plugin"))]
66            {
67                bail!("Calc Plugin enabled but not compiled in, please enable the calc feature");
68            }
69        }
70    }
71
72    Ok(())
73}
74
75#[cfg(test)]
76mod tests {
77    use super::*;
78    use crate::structs::*;
79
80    fn full() -> Config {
81        Config {
82            windows: Some(Windows {
83                overview: Some(Overview::default()),
84                switch: Some(Switch::default()),
85                ..Default::default()
86            }),
87            ..Default::default()
88        }
89    }
90
91    #[test_log::test]
92    #[test_log(default_log_filter = "trace")]
93    fn test_valid_config() {
94        let config = full();
95        assert!(check(&config).is_ok());
96    }
97
98    #[test_log::test]
99    #[test_log(default_log_filter = "trace")]
100    fn test_invalid_scale() {
101        let mut config = full();
102        config
103            .windows
104            .as_mut()
105            .expect("config option missing")
106            .scale = 20.0;
107        assert!(check(&config).is_err());
108        config
109            .windows
110            .as_mut()
111            .expect("config option missing")
112            .scale = 0.0;
113        assert!(check(&config).is_err());
114    }
115
116    #[test_log::test]
117    #[test_log(default_log_filter = "trace")]
118    fn test_same_modifier() {
119        let mut config = full();
120        let overview = config
121            .windows
122            .as_mut()
123            .expect("config option missing")
124            .overview
125            .as_mut()
126            .expect("config option missing");
127        overview.launcher.launch_modifier = overview.modifier;
128        assert!(check(&config).is_err());
129    }
130
131    #[test_log::test]
132    #[test_log(default_log_filter = "trace")]
133    fn test_invalid_key() {
134        let mut config = full();
135        let overview = config
136            .windows
137            .as_mut()
138            .expect("config option missing")
139            .overview
140            .as_mut()
141            .expect("config option missing");
142        overview.key = Box::from("super");
143        assert!(check(&config).is_err());
144    }
145
146    #[test_log::test]
147    #[test_log(default_log_filter = "trace")]
148    fn test_duplicate_engine_key() {
149        let mut config = full();
150        let launcher = &mut config
151            .windows
152            .as_mut()
153            .expect("config option missing")
154            .overview
155            .as_mut()
156            .expect("config option missing")
157            .launcher;
158        if let Some(ws) = launcher.plugins.websearch.as_mut() {
159            ws.engines.push(SearchEngine {
160                key: 'g',
161                name: Box::from("Google2"),
162                url: Box::from("https://google2.com"),
163            });
164        }
165        assert!(check(&config).is_err());
166    }
167
168    #[test_log::test]
169    #[test_log(default_log_filter = "trace")]
170    fn test_empty_engine_url() {
171        let mut config = full();
172        let launcher = &mut config
173            .windows
174            .as_mut()
175            .expect("config option missing")
176            .overview
177            .as_mut()
178            .expect("config option missing")
179            .launcher;
180        if let Some(ws) = launcher.plugins.websearch.as_mut() {
181            ws.engines[0].url = Box::from("");
182        }
183        assert!(check(&config).is_err());
184    }
185
186    #[test_log::test]
187    #[test_log(default_log_filter = "trace")]
188    fn test_empty_engine_name() {
189        let mut config = full();
190        let launcher = &mut config
191            .windows
192            .as_mut()
193            .expect("config option missing")
194            .overview
195            .as_mut()
196            .expect("config option missing")
197            .launcher;
198        if let Some(ws) = launcher.plugins.websearch.as_mut() {
199            ws.engines[0].name = Box::from("");
200        }
201        assert!(check(&config).is_err());
202    }
203
204    #[test_log::test]
205    #[test_log(default_log_filter = "trace")]
206    fn test_empty_terminal() {
207        let mut config = full();
208        let launcher = &mut config
209            .windows
210            .as_mut()
211            .expect("config option missing")
212            .overview
213            .as_mut()
214            .expect("config option missing")
215            .launcher;
216        launcher.default_terminal = Some(Box::from(""));
217        assert!(check(&config).is_err());
218    }
219}