summaryrefslogtreecommitdiffstats
path: root/browser/components/places/tests/unit/head_bookmarks.js
blob: 460295f96c927e83557ea5879cd8ce91de2227c5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

var Ci = Components.interfaces;
var Cc = Components.classes;
var Cr = Components.results;
var Cu = Components.utils;

Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/LoadContextInfo.jsm");

// Import common head.
var commonFile = do_get_file("../../../../../toolkit/components/places/tests/head_common.js", false);
if (commonFile) {
  let uri = Services.io.newFileURI(commonFile);
  Services.scriptloader.loadSubScript(uri.spec, this);
}

// Put any other stuff relative to this test folder below.

XPCOMUtils.defineLazyGetter(this, "PlacesUIUtils", function() {
  Cu.import("resource:///modules/PlacesUIUtils.jsm");
  return PlacesUIUtils;
});

const ORGANIZER_FOLDER_ANNO = "PlacesOrganizer/OrganizerFolder";
const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery";

// Needed by some test that relies on having an app registered.
Cu.import("resource://testing-common/AppInfo.jsm", this);
updateAppInfo({
  name: "PlacesTest",
  ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}",
  version: "1",
  platformVersion: "",
});

// Smart bookmarks constants.
const SMART_BOOKMARKS_VERSION = 8;
const SMART_BOOKMARKS_ON_TOOLBAR = 1;
const SMART_BOOKMARKS_ON_MENU =  2; // Takes into account the additional separator.

// Default bookmarks constants.
const DEFAULT_BOOKMARKS_ON_TOOLBAR = 1;
const DEFAULT_BOOKMARKS_ON_MENU = 1;

const SMART_BOOKMARKS_ANNO = "Places/SmartBookmark";

function checkItemHasAnnotation(guid, name) {
  return PlacesUtils.promiseItemId(guid).then(id => {
    let hasAnnotation = PlacesUtils.annotations.itemHasAnnotation(id, name);
    Assert.ok(hasAnnotation, `Expected annotation ${name}`);
  });
}

var createCorruptDB = Task.async(function* () {
  let dbPath = OS.Path.join(OS.Constants.Path.profileDir, "places.sqlite");
  yield OS.File.remove(dbPath);

  // Create a corrupt database.
  let dir = yield OS.File.getCurrentDirectory();
  let src = OS.Path.join(dir, "corruptDB.sqlite");
  yield OS.File.copy(src, dbPath);

  // Check there's a DB now.
  Assert.ok((yield OS.File.exists(dbPath)), "should have a DB now");
});

/**
 * Rebuilds smart bookmarks listening to console output to report any message or
 * exception generated.
 *
 * @return {Promise}
 *         Resolved when done.
 */
function rebuildSmartBookmarks() {
  let consoleListener = {
    observe(aMsg) {
      if (aMsg.message.startsWith("[JavaScript Warning:")) {
        // TODO (Bug 1300416): Ignore spurious strict warnings.
        return;
      }
      do_throw("Got console message: " + aMsg.message);
    },
    QueryInterface: XPCOMUtils.generateQI([ Ci.nsIConsoleListener ]),
  };
  Services.console.reset();
  Services.console.registerListener(consoleListener);
  do_register_cleanup(() => {
    try {
      Services.console.unregisterListener(consoleListener);
    } catch (ex) { /* will likely fail */ }
  });
  Cc["@mozilla.org/browser/browserglue;1"]
    .getService(Ci.nsIObserver)
    .observe(null, "browser-glue-test", "smart-bookmarks-init");
  return promiseTopicObserved("test-smart-bookmarks-done").then(() => {
    Services.console.unregisterListener(consoleListener);
  });
}

const SINGLE_TRY_TIMEOUT = 100;
const NUMBER_OF_TRIES = 30;

/**
 * Similar to waitForConditionPromise, but poll for an asynchronous value
 * every SINGLE_TRY_TIMEOUT ms, for no more than tryCount times.
 *
 * @param promiseFn
 *        A function to generate a promise, which resolves to the expected
 *        asynchronous value.
 * @param timeoutMsg
 *        The reason to reject the returned promise with.
 * @param [optional] tryCount
 *        Maximum times to try before rejecting the returned promise with
 *        timeoutMsg, defaults to NUMBER_OF_TRIES.
 * @return {Promise}
 * @resolves to the asynchronous value being polled.
 * @rejects if the asynchronous value is not available after tryCount attempts.
 */
var waitForResolvedPromise = Task.async(function* (promiseFn, timeoutMsg, tryCount=NUMBER_OF_TRIES) {
  let tries = 0;
  do {
    try {
      let value = yield promiseFn();
      return value;
    } catch (ex) {}
    yield new Promise(resolve => do_timeout(SINGLE_TRY_TIMEOUT, resolve));
  } while (++tries <= tryCount);
  throw new Error(timeoutMsg);
});