|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 function waitForBookmarkNotification(aNotification, aCallback, aProperty) |
|
5 { |
|
6 PlacesUtils.bookmarks.addObserver({ |
|
7 validate: function (aMethodName, aData) |
|
8 { |
|
9 if (aMethodName == aNotification && |
|
10 (!aProperty || aProperty == aData.property)) { |
|
11 PlacesUtils.bookmarks.removeObserver(this); |
|
12 aCallback(aData); |
|
13 } |
|
14 }, |
|
15 |
|
16 // nsINavBookmarkObserver |
|
17 QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver]), |
|
18 onBeginUpdateBatch: function onBeginUpdateBatch() |
|
19 this.validate(arguments.callee.name, arguments), |
|
20 onEndUpdateBatch: function onEndUpdateBatch() |
|
21 this.validate(arguments.callee.name, arguments), |
|
22 onItemAdded: function onItemAdded(aItemId, aParentId, aIndex, aItemType, |
|
23 aURI, aTitle) |
|
24 { |
|
25 return this.validate(arguments.callee.name, { id: aItemId, |
|
26 index: aIndex, |
|
27 type: aItemType, |
|
28 url: aURI ? aURI.spec : null, |
|
29 title: aTitle }); |
|
30 }, |
|
31 onItemRemoved: function onItemRemoved() |
|
32 this.validate(arguments.callee.name, arguments), |
|
33 onItemChanged: function onItemChanged(aItemId, aProperty, aIsAnno, |
|
34 aNewValue, aLastModified, aItemType) |
|
35 { |
|
36 return this.validate(arguments.callee.name, |
|
37 { id: aItemId, |
|
38 get index() PlacesUtils.bookmarks.getItemIndex(this.id), |
|
39 type: aItemType, |
|
40 property: aProperty, |
|
41 get url() aItemType == PlacesUtils.bookmarks.TYPE_BOOKMARK ? |
|
42 PlacesUtils.bookmarks.getBookmarkURI(this.id).spec : |
|
43 null, |
|
44 get title() PlacesUtils.bookmarks.getItemTitle(this.id), |
|
45 }); |
|
46 }, |
|
47 onItemVisited: function onItemVisited() |
|
48 this.validate(arguments.callee.name, arguments), |
|
49 onItemMoved: function onItemMoved(aItemId, aOldParentId, aOldIndex, |
|
50 aNewParentId, aNewIndex, aItemType) |
|
51 { |
|
52 this.validate(arguments.callee.name, { id: aItemId, |
|
53 index: aNewIndex, |
|
54 type: aItemType }); |
|
55 } |
|
56 }, false); |
|
57 } |
|
58 |
|
59 function wrapNodeByIdAndParent(aItemId, aParentId) |
|
60 { |
|
61 let wrappedNode; |
|
62 let root = PlacesUtils.getFolderContents(aParentId, false, false).root; |
|
63 for (let i = 0; i < root.childCount; ++i) { |
|
64 let node = root.getChild(i); |
|
65 if (node.itemId == aItemId) { |
|
66 let type; |
|
67 if (PlacesUtils.nodeIsContainer(node)) { |
|
68 type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER; |
|
69 } |
|
70 else if (PlacesUtils.nodeIsURI(node)) { |
|
71 type = PlacesUtils.TYPE_X_MOZ_PLACE; |
|
72 } |
|
73 else if (PlacesUtils.nodeIsSeparator(node)) { |
|
74 type = PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR; |
|
75 } |
|
76 else { |
|
77 do_throw("Unknown node type"); |
|
78 } |
|
79 wrappedNode = PlacesUtils.wrapNode(node, type); |
|
80 } |
|
81 } |
|
82 root.containerOpen = false; |
|
83 return JSON.parse(wrappedNode); |
|
84 } |
|
85 |
|
86 add_test(function test_text_paste() |
|
87 { |
|
88 const TEST_URL = "http://places.moz.org/" |
|
89 const TEST_TITLE = "Places bookmark" |
|
90 |
|
91 waitForBookmarkNotification("onItemAdded", function(aData) |
|
92 { |
|
93 do_check_eq(aData.title, TEST_TITLE); |
|
94 do_check_eq(aData.url, TEST_URL); |
|
95 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
96 do_check_eq(aData.index, 0); |
|
97 run_next_test(); |
|
98 }); |
|
99 |
|
100 let txn = PlacesUIUtils.makeTransaction( |
|
101 { title: TEST_TITLE, uri: TEST_URL }, |
|
102 PlacesUtils.TYPE_X_MOZ_URL, |
|
103 PlacesUtils.unfiledBookmarksFolderId, |
|
104 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
105 true // Unused for text. |
|
106 ); |
|
107 PlacesUtils.transactionManager.doTransaction(txn); |
|
108 }); |
|
109 |
|
110 add_test(function test_container() |
|
111 { |
|
112 const TEST_TITLE = "Places folder" |
|
113 |
|
114 waitForBookmarkNotification("onItemChanged", function(aData) |
|
115 { |
|
116 do_check_eq(aData.title, TEST_TITLE); |
|
117 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER); |
|
118 do_check_eq(aData.index, 1); |
|
119 |
|
120 waitForBookmarkNotification("onItemAdded", function(aData) |
|
121 { |
|
122 do_check_eq(aData.title, TEST_TITLE); |
|
123 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER); |
|
124 do_check_eq(aData.index, 2); |
|
125 let id = aData.id; |
|
126 |
|
127 waitForBookmarkNotification("onItemMoved", function(aData) |
|
128 { |
|
129 do_check_eq(aData.id, id); |
|
130 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_FOLDER); |
|
131 do_check_eq(aData.index, 1); |
|
132 |
|
133 run_next_test(); |
|
134 }); |
|
135 |
|
136 let txn = PlacesUIUtils.makeTransaction( |
|
137 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
138 0, // Unused for real nodes. |
|
139 PlacesUtils.unfiledBookmarksFolderId, |
|
140 1, // Move to position 1. |
|
141 false |
|
142 ); |
|
143 PlacesUtils.transactionManager.doTransaction(txn); |
|
144 }); |
|
145 |
|
146 try { |
|
147 let txn = PlacesUIUtils.makeTransaction( |
|
148 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
149 0, // Unused for real nodes. |
|
150 PlacesUtils.unfiledBookmarksFolderId, |
|
151 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
152 true |
|
153 ); |
|
154 PlacesUtils.transactionManager.doTransaction(txn); |
|
155 } catch(ex) { |
|
156 do_throw(ex); |
|
157 } |
|
158 }, "random-anno"); |
|
159 |
|
160 let id = PlacesUtils.bookmarks.createFolder(PlacesUtils.unfiledBookmarksFolderId, |
|
161 TEST_TITLE, |
|
162 PlacesUtils.bookmarks.DEFAULT_INDEX); |
|
163 PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO, |
|
164 "description", 0, |
|
165 PlacesUtils.annotations.EXPIRE_NEVER); |
|
166 PlacesUtils.annotations.setItemAnnotation(id, "random-anno", |
|
167 "random-value", 0, |
|
168 PlacesUtils.annotations.EXPIRE_NEVER); |
|
169 }); |
|
170 |
|
171 |
|
172 add_test(function test_separator() |
|
173 { |
|
174 waitForBookmarkNotification("onItemChanged", function(aData) |
|
175 { |
|
176 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); |
|
177 do_check_eq(aData.index, 3); |
|
178 |
|
179 waitForBookmarkNotification("onItemAdded", function(aData) |
|
180 { |
|
181 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); |
|
182 do_check_eq(aData.index, 4); |
|
183 let id = aData.id; |
|
184 |
|
185 waitForBookmarkNotification("onItemMoved", function(aData) |
|
186 { |
|
187 do_check_eq(aData.id, id); |
|
188 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_SEPARATOR); |
|
189 do_check_eq(aData.index, 1); |
|
190 |
|
191 run_next_test(); |
|
192 }); |
|
193 |
|
194 let txn = PlacesUIUtils.makeTransaction( |
|
195 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
196 0, // Unused for real nodes. |
|
197 PlacesUtils.unfiledBookmarksFolderId, |
|
198 1, // Move to position 1. |
|
199 false |
|
200 ); |
|
201 PlacesUtils.transactionManager.doTransaction(txn); |
|
202 }); |
|
203 |
|
204 try { |
|
205 let txn = PlacesUIUtils.makeTransaction( |
|
206 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
207 0, // Unused for real nodes. |
|
208 PlacesUtils.unfiledBookmarksFolderId, |
|
209 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
210 true |
|
211 ); |
|
212 PlacesUtils.transactionManager.doTransaction(txn); |
|
213 } catch(ex) { |
|
214 do_throw(ex); |
|
215 } |
|
216 }, "random-anno"); |
|
217 |
|
218 let id = PlacesUtils.bookmarks.insertSeparator(PlacesUtils.unfiledBookmarksFolderId, |
|
219 PlacesUtils.bookmarks.DEFAULT_INDEX); |
|
220 PlacesUtils.annotations.setItemAnnotation(id, "random-anno", |
|
221 "random-value", 0, |
|
222 PlacesUtils.annotations.EXPIRE_NEVER); |
|
223 }); |
|
224 |
|
225 add_test(function test_bookmark() |
|
226 { |
|
227 const TEST_URL = "http://places.moz.org/" |
|
228 const TEST_TITLE = "Places bookmark" |
|
229 |
|
230 waitForBookmarkNotification("onItemChanged", function(aData) |
|
231 { |
|
232 do_check_eq(aData.title, TEST_TITLE); |
|
233 do_check_eq(aData.url, TEST_URL); |
|
234 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
235 do_check_eq(aData.index, 5); |
|
236 |
|
237 waitForBookmarkNotification("onItemAdded", function(aData) |
|
238 { |
|
239 do_check_eq(aData.title, TEST_TITLE); |
|
240 do_check_eq(aData.url, TEST_URL); |
|
241 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
242 do_check_eq(aData.index, 6); |
|
243 let id = aData.id; |
|
244 |
|
245 waitForBookmarkNotification("onItemMoved", function(aData) |
|
246 { |
|
247 do_check_eq(aData.id, id); |
|
248 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
249 do_check_eq(aData.index, 1); |
|
250 |
|
251 run_next_test(); |
|
252 }); |
|
253 |
|
254 let txn = PlacesUIUtils.makeTransaction( |
|
255 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
256 0, // Unused for real nodes. |
|
257 PlacesUtils.unfiledBookmarksFolderId, |
|
258 1, // Move to position 1. |
|
259 false |
|
260 ); |
|
261 PlacesUtils.transactionManager.doTransaction(txn); |
|
262 }); |
|
263 |
|
264 try { |
|
265 let txn = PlacesUIUtils.makeTransaction( |
|
266 wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId), |
|
267 0, // Unused for real nodes. |
|
268 PlacesUtils.unfiledBookmarksFolderId, |
|
269 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
270 true |
|
271 ); |
|
272 PlacesUtils.transactionManager.doTransaction(txn); |
|
273 } catch(ex) { |
|
274 do_throw(ex); |
|
275 } |
|
276 }, "random-anno"); |
|
277 |
|
278 let id = PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, |
|
279 NetUtil.newURI(TEST_URL), |
|
280 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
281 TEST_TITLE); |
|
282 PlacesUtils.annotations.setItemAnnotation(id, PlacesUIUtils.DESCRIPTION_ANNO, |
|
283 "description", 0, |
|
284 PlacesUtils.annotations.EXPIRE_NEVER); |
|
285 PlacesUtils.annotations.setItemAnnotation(id, "random-anno", |
|
286 "random-value", 0, |
|
287 PlacesUtils.annotations.EXPIRE_NEVER); |
|
288 }); |
|
289 |
|
290 add_test(function test_visit() |
|
291 { |
|
292 const TEST_URL = "http://places.moz.org/" |
|
293 const TEST_TITLE = "Places bookmark" |
|
294 |
|
295 waitForBookmarkNotification("onItemAdded", function(aData) |
|
296 { |
|
297 do_check_eq(aData.title, TEST_TITLE); |
|
298 do_check_eq(aData.url, TEST_URL); |
|
299 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
300 do_check_eq(aData.index, 7); |
|
301 |
|
302 waitForBookmarkNotification("onItemAdded", function(aData) |
|
303 { |
|
304 do_check_eq(aData.title, TEST_TITLE); |
|
305 do_check_eq(aData.url, TEST_URL); |
|
306 do_check_eq(aData.type, PlacesUtils.bookmarks.TYPE_BOOKMARK); |
|
307 do_check_eq(aData.index, 8); |
|
308 run_next_test(); |
|
309 }); |
|
310 |
|
311 try { |
|
312 let node = wrapNodeByIdAndParent(aData.id, PlacesUtils.unfiledBookmarksFolderId); |
|
313 // Simulate a not-bookmarked node, will copy it to a new bookmark. |
|
314 node.id = -1; |
|
315 let txn = PlacesUIUtils.makeTransaction( |
|
316 node, |
|
317 0, // Unused for real nodes. |
|
318 PlacesUtils.unfiledBookmarksFolderId, |
|
319 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
320 true |
|
321 ); |
|
322 PlacesUtils.transactionManager.doTransaction(txn); |
|
323 } catch(ex) { |
|
324 do_throw(ex); |
|
325 } |
|
326 }); |
|
327 |
|
328 PlacesUtils.bookmarks.insertBookmark(PlacesUtils.unfiledBookmarksFolderId, |
|
329 NetUtil.newURI(TEST_URL), |
|
330 PlacesUtils.bookmarks.DEFAULT_INDEX, |
|
331 TEST_TITLE); |
|
332 }); |
|
333 |
|
334 add_test(function check_annotations() { |
|
335 // As last step check how many items for each annotation exist. |
|
336 |
|
337 // Copies should retain the description annotation. |
|
338 let descriptions = |
|
339 PlacesUtils.annotations.getItemsWithAnnotation(PlacesUIUtils.DESCRIPTION_ANNO, {}); |
|
340 do_check_eq(descriptions.length, 4); |
|
341 |
|
342 // Only the original bookmarks should have this annotation. |
|
343 let others = PlacesUtils.annotations.getItemsWithAnnotation("random-anno", {}); |
|
344 do_check_eq(others.length, 3); |
|
345 run_next_test(); |
|
346 }); |
|
347 |
|
348 function run_test() |
|
349 { |
|
350 run_next_test(); |
|
351 } |