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

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim:set ts=2 sw=2 sts=2 et: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 const bmsvc = PlacesUtils.bookmarks;
michael@0 8 const tagssvc = PlacesUtils.tagging;
michael@0 9 const annosvc = PlacesUtils.annotations;
michael@0 10 const PT = PlacesTransactions;
michael@0 11
michael@0 12 // Create and add bookmarks observer.
michael@0 13 let observer = {
michael@0 14 __proto__: NavBookmarkObserver.prototype,
michael@0 15
michael@0 16 tagRelatedGUIDs: new Set(),
michael@0 17
michael@0 18 reset: function () {
michael@0 19 this.itemsAdded = new Map();
michael@0 20 this.itemsRemoved = new Map();
michael@0 21 this.itemsChanged = new Map();
michael@0 22 this.itemsMoved = new Map();
michael@0 23 this.beginUpdateBatch = false;
michael@0 24 this.endUpdateBatch = false;
michael@0 25 },
michael@0 26
michael@0 27 onBeginUpdateBatch: function () {
michael@0 28 this.beginUpdateBatch = true;
michael@0 29 },
michael@0 30
michael@0 31 onEndUpdateBatch: function () {
michael@0 32 this.endUpdateBatch = true;
michael@0 33 },
michael@0 34
michael@0 35 onItemAdded:
michael@0 36 function (aItemId, aParentId, aIndex, aItemType, aURI, aTitle, aDateAdded,
michael@0 37 aGUID, aParentGUID) {
michael@0 38 // Ignore tag items.
michael@0 39 if (aParentId == PlacesUtils.tagsFolderId ||
michael@0 40 (aParentId != PlacesUtils.placesRootId &&
michael@0 41 bmsvc.getFolderIdForItem(aParentId) == PlacesUtils.tagsFolderId)) {
michael@0 42 this.tagRelatedGUIDs.add(aGUID);
michael@0 43 return;
michael@0 44 }
michael@0 45
michael@0 46 this.itemsAdded.set(aGUID, { itemId: aItemId
michael@0 47 , parentGUID: aParentGUID
michael@0 48 , index: aIndex
michael@0 49 , itemType: aItemType
michael@0 50 , title: aTitle
michael@0 51 , uri: aURI });
michael@0 52 },
michael@0 53
michael@0 54 onItemRemoved:
michael@0 55 function (aItemId, aParentId, aIndex, aItemType, aURI, aGUID, aParentGUID) {
michael@0 56 if (this.tagRelatedGUIDs.has(aGUID))
michael@0 57 return;
michael@0 58
michael@0 59 this.itemsRemoved.set(aGUID, { parentGUID: aParentGUID
michael@0 60 , index: aIndex
michael@0 61 , itemType: aItemType });
michael@0 62 },
michael@0 63
michael@0 64 onItemChanged:
michael@0 65 function (aItemId, aProperty, aIsAnnoProperty, aNewValue, aLastModified,
michael@0 66 aItemType, aParentId, aGUID, aParentGUID) {
michael@0 67 if (this.tagRelatedGUIDs.has(aGUID))
michael@0 68 return;
michael@0 69
michael@0 70 let changesForGUID = this.itemsChanged.get(aGUID);
michael@0 71 if (changesForGUID === undefined) {
michael@0 72 changesForGUID = new Map();
michael@0 73 this.itemsChanged.set(aGUID, changesForGUID);
michael@0 74 }
michael@0 75
michael@0 76 let newValue = aNewValue;
michael@0 77 if (aIsAnnoProperty) {
michael@0 78 if (annosvc.itemHasAnnotation(aItemId, aProperty))
michael@0 79 newValue = annosvc.getItemAnnotation(aItemId, aProperty);
michael@0 80 else
michael@0 81 newValue = null;
michael@0 82 }
michael@0 83 let change = { isAnnoProperty: aIsAnnoProperty
michael@0 84 , newValue: newValue
michael@0 85 , lastModified: aLastModified
michael@0 86 , itemType: aItemType };
michael@0 87 changesForGUID.set(aProperty, change);
michael@0 88 },
michael@0 89
michael@0 90 onItemVisited: () => {},
michael@0 91
michael@0 92 onItemMoved:
michael@0 93 function (aItemId, aOldParent, aOldIndex, aNewParent, aNewIndex, aItemType,
michael@0 94 aGUID, aOldParentGUID, aNewParentGUID) {
michael@0 95 this.itemsMoved.set(aGUID, { oldParentGUID: aOldParentGUID
michael@0 96 , oldIndex: aOldIndex
michael@0 97 , newParentGUID: aNewParentGUID
michael@0 98 , newIndex: aNewIndex
michael@0 99 , itemType: aItemType });
michael@0 100 }
michael@0 101 };
michael@0 102 observer.reset();
michael@0 103
michael@0 104 // index at which items should begin
michael@0 105 let bmStartIndex = 0;
michael@0 106
michael@0 107 // get bookmarks root id
michael@0 108 let root = PlacesUtils.bookmarksMenuFolderId;
michael@0 109
michael@0 110 function run_test() {
michael@0 111 bmsvc.addObserver(observer, false);
michael@0 112 do_register_cleanup(function () {
michael@0 113 bmsvc.removeObserver(observer);
michael@0 114 });
michael@0 115
michael@0 116 run_next_test();
michael@0 117 }
michael@0 118
michael@0 119 function sanityCheckTransactionHistory() {
michael@0 120 do_check_true(PT.undoPosition <= PT.length);
michael@0 121
michael@0 122 let check_entry_throws = f => {
michael@0 123 try {
michael@0 124 f();
michael@0 125 do_throw("PT.entry should throw for invalid input");
michael@0 126 } catch(ex) {}
michael@0 127 };
michael@0 128 check_entry_throws( () => PT.entry(-1) );
michael@0 129 check_entry_throws( () => PT.entry({}) );
michael@0 130 check_entry_throws( () => PT.entry(PT.length) );
michael@0 131
michael@0 132 if (PT.undoPosition < PT.length)
michael@0 133 do_check_eq(PT.topUndoEntry, PT.entry(PT.undoPosition));
michael@0 134 else
michael@0 135 do_check_null(PT.topUndoEntry);
michael@0 136 if (PT.undoPosition > 0)
michael@0 137 do_check_eq(PT.topRedoEntry, PT.entry(PT.undoPosition - 1));
michael@0 138 else
michael@0 139 do_check_null(PT.topRedoEntry);
michael@0 140 }
michael@0 141
michael@0 142 function getTransactionsHistoryState() {
michael@0 143 let history = [];
michael@0 144 for (let i = 0; i < PT.length; i++) {
michael@0 145 history.push(PT.entry(i));
michael@0 146 }
michael@0 147 return [history, PT.undoPosition];
michael@0 148 }
michael@0 149
michael@0 150 function ensureUndoState(aExpectedEntries = [], aExpectedUndoPosition = 0) {
michael@0 151 // ensureUndoState is called in various places during this test, so it's
michael@0 152 // a good places to sanity-check the transaction-history APIs in all
michael@0 153 // cases.
michael@0 154 sanityCheckTransactionHistory();
michael@0 155
michael@0 156 let [actualEntries, actualUndoPosition] = getTransactionsHistoryState();
michael@0 157 do_check_eq(actualEntries.length, aExpectedEntries.length);
michael@0 158 do_check_eq(actualUndoPosition, aExpectedUndoPosition);
michael@0 159
michael@0 160 function checkEqualEntries(aExpectedEntry, aActualEntry) {
michael@0 161 do_check_eq(aExpectedEntry.length, aActualEntry.length);
michael@0 162 aExpectedEntry.forEach( (t, i) => do_check_eq(t, aActualEntry[i]) );
michael@0 163 }
michael@0 164 aExpectedEntries.forEach( (e, i) => checkEqualEntries(e, actualEntries[i]) );
michael@0 165 }
michael@0 166
michael@0 167 function ensureItemsAdded(...items) {
michael@0 168 do_check_eq(observer.itemsAdded.size, items.length);
michael@0 169 for (let item of items) {
michael@0 170 do_check_true(observer.itemsAdded.has(item.GUID));
michael@0 171 let info = observer.itemsAdded.get(item.GUID);
michael@0 172 do_check_eq(info.parentGUID, item.parentGUID);
michael@0 173 if ("title" in item)
michael@0 174 do_check_eq(info.title, item.title);
michael@0 175 if ("index" in item)
michael@0 176 do_check_eq(info.index, item.index);
michael@0 177 if ("itemType" in item)
michael@0 178 do_check_eq(info.itemType, item.itemType);
michael@0 179 }
michael@0 180 }
michael@0 181
michael@0 182 function ensureItemsRemoved(...items) {
michael@0 183 do_check_eq(observer.itemsRemoved.size, items.length);
michael@0 184 for (let item of items) {
michael@0 185 do_check_true(observer.itemsRemoved.has(item.GUID));
michael@0 186 let info = observer.itemsRemoved.get(item.GUID);
michael@0 187 do_check_eq(info.parentGUID, item.parentGUID);
michael@0 188 if ("index" in item)
michael@0 189 do_check_eq(info.index, item.index);
michael@0 190 }
michael@0 191 }
michael@0 192
michael@0 193 function ensureItemsChanged(...items) {
michael@0 194 for (let item of items) {
michael@0 195 do_check_true(observer.itemsChanged.has(item.GUID));
michael@0 196 let changes = observer.itemsChanged.get(item.GUID);
michael@0 197 do_check_true(changes.has(item.property));
michael@0 198 let info = changes.get(item.property);
michael@0 199 do_check_eq(info.isAnnoProperty, Boolean(item.isAnnoProperty));
michael@0 200 do_check_eq(info.newValue, item.newValue);
michael@0 201 if ("uri" in item)
michael@0 202 do_check_true(item.uri.equals(info.uri));
michael@0 203 }
michael@0 204 }
michael@0 205
michael@0 206 function ensureAnnotationsSet(aGUID, aAnnos) {
michael@0 207 do_check_true(observer.itemsChanged.has(aGUID));
michael@0 208 let changes = observer.itemsChanged.get(aGUID);
michael@0 209 for (let anno of aAnnos) {
michael@0 210 do_check_true(changes.has(anno.name));
michael@0 211 let changeInfo = changes.get(anno.name);
michael@0 212 do_check_true(changeInfo.isAnnoProperty);
michael@0 213 do_check_eq(changeInfo.newValue, anno.value);
michael@0 214 }
michael@0 215 }
michael@0 216
michael@0 217 function ensureItemsMoved(...items) {
michael@0 218 do_check_true(observer.itemsMoved.size, items.length);
michael@0 219 for (let item of items) {
michael@0 220 do_check_true(observer.itemsMoved.has(item.GUID));
michael@0 221 let info = observer.itemsMoved.get(item.GUID);
michael@0 222 do_check_eq(info.oldParentGUID, item.oldParentGUID);
michael@0 223 do_check_eq(info.oldIndex, item.oldIndex);
michael@0 224 do_check_eq(info.newParentGUID, item.newParentGUID);
michael@0 225 do_check_eq(info.newIndex, item.newIndex);
michael@0 226 }
michael@0 227 }
michael@0 228
michael@0 229 function ensureTimestampsUpdated(aGUID, aCheckDateAdded = false) {
michael@0 230 do_check_true(observer.itemsChanged.has(aGUID));
michael@0 231 let changes = observer.itemsChanged.get(aGUID);
michael@0 232 if (aCheckDateAdded)
michael@0 233 do_check_true(changes.has("dateAdded"))
michael@0 234 do_check_true(changes.has("lastModified"));
michael@0 235 }
michael@0 236
michael@0 237 function ensureTagsForURI(aURI, aTags) {
michael@0 238 let tagsSet = tagssvc.getTagsForURI(aURI);
michael@0 239 do_check_eq(tagsSet.length, aTags.length);
michael@0 240 do_check_true(aTags.every( t => tagsSet.indexOf(t) != -1 ));
michael@0 241 }
michael@0 242
michael@0 243 function* createTestFolderInfo(aTitle = "Test Folder") {
michael@0 244 return { parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 245 , title: "Test Folder" };
michael@0 246 }
michael@0 247
michael@0 248 add_task(function* test_invalid_transact_calls() {
michael@0 249 try {
michael@0 250 PT.transact({ execute: () => {}, undo: () => {}, redo: () => {}});
michael@0 251 do_throw("transact shouldn't accept 'external' transactions");
michael@0 252 PT.transact(null);
michael@0 253 do_throw("transact should throw for invalid arguments");
michael@0 254 }
michael@0 255 catch(ex) { }
michael@0 256 });
michael@0 257
michael@0 258 add_task(function* test_recycled_transactions() {
michael@0 259 function ensureTransactThrowsFor(aTransaction) {
michael@0 260 let [txns, undoPosition] = getTransactionsHistoryState();
michael@0 261 try {
michael@0 262 yield PT.transact(aTransaction);
michael@0 263 do_throw("Shouldn't be able to use the same transaction twice");
michael@0 264 }
michael@0 265 catch(ex) { }
michael@0 266 ensureUndoState(txns, undoPosition);
michael@0 267 }
michael@0 268
michael@0 269 let txn_a = PT.NewFolder(yield createTestFolderInfo());
michael@0 270 ensureTransactThrowsFor(txn_a);
michael@0 271 yield PT.transact(txn_a);
michael@0 272 ensureUndoState([[txn_a]], 0);
michael@0 273
michael@0 274 yield PT.undo();
michael@0 275 ensureUndoState([[txn_a]], 1);
michael@0 276 ensureTransactThrowsFor(txn_a);
michael@0 277
michael@0 278 yield PT.clearTransactionsHistory();
michael@0 279 ensureUndoState();
michael@0 280 ensureTransactThrowsFor(txn_a);
michael@0 281
michael@0 282 let txn_b = PT.NewFolder(yield createTestFolderInfo());
michael@0 283 yield PT.transact(function* () {
michael@0 284 try {
michael@0 285 yield txn_a;
michael@0 286 do_throw("Shouldn't be able to use the same transaction twice");
michael@0 287 }
michael@0 288 catch(ex) { }
michael@0 289 ensureUndoState();
michael@0 290 yield txn_b;
michael@0 291 });
michael@0 292 ensureUndoState([[txn_b]], 0);
michael@0 293
michael@0 294 yield PT.undo();
michael@0 295 ensureUndoState([[txn_b]], 1);
michael@0 296 ensureTransactThrowsFor(txn_a);
michael@0 297 ensureTransactThrowsFor(txn_b);
michael@0 298
michael@0 299 yield PT.clearTransactionsHistory();
michael@0 300 ensureUndoState();
michael@0 301 observer.reset();
michael@0 302 });
michael@0 303
michael@0 304 add_task(function* test_nested_batches() {
michael@0 305 let txn_a = PT.NewFolder(yield createTestFolderInfo()),
michael@0 306 txn_b = PT.NewFolder(yield createTestFolderInfo());
michael@0 307 yield PT.transact(function* () {
michael@0 308 yield txn_a;
michael@0 309 yield (function*() {
michael@0 310 yield txn_b;
michael@0 311 }());
michael@0 312 });
michael@0 313 ensureUndoState([[txn_b, txn_a]], 0);
michael@0 314
michael@0 315 yield PT.undo();
michael@0 316 ensureUndoState([[txn_b, txn_a]], 1);
michael@0 317
michael@0 318 yield PT.clearTransactionsHistory();
michael@0 319 ensureUndoState();
michael@0 320 observer.reset();
michael@0 321 });
michael@0 322
michael@0 323 add_task(function* test_new_folder_with_annotation() {
michael@0 324 const ANNO = { name: "TestAnno", value: "TestValue" };
michael@0 325 let folder_info = yield createTestFolderInfo();
michael@0 326 folder_info.index = bmStartIndex;
michael@0 327 folder_info.annotations = [ANNO];
michael@0 328 ensureUndoState();
michael@0 329 let txn = PT.NewFolder(folder_info);
michael@0 330 folder_info.GUID = yield PT.transact(txn);
michael@0 331 let ensureDo = function* (aRedo = false) {
michael@0 332 ensureUndoState([[txn]], 0);
michael@0 333 yield ensureItemsAdded(folder_info);
michael@0 334 ensureAnnotationsSet(folder_info.GUID, [ANNO]);
michael@0 335 if (aRedo)
michael@0 336 ensureTimestampsUpdated(folder_info.GUID, true);
michael@0 337 observer.reset();
michael@0 338 };
michael@0 339
michael@0 340 let ensureUndo = () => {
michael@0 341 ensureUndoState([[txn]], 1);
michael@0 342 ensureItemsRemoved({ GUID: folder_info.GUID
michael@0 343 , parentGUID: folder_info.parentGUID
michael@0 344 , index: bmStartIndex });
michael@0 345 observer.reset();
michael@0 346 };
michael@0 347
michael@0 348 yield ensureDo();
michael@0 349 yield PT.undo();
michael@0 350 yield ensureUndo();
michael@0 351 yield PT.redo();
michael@0 352 yield ensureDo(true);
michael@0 353 yield PT.undo();
michael@0 354 ensureUndo();
michael@0 355 yield PT.clearTransactionsHistory();
michael@0 356 ensureUndoState();
michael@0 357 });
michael@0 358
michael@0 359 add_task(function* test_new_bookmark() {
michael@0 360 let bm_info = { parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 361 , uri: NetUtil.newURI("http://test_create_item.com")
michael@0 362 , index: bmStartIndex
michael@0 363 , title: "Test creating an item" };
michael@0 364
michael@0 365 ensureUndoState();
michael@0 366 let txn = PT.NewBookmark(bm_info);
michael@0 367 bm_info.GUID = yield PT.transact(txn);
michael@0 368
michael@0 369 let ensureDo = function* (aRedo = false) {
michael@0 370 ensureUndoState([[txn]], 0);
michael@0 371 yield ensureItemsAdded(bm_info);
michael@0 372 if (aRedo)
michael@0 373 ensureTimestampsUpdated(bm_info.GUID, true);
michael@0 374 observer.reset();
michael@0 375 };
michael@0 376 let ensureUndo = () => {
michael@0 377 ensureUndoState([[txn]], 1);
michael@0 378 ensureItemsRemoved({ GUID: bm_info.GUID
michael@0 379 , parentGUID: bm_info.parentGUID
michael@0 380 , index: bmStartIndex });
michael@0 381 observer.reset();
michael@0 382 };
michael@0 383
michael@0 384 yield ensureDo();
michael@0 385 yield PT.undo();
michael@0 386 ensureUndo();
michael@0 387 yield PT.redo(true);
michael@0 388 yield ensureDo();
michael@0 389 yield PT.undo();
michael@0 390 ensureUndo();
michael@0 391
michael@0 392 yield PT.clearTransactionsHistory();
michael@0 393 ensureUndoState();
michael@0 394 });
michael@0 395
michael@0 396 add_task(function* test_merge_create_folder_and_item() {
michael@0 397 let folder_info = yield createTestFolderInfo();
michael@0 398 let bm_info = { uri: NetUtil.newURI("http://test_create_item_to_folder.com")
michael@0 399 , title: "Test Bookmark"
michael@0 400 , index: bmStartIndex };
michael@0 401
michael@0 402 let { folderTxn, bkmTxn } = yield PT.transact( function* () {
michael@0 403 let folderTxn = PT.NewFolder(folder_info);
michael@0 404 folder_info.GUID = bm_info.parentGUID = yield folderTxn;
michael@0 405 let bkmTxn = PT.NewBookmark(bm_info);
michael@0 406 bm_info.GUID = yield bkmTxn;;
michael@0 407 return { folderTxn: folderTxn, bkmTxn: bkmTxn};
michael@0 408 });
michael@0 409
michael@0 410 let ensureDo = function* () {
michael@0 411 ensureUndoState([[bkmTxn, folderTxn]], 0);
michael@0 412 yield ensureItemsAdded(folder_info, bm_info);
michael@0 413 observer.reset();
michael@0 414 };
michael@0 415
michael@0 416 let ensureUndo = () => {
michael@0 417 ensureUndoState([[bkmTxn, folderTxn]], 1);
michael@0 418 ensureItemsRemoved(folder_info, bm_info);
michael@0 419 observer.reset();
michael@0 420 };
michael@0 421
michael@0 422 yield ensureDo();
michael@0 423 yield PT.undo();
michael@0 424 ensureUndo();
michael@0 425 yield PT.redo();
michael@0 426 yield ensureDo();
michael@0 427 yield PT.undo();
michael@0 428 ensureUndo();
michael@0 429
michael@0 430 yield PT.clearTransactionsHistory();
michael@0 431 ensureUndoState();
michael@0 432 });
michael@0 433
michael@0 434 add_task(function* test_move_items_to_folder() {
michael@0 435 let folder_a_info = yield createTestFolderInfo("Folder A");
michael@0 436 let bkm_a_info = { uri: NetUtil.newURI("http://test_move_items.com")
michael@0 437 , title: "Bookmark A" };
michael@0 438 let bkm_b_info = { uri: NetUtil.newURI("http://test_move_items.com")
michael@0 439 , title: "Bookmark B" };
michael@0 440
michael@0 441 // Test moving items within the same folder.
michael@0 442 let [folder_a_txn, bkm_a_txn, bkm_b_txn] = yield PT.transact(function* () {
michael@0 443 let folder_a_txn = PT.NewFolder(folder_a_info);
michael@0 444
michael@0 445 folder_a_info.GUID =
michael@0 446 bkm_a_info.parentGUID = bkm_b_info.parentGUID = yield folder_a_txn;
michael@0 447 let bkm_a_txn = PT.NewBookmark(bkm_a_info);
michael@0 448 bkm_a_info.GUID = yield bkm_a_txn;
michael@0 449 let bkm_b_txn = PT.NewBookmark(bkm_b_info);
michael@0 450 bkm_b_info.GUID = yield bkm_b_txn;
michael@0 451 return [folder_a_txn, bkm_a_txn, bkm_b_txn];
michael@0 452 });
michael@0 453
michael@0 454 ensureUndoState([[bkm_b_txn, bkm_a_txn, folder_a_txn]], 0);
michael@0 455
michael@0 456 let moveTxn = PT.MoveItem({ GUID: bkm_a_info.GUID
michael@0 457 , newParentGUID: folder_a_info.GUID });
michael@0 458 yield PT.transact(moveTxn);
michael@0 459
michael@0 460 let ensureDo = () => {
michael@0 461 ensureUndoState([[moveTxn], [bkm_b_txn, bkm_a_txn, folder_a_txn]], 0);
michael@0 462 ensureItemsMoved({ GUID: bkm_a_info.GUID
michael@0 463 , oldParentGUID: folder_a_info.GUID
michael@0 464 , newParentGUID: folder_a_info.GUID
michael@0 465 , oldIndex: 0
michael@0 466 , newIndex: 1 });
michael@0 467 observer.reset();
michael@0 468 };
michael@0 469 let ensureUndo = () => {
michael@0 470 ensureUndoState([[moveTxn], [bkm_b_txn, bkm_a_txn, folder_a_txn]], 1);
michael@0 471 ensureItemsMoved({ GUID: bkm_a_info.GUID
michael@0 472 , oldParentGUID: folder_a_info.GUID
michael@0 473 , newParentGUID: folder_a_info.GUID
michael@0 474 , oldIndex: 1
michael@0 475 , newIndex: 0 });
michael@0 476 observer.reset();
michael@0 477 };
michael@0 478
michael@0 479 ensureDo();
michael@0 480 yield PT.undo();
michael@0 481 ensureUndo();
michael@0 482 yield PT.redo();
michael@0 483 ensureDo();
michael@0 484 yield PT.undo();
michael@0 485 ensureUndo();
michael@0 486
michael@0 487 yield PT.clearTransactionsHistory(false, true);
michael@0 488 ensureUndoState([[bkm_b_txn, bkm_a_txn, folder_a_txn]], 0);
michael@0 489
michael@0 490 // Test moving items between folders.
michael@0 491 let folder_b_info = yield createTestFolderInfo("Folder B");
michael@0 492 let folder_b_txn = PT.NewFolder(folder_b_info);
michael@0 493 folder_b_info.GUID = yield PT.transact(folder_b_txn);
michael@0 494 ensureUndoState([ [folder_b_txn]
michael@0 495 , [bkm_b_txn, bkm_a_txn, folder_a_txn] ], 0);
michael@0 496
michael@0 497 moveTxn = PT.MoveItem({ GUID: bkm_a_info.GUID
michael@0 498 , newParentGUID: folder_b_info.GUID
michael@0 499 , newIndex: bmsvc.DEFAULT_INDEX });
michael@0 500 yield PT.transact(moveTxn);
michael@0 501
michael@0 502 ensureDo = () => {
michael@0 503 ensureUndoState([ [moveTxn]
michael@0 504 , [folder_b_txn]
michael@0 505 , [bkm_b_txn, bkm_a_txn, folder_a_txn] ], 0);
michael@0 506 ensureItemsMoved({ GUID: bkm_a_info.GUID
michael@0 507 , oldParentGUID: folder_a_info.GUID
michael@0 508 , newParentGUID: folder_b_info.GUID
michael@0 509 , oldIndex: 0
michael@0 510 , newIndex: 0 });
michael@0 511 observer.reset();
michael@0 512 };
michael@0 513 let ensureUndo = () => {
michael@0 514 ensureUndoState([ [moveTxn]
michael@0 515 , [folder_b_txn]
michael@0 516 , [bkm_b_txn, bkm_a_txn, folder_a_txn] ], 1);
michael@0 517 ensureItemsMoved({ GUID: bkm_a_info.GUID
michael@0 518 , oldParentGUID: folder_b_info.GUID
michael@0 519 , newParentGUID: folder_a_info.GUID
michael@0 520 , oldIndex: 0
michael@0 521 , newIndex: 0 });
michael@0 522 observer.reset();
michael@0 523 };
michael@0 524
michael@0 525 ensureDo();
michael@0 526 yield PT.undo();
michael@0 527 ensureUndo();
michael@0 528 yield PT.redo();
michael@0 529 ensureDo();
michael@0 530 yield PT.undo();
michael@0 531 ensureUndo();
michael@0 532
michael@0 533 // Clean up
michael@0 534 yield PT.undo(); // folder_b_txn
michael@0 535 yield PT.undo(); // folder_a_txn + the bookmarks;
michael@0 536 do_check_eq(observer.itemsRemoved.size, 4);
michael@0 537 ensureUndoState([ [moveTxn]
michael@0 538 , [folder_b_txn]
michael@0 539 , [bkm_b_txn, bkm_a_txn, folder_a_txn] ], 3);
michael@0 540 yield PT.clearTransactionsHistory();
michael@0 541 ensureUndoState();
michael@0 542 });
michael@0 543
michael@0 544 add_task(function* test_remove_folder() {
michael@0 545 let folder_level_1_info = yield createTestFolderInfo("Folder Level 1");
michael@0 546 let folder_level_2_info = { title: "Folder Level 2" };
michael@0 547 let [folder_level_1_txn,
michael@0 548 folder_level_2_txn] = yield PT.transact(function* () {
michael@0 549 let folder_level_1_txn = PT.NewFolder(folder_level_1_info);
michael@0 550 folder_level_1_info.GUID = yield folder_level_1_txn;
michael@0 551 folder_level_2_info.parentGUID = folder_level_1_info.GUID;
michael@0 552 let folder_level_2_txn = PT.NewFolder(folder_level_2_info);
michael@0 553 folder_level_2_info.GUID = yield folder_level_2_txn;
michael@0 554 return [folder_level_1_txn, folder_level_2_txn];
michael@0 555 });
michael@0 556
michael@0 557 ensureUndoState([[folder_level_2_txn, folder_level_1_txn]]);
michael@0 558 yield ensureItemsAdded(folder_level_1_info, folder_level_2_info);
michael@0 559 observer.reset();
michael@0 560
michael@0 561 let remove_folder_2_txn = PT.RemoveItem(folder_level_2_info);
michael@0 562 yield PT.transact(remove_folder_2_txn);
michael@0 563
michael@0 564 ensureUndoState([ [remove_folder_2_txn]
michael@0 565 , [folder_level_2_txn, folder_level_1_txn] ]);
michael@0 566 yield ensureItemsRemoved(folder_level_2_info);
michael@0 567
michael@0 568 // Undo RemoveItem "Folder Level 2"
michael@0 569 yield PT.undo();
michael@0 570 ensureUndoState([ [remove_folder_2_txn]
michael@0 571 , [folder_level_2_txn, folder_level_1_txn] ], 1);
michael@0 572 yield ensureItemsAdded(folder_level_2_info);
michael@0 573 ensureTimestampsUpdated(folder_level_2_info.GUID, true);
michael@0 574 observer.reset();
michael@0 575
michael@0 576 // Redo RemoveItem "Folder Level 2"
michael@0 577 yield PT.redo();
michael@0 578 ensureUndoState([ [remove_folder_2_txn]
michael@0 579 , [folder_level_2_txn, folder_level_1_txn] ]);
michael@0 580 yield ensureItemsRemoved(folder_level_2_info);
michael@0 581 observer.reset();
michael@0 582
michael@0 583 // Undo it again
michael@0 584 yield PT.undo();
michael@0 585 ensureUndoState([ [remove_folder_2_txn]
michael@0 586 , [folder_level_2_txn, folder_level_1_txn] ], 1);
michael@0 587 yield ensureItemsAdded(folder_level_2_info);
michael@0 588 ensureTimestampsUpdated(folder_level_2_info.GUID, true);
michael@0 589 observer.reset();
michael@0 590
michael@0 591 // Undo the creation of both folders
michael@0 592 yield PT.undo();
michael@0 593 ensureUndoState([ [remove_folder_2_txn]
michael@0 594 , [folder_level_2_txn, folder_level_1_txn] ], 2);
michael@0 595 yield ensureItemsRemoved(folder_level_2_info, folder_level_1_info);
michael@0 596 observer.reset();
michael@0 597
michael@0 598 // Redo the creation of both folders
michael@0 599 yield PT.redo();
michael@0 600 ensureUndoState([ [remove_folder_2_txn]
michael@0 601 , [folder_level_2_txn, folder_level_1_txn] ], 1);
michael@0 602 yield ensureItemsAdded(folder_level_1_info, folder_level_2_info);
michael@0 603 ensureTimestampsUpdated(folder_level_1_info.GUID, true);
michael@0 604 ensureTimestampsUpdated(folder_level_2_info.GUID, true);
michael@0 605 observer.reset();
michael@0 606
michael@0 607 // Redo RemoveItem "Folder Level 2"
michael@0 608 yield PT.redo();
michael@0 609 ensureUndoState([ [remove_folder_2_txn]
michael@0 610 , [folder_level_2_txn, folder_level_1_txn] ]);
michael@0 611 yield ensureItemsRemoved(folder_level_2_info);
michael@0 612 observer.reset();
michael@0 613
michael@0 614 // Undo everything one last time
michael@0 615 yield PT.undo();
michael@0 616 ensureUndoState([ [remove_folder_2_txn]
michael@0 617 , [folder_level_2_txn, folder_level_1_txn] ], 1);
michael@0 618 yield ensureItemsAdded(folder_level_2_info);
michael@0 619 observer.reset();
michael@0 620
michael@0 621 yield PT.undo();
michael@0 622 ensureUndoState([ [remove_folder_2_txn]
michael@0 623 , [folder_level_2_txn, folder_level_1_txn] ], 2);
michael@0 624 yield ensureItemsRemoved(folder_level_2_info, folder_level_2_info);
michael@0 625 observer.reset();
michael@0 626
michael@0 627 yield PT.clearTransactionsHistory();
michael@0 628 ensureUndoState();
michael@0 629 });
michael@0 630
michael@0 631 add_task(function* test_add_and_remove_bookmarks_with_additional_info() {
michael@0 632 const testURI = NetUtil.newURI("http://add.remove.tag")
michael@0 633 , TAG_1 = "TestTag1", TAG_2 = "TestTag2"
michael@0 634 , KEYWORD = "test_keyword"
michael@0 635 , POST_DATA = "post_data"
michael@0 636 , ANNO = { name: "TestAnno", value: "TestAnnoValue" };
michael@0 637
michael@0 638 let folder_info = yield createTestFolderInfo();
michael@0 639 folder_info.GUID = yield PT.transact(PT.NewFolder(folder_info));
michael@0 640 let ensureTags = ensureTagsForURI.bind(null, testURI);
michael@0 641
michael@0 642 // Check that the NewBookmark transaction preserves tags.
michael@0 643 observer.reset();
michael@0 644 let b1_info = { parentGUID: folder_info.GUID, uri: testURI, tags: [TAG_1] };
michael@0 645 b1_info.GUID = yield PT.transact(PT.NewBookmark(b1_info));
michael@0 646 ensureTags([TAG_1]);
michael@0 647 yield PT.undo();
michael@0 648 ensureTags([]);
michael@0 649
michael@0 650 observer.reset();
michael@0 651 yield PT.redo();
michael@0 652 ensureTimestampsUpdated(b1_info.GUID, true);
michael@0 653 ensureTags([TAG_1]);
michael@0 654
michael@0 655 // Check if the RemoveItem transaction removes and restores tags of children
michael@0 656 // correctly.
michael@0 657 yield PT.transact(PT.RemoveItem(folder_info.GUID));
michael@0 658 ensureTags([]);
michael@0 659
michael@0 660 observer.reset();
michael@0 661 yield PT.undo();
michael@0 662 ensureTimestampsUpdated(b1_info.GUID, true);
michael@0 663 ensureTags([TAG_1]);
michael@0 664
michael@0 665 yield PT.redo();
michael@0 666 ensureTags([]);
michael@0 667
michael@0 668 observer.reset();
michael@0 669 yield PT.undo();
michael@0 670 ensureTimestampsUpdated(b1_info.GUID, true);
michael@0 671 ensureTags([TAG_1]);
michael@0 672
michael@0 673 // * Check that no-op tagging (the uri is already tagged with TAG_1) is
michael@0 674 // also a no-op on undo.
michael@0 675 // * Test the "keyword" property of the NewBookmark transaction.
michael@0 676 observer.reset();
michael@0 677 let b2_info = { parentGUID: folder_info.GUID
michael@0 678 , uri: testURI, tags: [TAG_1, TAG_2]
michael@0 679 , keyword: KEYWORD
michael@0 680 , postData: POST_DATA
michael@0 681 , annotations: [ANNO] };
michael@0 682 b2_info.GUID = yield PT.transact(PT.NewBookmark(b2_info));
michael@0 683 let b2_post_creation_changes = [
michael@0 684 { GUID: b2_info.GUID
michael@0 685 , isAnnoProperty: true
michael@0 686 , property: ANNO.name
michael@0 687 , newValue: ANNO.value },
michael@0 688 { GUID: b2_info.GUID
michael@0 689 , property: "keyword"
michael@0 690 , newValue: KEYWORD },
michael@0 691 { GUID: b2_info.GUID
michael@0 692 , isAnnoProperty: true
michael@0 693 , property: PlacesUtils.POST_DATA_ANNO
michael@0 694 , newValue: POST_DATA } ];
michael@0 695 ensureItemsChanged(...b2_post_creation_changes);
michael@0 696 ensureTags([TAG_1, TAG_2]);
michael@0 697
michael@0 698 observer.reset();
michael@0 699 yield PT.undo();
michael@0 700 yield ensureItemsRemoved(b2_info);
michael@0 701 ensureTags([TAG_1]);
michael@0 702
michael@0 703 // Check if RemoveItem correctly restores keywords, tags and annotations.
michael@0 704 observer.reset();
michael@0 705 yield PT.redo();
michael@0 706 ensureItemsChanged(...b2_post_creation_changes);
michael@0 707 ensureTags([TAG_1, TAG_2]);
michael@0 708
michael@0 709 // Test RemoveItem for multiple items.
michael@0 710 observer.reset();
michael@0 711 yield PT.transact(PT.RemoveItem(b1_info.GUID));
michael@0 712 yield PT.transact(PT.RemoveItem(b2_info.GUID));
michael@0 713 yield PT.transact(PT.RemoveItem(folder_info.GUID));
michael@0 714 yield ensureItemsRemoved(b1_info, b2_info, folder_info);
michael@0 715 ensureTags([]);
michael@0 716
michael@0 717 observer.reset();
michael@0 718 yield PT.undo();
michael@0 719 yield ensureItemsAdded(folder_info);
michael@0 720 ensureTags([]);
michael@0 721
michael@0 722 observer.reset();
michael@0 723 yield PT.undo();
michael@0 724 ensureItemsChanged(...b2_post_creation_changes);
michael@0 725 ensureTags([TAG_1, TAG_2]);
michael@0 726
michael@0 727 observer.reset();
michael@0 728 yield PT.undo();
michael@0 729 yield ensureItemsAdded(b1_info);
michael@0 730 ensureTags([TAG_1, TAG_2]);
michael@0 731
michael@0 732 // The redo calls below cleanup everything we did.
michael@0 733 observer.reset();
michael@0 734 yield PT.redo();
michael@0 735 yield ensureItemsRemoved(b1_info);
michael@0 736 ensureTags([TAG_1, TAG_2]);
michael@0 737
michael@0 738 observer.reset();
michael@0 739 yield PT.redo();
michael@0 740 yield ensureItemsRemoved(b2_info);
michael@0 741 ensureTags([]);
michael@0 742
michael@0 743 observer.reset();
michael@0 744 yield PT.redo();
michael@0 745 yield ensureItemsRemoved(folder_info);
michael@0 746 ensureTags([]);
michael@0 747
michael@0 748 yield PT.clearTransactionsHistory();
michael@0 749 ensureUndoState();
michael@0 750 });
michael@0 751
michael@0 752 add_task(function* test_creating_and_removing_a_separator() {
michael@0 753 let folder_info = yield createTestFolderInfo();
michael@0 754 let separator_info = {};
michael@0 755 let undoEntries = [];
michael@0 756
michael@0 757 observer.reset();
michael@0 758 let create_txns = yield PT.transact(function* () {
michael@0 759 let folder_txn = PT.NewFolder(folder_info);
michael@0 760 folder_info.GUID = separator_info.parentGUID = yield folder_txn;
michael@0 761 let separator_txn = PT.NewSeparator(separator_info);
michael@0 762 separator_info.GUID = yield separator_txn;
michael@0 763 return [separator_txn, folder_txn];
michael@0 764 });
michael@0 765 undoEntries.unshift(create_txns);
michael@0 766 ensureUndoState(undoEntries, 0);
michael@0 767 ensureItemsAdded(folder_info, separator_info);
michael@0 768
michael@0 769 observer.reset();
michael@0 770 yield PT.undo();
michael@0 771 ensureUndoState(undoEntries, 1);
michael@0 772 ensureItemsRemoved(folder_info, separator_info);
michael@0 773
michael@0 774 observer.reset();
michael@0 775 yield PT.redo();
michael@0 776 ensureUndoState(undoEntries, 0);
michael@0 777 ensureItemsAdded(folder_info, separator_info);
michael@0 778
michael@0 779 observer.reset();
michael@0 780 let remove_sep_txn = PT.RemoveItem(separator_info);
michael@0 781 yield PT.transact(remove_sep_txn);
michael@0 782 undoEntries.unshift([remove_sep_txn]);
michael@0 783 ensureUndoState(undoEntries, 0);
michael@0 784 ensureItemsRemoved(separator_info);
michael@0 785
michael@0 786 observer.reset();
michael@0 787 yield PT.undo();
michael@0 788 ensureUndoState(undoEntries, 1);
michael@0 789 ensureItemsAdded(separator_info);
michael@0 790
michael@0 791 observer.reset();
michael@0 792 yield PT.undo();
michael@0 793 ensureUndoState(undoEntries, 2);
michael@0 794 ensureItemsRemoved(folder_info, separator_info);
michael@0 795
michael@0 796 observer.reset();
michael@0 797 yield PT.redo();
michael@0 798 ensureUndoState(undoEntries, 1);
michael@0 799 ensureItemsAdded(folder_info, separator_info);
michael@0 800
michael@0 801 // Clear redo entries and check that |redo| does nothing
michael@0 802 observer.reset();
michael@0 803 yield PT.clearTransactionsHistory(false, true);
michael@0 804 undoEntries.shift();
michael@0 805 ensureUndoState(undoEntries, 0);
michael@0 806 yield PT.redo();
michael@0 807 ensureItemsAdded();
michael@0 808 ensureItemsRemoved();
michael@0 809
michael@0 810 // Cleanup
michael@0 811 observer.reset();
michael@0 812 yield PT.undo();
michael@0 813 ensureUndoState(undoEntries, 1);
michael@0 814 ensureItemsRemoved(folder_info, separator_info);
michael@0 815 yield PT.clearTransactionsHistory();
michael@0 816 ensureUndoState();
michael@0 817 });
michael@0 818
michael@0 819 add_task(function* test_edit_title() {
michael@0 820 let bm_info = { parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 821 , uri: NetUtil.newURI("http://test_create_item.com")
michael@0 822 , title: "Original Title" };
michael@0 823
michael@0 824 function ensureTitleChange(aCurrentTitle) {
michael@0 825 ensureItemsChanged({ GUID: bm_info.GUID
michael@0 826 , property: "title"
michael@0 827 , newValue: aCurrentTitle});
michael@0 828 }
michael@0 829
michael@0 830 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 831
michael@0 832 observer.reset();
michael@0 833 yield PT.transact(PT.EditTitle({ GUID: bm_info.GUID, title: "New Title" }));
michael@0 834 ensureTitleChange("New Title");
michael@0 835
michael@0 836 observer.reset();
michael@0 837 yield PT.undo();
michael@0 838 ensureTitleChange("Original Title");
michael@0 839
michael@0 840 observer.reset();
michael@0 841 yield PT.redo();
michael@0 842 ensureTitleChange("New Title");
michael@0 843
michael@0 844 // Cleanup
michael@0 845 observer.reset();
michael@0 846 yield PT.undo();
michael@0 847 ensureTitleChange("Original Title");
michael@0 848 yield PT.undo();
michael@0 849 ensureItemsRemoved(bm_info);
michael@0 850
michael@0 851 yield PT.clearTransactionsHistory();
michael@0 852 ensureUndoState();
michael@0 853 });
michael@0 854
michael@0 855 add_task(function* test_edit_url() {
michael@0 856 let oldURI = NetUtil.newURI("http://old.test_editing_item_uri.com/");
michael@0 857 let newURI = NetUtil.newURI("http://new.test_editing_item_uri.com/");
michael@0 858 let bm_info = { parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 859 , uri: oldURI
michael@0 860 , tags: ["TestTag"]};
michael@0 861
michael@0 862 function ensureURIAndTags(aPreChangeURI, aPostChangeURI, aOLdURITagsPreserved) {
michael@0 863 ensureItemsChanged({ GUID: bm_info.GUID
michael@0 864 , property: "uri"
michael@0 865 , newValue: aPostChangeURI.spec });
michael@0 866 ensureTagsForURI(aPostChangeURI, bm_info.tags);
michael@0 867 ensureTagsForURI(aPreChangeURI, aOLdURITagsPreserved ? bm_info.tags : []);
michael@0 868 }
michael@0 869
michael@0 870 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 871 ensureTagsForURI(oldURI, bm_info.tags);
michael@0 872
michael@0 873 // When there's a single bookmark for the same url, tags should be moved.
michael@0 874 observer.reset();
michael@0 875 yield PT.transact(PT.EditURI({ GUID: bm_info.GUID, uri: newURI }));
michael@0 876 ensureURIAndTags(oldURI, newURI, false);
michael@0 877
michael@0 878 observer.reset();
michael@0 879 yield PT.undo();
michael@0 880 ensureURIAndTags(newURI, oldURI, false);
michael@0 881
michael@0 882 observer.reset();
michael@0 883 yield PT.redo();
michael@0 884 ensureURIAndTags(oldURI, newURI, false);
michael@0 885
michael@0 886 observer.reset();
michael@0 887 yield PT.undo();
michael@0 888 ensureURIAndTags(newURI, oldURI, false);
michael@0 889
michael@0 890 // When there're multiple bookmarks for the same url, tags should be copied.
michael@0 891 let bm2_info = Object.create(bm_info);
michael@0 892 bm2_info.GUID = yield PT.transact(PT.NewBookmark(bm2_info));
michael@0 893 let bm3_info = Object.create(bm_info);
michael@0 894 bm3_info.uri = newURI;
michael@0 895 bm3_info.GUID = yield PT.transact(PT.NewBookmark(bm3_info));
michael@0 896
michael@0 897 observer.reset();
michael@0 898 yield PT.transact(PT.EditURI({ GUID: bm_info.GUID, uri: newURI }));
michael@0 899 ensureURIAndTags(oldURI, newURI, true);
michael@0 900
michael@0 901 observer.reset();
michael@0 902 yield PT.undo();
michael@0 903 ensureURIAndTags(newURI, oldURI, true);
michael@0 904
michael@0 905 observer.reset();
michael@0 906 yield PT.redo();
michael@0 907 ensureURIAndTags(oldURI, newURI, true);
michael@0 908
michael@0 909 // Cleanup
michael@0 910 observer.reset();
michael@0 911 yield PT.undo();
michael@0 912 ensureURIAndTags(newURI, oldURI, true);
michael@0 913 yield PT.undo();
michael@0 914 yield PT.undo();
michael@0 915 yield PT.undo();
michael@0 916 ensureItemsRemoved(bm3_info, bm2_info, bm_info);
michael@0 917
michael@0 918 yield PT.clearTransactionsHistory();
michael@0 919 ensureUndoState();
michael@0 920 });
michael@0 921
michael@0 922 add_task(function* test_edit_keyword() {
michael@0 923 let bm_info = { parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 924 , uri: NetUtil.newURI("http://test.edit.keyword") };
michael@0 925 const KEYWORD = "test_keyword";
michael@0 926 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 927 function ensureKeywordChange(aCurrentKeyword = "") {
michael@0 928 ensureItemsChanged({ GUID: bm_info.GUID
michael@0 929 , property: "keyword"
michael@0 930 , newValue: aCurrentKeyword });
michael@0 931 }
michael@0 932
michael@0 933 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 934
michael@0 935 observer.reset();
michael@0 936 yield PT.transact(PT.EditKeyword({ GUID: bm_info.GUID, keyword: KEYWORD }));
michael@0 937 ensureKeywordChange(KEYWORD);
michael@0 938
michael@0 939 observer.reset();
michael@0 940 yield PT.undo();
michael@0 941 ensureKeywordChange();
michael@0 942
michael@0 943 observer.reset();
michael@0 944 yield PT.redo();
michael@0 945 ensureKeywordChange(KEYWORD);
michael@0 946
michael@0 947 // Cleanup
michael@0 948 observer.reset();
michael@0 949 yield PT.undo();
michael@0 950 ensureKeywordChange();
michael@0 951 yield PT.undo();
michael@0 952 ensureItemsRemoved(bm_info);
michael@0 953
michael@0 954 yield PT.clearTransactionsHistory();
michael@0 955 ensureUndoState();
michael@0 956 });
michael@0 957
michael@0 958 add_task(function* test_tag_uri_unbookmarked_uri() {
michael@0 959 let info = { uri: NetUtil.newURI("http://un.book.marked"), tags: ["MyTag"] };
michael@0 960
michael@0 961 function ensureDo() {
michael@0 962 // A new bookmark should be created.
michael@0 963 // (getMostRecentBookmarkForURI ignores tags)
michael@0 964 do_check_neq(PlacesUtils.getMostRecentBookmarkForURI(info.uri), -1);
michael@0 965 ensureTagsForURI(info.uri, info.tags);
michael@0 966 }
michael@0 967 function ensureUndo() {
michael@0 968 do_check_eq(PlacesUtils.getMostRecentBookmarkForURI(info.uri), -1);
michael@0 969 ensureTagsForURI(info.uri, []);
michael@0 970 }
michael@0 971
michael@0 972 yield PT.transact(PT.TagURI(info));
michael@0 973 ensureDo();
michael@0 974 yield PT.undo();
michael@0 975 ensureUndo();
michael@0 976 yield PT.redo();
michael@0 977 ensureDo();
michael@0 978 yield PT.undo();
michael@0 979 ensureUndo();
michael@0 980 });
michael@0 981
michael@0 982 add_task(function* test_tag_uri_bookmarked_uri() {
michael@0 983 let bm_info = { uri: NetUtil.newURI("http://bookmarked.uri")
michael@0 984 , parentGUID: yield PlacesUtils.promiseItemGUID(root) };
michael@0 985 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 986
michael@0 987 let tagging_info = { uri: bm_info.uri, tags: ["MyTag"] };
michael@0 988 yield PT.transact(PT.TagURI(tagging_info));
michael@0 989 ensureTagsForURI(tagging_info.uri, tagging_info.tags);
michael@0 990
michael@0 991 yield PT.undo();
michael@0 992 ensureTagsForURI(tagging_info.uri, []);
michael@0 993 yield PT.redo();
michael@0 994 ensureTagsForURI(tagging_info.uri, tagging_info.tags);
michael@0 995
michael@0 996 // Cleanup
michael@0 997 yield PT.undo();
michael@0 998 ensureTagsForURI(tagging_info.uri, []);
michael@0 999 observer.reset();
michael@0 1000 yield PT.undo();
michael@0 1001 ensureItemsRemoved(bm_info);
michael@0 1002
michael@0 1003 yield PT.clearTransactionsHistory();
michael@0 1004 ensureUndoState();
michael@0 1005 });
michael@0 1006
michael@0 1007 add_task(function* test_untag_uri() {
michael@0 1008 let bm_info = { uri: NetUtil.newURI("http://test.untag.uri")
michael@0 1009 , parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 1010 , tags: ["T"]};
michael@0 1011 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 1012
michael@0 1013 yield PT.transact(PT.UntagURI(bm_info));
michael@0 1014 ensureTagsForURI(bm_info.uri, []);
michael@0 1015 yield PT.undo();
michael@0 1016 ensureTagsForURI(bm_info.uri, bm_info.tags);
michael@0 1017 yield PT.redo();
michael@0 1018 ensureTagsForURI(bm_info.uri, []);
michael@0 1019 yield PT.undo();
michael@0 1020 ensureTagsForURI(bm_info.uri, bm_info.tags);
michael@0 1021
michael@0 1022 // Also test just passing the uri (should remove all tags)
michael@0 1023 yield PT.transact(PT.UntagURI(bm_info.uri));
michael@0 1024 ensureTagsForURI(bm_info.uri, []);
michael@0 1025 yield PT.undo();
michael@0 1026 ensureTagsForURI(bm_info.uri, bm_info.tags);
michael@0 1027 yield PT.redo();
michael@0 1028 ensureTagsForURI(bm_info.uri, []);
michael@0 1029 });
michael@0 1030
michael@0 1031 add_task(function* test_set_item_annotation() {
michael@0 1032 let bm_info = { uri: NetUtil.newURI("http://test.item.annotation")
michael@0 1033 , parentGUID: yield PlacesUtils.promiseItemGUID(root) };
michael@0 1034 let anno_info = { name: "TestAnno", value: "TestValue" };
michael@0 1035 function ensureAnnoState(aSet) {
michael@0 1036 ensureAnnotationsSet(bm_info.GUID,
michael@0 1037 [{ name: anno_info.name
michael@0 1038 , value: aSet ? anno_info.value : null }]);
michael@0 1039 }
michael@0 1040
michael@0 1041 bm_info.GUID = yield PT.transact(PT.NewBookmark(bm_info));
michael@0 1042
michael@0 1043 observer.reset();
michael@0 1044 yield PT.transact(PT.SetItemAnnotation({ GUID: bm_info.GUID
michael@0 1045 , annotationObject: anno_info }));
michael@0 1046 ensureAnnoState(true);
michael@0 1047
michael@0 1048 observer.reset();
michael@0 1049 yield PT.undo();
michael@0 1050 ensureAnnoState(false);
michael@0 1051
michael@0 1052 observer.reset();
michael@0 1053 yield PT.redo();
michael@0 1054 ensureAnnoState(true);
michael@0 1055
michael@0 1056 // Test removing the annotation by not passing the |value| property.
michael@0 1057 observer.reset();
michael@0 1058 yield PT.transact(
michael@0 1059 PT.SetItemAnnotation({ GUID: bm_info.GUID
michael@0 1060 , annotationObject: { name: anno_info.name }}));
michael@0 1061 ensureAnnoState(false);
michael@0 1062
michael@0 1063 observer.reset();
michael@0 1064 yield PT.undo();
michael@0 1065 ensureAnnoState(true);
michael@0 1066
michael@0 1067 observer.reset();
michael@0 1068 yield PT.redo();
michael@0 1069 ensureAnnoState(false);
michael@0 1070 });
michael@0 1071
michael@0 1072 add_task(function* test_sort_folder_by_name() {
michael@0 1073 let folder_info = yield createTestFolderInfo();
michael@0 1074
michael@0 1075 let uri = NetUtil.newURI("http://sort.by.name/");
michael@0 1076 let preSep = [{ title: i, uri: uri } for (i of ["3","2","1"])];
michael@0 1077 let sep = {};
michael@0 1078 let postSep = [{ title: l, uri: uri } for (l of ["c","b","a"])];
michael@0 1079 let originalOrder = [...preSep, sep, ...postSep];
michael@0 1080 let sortedOrder = [...preSep.slice(0).reverse(),
michael@0 1081 sep,
michael@0 1082 ...postSep.slice(0).reverse()];
michael@0 1083 yield PT.transact(function* () {
michael@0 1084 folder_info.GUID = yield PT.NewFolder(folder_info);
michael@0 1085 for (let info of originalOrder) {
michael@0 1086 info.parentGUID = folder_info.GUID;
michael@0 1087 info.GUID = yield info == sep ?
michael@0 1088 PT.NewSeparator(info) : PT.NewBookmark(info);
michael@0 1089 }
michael@0 1090 });
michael@0 1091
michael@0 1092 let folderId = yield PlacesUtils.promiseItemId(folder_info.GUID);
michael@0 1093 let folderContainer = PlacesUtils.getFolderContents(folderId).root;
michael@0 1094 function ensureOrder(aOrder) {
michael@0 1095 for (let i = 0; i < folderContainer.childCount; i++) {
michael@0 1096 do_check_eq(folderContainer.getChild(i).bookmarkGuid, aOrder[i].GUID);
michael@0 1097 }
michael@0 1098 }
michael@0 1099
michael@0 1100 ensureOrder(originalOrder);
michael@0 1101 yield PT.transact(PT.SortByName(folder_info.GUID));
michael@0 1102 ensureOrder(sortedOrder);
michael@0 1103 yield PT.undo();
michael@0 1104 ensureOrder(originalOrder);
michael@0 1105 yield PT.redo();
michael@0 1106 ensureOrder(sortedOrder);
michael@0 1107
michael@0 1108 // Cleanup
michael@0 1109 observer.reset();
michael@0 1110 yield PT.undo();
michael@0 1111 ensureOrder(originalOrder);
michael@0 1112 yield PT.undo();
michael@0 1113 ensureItemsRemoved(...originalOrder, folder_info);
michael@0 1114 });
michael@0 1115
michael@0 1116 add_task(function* test_livemark_txns() {
michael@0 1117 let livemark_info =
michael@0 1118 { feedURI: NetUtil.newURI("http://test.feed.uri")
michael@0 1119 , parentGUID: yield PlacesUtils.promiseItemGUID(root)
michael@0 1120 , title: "Test Livemark" };
michael@0 1121 function ensureLivemarkAdded() {
michael@0 1122 ensureItemsAdded({ GUID: livemark_info.GUID
michael@0 1123 , title: livemark_info.title
michael@0 1124 , parentGUID: livemark_info.parentGUID
michael@0 1125 , itemType: bmsvc.TYPE_FOLDER });
michael@0 1126 let annos = [{ name: PlacesUtils.LMANNO_FEEDURI
michael@0 1127 , value: livemark_info.feedURI.spec }];
michael@0 1128 if ("siteURI" in livemark_info) {
michael@0 1129 annos.push({ name: PlacesUtils.LMANNO_SITEURI
michael@0 1130 , value: livemark_info.siteURI.spec });
michael@0 1131 }
michael@0 1132 ensureAnnotationsSet(livemark_info.GUID, annos);
michael@0 1133 }
michael@0 1134 function ensureLivemarkRemoved() {
michael@0 1135 ensureItemsRemoved({ GUID: livemark_info.GUID
michael@0 1136 , parentGUID: livemark_info.parentGUID });
michael@0 1137 }
michael@0 1138
michael@0 1139 function* _testDoUndoRedoUndo() {
michael@0 1140 observer.reset();
michael@0 1141 livemark_info.GUID = yield PT.transact(PT.NewLivemark(livemark_info));
michael@0 1142 ensureLivemarkAdded();
michael@0 1143
michael@0 1144 observer.reset();
michael@0 1145 yield PT.undo();
michael@0 1146 ensureLivemarkRemoved();
michael@0 1147
michael@0 1148 observer.reset();
michael@0 1149 yield PT.redo();
michael@0 1150 ensureLivemarkAdded();
michael@0 1151
michael@0 1152 yield PT.undo();
michael@0 1153 ensureLivemarkRemoved();
michael@0 1154 }
michael@0 1155
michael@0 1156 yield* _testDoUndoRedoUndo()
michael@0 1157 livemark_info.siteURI = NetUtil.newURI("http://feed.site.uri");
michael@0 1158 yield* _testDoUndoRedoUndo();
michael@0 1159
michael@0 1160 yield PT.clearTransactionsHistory();
michael@0 1161 });

mercurial