toolkit/components/places/tests/unit/test_bookmarks_html.js

branch
TOR_BUG_9701
changeset 15
b8a032363ba2
equal deleted inserted replaced
-1:000000000000 0:4a04dd560534
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 const LOAD_IN_SIDEBAR_ANNO = "bookmarkProperties/loadInSidebar";
8 const DESCRIPTION_ANNO = "bookmarkProperties/description";
9
10 // An object representing the contents of bookmarks.preplaces.html.
11 let test_bookmarks = {
12 menu: [
13 { title: "Mozilla Firefox",
14 children: [
15 { title: "Help and Tutorials",
16 url: "http://en-us.www.mozilla.com/en-US/firefox/help/",
17 icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
18 },
19 { title: "Customize Firefox",
20 url: "http://en-us.www.mozilla.com/en-US/firefox/customize/",
21 icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
22 },
23 { title: "Get Involved",
24 url: "http://en-us.www.mozilla.com/en-US/firefox/community/",
25 icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
26 },
27 { title: "About Us",
28 url: "http://en-us.www.mozilla.com/en-US/about/",
29 icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
30 }
31 ]
32 },
33 {
34 type: Ci.nsINavHistoryResultNode.RESULT_TYPE_SEPARATOR
35 },
36 { title: "test",
37 description: "folder test comment",
38 dateAdded: 1177541020000000,
39 lastModified: 1177541050000000,
40 children: [
41 { title: "test post keyword",
42 description: "item description",
43 dateAdded: 1177375336000000,
44 lastModified: 1177375423000000,
45 keyword: "test",
46 sidebar: true,
47 postData: "hidden1%3Dbar&text1%3D%25s",
48 charset: "ISO-8859-1"
49 }
50 ]
51 }
52 ],
53 toolbar: [
54 { title: "Getting Started",
55 url: "http://en-us.www.mozilla.com/en-US/firefox/central/",
56 icon: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABGdBTUEAAK/INwWK6QAAABl0RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAHWSURBVHjaYvz//z8DJQAggJiQOe/fv2fv7Oz8rays/N+VkfG/iYnJfyD/1+rVq7ffu3dPFpsBAAHEAHIBCJ85c8bN2Nj4vwsDw/8zQLwKiO8CcRoQu0DxqlWrdsHUwzBAAIGJmTNnPgYa9j8UqhFElwPxf2MIDeIrKSn9FwSJoRkAEEAM0DD4DzMAyPi/G+QKY4hh5WAXGf8PDQ0FGwJ22d27CjADAAIIrLmjo+MXA9R2kAHvGBA2wwx6B8W7od6CeQcggKCmCEL8bgwxYCbUIGTDVkHDBia+CuotgACCueD3TDQN75D4xmAvCoK9ARMHBzAw0AECiBHkAlC0Mdy7x9ABNA3obAZXIAa6iKEcGlMVQHwWyjYuL2d4v2cPg8vZswx7gHyAAAK7AOif7SAbOqCmn4Ha3AHFsIDtgPq/vLz8P4MSkJ2W9h8ggBjevXvHDo4FQUQg/kdypqCg4H8lUIACnQ/SOBMYI8bAsAJFPcj1AAEEjwVQqLpAbXmH5BJjqI0gi9DTAAgDBBCcAVLkgmQ7yKCZxpCQxqUZhAECCJ4XgMl493ug21ZD+aDAXH0WLM4A9MZPXJkJIIAwTAR5pQMalaCABQUULttBGCCAGCnNzgABBgAMJ5THwGvJLAAAAABJRU5ErkJggg=="
57 },
58 { title: "Latest Headlines",
59 url: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/livebookmarks/",
60 feedUrl: "http://en-us.fxfeeds.mozilla.com/en-US/firefox/headlines.xml"
61 }
62 ],
63 unfiled: [
64 { title: "Example.tld",
65 url: "http://example.tld/"
66 }
67 ]
68 };
69
70 // Pre-Places bookmarks.html file pointer.
71 let gBookmarksFileOld;
72 // Places bookmarks.html file pointer.
73 let gBookmarksFileNew;
74
75 Cu.import("resource://gre/modules/BookmarkHTMLUtils.jsm");
76
77 function run_test()
78 {
79 run_next_test();
80 }
81
82 add_task(function setup() {
83 // Avoid creating smart bookmarks during the test.
84 Services.prefs.setIntPref("browser.places.smartBookmarksVersion", -1);
85
86 // File pointer to legacy bookmarks file.
87 gBookmarksFileOld = do_get_file("bookmarks.preplaces.html");
88
89 // File pointer to a new Places-exported bookmarks file.
90 gBookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
91 gBookmarksFileNew.append("bookmarks.exported.html");
92 if (gBookmarksFileNew.exists()) {
93 gBookmarksFileNew.remove(false);
94 }
95
96 // This test must be the first one, since it setups the new bookmarks.html.
97 // Test importing a pre-Places canonical bookmarks file.
98 // 1. import bookmarks.preplaces.html
99 // 2. run the test-suite
100 // Note: we do not empty the db before this import to catch bugs like 380999
101 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileOld, true);
102 yield promiseAsyncUpdates();
103 yield testImportedBookmarks();
104
105 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
106 yield promiseAsyncUpdates();
107 remove_all_bookmarks();
108 });
109
110 add_task(function test_import_new()
111 {
112 // Test importing a Places bookmarks.html file.
113 // 1. import bookmarks.exported.html
114 // 2. run the test-suite
115 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
116 yield promiseAsyncUpdates();
117
118 yield testImportedBookmarks();
119 yield promiseAsyncUpdates();
120
121 remove_all_bookmarks();
122 });
123
124 add_task(function test_emptytitle_export()
125 {
126 // Test exporting and importing with an empty-titled bookmark.
127 // 1. import bookmarks
128 // 2. create an empty-titled bookmark.
129 // 3. export to bookmarks.exported.html
130 // 4. empty bookmarks db
131 // 5. import bookmarks.exported.html
132 // 6. run the test-suite
133 // 7. remove the empty-titled bookmark
134 // 8. export to bookmarks.exported.html
135 // 9. empty bookmarks db and continue
136
137 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
138
139 const NOTITLE_URL = "http://notitle.mozilla.org/";
140 let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
141 NetUtil.newURI(NOTITLE_URL),
142 PlacesUtils.bookmarks.DEFAULT_INDEX,
143 "");
144 test_bookmarks.unfiled.push({ title: "", url: NOTITLE_URL });
145
146 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
147 remove_all_bookmarks();
148
149 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
150 yield promiseAsyncUpdates();
151 yield testImportedBookmarks();
152
153 // Cleanup.
154 test_bookmarks.unfiled.pop();
155 PlacesUtils.bookmarks.removeItem(id);
156
157 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
158 yield promiseAsyncUpdates();
159 remove_all_bookmarks();
160 });
161
162 add_task(function test_import_chromefavicon()
163 {
164 // Test exporting and importing with a bookmark pointing to a chrome favicon.
165 // 1. import bookmarks
166 // 2. create a bookmark pointing to a chrome favicon.
167 // 3. export to bookmarks.exported.html
168 // 4. empty bookmarks db
169 // 5. import bookmarks.exported.html
170 // 6. run the test-suite
171 // 7. remove the bookmark pointing to a chrome favicon.
172 // 8. export to bookmarks.exported.html
173 // 9. empty bookmarks db and continue
174
175 const PAGE_URI = NetUtil.newURI("http://example.com/chromefavicon_page");
176 const CHROME_FAVICON_URI = NetUtil.newURI("chrome://global/skin/icons/information-16.png");
177 const CHROME_FAVICON_URI_2 = NetUtil.newURI("chrome://global/skin/icons/error-16.png");
178
179 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
180 let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId,
181 PAGE_URI,
182 PlacesUtils.bookmarks.DEFAULT_INDEX,
183 "Test");
184
185 let deferred = Promise.defer();
186 PlacesUtils.favicons.setAndFetchFaviconForPage(
187 PAGE_URI, CHROME_FAVICON_URI, true,
188 PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
189 deferred.resolve);
190 yield deferred.promise;
191
192 deferred = Promise.defer();
193 PlacesUtils.favicons.getFaviconDataForPage(PAGE_URI,
194 function (aURI, aDataLen, aData, aMimeType) deferred.resolve(aData));
195 let data = yield deferred.promise;
196
197 let base64Icon = "data:image/png;base64," +
198 base64EncodeString(String.fromCharCode.apply(String, data));
199
200 test_bookmarks.unfiled.push(
201 { title: "Test", url: PAGE_URI.spec, icon: base64Icon });
202
203 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
204
205 // Change the favicon to check it's really imported again later.
206 deferred = Promise.defer();
207 PlacesUtils.favicons.setAndFetchFaviconForPage(
208 PAGE_URI, CHROME_FAVICON_URI_2, true,
209 PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
210 deferred.resolve);
211 yield deferred.promise;
212
213 remove_all_bookmarks();
214
215 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
216 yield promiseAsyncUpdates();
217 yield testImportedBookmarks();
218
219 // Cleanup.
220 test_bookmarks.unfiled.pop();
221 PlacesUtils.bookmarks.removeItem(id);
222
223 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
224 yield promiseAsyncUpdates();
225 remove_all_bookmarks();
226 });
227
228 add_task(function test_import_ontop()
229 {
230 // Test importing the exported bookmarks.html file *on top of* the existing
231 // bookmarks.
232 // 1. empty bookmarks db
233 // 2. import the exported bookmarks file
234 // 3. export to file
235 // 3. import the exported bookmarks file
236 // 4. run the test-suite
237
238 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
239 yield BookmarkHTMLUtils.exportToFile(gBookmarksFileNew);
240 yield BookmarkHTMLUtils.importFromFile(gBookmarksFileNew, true);
241 yield promiseAsyncUpdates();
242 yield testImportedBookmarks();
243 yield promiseAsyncUpdates();
244 remove_all_bookmarks();
245 });
246
247 function testImportedBookmarks()
248 {
249 for (let group in test_bookmarks) {
250 do_print("[testImportedBookmarks()] Checking group '" + group + "'");
251
252 let root;
253 switch (group) {
254 case "menu":
255 root = PlacesUtils.getFolderContents(PlacesUtils.bookmarksMenuFolderId).root;
256 break;
257 case "toolbar":
258 root = PlacesUtils.getFolderContents(PlacesUtils.toolbarFolderId).root;
259 break;
260 case "unfiled":
261 root = PlacesUtils.getFolderContents(PlacesUtils.unfiledBookmarksFolderId).root;
262 break;
263 }
264
265 let items = test_bookmarks[group];
266 do_check_eq(root.childCount, items.length);
267
268 for (let key in items) {
269 yield checkItem(items[key], root.getChild(key));
270 }
271
272 root.containerOpen = false;
273 }
274 }
275
276 function testImportedBookmarksToFolder(aFolder)
277 {
278 root = PlacesUtils.getFolderContents(aFolder).root;
279
280 // Menu bookmarks are put directly into the folder, while other roots are
281 // imported into subfolders.
282 let rootFolderCount = test_bookmarks.menu.length;
283
284 for (let i = 0; i < root.childCount; i++) {
285 let child = root.getChild(i);
286 // This check depends on all "menu" bookmarks being listed first in the imported file :-|
287 if (i < rootFolderCount) {
288 checkItem(test_bookmarks.menu[i], child);
289 }
290 else {
291 let container = child.QueryInterface(Ci.nsINavHistoryContainerResultNode);
292 let group = /Toolbar/.test(container.title) ? test_bookmarks.toolbar
293 : test_bookmarks.unfiled;
294 container.containerOpen = true;
295 do_print("[testImportedBookmarksToFolder()] Checking container '" + container.title + "'");
296 for (let t = 0; t < container.childCount; t++) {
297 checkItem(group[t], container.getChild(t));
298 }
299 container.containerOpen = false;
300 }
301 }
302
303 root.containerOpen = false;
304 }
305
306 function checkItem(aExpected, aNode)
307 {
308 let id = aNode.itemId;
309
310 return Task.spawn(function() {
311 for (prop in aExpected) {
312 switch (prop) {
313 case "type":
314 do_check_eq(aNode.type, aExpected.type);
315 break;
316 case "title":
317 do_check_eq(aNode.title, aExpected.title);
318 break;
319 case "description":
320 do_check_eq(PlacesUtils.annotations
321 .getItemAnnotation(id, DESCRIPTION_ANNO),
322 aExpected.description);
323 break;
324 case "dateAdded":
325 do_check_eq(PlacesUtils.bookmarks.getItemDateAdded(id),
326 aExpected.dateAdded);
327 break;
328 case "lastModified":
329 do_check_eq(PlacesUtils.bookmarks.getItemLastModified(id),
330 aExpected.lastModified);
331 break;
332 case "url":
333 if (!("feedUrl" in aExpected))
334 do_check_eq(aNode.uri, aExpected.url)
335 break;
336 case "icon":
337 let (deferred = Promise.defer(), data) {
338 PlacesUtils.favicons.getFaviconDataForPage(
339 NetUtil.newURI(aExpected.url),
340 function (aURI, aDataLen, aData, aMimeType) {
341 deferred.resolve(aData);
342 });
343 data = yield deferred.promise;
344 let base64Icon = "data:image/png;base64," +
345 base64EncodeString(String.fromCharCode.apply(String, data));
346 do_check_true(base64Icon == aExpected.icon);
347 }
348 break;
349 case "keyword":
350 break;
351 case "sidebar":
352 do_check_eq(PlacesUtils.annotations
353 .itemHasAnnotation(id, LOAD_IN_SIDEBAR_ANNO),
354 aExpected.sidebar);
355 break;
356 case "postData":
357 do_check_eq(PlacesUtils.annotations
358 .getItemAnnotation(id, PlacesUtils.POST_DATA_ANNO),
359 aExpected.postData);
360 break;
361 case "charset":
362 let testURI = NetUtil.newURI(aNode.uri);
363 do_check_eq((yield PlacesUtils.getCharsetForURI(testURI)), aExpected.charset);
364 break;
365 case "feedUrl":
366 let livemark = yield PlacesUtils.livemarks.getLivemark({ id: id });
367 do_check_eq(livemark.siteURI.spec, aExpected.url);
368 do_check_eq(livemark.feedURI.spec, aExpected.feedUrl);
369 break;
370 case "children":
371 let folder = aNode.QueryInterface(Ci.nsINavHistoryContainerResultNode);
372 do_check_eq(folder.hasChildren, aExpected.children.length > 0);
373 folder.containerOpen = true;
374 do_check_eq(folder.childCount, aExpected.children.length);
375
376 aExpected.children.forEach(function (item, index) checkItem(item, folder.getChild(index)));
377
378 folder.containerOpen = false;
379 break;
380 default:
381 throw new Error("Unknown property");
382 }
383 }
384 });
385 }

mercurial