|
1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* vim:set ts=2 sw=2 sts=2 et: */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm"); |
|
8 |
|
9 /** |
|
10 * Tests the bookmarks-restore-* nsIObserver notifications after restoring |
|
11 * bookmarks from JSON and HTML. See bug 470314. |
|
12 */ |
|
13 |
|
14 // The topics and data passed to nsIObserver.observe() on bookmarks restore |
|
15 const NSIOBSERVER_TOPIC_BEGIN = "bookmarks-restore-begin"; |
|
16 const NSIOBSERVER_TOPIC_SUCCESS = "bookmarks-restore-success"; |
|
17 const NSIOBSERVER_TOPIC_FAILED = "bookmarks-restore-failed"; |
|
18 const NSIOBSERVER_DATA_JSON = "json"; |
|
19 const NSIOBSERVER_DATA_HTML = "html"; |
|
20 const NSIOBSERVER_DATA_HTML_INIT = "html-initial"; |
|
21 |
|
22 // Bookmarks are added for these URIs |
|
23 var uris = [ |
|
24 "http://example.com/1", |
|
25 "http://example.com/2", |
|
26 "http://example.com/3", |
|
27 "http://example.com/4", |
|
28 "http://example.com/5", |
|
29 ]; |
|
30 |
|
31 // Add tests here. Each is an object with these properties: |
|
32 // desc: description printed before test is run |
|
33 // currTopic: the next expected topic that should be observed for the test; |
|
34 // set to NSIOBSERVER_TOPIC_BEGIN to begin |
|
35 // finalTopic: the last expected topic that should be observed for the test, |
|
36 // which then causes the next test to be run |
|
37 // data: the data passed to nsIObserver.observe() corresponding to the |
|
38 // test |
|
39 // file: the nsILocalFile that the test creates |
|
40 // folderId: for HTML restore into a folder, the folder ID to restore into; |
|
41 // otherwise, set it to null |
|
42 // run: a method that actually runs the test |
|
43 var tests = [ |
|
44 { |
|
45 desc: "JSON restore: normal restore should succeed", |
|
46 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
47 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
48 data: NSIOBSERVER_DATA_JSON, |
|
49 folderId: null, |
|
50 run: function () { |
|
51 Task.spawn(function () { |
|
52 this.file = yield promiseFile("bookmarks-test_restoreNotification.json"); |
|
53 addBookmarks(); |
|
54 |
|
55 yield BookmarkJSONUtils.exportToFile(this.file); |
|
56 remove_all_bookmarks(); |
|
57 try { |
|
58 yield BookmarkJSONUtils.importFromFile(this.file, true); |
|
59 } |
|
60 catch (e) { |
|
61 do_throw(" Restore should not have failed"); |
|
62 } |
|
63 }.bind(this)); |
|
64 } |
|
65 }, |
|
66 |
|
67 { |
|
68 desc: "JSON restore: empty file should succeed", |
|
69 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
70 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
71 data: NSIOBSERVER_DATA_JSON, |
|
72 folderId: null, |
|
73 run: function () { |
|
74 Task.spawn(function() { |
|
75 this.file = yield promiseFile("bookmarks-test_restoreNotification.json"); |
|
76 try { |
|
77 yield BookmarkJSONUtils.importFromFile(this.file, true); |
|
78 } |
|
79 catch (e) { |
|
80 do_throw(" Restore should not have failed" + e); |
|
81 } |
|
82 }.bind(this)); |
|
83 } |
|
84 }, |
|
85 |
|
86 { |
|
87 desc: "JSON restore: nonexistent file should fail", |
|
88 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
89 finalTopic: NSIOBSERVER_TOPIC_FAILED, |
|
90 data: NSIOBSERVER_DATA_JSON, |
|
91 folderId: null, |
|
92 run: function () { |
|
93 this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile); |
|
94 this.file.append("this file doesn't exist because nobody created it"); |
|
95 Task.spawn(function() { |
|
96 try { |
|
97 yield BookmarkJSONUtils.importFromFile(this.file, true); |
|
98 do_throw(" Restore should have failed"); |
|
99 } |
|
100 catch (e) { |
|
101 } |
|
102 }.bind(this)); |
|
103 } |
|
104 }, |
|
105 |
|
106 { |
|
107 desc: "HTML restore: normal restore should succeed", |
|
108 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
109 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
110 data: NSIOBSERVER_DATA_HTML, |
|
111 folderId: null, |
|
112 run: function () { |
|
113 Task.spawn(function() { |
|
114 this.file = yield promiseFile("bookmarks-test_restoreNotification.html"); |
|
115 addBookmarks(); |
|
116 yield BookmarkHTMLUtils.exportToFile(this.file); |
|
117 remove_all_bookmarks(); |
|
118 try { |
|
119 BookmarkHTMLUtils.importFromFile(this.file, false) |
|
120 .then(null, do_report_unexpected_exception); |
|
121 } |
|
122 catch (e) { |
|
123 do_throw(" Restore should not have failed"); |
|
124 } |
|
125 }.bind(this)); |
|
126 } |
|
127 }, |
|
128 |
|
129 { |
|
130 desc: "HTML restore: empty file should succeed", |
|
131 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
132 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
133 data: NSIOBSERVER_DATA_HTML, |
|
134 folderId: null, |
|
135 run: function () { |
|
136 Task.spawn(function (){ |
|
137 this.file = yield promiseFile("bookmarks-test_restoreNotification.init.html"); |
|
138 try { |
|
139 BookmarkHTMLUtils.importFromFile(this.file, false) |
|
140 .then(null, do_report_unexpected_exception); |
|
141 } |
|
142 catch (e) { |
|
143 do_throw(" Restore should not have failed"); |
|
144 } |
|
145 }.bind(this)); |
|
146 } |
|
147 }, |
|
148 |
|
149 { |
|
150 desc: "HTML restore: nonexistent file should fail", |
|
151 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
152 finalTopic: NSIOBSERVER_TOPIC_FAILED, |
|
153 data: NSIOBSERVER_DATA_HTML, |
|
154 folderId: null, |
|
155 run: function () { |
|
156 this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile); |
|
157 this.file.append("this file doesn't exist because nobody created it"); |
|
158 try { |
|
159 BookmarkHTMLUtils.importFromFile(this.file, false) |
|
160 .then(function onSuccess() do_throw("Should fail!"), |
|
161 null); |
|
162 } |
|
163 catch (e) {} |
|
164 } |
|
165 }, |
|
166 |
|
167 { |
|
168 desc: "HTML initial restore: normal restore should succeed", |
|
169 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
170 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
171 data: NSIOBSERVER_DATA_HTML_INIT, |
|
172 folderId: null, |
|
173 run: function () { |
|
174 Task.spawn(function () { |
|
175 this.file = yield promiseFile("bookmarks-test_restoreNotification.init.html"); |
|
176 addBookmarks(); |
|
177 yield BookmarkHTMLUtils.exportToFile(this.file); |
|
178 remove_all_bookmarks(); |
|
179 try { |
|
180 BookmarkHTMLUtils.importFromFile(this.file, true) |
|
181 .then(null, do_report_unexpected_exception); |
|
182 } |
|
183 catch (e) { |
|
184 do_throw(" Restore should not have failed"); |
|
185 } |
|
186 }.bind(this)); |
|
187 } |
|
188 }, |
|
189 |
|
190 { |
|
191 desc: "HTML initial restore: empty file should succeed", |
|
192 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
193 finalTopic: NSIOBSERVER_TOPIC_SUCCESS, |
|
194 data: NSIOBSERVER_DATA_HTML_INIT, |
|
195 folderId: null, |
|
196 run: function () { |
|
197 Task.spawn(function () { |
|
198 this.file = yield promiseFile("bookmarks-test_restoreNotification.init.html"); |
|
199 try { |
|
200 BookmarkHTMLUtils.importFromFile(this.file, true) |
|
201 .then(null, do_report_unexpected_exception); |
|
202 } |
|
203 catch (e) { |
|
204 do_throw(" Restore should not have failed"); |
|
205 } |
|
206 }.bind(this)); |
|
207 } |
|
208 }, |
|
209 |
|
210 { |
|
211 desc: "HTML initial restore: nonexistent file should fail", |
|
212 currTopic: NSIOBSERVER_TOPIC_BEGIN, |
|
213 finalTopic: NSIOBSERVER_TOPIC_FAILED, |
|
214 data: NSIOBSERVER_DATA_HTML_INIT, |
|
215 folderId: null, |
|
216 run: function () { |
|
217 this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile); |
|
218 this.file.append("this file doesn't exist because nobody created it"); |
|
219 try { |
|
220 BookmarkHTMLUtils.importFromFile(this.file, true) |
|
221 .then(function onSuccess() do_throw("Should fail!"), |
|
222 null); |
|
223 } |
|
224 catch (e) {} |
|
225 } |
|
226 } |
|
227 ]; |
|
228 |
|
229 // nsIObserver that observes bookmarks-restore-begin. |
|
230 var beginObserver = { |
|
231 observe: function _beginObserver(aSubject, aTopic, aData) { |
|
232 var test = tests[currTestIndex]; |
|
233 |
|
234 print(" Observed " + aTopic); |
|
235 print(" Topic for current test should be what is expected"); |
|
236 do_check_eq(aTopic, test.currTopic); |
|
237 |
|
238 print(" Data for current test should be what is expected"); |
|
239 do_check_eq(aData, test.data); |
|
240 |
|
241 // Update current expected topic to the next expected one. |
|
242 test.currTopic = test.finalTopic; |
|
243 } |
|
244 }; |
|
245 |
|
246 // nsIObserver that observes bookmarks-restore-success/failed. This starts |
|
247 // the next test. |
|
248 var successAndFailedObserver = { |
|
249 observe: function _successAndFailedObserver(aSubject, aTopic, aData) { |
|
250 var test = tests[currTestIndex]; |
|
251 |
|
252 print(" Observed " + aTopic); |
|
253 print(" Topic for current test should be what is expected"); |
|
254 do_check_eq(aTopic, test.currTopic); |
|
255 |
|
256 print(" Data for current test should be what is expected"); |
|
257 do_check_eq(aData, test.data); |
|
258 |
|
259 // On restore failed, file may not exist, so wrap in try-catch. |
|
260 try { |
|
261 test.file.remove(false); |
|
262 } |
|
263 catch (exc) {} |
|
264 |
|
265 // Make sure folder ID is what is expected. For importing HTML into a |
|
266 // folder, this will be an integer, otherwise null. |
|
267 if (aSubject) { |
|
268 do_check_eq(aSubject.QueryInterface(Ci.nsISupportsPRInt64).data, |
|
269 test.folderId); |
|
270 } |
|
271 else |
|
272 do_check_eq(test.folderId, null); |
|
273 |
|
274 remove_all_bookmarks(); |
|
275 do_execute_soon(doNextTest); |
|
276 } |
|
277 }; |
|
278 |
|
279 // Index of the currently running test. See doNextTest(). |
|
280 var currTestIndex = -1; |
|
281 |
|
282 var bmsvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. |
|
283 getService(Ci.nsINavBookmarksService); |
|
284 |
|
285 var obssvc = Cc["@mozilla.org/observer-service;1"]. |
|
286 getService(Ci.nsIObserverService); |
|
287 |
|
288 /////////////////////////////////////////////////////////////////////////////// |
|
289 |
|
290 /** |
|
291 * Adds some bookmarks for the URIs in |uris|. |
|
292 */ |
|
293 function addBookmarks() { |
|
294 uris.forEach(function (u) bmsvc.insertBookmark(bmsvc.bookmarksMenuFolder, |
|
295 uri(u), |
|
296 bmsvc.DEFAULT_INDEX, |
|
297 u)); |
|
298 checkBookmarksExist(); |
|
299 } |
|
300 |
|
301 /** |
|
302 * Checks that all of the bookmarks created for |uris| exist. It works by |
|
303 * creating one query per URI and then ORing all the queries. The number of |
|
304 * results returned should be uris.length. |
|
305 */ |
|
306 function checkBookmarksExist() { |
|
307 var hs = Cc["@mozilla.org/browser/nav-history-service;1"]. |
|
308 getService(Ci.nsINavHistoryService); |
|
309 var queries = uris.map(function (u) { |
|
310 var q = hs.getNewQuery(); |
|
311 q.uri = uri(u); |
|
312 return q; |
|
313 }); |
|
314 var options = hs.getNewQueryOptions(); |
|
315 options.queryType = options.QUERY_TYPE_BOOKMARKS; |
|
316 var root = hs.executeQueries(queries, uris.length, options).root; |
|
317 root.containerOpen = true; |
|
318 do_check_eq(root.childCount, uris.length); |
|
319 root.containerOpen = false; |
|
320 } |
|
321 |
|
322 /** |
|
323 * Creates an file in the profile directory. |
|
324 * |
|
325 * @param aBasename |
|
326 * e.g., "foo.txt" in the path /some/long/path/foo.txt |
|
327 * @return {Promise} |
|
328 * @resolves to an OS.File path |
|
329 */ |
|
330 function promiseFile(aBasename) { |
|
331 let path = OS.Path.join(OS.Constants.Path.profileDir, aBasename); |
|
332 dump("\n\nopening " + path + "\n\n"); |
|
333 return OS.File.open(path, { truncate: true }).then(aFile => { aFile.close(); return path; }); |
|
334 } |
|
335 |
|
336 /** |
|
337 * Runs the next test or if all tests have been run, finishes. |
|
338 */ |
|
339 function doNextTest() { |
|
340 currTestIndex++; |
|
341 if (currTestIndex >= tests.length) { |
|
342 obssvc.removeObserver(beginObserver, NSIOBSERVER_TOPIC_BEGIN); |
|
343 obssvc.removeObserver(successAndFailedObserver, NSIOBSERVER_TOPIC_SUCCESS); |
|
344 obssvc.removeObserver(successAndFailedObserver, NSIOBSERVER_TOPIC_FAILED); |
|
345 do_test_finished(); |
|
346 } |
|
347 else { |
|
348 var test = tests[currTestIndex]; |
|
349 print("Running test: " + test.desc); |
|
350 test.run(); |
|
351 } |
|
352 } |
|
353 |
|
354 /////////////////////////////////////////////////////////////////////////////// |
|
355 |
|
356 function run_test() { |
|
357 do_test_pending(); |
|
358 obssvc.addObserver(beginObserver, NSIOBSERVER_TOPIC_BEGIN, false); |
|
359 obssvc.addObserver(successAndFailedObserver, NSIOBSERVER_TOPIC_SUCCESS, false); |
|
360 obssvc.addObserver(successAndFailedObserver, NSIOBSERVER_TOPIC_FAILED, false); |
|
361 doNextTest(); |
|
362 } |