|
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 // Get services. |
|
8 try { |
|
9 var histSvc = Cc["@mozilla.org/browser/nav-history-service;1"]. |
|
10 getService(Ci.nsINavHistoryService); |
|
11 var bmSvc = Cc["@mozilla.org/browser/nav-bookmarks-service;1"]. |
|
12 getService(Ci.nsINavBookmarksService); |
|
13 var annoSvc = Cc["@mozilla.org/browser/annotation-service;1"] |
|
14 .getService(Ci.nsIAnnotationService); |
|
15 } catch(ex) { |
|
16 do_throw("Could not get services\n"); |
|
17 } |
|
18 |
|
19 var validAnnoName = "validAnno"; |
|
20 var validItemName = "validItem"; |
|
21 var deletedAnnoName = "deletedAnno"; |
|
22 var deletedItemName = "deletedItem"; |
|
23 var bookmarkedURI = uri("http://www.mozilla.org/"); |
|
24 // set lastModified to the past to prevent VM timing bugs |
|
25 var pastDate = Date.now() * 1000 - 1; |
|
26 var deletedBookmarkIds = []; |
|
27 |
|
28 // bookmarks observer |
|
29 var observer = { |
|
30 // cached ordered array of notified items |
|
31 _onItemRemovedItemIds: [], |
|
32 onItemRemoved: function(aItemId, aParentId, aIndex) { |
|
33 // We should first get notifications for children, then for their parent |
|
34 do_check_eq(this._onItemRemovedItemIds.indexOf(aParentId), -1); |
|
35 // Ensure we are not wrongly removing 1 level up |
|
36 do_check_neq(aParentId, bmSvc.toolbarFolder); |
|
37 // Removed item must be one of those we have manually deleted |
|
38 do_check_neq(deletedBookmarkIds.indexOf(aItemId), -1); |
|
39 this._onItemRemovedItemIds.push(aItemId); |
|
40 }, |
|
41 |
|
42 QueryInterface: function(aIID) { |
|
43 if (aIID.equals(Ci.nsINavBookmarkObserver) || |
|
44 aIID.equals(Ci.nsISupports)) { |
|
45 return this; |
|
46 } |
|
47 throw Cr.NS_ERROR_NO_INTERFACE; |
|
48 } |
|
49 }; |
|
50 |
|
51 bmSvc.addObserver(observer, false); |
|
52 |
|
53 function add_bookmarks() { |
|
54 // This is the folder we will cleanup |
|
55 var validFolderId = bmSvc.createFolder(bmSvc.toolbarFolder, |
|
56 validItemName, |
|
57 bmSvc.DEFAULT_INDEX); |
|
58 annoSvc.setItemAnnotation(validFolderId, validAnnoName, |
|
59 "annotation", 0, |
|
60 annoSvc.EXPIRE_NEVER); |
|
61 bmSvc.setItemLastModified(validFolderId, pastDate); |
|
62 |
|
63 // This bookmark should not be deleted |
|
64 var validItemId = bmSvc.insertBookmark(bmSvc.toolbarFolder, |
|
65 bookmarkedURI, |
|
66 bmSvc.DEFAULT_INDEX, |
|
67 validItemName); |
|
68 annoSvc.setItemAnnotation(validItemId, validAnnoName, |
|
69 "annotation", 0, annoSvc.EXPIRE_NEVER); |
|
70 |
|
71 // The following contents should be deleted |
|
72 var deletedItemId = bmSvc.insertBookmark(validFolderId, |
|
73 bookmarkedURI, |
|
74 bmSvc.DEFAULT_INDEX, |
|
75 deletedItemName); |
|
76 annoSvc.setItemAnnotation(deletedItemId, deletedAnnoName, |
|
77 "annotation", 0, annoSvc.EXPIRE_NEVER); |
|
78 deletedBookmarkIds.push(deletedItemId); |
|
79 |
|
80 var internalFolderId = bmSvc.createFolder(validFolderId, |
|
81 deletedItemName, |
|
82 bmSvc.DEFAULT_INDEX); |
|
83 annoSvc.setItemAnnotation(internalFolderId, deletedAnnoName, |
|
84 "annotation", 0, annoSvc.EXPIRE_NEVER); |
|
85 deletedBookmarkIds.push(internalFolderId); |
|
86 |
|
87 deletedItemId = bmSvc.insertBookmark(internalFolderId, |
|
88 bookmarkedURI, |
|
89 bmSvc.DEFAULT_INDEX, |
|
90 deletedItemName); |
|
91 annoSvc.setItemAnnotation(deletedItemId, deletedAnnoName, |
|
92 "annotation", 0, annoSvc.EXPIRE_NEVER); |
|
93 deletedBookmarkIds.push(deletedItemId); |
|
94 |
|
95 return validFolderId; |
|
96 } |
|
97 |
|
98 function check_bookmarks(aFolderId) { |
|
99 // check that we still have valid bookmarks |
|
100 var bookmarks = bmSvc.getBookmarkIdsForURI(bookmarkedURI); |
|
101 for(var i = 0; i < bookmarks.length; i++) { |
|
102 do_check_eq(bmSvc.getItemTitle(bookmarks[i]), validItemName); |
|
103 do_check_true(annoSvc.itemHasAnnotation(bookmarks[i],validAnnoName)); |
|
104 } |
|
105 |
|
106 // check that folder exists and has still its annotation |
|
107 do_check_eq(bmSvc.getItemTitle(aFolderId), validItemName); |
|
108 do_check_true(annoSvc.itemHasAnnotation(aFolderId, validAnnoName)); |
|
109 |
|
110 // check that folder is empty |
|
111 var options = histSvc.getNewQueryOptions(); |
|
112 var query = histSvc.getNewQuery(); |
|
113 query.setFolders([aFolderId], 1); |
|
114 var result = histSvc.executeQuery(query, options); |
|
115 var root = result.root; |
|
116 root.containerOpen = true; |
|
117 do_check_eq(root.childCount, 0); |
|
118 root.containerOpen = false; |
|
119 |
|
120 // test that lastModified got updated |
|
121 do_check_true(pastDate < bmSvc.getItemLastModified(aFolderId)); |
|
122 |
|
123 // test that all children have been deleted, we use annos for that |
|
124 var deletedItems = annoSvc.getItemsWithAnnotation(deletedAnnoName); |
|
125 do_check_eq(deletedItems.length, 0); |
|
126 |
|
127 // test that observer has been called for (and only for) deleted items |
|
128 do_check_eq(observer._onItemRemovedItemIds.length, deletedBookmarkIds.length); |
|
129 |
|
130 // Sanity check: all roots should be intact |
|
131 do_check_eq(bmSvc.getFolderIdForItem(bmSvc.placesRoot), 0); |
|
132 do_check_eq(bmSvc.getFolderIdForItem(bmSvc.bookmarksMenuFolder), bmSvc.placesRoot); |
|
133 do_check_eq(bmSvc.getFolderIdForItem(bmSvc.tagsFolder), bmSvc.placesRoot); |
|
134 do_check_eq(bmSvc.getFolderIdForItem(bmSvc.unfiledBookmarksFolder), bmSvc.placesRoot); |
|
135 do_check_eq(bmSvc.getFolderIdForItem(bmSvc.toolbarFolder), bmSvc.placesRoot); |
|
136 } |
|
137 |
|
138 // main |
|
139 function run_test() { |
|
140 var folderId = add_bookmarks(); |
|
141 bmSvc.removeFolderChildren(folderId); |
|
142 check_bookmarks(folderId); |
|
143 } |