Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Paweł Forysiuk | ||||
Approved revision: | 6423 | ||||
Merged at revision: | 6547 | ||||
Proposed branch: | lp:~midori/midori/desktop | ||||
Merge into: | lp:midori | ||||
Diff against target: |
418 lines (+183/-97) 5 files modified
cmake/ContainTest.cmake (+1/-0) extensions/apps.vala (+132/-61) midori/midori-dialog.vala (+32/-1) tests/completion.vala (+17/-34) tests/extensions.c (+1/-1) |
||||
To merge this branch: | bzr merge lp:~midori/midori/desktop | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Forysiuk | Approve | ||
Review via email: mp+195292@code.launchpad.net |
Commit message
More robust app/ profile creation
Description of the change
This branch includes new Test.init and Test.Job API which were found to be invaluable specifically with the apps test.
To post a comment you must log in.
lp:~midori/midori/desktop
updated
- 6423. By Cris Dywan
-
Remove contained folders in ContainTest
Revision history for this message
Paweł Forysiuk (tuxator) : | # |
review:
Approve
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'cmake/ContainTest.cmake' |
2 | --- cmake/ContainTest.cmake 2013-10-01 21:35:39 +0000 |
3 | +++ cmake/ContainTest.cmake 2014-01-26 21:49:39 +0000 |
4 | @@ -7,6 +7,7 @@ |
5 | set(TEST_ENV "") |
6 | foreach(VARIABLE XDG_DATA_HOME XDG_CONFIG_HOME XDG_CACHE_HOME XDG_DATA_HOME XDG_RUNTIME_DIR TMPDIR) |
7 | set(CONTAINER "${CMAKE_CURRENT_BINARY_DIR}/${test_name}-folders/${VARIABLE}") |
8 | + file(REMOVE_RECURSE ${CONTAINER}) |
9 | file(MAKE_DIRECTORY ${CONTAINER}) |
10 | set(TEST_ENV "${TEST_ENV}${VARIABLE}=${CONTAINER};") |
11 | endforeach() |
12 | |
13 | === modified file 'extensions/apps.vala' |
14 | --- extensions/apps.vala 2013-08-09 22:48:35 +0000 |
15 | +++ extensions/apps.vala 2014-01-26 21:49:39 +0000 |
16 | @@ -20,10 +20,37 @@ |
17 | internal string exec; |
18 | internal string uri; |
19 | |
20 | - internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) { |
21 | - /* Strip LRE leading character and / */ |
22 | - string name = title.delimit ("/", ' ').strip(); |
23 | - string filename = Midori.Download.clean_filename (name); |
24 | + internal static string get_favicon_name_for_uri (string prefix, GLib.File folder, string uri, bool testing) |
25 | + { |
26 | + string icon_name = Midori.Stock.WEB_BROWSER; |
27 | + |
28 | + if (testing == true) |
29 | + return icon_name; |
30 | + |
31 | + if (prefix != PROFILE_PREFIX) |
32 | + { |
33 | + try { |
34 | + var pixbuf = Midori.Paths.get_icon (uri, null); |
35 | + if (pixbuf == null) |
36 | + throw new FileError.EXIST ("No favicon loaded"); |
37 | + string icon_filename = folder.get_child ("icon.png").get_path (); |
38 | + pixbuf.save (icon_filename, "png", null, "compression", "7", null); |
39 | +#if HAVE_WIN32 |
40 | + string doubleslash_icon = icon_filename.replace ("\\", "\\\\"); |
41 | + icon_name = doubleslash_icon; |
42 | +#else |
43 | + icon_name = icon_filename; |
44 | +#endif |
45 | + } |
46 | + catch (Error error) { |
47 | + GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message); |
48 | + } |
49 | + } |
50 | + return icon_name; |
51 | + } |
52 | + |
53 | + internal static string prepare_desktop_file (string prefix, string name, string uri, string title, string icon_name) |
54 | + { |
55 | string exec; |
56 | #if HAVE_WIN32 |
57 | string doubleslash_uri = uri.replace ("\\", "\\\\"); |
58 | @@ -32,62 +59,100 @@ |
59 | #else |
60 | exec = prefix + uri; |
61 | #endif |
62 | + var keyfile = new GLib.KeyFile (); |
63 | + string entry = "Desktop Entry"; |
64 | + |
65 | + keyfile.set_string (entry, "Version", "1.0"); |
66 | + keyfile.set_string (entry, "Type", "Application"); |
67 | + keyfile.set_string (entry, "Name", name); |
68 | + keyfile.set_string (entry, "Exec", exec); |
69 | + keyfile.set_string (entry, "TryExec", PACKAGE_NAME); |
70 | + keyfile.set_string (entry, "Icon", icon_name); |
71 | + keyfile.set_string (entry, "Categories", "Network;"); |
72 | + |
73 | + return keyfile.to_data(); |
74 | + } |
75 | + |
76 | + internal static File get_app_folder () { |
77 | + var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME); |
78 | + return data_dir.get_child ("apps"); |
79 | + } |
80 | + |
81 | + internal static async File create_app (string uri, string title, Gtk.Widget? proxy) { |
82 | + string checksum = Checksum.compute_for_string (ChecksumType.MD5, uri, -1); |
83 | + var folder = get_app_folder (); |
84 | + yield Launcher.create (APP_PREFIX, folder.get_child (checksum), |
85 | + uri, title, proxy); |
86 | + return folder.get_child (checksum); |
87 | + } |
88 | + |
89 | + internal static File get_profile_folder () { |
90 | + var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME); |
91 | + return data_dir.get_child ("profiles"); |
92 | + } |
93 | + |
94 | + internal static async File create_profile (Gtk.Widget? proxy) { |
95 | + string uuid = g_dbus_generate_guid (); |
96 | + string config = Path.build_path (Path.DIR_SEPARATOR_S, |
97 | + Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid); |
98 | + var folder = get_profile_folder (); |
99 | + yield Launcher.create (PROFILE_PREFIX, folder.get_child (uuid), |
100 | + config, _("Midori (%s)").printf (uuid), proxy); |
101 | + return folder.get_child (uuid); |
102 | + } |
103 | + |
104 | + internal static async void create (string prefix, GLib.File folder, string uri, string title, Gtk.Widget proxy) { |
105 | + /* Strip LRE leading character and / */ |
106 | + string name = title.delimit ("/", ' ').strip(); |
107 | + string filename = Midori.Download.clean_filename (name); |
108 | + string icon_name = Midori.Stock.WEB_BROWSER; |
109 | + bool testing = false; |
110 | + if (proxy == null) |
111 | + testing = true; |
112 | + var file = folder.get_child ("desc"); |
113 | + |
114 | try { |
115 | folder.make_directory_with_parents (null); |
116 | - } |
117 | - catch (Error error) { |
118 | - /* It's not an error if the folder already exists; |
119 | - any fatal problems will fail further down the line */ |
120 | - } |
121 | - |
122 | - string icon_name = Midori.Stock.WEB_BROWSER; |
123 | - try { |
124 | - var pixbuf = Midori.Paths.get_icon (uri, null); |
125 | - if (pixbuf == null) |
126 | - throw new FileError.EXIST ("No favicon loaded"); |
127 | - string icon_filename = folder.get_child ("icon.png").get_path (); |
128 | - pixbuf.save (icon_filename, "png", null, "compression", "7", null); |
129 | -#if HAVE_WIN32 |
130 | - string doubleslash_icon = icon_filename.replace ("\\", "\\\\"); |
131 | - icon_name = doubleslash_icon; |
132 | -#else |
133 | - icon_name = icon_filename; |
134 | -#endif |
135 | - } |
136 | - catch (Error error) { |
137 | - GLib.warning (_("Failed to fetch application icon in %s: %s"), folder.get_path (), error.message); |
138 | - } |
139 | - string contents = """ |
140 | - [Desktop Entry] |
141 | - Version=1.0 |
142 | - Type=Application |
143 | - Name=%s |
144 | - Exec=%s |
145 | - TryExec=%s |
146 | - Icon=%s |
147 | - Categories=Network; |
148 | - """.printf (name, exec, PACKAGE_NAME, icon_name); |
149 | - var file = folder.get_child ("desc"); |
150 | - var browser = proxy.get_toplevel () as Midori.Browser; |
151 | + } catch (IOError.EXISTS exist_error) { |
152 | + /* It's no error if the folder already exists */ |
153 | + } catch (Error error) { |
154 | + warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message); |
155 | + } |
156 | + |
157 | + icon_name = get_favicon_name_for_uri (prefix, folder, uri, testing); |
158 | + string desktop_file = prepare_desktop_file (prefix, name, uri, title, icon_name); |
159 | + |
160 | try { |
161 | var stream = yield file.replace_async (null, false, GLib.FileCreateFlags.NONE); |
162 | - yield stream.write_async (contents.data); |
163 | + yield stream.write_async (desktop_file.data); |
164 | // Create a launcher/ menu |
165 | #if HAVE_WIN32 |
166 | Midori.Sokoke.create_win32_desktop_lnk (prefix, filename, uri); |
167 | #else |
168 | var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()); |
169 | - yield file.copy_async (data_dir.get_child ("applications").get_child (filename + ".desktop"), |
170 | + var desktop_dir = data_dir.get_child ("applications"); |
171 | + try { |
172 | + desktop_dir.make_directory_with_parents (null); |
173 | + } catch (IOError.EXISTS exist_error) { |
174 | + /* It's no error if the folder already exists */ |
175 | + } |
176 | + |
177 | + yield file.copy_async (desktop_dir.get_child (filename + ".desktop"), |
178 | GLib.FileCopyFlags.NONE); |
179 | #endif |
180 | - |
181 | - browser.send_notification (_("Launcher created"), |
182 | - _("You can now run <b>%s</b> from your launcher or menu").printf (name)); |
183 | + if (proxy != null) { |
184 | + var browser = proxy.get_toplevel () as Midori.Browser; |
185 | + browser.send_notification (_("Launcher created"), |
186 | + _("You can now run <b>%s</b> from your launcher or menu").printf (name)); |
187 | + } |
188 | } |
189 | catch (Error error) { |
190 | warning (_("Failed to create new launcher (%s): %s"), file.get_path (), error.message); |
191 | - browser.send_notification (_("Error creating launcher"), |
192 | - _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message)); |
193 | + if (proxy != null) { |
194 | + var browser = proxy.get_toplevel () as Midori.Browser; |
195 | + browser.send_notification (_("Error creating launcher"), |
196 | + _("Failed to create new launcher (%s): %s").printf (file.get_path (), error.message)); |
197 | + } |
198 | } |
199 | } |
200 | |
201 | @@ -139,11 +204,7 @@ |
202 | profile.is_important = true; |
203 | profile.show (); |
204 | profile.clicked.connect (() => { |
205 | - string uuid = g_dbus_generate_guid (); |
206 | - string config = Path.build_path (Path.DIR_SEPARATOR_S, |
207 | - Midori.Paths.get_user_data_dir (), PACKAGE_NAME, "profiles", uuid); |
208 | - Launcher.create.begin (PROFILE_PREFIX, profile_folder.get_child (uuid), |
209 | - config, _("Midori (%s)").printf (uuid), this); |
210 | + Launcher.create_profile.begin (this); |
211 | }); |
212 | toolbar.insert (profile, -1); |
213 | #endif |
214 | @@ -349,10 +410,8 @@ |
215 | try { |
216 | try { |
217 | app_folder.make_directory_with_parents (null); |
218 | - } |
219 | - catch (IOError folder_error) { |
220 | - if (!(folder_error is IOError.EXISTS)) |
221 | - throw folder_error; |
222 | + } catch (IOError.EXISTS exist_error) { |
223 | + /* It's no error if the folder already exists */ |
224 | } |
225 | |
226 | var monitor = app_folder.monitor_directory (0, null); |
227 | @@ -392,9 +451,7 @@ |
228 | _("Creates a new app for a specific site"), null); |
229 | action.activate.connect (() => { |
230 | var view = browser.tab as Midori.View; |
231 | - string checksum = Checksum.compute_for_string (ChecksumType.MD5, view.get_display_uri (), -1); |
232 | - Launcher.create.begin (APP_PREFIX, app_folder.get_child (checksum), |
233 | - view.get_display_uri (), view.get_display_title (), browser); |
234 | + Launcher.create_app.begin (view.get_display_uri (), view.get_display_title (), view); |
235 | }); |
236 | action_group.add_action_with_accel (action, "<Ctrl><Shift>A"); |
237 | action.set_accel_group (accels); |
238 | @@ -408,12 +465,11 @@ |
239 | |
240 | void activated (Midori.App app) { |
241 | array = new Katze.Array (typeof (Launcher)); |
242 | - var data_dir = File.new_for_path (Midori.Paths.get_user_data_dir ()).get_child (PACKAGE_NAME); |
243 | monitors = new GLib.List<GLib.FileMonitor> (); |
244 | - app_folder = data_dir.get_child ("apps"); |
245 | + app_folder = Launcher.get_app_folder (); |
246 | populate_apps.begin (app_folder); |
247 | /* FIXME: Profiles are broken on win32 because of no multi instance support */ |
248 | - profile_folder = data_dir.get_child ("profiles"); |
249 | + profile_folder = Launcher.get_profile_folder (); |
250 | #if !HAVE_WIN32 |
251 | populate_apps.begin (profile_folder); |
252 | #endif |
253 | @@ -456,3 +512,18 @@ |
254 | return new Apps.Manager (); |
255 | } |
256 | |
257 | +class ExtensionsAppsDesktop : Midori.Test.Job { |
258 | + public static void test () { new ExtensionsAppsDesktop ().run_sync (); } |
259 | + public override async void run (Cancellable cancellable) throws GLib.Error { |
260 | + var folder = yield Apps.Launcher.create_app ("http://example.com", "Example", null); |
261 | + var launcher = new Apps.Launcher (folder); |
262 | + launcher.init (); |
263 | + Katze.assert_str_equal (folder.get_path (), launcher.uri, "http://example.com"); |
264 | + yield Apps.Launcher.create_profile (null); |
265 | + } |
266 | +} |
267 | + |
268 | +public void extension_test () { |
269 | + Test.add_func ("/extensions/apps/desktop", ExtensionsAppsDesktop.test); |
270 | +} |
271 | + |
272 | |
273 | === modified file 'midori/midori-dialog.vala' |
274 | --- midori/midori-dialog.vala 2013-11-05 14:51:49 +0000 |
275 | +++ midori/midori-dialog.vala 2014-01-26 21:49:39 +0000 |
276 | @@ -24,13 +24,24 @@ |
277 | } |
278 | |
279 | namespace Test { |
280 | + public void init ([CCode (array_length_pos = 0.9)] ref unowned string[] args) { |
281 | + GLib.Test.init (ref args); |
282 | + |
283 | + /* Always log to stderr */ |
284 | + Log.set_handler (null, |
285 | + LogLevelFlags.LEVEL_MASK | LogLevelFlags.FLAG_FATAL | LogLevelFlags.FLAG_RECURSION, |
286 | + (domain, log_levels, message) => { |
287 | + stderr.printf ("** %s\n", message); |
288 | + }); |
289 | + } |
290 | + |
291 | internal static uint test_max_timeout = 0; |
292 | internal static string? test_first_try = null; |
293 | public void grab_max_timeout () { |
294 | int seconds = (Environment.get_variable ("MIDORI_TIMEOUT") ?? "42").to_int (); |
295 | test_first_try = "once"; |
296 | test_max_timeout = GLib.Timeout.add_seconds (seconds > 0 ? seconds / 2 : 0, ()=>{ |
297 | - stdout.printf ("Timed out %s%s\n", test_first_try, |
298 | + stderr.printf ("Timed out %s%s\n", test_first_try, |
299 | MainContext.default ().pending () ? " (loop)" : ""); |
300 | if (test_first_try == "twice") |
301 | Process.exit (0); |
302 | @@ -50,6 +61,26 @@ |
303 | test_idle_timeouts = true; |
304 | } |
305 | |
306 | + public abstract class Job : GLib.Object { |
307 | + bool done; |
308 | + public abstract async void run (Cancellable cancellable) throws GLib.Error; |
309 | + async void run_wrapped (Cancellable cancellable) { |
310 | + try { |
311 | + yield run (cancellable); |
312 | + } catch (Error error) { |
313 | + GLib.error (error.message); |
314 | + } |
315 | + done = true; |
316 | + } |
317 | + public void run_sync () { |
318 | + var loop = MainContext.default (); |
319 | + var cancellable = new Cancellable (); |
320 | + done = false; |
321 | + run_wrapped.begin (cancellable); |
322 | + do { loop.iteration (true); } while (!done); |
323 | + } |
324 | + } |
325 | + |
326 | public void log_set_fatal_handler_for_icons () { |
327 | GLib.Test.log_set_fatal_handler ((domain, log_levels, message)=> { |
328 | return !message.contains ("Error loading theme icon") |
329 | |
330 | === modified file 'tests/completion.vala' |
331 | --- tests/completion.vala 2013-12-16 22:38:24 +0000 |
332 | +++ tests/completion.vala 2014-01-26 21:49:39 +0000 |
333 | @@ -87,43 +87,26 @@ |
334 | error ("Expected %d but got %d", 3, n); |
335 | } |
336 | |
337 | -async void complete_history (Midori.HistoryDatabase history) { |
338 | - try { |
339 | - history.insert ("http://example.com", "Ejemplo", 0, 0); |
340 | - } catch (Error error) { |
341 | - assert_not_reached (); |
342 | - } |
343 | - var cancellable = new Cancellable (); |
344 | - var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable); |
345 | - assert (results.length () == 1); |
346 | - var first = results.nth_data (0); |
347 | - assert (first.title == "Ejemplo"); |
348 | - results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable); |
349 | - assert (results.length () == 1); |
350 | - first = results.nth_data (0); |
351 | - assert (first.title == "Ejemplo"); |
352 | - complete_history_done = true; |
353 | -} |
354 | - |
355 | -bool complete_history_done = false; |
356 | -void completion_history () { |
357 | - var app = new Midori.App (); |
358 | - Midori.HistoryDatabase history; |
359 | - try { |
360 | +class CompletionHistory : Midori.Test.Job { |
361 | + public static void test () { new CompletionHistory ().run_sync (); } |
362 | + public override async void run (Cancellable cancellable) throws GLib.Error { |
363 | var bookmarks_database = new Midori.BookmarksDatabase (); |
364 | assert (bookmarks_database.db != null); |
365 | - history = new Midori.HistoryDatabase (app); |
366 | + |
367 | + Midori.HistoryDatabase history = new Midori.HistoryDatabase (null); |
368 | assert (history.db != null); |
369 | history.clear (0); |
370 | - } catch (Midori.DatabaseError error) { |
371 | - assert_not_reached(); |
372 | + |
373 | + history.insert ("http://example.com", "Ejemplo", 0, 0); |
374 | + var results = yield history.list_by_count_with_bookmarks ("example", 1, cancellable); |
375 | + assert (results.length () == 1); |
376 | + var first = results.nth_data (0); |
377 | + assert (first.title == "Ejemplo"); |
378 | + results = yield history.list_by_count_with_bookmarks ("ejemplo", 1, cancellable); |
379 | + assert (results.length () == 1); |
380 | + first = results.nth_data (0); |
381 | + assert (first.title == "Ejemplo"); |
382 | } |
383 | - |
384 | - Midori.Test.grab_max_timeout (); |
385 | - var loop = MainContext.default (); |
386 | - complete_history.begin (history); |
387 | - do { loop.iteration (true); } while (!complete_history_done); |
388 | - Midori.Test.release_max_timeout (); |
389 | } |
390 | |
391 | struct TestCaseRender { |
392 | @@ -154,11 +137,11 @@ |
393 | } |
394 | |
395 | void main (string[] args) { |
396 | - Test.init (ref args); |
397 | + Midori.Test.init (ref args); |
398 | Midori.App.setup (ref args, null); |
399 | Midori.Paths.init (Midori.RuntimeMode.NORMAL, null); |
400 | Test.add_func ("/completion/autocompleter", completion_autocompleter); |
401 | - Test.add_func ("/completion/history", completion_history); |
402 | + Test.add_func ("/completion/history", CompletionHistory.test); |
403 | Test.add_func ("/completion/location-action", completion_location_action); |
404 | Test.run (); |
405 | } |
406 | |
407 | === modified file 'tests/extensions.c' |
408 | --- tests/extensions.c 2013-10-29 18:45:01 +0000 |
409 | +++ tests/extensions.c 2014-01-26 21:49:39 +0000 |
410 | @@ -216,7 +216,7 @@ |
411 | main (int argc, |
412 | char** argv) |
413 | { |
414 | - g_test_init (&argc, &argv, NULL); |
415 | + midori_test_init (&argc, &argv); |
416 | midori_app_setup (&argc, &argv, NULL); |
417 | midori_paths_init (MIDORI_RUNTIME_MODE_NORMAL, NULL); |
418 | #ifndef HAVE_WEBKIT2 |