freedesktop_file_parser/
lib.rs1pub mod internal_structs;
2pub mod parser;
3pub mod structs;
4
5pub use parser::parse;
6pub use structs::*;
7
8#[cfg(test)]
9mod tests {
10 use super::*;
11
12 #[test]
13 fn test_basic_valid_entry() {
14 let content = r#"
15[Desktop Entry]
16Name=Firefox
17Exec=firefox %U
18Type=Application
19Categories=Network;WebBrowser;
20"#;
21 let f = parse(content).unwrap();
22 let entry = f.entry;
23
24 assert_eq!(entry.name.default, "Firefox");
25
26 match entry.entry_type {
27 EntryType::Application(fields) => {
28 assert_eq!(fields.exec.unwrap(), "firefox %U");
29 assert_eq!(fields.categories.unwrap(), vec!["Network", "WebBrowser"]);
30 }
31 _ => panic!("Entry type is not Application"),
32 }
33 }
34
35 #[test]
36 fn test_localized_strings() {
37 let content = r#"
38[Desktop Entry]
39Name=Text Editor
40Name[es]=Editor de texto
41Name[fr]=Éditeur de texte
42Name[de]=Texteditor
43GenericName=Text Editor
44GenericName[es]=Editor
45Comment=Edit text files
46Comment[fr]=Éditer des fichiers texte
47Exec=gedit %F
48Type=Application
49"#;
50 let f = parse(content).unwrap();
51 let entry = f.entry;
52
53 let name = entry.name;
54 assert_eq!(name.default, "Text Editor");
55 assert_eq!(name.variants.get("es").unwrap(), "Editor de texto");
56 assert_eq!(name.variants.get("fr").unwrap(), "Éditeur de texte");
57 assert_eq!(name.variants.get("de").unwrap(), "Texteditor");
58
59 let generic_name = entry.generic_name.unwrap();
60 assert_eq!(generic_name.default, "Text Editor");
61 assert_eq!(generic_name.variants.get("es").unwrap(), "Editor");
62
63 let comment = entry.comment.unwrap();
64 assert_eq!(comment.default, "Edit text files");
65 assert_eq!(
66 comment.variants.get("fr").unwrap(),
67 "Éditer des fichiers texte"
68 );
69 }
70
71 #[test]
72 fn test_desktop_actions() {
73 let content = r#"
74[Desktop Entry]
75Name=Firefox
76Exec=firefox %U
77Type=Application
78Actions=new-window;new-private-window;
79
80[Desktop Action new-window]
81Name=New Window
82Name[es]=Nueva ventana
83Exec=firefox --new-window
84Icon=firefox-new-window
85
86[Desktop Action new-private-window]
87Name=New Private Window
88Exec=firefox --private-window
89"#;
90 let f = parse(content).unwrap();
91 let actions = f.actions;
92
93 assert_eq!(actions.len(), 2);
94
95 assert_eq!(
96 actions.get("new-window").unwrap().name.default,
97 "New Window"
98 );
99 assert_eq!(
100 actions
101 .get("new-window")
102 .unwrap()
103 .name
104 .variants
105 .get("es")
106 .unwrap(),
107 "Nueva ventana"
108 );
109 assert_eq!(
110 actions.get("new-window").unwrap().exec.as_ref().unwrap(),
111 "firefox --new-window"
112 );
113 assert_eq!(
114 actions
115 .get("new-window")
116 .unwrap()
117 .icon
118 .as_ref()
119 .unwrap()
120 .content,
121 "firefox-new-window"
122 );
123
124 assert_eq!(
125 actions.get("new-private-window").unwrap().name.default,
126 "New Private Window"
127 );
128 assert_eq!(
129 actions
130 .get("new-private-window")
131 .unwrap()
132 .exec
133 .as_ref()
134 .unwrap(),
135 "firefox --private-window"
136 );
137 assert!(actions.get("new-private-window").unwrap().icon.is_none());
138 }
139
140 #[test]
141 fn test_boolean_values() {
142 let content = r#"
143[Desktop Entry]
144Name=Test App
145Exec=test
146Type=Application
147Terminal=true
148NoDisplay=false
149Hidden=true
150DBusActivatable=true
151StartupNotify=true
152PrefersNonDefaultGPU=true
153SingleMainWindow=true
154"#;
155 let f = parse(content).unwrap();
156 let entry = f.entry;
157
158 assert_eq!(entry.no_display.unwrap(), false);
159 assert_eq!(entry.hidden.unwrap(), true);
160 assert_eq!(entry.dbus_activatable.unwrap(), true);
161
162 match entry.entry_type {
163 EntryType::Application(fields) => {
164 assert_eq!(fields.terminal.unwrap(), true);
165 assert_eq!(fields.startup_notify.unwrap(), true);
166 assert_eq!(fields.prefers_non_default_gpu.unwrap(), true);
167 assert_eq!(fields.single_main_window.unwrap(), true);
168 }
169 _ => panic!("Type not Application"),
170 }
171 }
172
173 #[test]
174 fn test_list_values() {
175 let content = r#"
176[Desktop Entry]
177Name=Test App
178Exec=test
179Type=Application
180Categories=Development;IDE;Programming;
181MimeType=text/plain;application/x-python;
182OnlyShowIn=GNOME;KDE;
183NotShowIn=XFCE;
184Keywords=development;coding;
185Keywords[es]=desarrollo;programación;
186Implements=org.freedesktop.Application;
187"#;
188 let f = parse(content).unwrap();
189 let entry = f.entry;
190 assert_eq!(entry.only_show_in.unwrap(), vec!["GNOME", "KDE"]);
191 assert_eq!(entry.not_show_in.unwrap(), vec!["XFCE"]);
192
193 match entry.entry_type {
194 EntryType::Application(fields) => {
195 let keywords = fields.keywords.unwrap();
196 assert_eq!(keywords.default, vec!["development", "coding"]);
197 assert_eq!(
198 keywords.variants.get("es").unwrap(),
199 &vec!["desarrollo", "programación"]
200 );
201
202 assert_eq!(
203 fields.categories.unwrap(),
204 vec!["Development", "IDE", "Programming"]
205 );
206 assert_eq!(
207 fields.mime_type.unwrap(),
208 vec!["text/plain", "application/x-python"]
209 );
210 assert_eq!(
211 fields.implements.unwrap(),
212 vec!["org.freedesktop.Application"]
213 );
214 }
215 _ => panic!("Entry type is not Application"),
216 }
217 }
218
219 #[test]
220 fn test_entry_types() {
221 let app_content = "[Desktop Entry]\nType=Application\nName=Test\nExec=test";
222 let link_content = "[Desktop Entry]\nType=Link\nName=Test\nURL=https://example.com";
223 let dir_content = "[Desktop Entry]\nType=Directory\nName=Test";
224 let unknown_content = "[Desktop Entry]\nType=CustomType\nName=Test";
225
226 let f = parse(app_content).unwrap();
227 let app_entry = f.entry;
228 let f = parse(link_content).unwrap();
229 let link_entry = f.entry;
230 let f = parse(dir_content).unwrap();
231 let dir_entry = f.entry;
232 let f = parse(unknown_content).unwrap();
233 let unknown_entry = f.entry;
234
235 assert!(matches!(app_entry.entry_type, EntryType::Application(_)));
236 assert!(matches!(link_entry.entry_type, EntryType::Link(_)));
237 assert!(matches!(dir_entry.entry_type, EntryType::Directory));
238 assert!(matches!(unknown_entry.entry_type, EntryType::Unknown));
239 }
240
241 #[test]
242 fn test_icon_string() {
243 let content = r#"
244[Desktop Entry]
245Name=Test App
246Exec=test
247Type=Application
248Icon=test-icon
249"#;
250 let f = parse(content).unwrap();
251 let entry = f.entry;
252 let icon = entry.icon.unwrap();
253 assert_eq!(icon.content, "test-icon");
254 }
256
257 #[test]
258 #[should_panic]
259 fn test_missing_required_fields() {
260 let content = r#"
261[Desktop Entry]
262Exec=test
263Type=Application
264"#;
265 parse(content).unwrap();
266 }
267}