summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/unifiedcomplete
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/components/places/tests/unifiedcomplete
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/places/tests/unifiedcomplete')
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/.eslintrc.js5
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/data/engine-rel-searchform.xml5
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/data/engine-suggestions.xml14
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js578
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_416211.js31
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_416214.js57
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_417798.js71
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_418257.js112
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_422277.js21
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_autocomplete_stopSearch_no_throw.js22
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_do_not_trim.js90
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_download_embed_bookmarks.js77
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_empty_search.js104
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_escape_self.js33
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_history_autocomplete_tags.js162
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js26
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js178
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js357
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_multi_word_search.js80
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js322
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js408
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_search_engine_alias.js108
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_search_engine_restyle.js90
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_special_search.js539
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js163
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js263
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js266
-rw-r--r--toolkit/components/places/tests/unifiedcomplete/xpcshell.ini33
28 files changed, 4215 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/unifiedcomplete/.eslintrc.js b/toolkit/components/places/tests/unifiedcomplete/.eslintrc.js
new file mode 100644
index 0000000000..69e89d0054
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/.eslintrc.js
@@ -0,0 +1,5 @@
+"use strict";
+
+module.exports = {
+ extends: ["plugin:mozilla/xpcshell-test"],
+};
diff --git a/toolkit/components/places/tests/unifiedcomplete/data/engine-rel-searchform.xml b/toolkit/components/places/tests/unifiedcomplete/data/engine-rel-searchform.xml
new file mode 100644
index 0000000000..f4baad28ab
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/data/engine-rel-searchform.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>engine-rel-searchform.xml</ShortName>
+<Url type="text/html" method="GET" template="http://example.com/?search" rel="searchform"/>
+</SearchPlugin>
diff --git a/toolkit/components/places/tests/unifiedcomplete/data/engine-suggestions.xml b/toolkit/components/places/tests/unifiedcomplete/data/engine-suggestions.xml
new file mode 100644
index 0000000000..a322a7c86e
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/data/engine-suggestions.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Any copyright is dedicated to the Public Domain.
+ - http://creativecommons.org/publicdomain/zero/1.0/ -->
+
+<SearchPlugin xmlns="http://www.mozilla.org/2006/browser/search/">
+<ShortName>engine-suggestions.xml</ShortName>
+<Url type="application/x-suggestions+json"
+ method="GET"
+ template="http://localhost:9000/suggest?{searchTerms}"/>
+<Url type="text/html"
+ method="GET"
+ template="http://localhost:9000/search"
+ rel="searchform"/>
+</SearchPlugin>
diff --git a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
new file mode 100644
index 0000000000..0fb763095a
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js
@@ -0,0 +1,578 @@
+/* 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/. */
+
+const FRECENCY_DEFAULT = 10000;
+
+var { ObjectUtils } = ChromeUtils.import(
+ "resource://gre/modules/ObjectUtils.jsm"
+);
+var { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+var {
+ HTTP_400,
+ HTTP_401,
+ HTTP_402,
+ HTTP_403,
+ HTTP_404,
+ HTTP_405,
+ HTTP_406,
+ HTTP_407,
+ HTTP_408,
+ HTTP_409,
+ HTTP_410,
+ HTTP_411,
+ HTTP_412,
+ HTTP_413,
+ HTTP_414,
+ HTTP_415,
+ HTTP_417,
+ HTTP_500,
+ HTTP_501,
+ HTTP_502,
+ HTTP_503,
+ HTTP_504,
+ HTTP_505,
+ HttpError,
+ HttpServer,
+} = ChromeUtils.import("resource://testing-common/httpd.js");
+
+// Import common head.
+{
+ /* import-globals-from ../head_common.js */
+ let commonFile = do_get_file("../head_common.js", false);
+ let uri = Services.io.newFileURI(commonFile);
+ Services.scriptloader.loadSubScript(uri.spec, this);
+}
+
+// Put any other stuff relative to this test folder below.
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
+ UrlbarProviderOpenTabs: "resource:///modules/UrlbarProviderOpenTabs.jsm",
+ UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
+ UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
+});
+
+const { AddonTestUtils } = ChromeUtils.import(
+ "resource://testing-common/AddonTestUtils.jsm"
+);
+AddonTestUtils.init(this, false);
+AddonTestUtils.createAppInfo(
+ "xpcshell@tests.mozilla.org",
+ "XPCShell",
+ "42",
+ "42"
+);
+
+add_task(async function setup() {
+ await AddonTestUtils.promiseStartupManager();
+});
+
+async function cleanup() {
+ Services.prefs.clearUserPref("browser.urlbar.autoFill");
+ Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines");
+ let suggestPrefs = ["history", "bookmark", "openpage", "searches"];
+ for (let type of suggestPrefs) {
+ Services.prefs.clearUserPref("browser.urlbar.suggest." + type);
+ }
+ Services.prefs.clearUserPref("browser.search.suggest.enabled");
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesUtils.history.clear();
+}
+registerCleanupFunction(cleanup);
+
+/**
+ * @param {Array} aSearches Array of AutoCompleteSearch names.
+ */
+function AutoCompleteInput(aSearches) {
+ this.searches = aSearches;
+}
+AutoCompleteInput.prototype = {
+ popup: {
+ selectedIndex: -1,
+ invalidate() {},
+ QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"]),
+ },
+ popupOpen: false,
+
+ disableAutoComplete: false,
+ completeDefaultIndex: true,
+ completeSelectedIndex: true,
+ forceComplete: false,
+
+ minResultsForPopup: 0,
+ maxRows: 0,
+
+ timeout: 10,
+ searchParam: "",
+
+ get searchCount() {
+ return this.searches.length;
+ },
+ getSearchAt(aIndex) {
+ return this.searches[aIndex];
+ },
+
+ textValue: "",
+ // Text selection range
+ _selStart: 0,
+ _selEnd: 0,
+ get selectionStart() {
+ return this._selStart;
+ },
+ get selectionEnd() {
+ return this._selEnd;
+ },
+ selectTextRange(aStart, aEnd) {
+ this._selStart = aStart;
+ this._selEnd = aEnd;
+ },
+
+ onSearchBegin() {},
+ onSearchComplete() {},
+
+ onTextEntered: () => false,
+ onTextReverted: () => false,
+
+ QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"]),
+};
+
+/**
+ * A helper for check_autocomplete to check a specific match against data from
+ * the controller.
+ *
+ * @param {Object} match The expected match for the result, in the following form:
+ * {
+ * uri: {String|nsIURI} The expected uri. Note: nsIURI should be considered
+ * deprecated.
+ * title: {String} The title of the entry.
+ * tags: {String} The tags for the entry.
+ * style: {Array} The style of the entry.
+ * }
+ * @param {Object} result The result to compare the result against with the same
+ * properties as the match param.
+ * @returns {boolean} Returns true if the result matches.
+ */
+async function _check_autocomplete_matches(match, result) {
+ let { uri, tags, style } = match;
+ if (uri instanceof Ci.nsIURI) {
+ uri = uri.spec;
+ }
+ let title = match.comment || match.title;
+
+ if (tags) {
+ title += UrlbarUtils.TITLE_TAGS_SEPARATOR + tags.sort().join(", ");
+ }
+ if (style) {
+ style = style.sort();
+ } else {
+ style = ["favicon"];
+ }
+
+ let actual = { value: result.value, comment: result.comment };
+ let expected = { value: match.value || uri, comment: title };
+ info(
+ `Checking match: ` +
+ `actual=${JSON.stringify(actual)} ... ` +
+ `expected=${JSON.stringify(expected)}`
+ );
+
+ let actualAction = PlacesUtils.parseActionUrl(actual.value);
+ let expectedAction = PlacesUtils.parseActionUrl(expected.value);
+ if (actualAction && expectedAction) {
+ if (!ObjectUtils.deepEqual(actualAction, expectedAction)) {
+ return false;
+ }
+ } else if (actual.value != expected.value) {
+ return false;
+ }
+
+ if (actual.comment != expected.comment) {
+ return false;
+ }
+
+ let actualStyle = result.style.split(/\s+/).sort();
+ if (style) {
+ Assert.equal(
+ actualStyle.toString(),
+ style.toString(),
+ "Match should have expected style"
+ );
+ }
+ if (uri && uri.startsWith("moz-action:")) {
+ Assert.ok(
+ actualStyle.includes("action"),
+ "moz-action results should always have 'action' in their style"
+ );
+ }
+
+ if (match.icon) {
+ await compareFavicons(
+ result.image,
+ match.icon,
+ "Match should have the expected icon"
+ );
+ }
+
+ return true;
+}
+
+/**
+ * Helper function to test an autocomplete entry and check the resultant matches.
+ *
+ * @param {Object} test An object representing the test to run, in the following form:
+ * {
+ * search: {String} The string to enter for autocompleting.
+ * searchParam: {String} The search parameters to apply to the
+ * autocomplete search.
+ * matches: {Object[]} The expected results in match format. see
+ * _check_autocomplete_matches.
+ * }
+ */
+async function check_autocomplete(test) {
+ // At this point frecency could still be updating due to latest pages
+ // updates.
+ // This is not a problem in real life, but autocomplete tests should
+ // return reliable resultsets, thus we have to wait.
+ await PlacesTestUtils.promiseAsyncUpdates();
+
+ // Make an AutoCompleteInput that uses our searches and confirms results.
+ let input = test.input || new AutoCompleteInput(["unifiedcomplete"]);
+ input.textValue = test.search;
+
+ if (test.searchParam) {
+ input.searchParam = test.searchParam;
+ }
+
+ // Caret must be at the end for autoFill to happen.
+ let strLen = test.search.length;
+ input.selectTextRange(strLen, strLen);
+ Assert.equal(input.selectionStart, strLen, "Selection starts at end");
+ Assert.equal(input.selectionEnd, strLen, "Selection ends at the end");
+
+ let controller = Cc["@mozilla.org/autocomplete/controller;1"].getService(
+ Ci.nsIAutoCompleteController
+ );
+ controller.input = input;
+
+ let numSearchesStarted = 0;
+ input.onSearchBegin = () => {
+ info("onSearchBegin received");
+ numSearchesStarted++;
+ };
+ let searchCompletePromise = new Promise(resolve => {
+ input.onSearchComplete = () => {
+ info("onSearchComplete received");
+ resolve();
+ };
+ });
+ let expectedSearches = 1;
+
+ info("Searching for: '" + test.search + "'");
+ controller.startSearch(test.search);
+ await searchCompletePromise;
+
+ Assert.equal(numSearchesStarted, expectedSearches, "All searches started");
+
+ // Check to see the expected uris and titles match up. If 'enable-actions'
+ // is specified, we check that the first specified match is the first
+ // controller value (as this is the "special" always selected item), but the
+ // rest can match in any order.
+ // If 'enable-actions' is not specified, they can match in any order.
+ if (test.matches) {
+ // Do not modify the test original matches.
+ let matches = test.matches.slice();
+
+ if (matches.length) {
+ let firstIndexToCheck = 0;
+ if (test.searchParam && test.searchParam.includes("enable-actions")) {
+ let result = {
+ value: controller.getValueAt(0),
+ comment: controller.getCommentAt(0),
+ style: controller.getStyleAt(0),
+ image: controller.getImageAt(0),
+ };
+ // We only care about the positioning of the first result if it is
+ // heuristic.
+ if (result.style.includes("heuristic")) {
+ info("Checking first match is first autocomplete entry");
+ info(`First match is "${result.value}", "${result.comment}"`);
+ Assert.ok(
+ await _check_autocomplete_matches(matches[0], result),
+ "first item is correct"
+ );
+ info("Checking rest of the matches");
+ firstIndexToCheck = 1;
+ }
+ }
+
+ for (let i = firstIndexToCheck; i < controller.matchCount; i++) {
+ let result = {
+ value: controller.getValueAt(i),
+ comment: controller.getCommentAt(i),
+ style: controller.getStyleAt(i),
+ image: controller.getImageAt(i),
+ };
+ info(`Actual result at index ${i}: ${JSON.stringify(result)}`);
+ let lowerBound = test.checkSorting ? i : firstIndexToCheck;
+ let upperBound = test.checkSorting ? i + 1 : matches.length;
+ let found = false;
+ for (let j = lowerBound; j < upperBound; ++j) {
+ // Skip processed expected results
+ if (matches[j] == undefined) {
+ continue;
+ }
+ if (await _check_autocomplete_matches(matches[j], result)) {
+ info("Got a match at index " + j + "!");
+ // Make it undefined so we don't process it again
+ matches[j] = undefined;
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ do_throw(
+ `Didn't find the current result ("${result.value}", "${result.comment}") in matches`
+ );
+ } // ' (Emacs syntax highlighting fix)
+ }
+ }
+
+ Assert.equal(
+ controller.matchCount,
+ matches.length,
+ "Got as many results as expected"
+ );
+
+ // If we expect results, make sure we got matches.
+ Assert.equal(
+ controller.searchStatus,
+ matches.length
+ ? Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH
+ : Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH
+ );
+ }
+
+ if (test.autofilled) {
+ // Check the autoFilled result.
+ Assert.equal(
+ input.textValue,
+ test.autofilled,
+ "Autofilled value is correct"
+ );
+
+ // Now force completion and check correct casing of the result.
+ // This ensures the controller is able to do its magic case-preserving
+ // stuff and correct replacement of the user's casing with result's one.
+ controller.handleEnter(false);
+ Assert.equal(input.textValue, test.completed, "Completed value is correct");
+ }
+ return input;
+}
+
+async function addOpenPages(aUri, aCount = 1, aUserContextId = 0) {
+ for (let i = 0; i < aCount; i++) {
+ await UrlbarProviderOpenTabs.registerOpenTab(aUri.spec, aUserContextId);
+ }
+}
+
+async function removeOpenPages(aUri, aCount = 1, aUserContextId = 0) {
+ for (let i = 0; i < aCount; i++) {
+ await UrlbarProviderOpenTabs.unregisterOpenTab(aUri.spec, aUserContextId);
+ }
+}
+
+/**
+ * Strip prefixes from the URI that we don't care about for searching.
+ *
+ * @param {String} spec
+ * The text to modify.
+ * @return {String} the modified spec.
+ */
+function stripPrefix(spec) {
+ ["http://", "https://", "ftp://"].some(scheme => {
+ if (spec.startsWith(scheme)) {
+ spec = spec.slice(scheme.length);
+ return true;
+ }
+ return false;
+ });
+
+ if (spec.startsWith("www.")) {
+ spec = spec.slice(4);
+ }
+ return spec;
+}
+
+function makeActionURI(action, params) {
+ let encodedParams = {};
+ for (let key in params) {
+ encodedParams[key] = encodeURIComponent(params[key]);
+ }
+ let url = "moz-action:" + action + "," + JSON.stringify(encodedParams);
+ return Services.io.newURI(url);
+}
+
+// Creates a full "match" entry for a search result, suitable for passing as
+// an entry to check_autocomplete.
+function makeSearchMatch(input, extra = {}) {
+ let params = {
+ engineName: extra.engineName || "MozSearch",
+ input,
+ searchQuery: "searchQuery" in extra ? extra.searchQuery : input,
+ };
+ let style = ["action", "searchengine"];
+ if ("style" in extra && Array.isArray(extra.style)) {
+ style.push(...extra.style);
+ }
+ if (extra.heuristic) {
+ style.push("heuristic");
+ }
+ if ("alias" in extra) {
+ params.alias = extra.alias;
+ style.push("alias");
+ }
+ if ("searchSuggestion" in extra) {
+ params.searchSuggestion = extra.searchSuggestion;
+ style.push("suggestion");
+ }
+ if ("isSearchHistory" in extra) {
+ params.isSearchHistory = extra.isSearchHistory;
+ }
+ return {
+ uri: makeActionURI("searchengine", params),
+ title: params.engineName,
+ style,
+ };
+}
+
+// Creates a full "match" entry for a search result, suitable for passing as
+// an entry to check_autocomplete.
+function makeVisitMatch(input, url, extra = {}) {
+ // Note that counter-intuitively, the order the object properties are defined
+ // in the object passed to makeActionURI is important for check_autocomplete
+ // to match them :(
+ let params = {
+ url,
+ input,
+ };
+ let style = ["action", "visiturl"];
+ if (extra.heuristic) {
+ style.push("heuristic");
+ }
+ let displaySpec = Services.textToSubURI.unEscapeURIForUI(url);
+ return {
+ uri: makeActionURI("visiturl", params),
+ title: extra.title || displaySpec,
+ style,
+ };
+}
+
+function makeSwitchToTabMatch(url, extra = {}) {
+ let displaySpec = Services.textToSubURI.unEscapeURIForUI(url);
+ return {
+ uri: makeActionURI("switchtab", { url }),
+ title: extra.title || displaySpec,
+ style: ["action", "switchtab"],
+ };
+}
+
+function makeExtensionMatch(extra = {}) {
+ let style = ["action", "extension"];
+ if (extra.heuristic) {
+ style.push("heuristic");
+ }
+
+ return {
+ uri: makeActionURI("extension", {
+ content: extra.content,
+ keyword: extra.keyword,
+ }),
+ title: extra.description,
+ style,
+ };
+}
+
+function makeTestServer(port = -1) {
+ let httpServer = new HttpServer();
+ httpServer.start(port);
+ registerCleanupFunction(() => httpServer.stop(() => {}));
+ return httpServer;
+}
+
+function addTestEngine(basename, httpServer = undefined) {
+ httpServer = httpServer || makeTestServer();
+ httpServer.registerDirectory("/", do_get_cwd());
+ let dataUrl =
+ "http://localhost:" + httpServer.identity.primaryPort + "/data/";
+
+ info("Adding engine: " + basename);
+ return new Promise(resolve => {
+ Services.obs.addObserver(function obs(subject, topic, data) {
+ let engine = subject.QueryInterface(Ci.nsISearchEngine);
+ info("Observed " + data + " for " + engine.name);
+ if (data != "engine-added" || engine.name != basename) {
+ return;
+ }
+
+ Services.obs.removeObserver(obs, "browser-search-engine-modified");
+ registerCleanupFunction(() => Services.search.removeEngine(engine));
+ resolve(engine);
+ }, "browser-search-engine-modified");
+
+ info("Adding engine from URL: " + dataUrl + basename);
+ Services.search.addOpenSearchEngine(dataUrl + basename, null);
+ });
+}
+
+/**
+ * Sets up a search engine that provides some suggestions by appending strings
+ * onto the search query.
+ *
+ * @param {function} suggestionsFn
+ * A function that returns an array of suggestion strings given a
+ * search string. If not given, a default function is used.
+ * @returns {nsISearchEngine} The new engine.
+ */
+async function addTestSuggestionsEngine(suggestionsFn = null) {
+ // This port number should match the number in engine-suggestions.xml.
+ let server = makeTestServer(9000);
+ server.registerPathHandler("/suggest", (req, resp) => {
+ // URL query params are x-www-form-urlencoded, which converts spaces into
+ // plus signs, so un-convert any plus signs back to spaces.
+ let searchStr = decodeURIComponent(req.queryString.replace(/\+/g, " "));
+ let suggestions = suggestionsFn
+ ? suggestionsFn(searchStr)
+ : [searchStr].concat(["foo", "bar"].map(s => searchStr + " " + s));
+ let data = [searchStr, suggestions];
+ resp.setHeader("Content-Type", "application/json", false);
+ resp.write(JSON.stringify(data));
+ });
+ let engine = await addTestEngine("engine-suggestions.xml", server);
+ return engine;
+}
+
+// Ensure we have a default search engine and the keyword.enabled preference
+// set.
+add_task(async function ensure_search_engine() {
+ // keyword.enabled is necessary for the tests to see keyword searches.
+ Services.prefs.setBoolPref("keyword.enabled", true);
+
+ // Before initializing the search service, set the geo IP url pref to a dummy
+ // string. When the search service is initialized, it contacts the URI named
+ // in this pref, causing unnecessary error logs.
+ let geoPref = "browser.search.geoip.url";
+ Services.prefs.setCharPref(geoPref, "");
+ registerCleanupFunction(() => Services.prefs.clearUserPref(geoPref));
+ // Remove any existing engines before adding ours.
+ for (let engine of await Services.search.getEngines()) {
+ await Services.search.removeEngine(engine);
+ }
+ await Services.search.addEngineWithDetails("MozSearch", {
+ method: "GET",
+ template: "http://s.example.com/search",
+ });
+ let engine = Services.search.getEngineByName("MozSearch");
+ await Services.search.setDefault(engine);
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_416211.js b/toolkit/components/places/tests/unifiedcomplete/test_416211.js
new file mode 100644
index 0000000000..06fea799aa
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_416211.js
@@ -0,0 +1,31 @@
+/* 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/. */
+
+/*
+ * Test bug 416211 to make sure results that match the tag show the bookmark
+ * title instead of the page title.
+ */
+
+add_task(async function test_tag_match_has_bookmark_title() {
+ info("Make sure the tag match gives the bookmark title");
+ let uri = NetUtil.newURI("http://theuri/");
+ await PlacesTestUtils.addVisits({ uri, title: "Page title" });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri,
+ title: "Bookmark title",
+ tags: ["superTag"],
+ });
+ await check_autocomplete({
+ search: "superTag",
+ matches: [
+ {
+ uri,
+ title: "Bookmark title",
+ tags: ["superTag"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_416214.js b/toolkit/components/places/tests/unifiedcomplete/test_416214.js
new file mode 100644
index 0000000000..117767d93e
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_416214.js
@@ -0,0 +1,57 @@
+/* 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/. */
+
+/*
+ * Test autocomplete for non-English URLs that match the tag bug 416214. Also
+ * test bug 417441 by making sure escaped ascii characters like "+" remain
+ * escaped.
+ *
+ * - add a visit for a page with a non-English URL
+ * - add a tag for the page
+ * - search for the tag
+ * - test number of matches (should be exactly one)
+ * - make sure the url is decoded
+ */
+
+add_task(async function test_tag_match_url() {
+ info(
+ "Make sure tag matches return the right url as well as '+' remain escaped"
+ );
+ let uri1 = NetUtil.newURI("http://escaped/ユニコード");
+ let uri2 = NetUtil.newURI("http://asciiescaped/blocking-firefox3%2B");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "title",
+ tags: ["superTag"],
+ style: ["bookmark-tag"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "title",
+ tags: ["superTag"],
+ style: ["bookmark-tag"],
+ });
+ await check_autocomplete({
+ search: "superTag",
+ matches: [
+ {
+ uri: uri1,
+ title: "title",
+ tags: ["superTag"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri2,
+ title: "title",
+ tags: ["superTag"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_417798.js b/toolkit/components/places/tests/unifiedcomplete/test_417798.js
new file mode 100644
index 0000000000..37d0a544fa
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_417798.js
@@ -0,0 +1,71 @@
+/* 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/. */
+
+/**
+ * Test for bug 417798 to make sure javascript: URIs don't show up unless the
+ * user searches for javascript: explicitly.
+ */
+
+add_task(async function test_javascript_match() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
+
+ let uri1 = NetUtil.newURI("http://abc/def");
+ let uri2 = NetUtil.newURI("javascript:5");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "Title with javascript:" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "Title with javascript:",
+ });
+
+ info("Match non-javascript: with plain search");
+ await check_autocomplete({
+ search: "a",
+ matches: [{ uri: uri1, title: "Title with javascript:" }],
+ });
+
+ info("Match non-javascript: with 'javascript'");
+ await check_autocomplete({
+ search: "javascript",
+ matches: [{ uri: uri1, title: "Title with javascript:" }],
+ });
+
+ info("Match non-javascript with 'javascript:'");
+ await check_autocomplete({
+ search: "javascript:",
+ matches: [{ uri: uri1, title: "Title with javascript:" }],
+ });
+
+ info("Match nothing with '5 javascript:'");
+ await check_autocomplete({
+ search: "5 javascript:",
+ matches: [],
+ });
+
+ info("Match non-javascript: with 'a javascript:'");
+ await check_autocomplete({
+ search: "a javascript:",
+ matches: [{ uri: uri1, title: "Title with javascript:" }],
+ });
+
+ info("Match non-javascript: and javascript: with 'javascript: a'");
+ await check_autocomplete({
+ search: "javascript: a",
+ matches: [
+ { uri: uri1, title: "Title with javascript:" },
+ { uri: uri2, title: "Title with javascript:", style: ["bookmark"] },
+ ],
+ });
+
+ info("Match javascript: with 'javascript: 5'");
+ await check_autocomplete({
+ search: "javascript: 5",
+ matches: [
+ { uri: uri2, title: "Title with javascript:", style: ["bookmark"] },
+ ],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_418257.js b/toolkit/components/places/tests/unifiedcomplete/test_418257.js
new file mode 100644
index 0000000000..bbb05eaa5c
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_418257.js
@@ -0,0 +1,112 @@
+/* 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/. */
+
+/**
+ * Test bug 418257 by making sure tags are returned with the title as part of
+ * the "comment" if there are tags even if we didn't match in the tags. They
+ * are separated from the title by a endash.
+ */
+
+add_task(async function test() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ let uri1 = NetUtil.newURI("http://page1");
+ let uri2 = NetUtil.newURI("http://page2");
+ let uri3 = NetUtil.newURI("http://page3");
+ let uri4 = NetUtil.newURI("http://page4");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "tagged" },
+ { uri: uri2, title: "tagged" },
+ { uri: uri3, title: "tagged" },
+ { uri: uri4, title: "tagged" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "tagged",
+ tags: ["tag1"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "tagged",
+ tags: ["tag1", "tag2"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri3,
+ title: "tagged",
+ tags: ["tag1", "tag3"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri4,
+ title: "tagged",
+ tags: ["tag1", "tag2", "tag3"],
+ });
+
+ info("Make sure tags come back in the title when matching tags");
+ await check_autocomplete({
+ search: "page1 tag",
+ matches: [
+ { uri: uri1, title: "tagged", tags: ["tag1"], style: ["bookmark-tag"] },
+ ],
+ });
+
+ info("Check tags in title for page2");
+ await check_autocomplete({
+ search: "page2 tag",
+ matches: [
+ {
+ uri: uri2,
+ title: "tagged",
+ tags: ["tag1", "tag2"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("Make sure tags appear even when not matching the tag");
+ await check_autocomplete({
+ search: "page3",
+ matches: [
+ {
+ uri: uri3,
+ title: "tagged",
+ tags: ["tag1", "tag3"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("Multiple tags come in commas for page4");
+ await check_autocomplete({
+ search: "page4",
+ matches: [
+ {
+ uri: uri4,
+ title: "tagged",
+ tags: ["tag1", "tag2", "tag3"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("Extra test just to make sure we match the title");
+ await check_autocomplete({
+ search: "tag2",
+ matches: [
+ {
+ uri: uri2,
+ title: "tagged",
+ tags: ["tag1", "tag2"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri4,
+ title: "tagged",
+ tags: ["tag1", "tag2", "tag3"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_422277.js b/toolkit/components/places/tests/unifiedcomplete/test_422277.js
new file mode 100644
index 0000000000..b85c1d1c44
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_422277.js
@@ -0,0 +1,21 @@
+/* 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/. */
+
+/**
+ * Test bug 422277 to make sure bad escaped uris don't get escaped. This makes
+ * sure we don't hit an assertion for "not a UTF8 string".
+ */
+
+add_task(async function test() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ info("Bad escaped uri stays escaped");
+ let uri1 = NetUtil.newURI("http://site/%EAid");
+ await PlacesTestUtils.addVisits([{ uri: uri1, title: "title" }]);
+ await check_autocomplete({
+ search: "site",
+ matches: [{ uri: uri1, title: "title" }],
+ });
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_autocomplete_stopSearch_no_throw.js b/toolkit/components/places/tests/unifiedcomplete/test_autocomplete_stopSearch_no_throw.js
new file mode 100644
index 0000000000..1d3cff6248
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_autocomplete_stopSearch_no_throw.js
@@ -0,0 +1,22 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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/. */
+
+/**
+ * Added with bug 508102 to make sure that calling stopSearch on our
+ * AutoComplete implementation does not throw.
+ */
+
+var ac = Cc[
+ "@mozilla.org/autocomplete/search;1?name=unifiedcomplete"
+].getService(Ci.nsIAutoCompleteSearch);
+
+add_task(async function test_stopSearch() {
+ try {
+ ac.stopSearch();
+ } catch (e) {
+ do_throw("we should not have caught anything!");
+ }
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_do_not_trim.js b/toolkit/components/places/tests/unifiedcomplete/test_do_not_trim.js
new file mode 100644
index 0000000000..d7f5f14841
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_do_not_trim.js
@@ -0,0 +1,90 @@
+/* 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/. */
+
+// Inline should never return matches shorter than the search string, since
+// that largely confuses completeDefaultIndex
+
+add_task(async function test_not_autofill_ws_1() {
+ info("Do not autofill whitespaced entry 1");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: "mozilla.org ",
+ autofilled: "mozilla.org ",
+ completed: "mozilla.org ",
+ });
+ await cleanup();
+});
+
+add_task(async function test_not_autofill_ws_2() {
+ info("Do not autofill whitespaced entry 2");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: "mozilla.org/ ",
+ autofilled: "mozilla.org/ ",
+ completed: "mozilla.org/ ",
+ });
+ await cleanup();
+});
+
+add_task(async function test_not_autofill_ws_3() {
+ info("Do not autofill whitespaced entry 3");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: "mozilla.org/link ",
+ autofilled: "mozilla.org/link ",
+ completed: "mozilla.org/link ",
+ });
+ await cleanup();
+});
+
+add_task(async function test_not_autofill_ws_4() {
+ info("Do not autofill whitespaced entry 4");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: "mozilla.org/link/ ",
+ autofilled: "mozilla.org/link/ ",
+ completed: "mozilla.org/link/ ",
+ });
+ await cleanup();
+});
+
+add_task(async function test_not_autofill_ws_5() {
+ info("Do not autofill whitespaced entry 5");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: "moz illa ",
+ autofilled: "moz illa ",
+ completed: "moz illa ",
+ });
+ await cleanup();
+});
+
+add_task(async function test_not_autofill_ws_6() {
+ info("Do not autofill whitespaced entry 6");
+ await PlacesTestUtils.addVisits({
+ uri: NetUtil.newURI("http://mozilla.org/link/"),
+ transition: TRANSITION_TYPED,
+ });
+ await check_autocomplete({
+ search: " mozilla",
+ autofilled: " mozilla",
+ completed: " mozilla",
+ });
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_download_embed_bookmarks.js b/toolkit/components/places/tests/unifiedcomplete/test_download_embed_bookmarks.js
new file mode 100644
index 0000000000..824cb9c431
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_download_embed_bookmarks.js
@@ -0,0 +1,77 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim:set ts=2 sw=2 sts=2 et:
+ * 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/. */
+
+/**
+ * Tests bug 449406 to ensure that TRANSITION_DOWNLOAD, TRANSITION_EMBED and
+ * TRANSITION_FRAMED_LINK bookmarked uri's show up in the location bar.
+ */
+
+add_task(async function test_download_embed_bookmarks() {
+ let uri1 = NetUtil.newURI("http://download/bookmarked");
+ let uri2 = NetUtil.newURI("http://embed/bookmarked");
+ let uri3 = NetUtil.newURI("http://framed/bookmarked");
+ let uri4 = NetUtil.newURI("http://download");
+ let uri5 = NetUtil.newURI("http://embed");
+ let uri6 = NetUtil.newURI("http://framed");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "download-bookmark", transition: TRANSITION_DOWNLOAD },
+ { uri: uri2, title: "embed-bookmark", transition: TRANSITION_EMBED },
+ { uri: uri3, title: "framed-bookmark", transition: TRANSITION_FRAMED_LINK },
+ { uri: uri4, title: "download2", transition: TRANSITION_DOWNLOAD },
+ { uri: uri5, title: "embed2", transition: TRANSITION_EMBED },
+ { uri: uri6, title: "framed2", transition: TRANSITION_FRAMED_LINK },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "download-bookmark",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "embed-bookmark",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri3,
+ title: "framed-bookmark",
+ });
+
+ info("Searching for bookmarked download uri matches");
+ await check_autocomplete({
+ search: "download-bookmark",
+ matches: [{ uri: uri1, title: "download-bookmark", style: ["bookmark"] }],
+ });
+
+ info("Searching for bookmarked embed uri matches");
+ await check_autocomplete({
+ search: "embed-bookmark",
+ matches: [{ uri: uri2, title: "embed-bookmark", style: ["bookmark"] }],
+ });
+
+ info("Searching for bookmarked framed uri matches");
+ await check_autocomplete({
+ search: "framed-bookmark",
+ matches: [{ uri: uri3, title: "framed-bookmark", style: ["bookmark"] }],
+ });
+
+ info("Searching for download uri does not match");
+ await check_autocomplete({
+ search: "download2",
+ matches: [],
+ });
+
+ info("Searching for embed uri does not match");
+ await check_autocomplete({
+ search: "embed2",
+ matches: [],
+ });
+
+ info("Searching for framed uri does not match");
+ await check_autocomplete({
+ search: "framed2",
+ matches: [],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js b/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js
new file mode 100644
index 0000000000..733a12dd3b
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js
@@ -0,0 +1,104 @@
+/* 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/. */
+
+/**
+ * Test for bug 426864 that makes sure the empty search (drop down list) only
+ * shows typed pages from history.
+ */
+
+add_task(async function test_javascript_match() {
+ let uri1 = NetUtil.newURI("http://t.foo/0");
+ let uri2 = NetUtil.newURI("http://t.foo/1");
+ let uri3 = NetUtil.newURI("http://t.foo/2");
+ let uri4 = NetUtil.newURI("http://t.foo/3");
+ let uri5 = NetUtil.newURI("http://t.foo/4");
+ let uri6 = NetUtil.newURI("http://t.foo/5");
+ let uri7 = NetUtil.newURI("http://t.foo/6");
+
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "title" },
+ { uri: uri6, title: "title" },
+ { uri: uri7, title: "title" },
+ ]);
+
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri2, title: "title" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri4, title: "title" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri5, title: "title" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri6, title: "title" });
+
+ await addOpenPages(uri7, 1);
+
+ // Now remove page 6 from history, so it is an unvisited bookmark.
+ await PlacesUtils.history.remove(uri6);
+
+ info("Match everything");
+ await check_autocomplete({
+ search: "foo",
+ searchParam: "enable-actions",
+ matches: [
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title", style: ["bookmark"] },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "title", style: ["bookmark"] },
+ { uri: uri5, title: "title", style: ["bookmark"] },
+ { uri: uri6, title: "title", style: ["bookmark"] },
+ makeSwitchToTabMatch("http://t.foo/6", { title: "title" }),
+ ],
+ });
+
+ // Note the next few tests do *not* get a search result as enable-actions
+ // isn't specified.
+ info("Match only history");
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.HISTORY}`,
+ matches: [
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "title" },
+ { uri: uri7, title: "title" },
+ ],
+ });
+
+ info("Drop-down empty search matches history sorted by frecency desc");
+ await check_autocomplete({
+ search: "",
+ matches: [
+ { uri: uri7, title: "title" },
+ { uri: uri4, title: "title" },
+ { uri: uri3, title: "title" },
+ { uri: uri2, title: "title" },
+ { uri: uri1, title: "title" },
+ ],
+ });
+
+ info("Drop-down empty search matches only bookmarks");
+ Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
+ Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
+ await check_autocomplete({
+ search: "",
+ matches: [
+ { uri: uri2, title: "title", style: ["bookmark"] },
+ { uri: uri4, title: "title", style: ["bookmark"] },
+ { uri: uri5, title: "title", style: ["bookmark"] },
+ { uri: uri6, title: "title", style: ["bookmark"] },
+ ],
+ });
+
+ info("Drop-down empty search matches only open tabs");
+ Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", false);
+ await check_autocomplete({
+ search: "",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("http://t.foo/6", { title: "title" })],
+ });
+
+ Services.prefs.clearUserPref("browser.urlbar.suggest.history");
+ Services.prefs.clearUserPref("browser.urlbar.suggest.bookmark");
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_escape_self.js b/toolkit/components/places/tests/unifiedcomplete/test_escape_self.js
new file mode 100644
index 0000000000..7359c9540f
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_escape_self.js
@@ -0,0 +1,33 @@
+/* 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/. */
+
+/**
+ * Test bug 422698 to make sure searches with urls from the location bar
+ * correctly match itself when it contains escaped characters.
+ */
+
+add_task(async function test_escape() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ let uri1 = NetUtil.newURI("http://unescapeduri/");
+ let uri2 = NetUtil.newURI("http://escapeduri/%40/");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ ]);
+
+ info("Unescaped location matches itself");
+ await check_autocomplete({
+ search: "http://unescapeduri/",
+ matches: [{ uri: uri1, title: "title" }],
+ });
+
+ info("Escaped location matches itself");
+ await check_autocomplete({
+ search: "http://escapeduri/%40/",
+ matches: [{ uri: uri2, title: "title" }],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_history_autocomplete_tags.js b/toolkit/components/places/tests/unifiedcomplete/test_history_autocomplete_tags.js
new file mode 100644
index 0000000000..2cbe150bfa
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_history_autocomplete_tags.js
@@ -0,0 +1,162 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+/* 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 current_test = 0;
+
+function AutoCompleteInput(aSearches) {
+ this.searches = aSearches;
+}
+AutoCompleteInput.prototype = {
+ constructor: AutoCompleteInput,
+
+ searches: null,
+
+ minResultsForPopup: 0,
+ timeout: 10,
+ searchParam: "",
+ textValue: "",
+ disableAutoComplete: false,
+ completeDefaultIndex: false,
+
+ get searchCount() {
+ return this.searches.length;
+ },
+
+ getSearchAt(aIndex) {
+ return this.searches[aIndex];
+ },
+
+ onSearchBegin() {},
+ onSearchComplete() {},
+
+ popupOpen: false,
+
+ popup: {
+ setSelectedIndex(aIndex) {},
+ invalidate() {},
+
+ // nsISupports implementation
+ QueryInterface: ChromeUtils.generateQI(["nsIAutoCompletePopup"]),
+ },
+
+ // nsISupports implementation
+ QueryInterface: ChromeUtils.generateQI(["nsIAutoCompleteInput"]),
+};
+
+async function ensure_tag_results(uris, searchTerm) {
+ print("Searching for '" + searchTerm + "'");
+ var controller = Cc["@mozilla.org/autocomplete/controller;1"].getService(
+ Ci.nsIAutoCompleteController
+ );
+
+ // Make an AutoCompleteInput that uses our searches
+ // and confirms results on search complete
+ var input = new AutoCompleteInput(["unifiedcomplete"]);
+
+ controller.input = input;
+
+ return new Promise(resolve => {
+ var numSearchesStarted = 0;
+ input.onSearchBegin = function() {
+ numSearchesStarted++;
+ Assert.equal(numSearchesStarted, 1);
+ };
+
+ input.onSearchComplete = function() {
+ Assert.equal(numSearchesStarted, 1);
+ Assert.equal(
+ controller.searchStatus,
+ uris.length
+ ? Ci.nsIAutoCompleteController.STATUS_COMPLETE_MATCH
+ : Ci.nsIAutoCompleteController.STATUS_COMPLETE_NO_MATCH
+ );
+ Assert.equal(controller.matchCount, uris.length);
+ let vals = [];
+ for (let i = 0; i < controller.matchCount; i++) {
+ // Keep the URL for later because order of tag results is undefined
+ vals.push(controller.getValueAt(i));
+ Assert.equal(controller.getStyleAt(i), "bookmark-tag");
+ }
+ // Sort the results then check if we have the right items
+ vals.sort().forEach((val, i) => Assert.equal(val, uris[i]));
+
+ resolve();
+ };
+
+ controller.startSearch(searchTerm);
+ });
+}
+
+var uri1 = "http://site.tld/1/aaa";
+var uri2 = "http://site.tld/2/bbb";
+var uri3 = "http://site.tld/3/aaa";
+var uri4 = "http://site.tld/4/bbb";
+var uri5 = "http://site.tld/5/aaa";
+var uri6 = "http://site.tld/6/bbb";
+
+var tests = [
+ () => ensure_tag_results([uri1, uri4, uri6], "foo"),
+ () => ensure_tag_results([uri1], "foo aaa"),
+ () => ensure_tag_results([uri4, uri6], "foo bbb"),
+ () => ensure_tag_results([uri2, uri4, uri5, uri6], "bar"),
+ () => ensure_tag_results([uri5], "bar aaa"),
+ () => ensure_tag_results([uri2, uri4, uri6], "bar bbb"),
+ () => ensure_tag_results([uri3, uri5, uri6], "cheese"),
+ () => ensure_tag_results([uri3, uri5], "chees aaa"),
+ () => ensure_tag_results([uri6], "chees bbb"),
+ () => ensure_tag_results([uri4, uri6], "fo bar"),
+ () => ensure_tag_results([], "fo bar aaa"),
+ () => ensure_tag_results([uri4, uri6], "fo bar bbb"),
+ () => ensure_tag_results([uri4, uri6], "ba foo"),
+ () => ensure_tag_results([], "ba foo aaa"),
+ () => ensure_tag_results([uri4, uri6], "ba foo bbb"),
+ () => ensure_tag_results([uri5, uri6], "ba chee"),
+ () => ensure_tag_results([uri5], "ba chee aaa"),
+ () => ensure_tag_results([uri6], "ba chee bbb"),
+ () => ensure_tag_results([uri5, uri6], "cheese bar"),
+ () => ensure_tag_results([uri5], "cheese bar aaa"),
+ () => ensure_tag_results([uri6], "chees bar bbb"),
+ () => ensure_tag_results([uri6], "cheese bar foo"),
+ () => ensure_tag_results([], "foo bar cheese aaa"),
+ () => ensure_tag_results([uri6], "foo bar cheese bbb"),
+];
+
+/**
+ * Properly tags a uri adding it to bookmarks.
+ *
+ * @param url
+ * The nsIURI to tag.
+ * @param tags
+ * The tags to add.
+ */
+async function tagURI(url, tags) {
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url,
+ title: "A title",
+ });
+ PlacesUtils.tagging.tagURI(uri(url), tags);
+}
+
+/**
+ * Test history autocomplete
+ */
+add_task(async function test_history_autocomplete_tags() {
+ // always search in history + bookmarks, no matter what the default is
+ Services.prefs.setIntPref("browser.urlbar.search.sources", 3);
+ Services.prefs.setIntPref("browser.urlbar.default.behavior", 0);
+
+ await tagURI(uri1, ["foo"]);
+ await tagURI(uri2, ["bar"]);
+ await tagURI(uri3, ["cheese"]);
+ await tagURI(uri4, ["foo bar"]);
+ await tagURI(uri5, ["bar cheese"]);
+ await tagURI(uri6, ["foo bar cheese"]);
+
+ for (let tagTest of tests) {
+ await tagTest();
+ }
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js b/toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js
new file mode 100644
index 0000000000..8140cc211a
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_ignore_protocol.js
@@ -0,0 +1,26 @@
+/* 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/. */
+
+/**
+ * Test bug 424509 to make sure searching for "h" doesn't match "http" of urls.
+ */
+
+add_task(async function test_escape() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ let uri1 = NetUtil.newURI("http://site/");
+ let uri2 = NetUtil.newURI("http://happytimes/");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ ]);
+
+ info("Searching for h matches site and not http://");
+ await check_autocomplete({
+ search: "h",
+ matches: [{ uri: uri2, title: "title" }],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
new file mode 100644
index 0000000000..1e889da3fd
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search.js
@@ -0,0 +1,178 @@
+/* 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/. */
+
+/**
+ * Test for bug 392143 that puts keyword results into the autocomplete. Makes
+ * sure that multiple parameter queries get spaces converted to +, + converted
+ * to %2B, non-ascii become escaped, and pages in history that match the
+ * keyword uses the page's title.
+ *
+ * Also test for bug 249468 by making sure multiple keyword bookmarks with the
+ * same keyword appear in the list.
+ */
+
+add_task(async function test_keyword_search() {
+ let uri1 = NetUtil.newURI("http://abc/?search=%s");
+ let uri2 = NetUtil.newURI("http://abc/?search=ThisPageIsInHistory");
+ let uri3 = NetUtil.newURI("http://somedomain.example/key");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "Generic page title" },
+ { uri: uri2, title: "Generic page title" },
+ { uri: uri3, title: "This page uri contains the keyword" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "Bookmark title",
+ keyword: "key",
+ });
+
+ info("Plain keyword query");
+ await check_autocomplete({
+ search: "key term",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=term"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Plain keyword UC");
+ await check_autocomplete({
+ search: "key TERM",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=TERM"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Multi-word keyword query");
+ await check_autocomplete({
+ search: "key multi word",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=multi%20word"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword query with +");
+ await check_autocomplete({
+ search: "key blocking+",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=blocking%2B"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Unescaped term in query");
+ await check_autocomplete({
+ search: "key ユニコード",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=ユニコード"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword with query that happens to match a page");
+ await check_autocomplete({
+ search: "key ThisPageIsInHistory",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword with query that partially matches a page");
+ await check_autocomplete({
+ search: "key ThisPage",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=ThisPage"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ {
+ uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"),
+ title: "Generic page title",
+ },
+ ],
+ });
+
+ info("Keyword without query (without space)");
+ await check_autocomplete({
+ search: "key",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search="),
+ style: ["keyword", "heuristic"],
+ },
+ {
+ uri: NetUtil.newURI("http://abc/?search=%s"),
+ title: "Bookmark title",
+ style: ["bookmark"],
+ },
+ {
+ uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"),
+ title: "Generic page title",
+ },
+ ],
+ });
+
+ info("Keyword without query (with space)");
+ await check_autocomplete({
+ search: "key ",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search="),
+ style: ["keyword", "heuristic"],
+ },
+ {
+ uri: NetUtil.newURI("http://abc/?search=%s"),
+ title: "Bookmark title",
+ style: ["bookmark"],
+ },
+ {
+ uri: NetUtil.newURI("http://abc/?search=ThisPageIsInHistory"),
+ title: "Generic page title",
+ },
+ ],
+ });
+
+ info("Bug 1228111 - Keyword with a space in front");
+ await check_autocomplete({
+ search: " key test",
+ matches: [
+ {
+ uri: NetUtil.newURI("http://abc/?search=test"),
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Bug 1481319 - Keyword with a prefix in front");
+ await check_autocomplete({
+ search: "http://key",
+ matches: [{ uri: uri3, title: "This page uri contains the keyword" }],
+ completed: "http://key",
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
new file mode 100644
index 0000000000..35be972a8a
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_keyword_search_actions.js
@@ -0,0 +1,357 @@
+/* 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/. */
+
+/**
+ * Test for bug 392143 that puts keyword results into the autocomplete. Makes
+ * sure that multiple parameter queries get spaces converted to +, + converted
+ * to %2B, non-ascii become escaped, and pages in history that match the
+ * keyword uses the page's title.
+ *
+ * Also test for bug 249468 by making sure multiple keyword bookmarks with the
+ * same keyword appear in the list.
+ */
+
+add_task(async function test_keyword_search() {
+ let uri1 = "http://abc/?search=%s";
+ let uri2 = "http://abc/?search=ThisPageIsInHistory";
+ let uri3 = "http://abc/?search=%s&raw=%S";
+ let uri4 = "http://abc/?search=%s&raw=%S&mozcharset=ISO-8859-1";
+ let uri5 = "http://def/?search=%s";
+ let uri6 = "http://ghi/?search=%s&raw=%S";
+ await PlacesTestUtils.addVisits([
+ { uri: uri1 },
+ { uri: uri2 },
+ { uri: uri3 },
+ { uri: uri6 },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "Keyword",
+ keyword: "key",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri1,
+ title: "Post",
+ keyword: "post",
+ postData: "post_search=%s",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri3,
+ title: "Encoded",
+ keyword: "encoded",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri4,
+ title: "Charset",
+ keyword: "charset",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "Noparam",
+ keyword: "noparam",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri2,
+ title: "Noparam-Post",
+ keyword: "post_noparam",
+ postData: "noparam=1",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri5,
+ title: "Keyword",
+ keyword: "key2",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri6,
+ title: "Charset-history",
+ keyword: "charset_history",
+ });
+
+ await PlacesUtils.history.update({
+ url: uri6,
+ annotations: new Map([[PlacesUtils.CHARSET_ANNO, "ISO-8859-1"]]),
+ });
+
+ info("Plain keyword query");
+ await check_autocomplete({
+ search: "key term",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=term",
+ keyword: "key",
+ input: "key term",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Plain keyword UC");
+ await check_autocomplete({
+ search: "key TERM",
+ matches: [
+ {
+ uri: "http://abc/?search=TERM",
+ title: "abc",
+ style: ["keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Multi-word keyword query");
+ await check_autocomplete({
+ search: "key multi word",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=multi%20word",
+ keyword: "key",
+ input: "key multi word",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword query with +");
+ await check_autocomplete({
+ search: "key blocking+",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=blocking%2B",
+ keyword: "key",
+ input: "key blocking+",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Unescaped term in query");
+ // ... but note that UnifiedComplete calls encodeURIComponent() on the query
+ // string when it builds the URL, so the expected result will have the
+ // ユニコード substring encoded in the URL.
+ await check_autocomplete({
+ search: "key ユニコード",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=" + encodeURIComponent("ユニコード"),
+ keyword: "key",
+ input: "key ユニコード",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword that happens to match a page");
+ await check_autocomplete({
+ search: "key ThisPageIsInHistory",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=ThisPageIsInHistory",
+ keyword: "key",
+ input: "key ThisPageIsInHistory",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Keyword with partial page match");
+ await check_autocomplete({
+ search: "key ThisPage",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=ThisPage",
+ keyword: "key",
+ input: "key ThisPage",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ // Only the most recent bookmark for the URL:
+ {
+ value: "http://abc/?search=ThisPageIsInHistory",
+ title: "Noparam-Post",
+ style: ["bookmark"],
+ },
+ ],
+ });
+
+ // For the keyword with no query terms (with or without space after), the
+ // domain is different from the other tests because otherwise all the other
+ // test bookmarks and history entries would be matches.
+ info("Keyword without query (without space)");
+ await check_autocomplete({
+ search: "key2",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://def/?search=",
+ keyword: "key2",
+ input: "key2",
+ }),
+ style: ["action", "keyword", "heuristic"],
+ },
+ { uri: uri5, title: "Keyword", style: ["bookmark"] },
+ ],
+ });
+
+ info("Keyword without query (with space)");
+ await check_autocomplete({
+ search: "key2 ",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://def/?search=",
+ keyword: "key2",
+ input: "key2 ",
+ }),
+ style: ["action", "keyword", "heuristic"],
+ },
+ { uri: uri5, title: "Keyword", style: ["bookmark"] },
+ ],
+ });
+
+ info("POST Keyword");
+ await check_autocomplete({
+ search: "post foo",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=foo",
+ keyword: "post",
+ input: "post foo",
+ postData: "post_search=foo",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("escaping with default UTF-8 charset");
+ await check_autocomplete({
+ search: "encoded foé",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=fo%C3%A9&raw=foé",
+ keyword: "encoded",
+ input: "encoded foé",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("escaping with forced ISO-8859-1 charset");
+ await check_autocomplete({
+ search: "charset foé",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=fo%E9&raw=foé",
+ keyword: "charset",
+ input: "charset foé",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("escaping with ISO-8859-1 charset annotated in history");
+ await check_autocomplete({
+ search: "charset_history foé",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://ghi/?search=fo%E9&raw=foé",
+ keyword: "charset_history",
+ input: "charset_history foé",
+ }),
+ title: "ghi",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Bug 359809: escaping +, / and @ with default UTF-8 charset");
+ await check_autocomplete({
+ search: "encoded +/@",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=%2B%2F%40&raw=+/@",
+ keyword: "encoded",
+ input: "encoded +/@",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Bug 359809: escaping +, / and @ with forced ISO-8859-1 charset");
+ await check_autocomplete({
+ search: "charset +/@",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=%2B%2F%40&raw=+/@",
+ keyword: "charset",
+ input: "charset +/@",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ info("Bug 1228111 - Keyword with a space in front");
+ await check_autocomplete({
+ search: " key test",
+ searchParam: "enable-actions",
+ matches: [
+ {
+ uri: makeActionURI("keyword", {
+ url: "http://abc/?search=test",
+ keyword: "key",
+ input: " key test",
+ }),
+ title: "abc",
+ style: ["action", "keyword", "heuristic"],
+ },
+ ],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_multi_word_search.js b/toolkit/components/places/tests/unifiedcomplete/test_multi_word_search.js
new file mode 100644
index 0000000000..4187641c15
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_multi_word_search.js
@@ -0,0 +1,80 @@
+/* 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/. */
+
+/**
+ * Test for bug 401869 to allow multiple words separated by spaces to match in
+ * the page title, page url, or bookmark title to be considered a match. All
+ * terms must match but not all terms need to be in the title, etc.
+ *
+ * Test bug 424216 by making sure bookmark titles are always shown if one is
+ * available. Also bug 425056 makes sure matches aren't found partially in the
+ * page title and partially in the bookmark.
+ */
+
+add_task(async function test_match_beginning() {
+ let uri1 = NetUtil.newURI("http://a.b.c/d-e_f/h/t/p");
+ let uri2 = NetUtil.newURI("http://d.e.f/g-h_i/h/t/p");
+ let uri3 = NetUtil.newURI("http://g.h.i/j-k_l/h/t/p");
+ let uri4 = NetUtil.newURI("http://j.k.l/m-n_o/h/t/p");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "f(o)o b<a>r" },
+ { uri: uri2, title: "b(a)r b<a>z" },
+ { uri: uri3, title: "f(o)o b<a>r" },
+ { uri: uri4, title: "f(o)o b<a>r" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri3,
+ title: "f(o)o b<a>r",
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri4,
+ title: "b(a)r b<a>z",
+ });
+
+ info("Match 2 terms all in url");
+ await check_autocomplete({
+ search: "c d",
+ matches: [{ uri: uri1, title: "f(o)o b<a>r" }],
+ });
+
+ info("Match 1 term in url and 1 term in title");
+ await check_autocomplete({
+ search: "b e",
+ matches: [
+ { uri: uri1, title: "f(o)o b<a>r" },
+ { uri: uri2, title: "b(a)r b<a>z" },
+ ],
+ });
+
+ info("Match 3 terms all in title; display bookmark title if matched");
+ await check_autocomplete({
+ search: "b a z",
+ matches: [
+ { uri: uri2, title: "b(a)r b<a>z" },
+ { uri: uri4, title: "b(a)r b<a>z", style: ["bookmark"] },
+ ],
+ });
+
+ info(
+ "Match 2 terms in url and 1 in title; make sure bookmark title is used for search"
+ );
+ await check_autocomplete({
+ search: "k f t",
+ matches: [{ uri: uri3, title: "f(o)o b<a>r", style: ["bookmark"] }],
+ });
+
+ info("Match 3 terms in url and 1 in title");
+ await check_autocomplete({
+ search: "d i g z",
+ matches: [{ uri: uri2, title: "b(a)r b<a>z" }],
+ });
+
+ info("Match nothing");
+ await check_autocomplete({
+ search: "m o z i",
+ matches: [],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js b/toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js
new file mode 100644
index 0000000000..62c12ad79c
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_preloaded_sites.js
@@ -0,0 +1,322 @@
+/**
+ * Test for bug 1211726 - preload list of top web sites for better
+ * autocompletion on empty profiles.
+ */
+
+const PREF_FEATURE_ENABLED = "browser.urlbar.usepreloadedtopurls.enabled";
+const PREF_FEATURE_EXPIRE_DAYS =
+ "browser.urlbar.usepreloadedtopurls.expire_days";
+
+const autocompleteObject = Cc[
+ "@mozilla.org/autocomplete/search;1?name=unifiedcomplete"
+].getService(Ci.mozIPlacesAutoComplete);
+
+Cu.importGlobalProperties(["fetch"]);
+
+// With or without trailing slash - no matter. URI.spec does have it always.
+// Then, check_autocomplete() doesn't cut it off (uses stripPrefix()).
+let yahoooURI = NetUtil.newURI("https://yahooo.com/");
+let gooogleURI = NetUtil.newURI("https://gooogle.com/");
+
+autocompleteObject.populatePreloadedSiteStorage([
+ [yahoooURI.spec, "Yahooo"],
+ [gooogleURI.spec, "Gooogle"],
+]);
+
+async function assert_feature_works(condition) {
+ info("List Results do appear " + condition);
+ await check_autocomplete({
+ search: "ooo",
+ matches: [
+ { uri: yahoooURI, title: "Yahooo", style: ["preloaded-top-site"] },
+ { uri: gooogleURI, title: "Gooogle", style: ["preloaded-top-site"] },
+ ],
+ });
+
+ info("Autofill does appear " + condition);
+ await check_autocomplete({
+ search: "gooo",
+ autofilled: "gooogle.com/", // Will fail without trailing slash
+ completed: "https://gooogle.com/",
+ });
+}
+
+async function assert_feature_does_not_appear(condition) {
+ info("List Results don't appear " + condition);
+ await check_autocomplete({
+ search: "ooo",
+ matches: [],
+ });
+
+ info("Autofill doesn't appear " + condition);
+ // "search" is what you type,
+ // "autofilled" is what you get in response in the url bar,
+ // "completed" is what you get there when you hit enter.
+ // So if they are all equal - it's the proof there was no autofill
+ // (knowing we have a suitable preloaded top site).
+ await check_autocomplete({
+ search: "gooo",
+ autofilled: "gooo",
+ completed: "gooo",
+ });
+}
+
+add_task(async function test_it_works() {
+ // Not expired but OFF
+ Services.prefs.setIntPref(PREF_FEATURE_EXPIRE_DAYS, 14);
+ Services.prefs.setBoolPref(PREF_FEATURE_ENABLED, false);
+ await assert_feature_does_not_appear("when OFF by prefs");
+
+ // Now turn it ON
+ Services.prefs.setBoolPref(PREF_FEATURE_ENABLED, true);
+ await assert_feature_works("when ON by prefs");
+
+ // And expire
+ Services.prefs.setIntPref(PREF_FEATURE_EXPIRE_DAYS, 0);
+ await assert_feature_does_not_appear("when expired");
+
+ await cleanup();
+});
+
+add_task(async function test_sorting_against_bookmark() {
+ let boookmarkURI = NetUtil.newURI("https://boookmark.com");
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: boookmarkURI,
+ title: "Boookmark",
+ });
+
+ Services.prefs.setBoolPref(PREF_FEATURE_ENABLED, true);
+ Services.prefs.setIntPref(PREF_FEATURE_EXPIRE_DAYS, 14);
+
+ info("Preloaded Top Sites are placed lower than Bookmarks");
+ await check_autocomplete({
+ checkSorting: true,
+ search: "ooo",
+ matches: [
+ { uri: boookmarkURI, title: "Boookmark", style: ["bookmark"] },
+ { uri: yahoooURI, title: "Yahooo", style: ["preloaded-top-site"] },
+ { uri: gooogleURI, title: "Gooogle", style: ["preloaded-top-site"] },
+ ],
+ });
+
+ await cleanup();
+});
+
+add_task(async function test_sorting_against_history() {
+ let histoooryURI = NetUtil.newURI("https://histooory.com");
+ await PlacesTestUtils.addVisits({ uri: histoooryURI, title: "Histooory" });
+
+ Services.prefs.setBoolPref(PREF_FEATURE_ENABLED, true);
+ Services.prefs.setIntPref(PREF_FEATURE_EXPIRE_DAYS, 14);
+
+ info("Preloaded Top Sites are placed lower than History entries");
+ await check_autocomplete({
+ checkSorting: true,
+ search: "ooo",
+ matches: [
+ { uri: histoooryURI, title: "Histooory" },
+ { uri: yahoooURI, title: "Yahooo", style: ["preloaded-top-site"] },
+ { uri: gooogleURI, title: "Gooogle", style: ["preloaded-top-site"] },
+ ],
+ });
+
+ await cleanup();
+});
+
+add_task(async function test_scheme_and_www() {
+ // Order is important to check sorting
+ let sites = [
+ ["https://www.ooops-https-www.com/", "Ooops"],
+ ["https://ooops-https.com/", "Ooops"],
+ ["HTTP://ooops-HTTP.com/", "Ooops"],
+ ["HTTP://www.ooops-HTTP-www.com/", "Ooops"],
+ ["https://foo.com/", "Title with www"],
+ ["https://www.bar.com/", "Tile"],
+ ];
+
+ let titlesMap = new Map(sites);
+
+ autocompleteObject.populatePreloadedSiteStorage(sites);
+
+ let tests = [
+ // User typed,
+ // Inline autofill (`autofilled`),
+ // Substitute after enter is pressed (`completed`),
+ // [List matches, with sorting]
+ // not tested if omitted
+ // !!! first one is always an autofill entry !!!
+
+ [
+ // Protocol by itself doesn't match anything
+ "https://",
+ "https://",
+ "https://",
+ [],
+ ],
+
+ [
+ "www.",
+ "www.ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [
+ ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+ "HTTP://www.ooops-HTTP-www.com/",
+ "https://www.bar.com/",
+ ],
+ ],
+
+ [
+ "http://www.",
+ "http://www.ooops-http-www.com/",
+ "http://www.ooops-http-www.com/",
+ [["http://www.ooops-http-www.com/", "www.ooops-http-www.com"]],
+ ],
+
+ ["ftp://ooops", "ftp://ooops", "ftp://ooops", []],
+
+ [
+ "ww",
+ "www.ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [
+ ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+ "HTTP://www.ooops-HTTP-www.com/",
+ ["https://foo.com/", "Title with www", ["preloaded-top-site"]],
+ "https://www.bar.com/",
+ ],
+ ],
+
+ [
+ "ooops",
+ "ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [
+ ["ooops-https-www.com/", "https://www.ooops-https-www.com"],
+ "https://ooops-https.com/",
+ "HTTP://ooops-HTTP.com/",
+ "HTTP://www.ooops-HTTP-www.com/",
+ ],
+ ],
+
+ [
+ "www.ooops",
+ "www.ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [
+ ["www.ooops-https-www.com/", "https://www.ooops-https-www.com"],
+ "HTTP://www.ooops-HTTP-www.com/",
+ ],
+ ],
+
+ [
+ "ooops-https-www",
+ "ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [["ooops-https-www.com/", "https://www.ooops-https-www.com"]],
+ ],
+
+ ["www.ooops-https.", "www.ooops-https.", "www.ooops-https.", []],
+
+ [
+ "https://ooops",
+ "https://ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [
+ ["https://ooops-https-www.com/", "https://www.ooops-https-www.com"],
+ "https://ooops-https.com/",
+ ],
+ ],
+
+ [
+ "https://www.ooops",
+ "https://www.ooops-https-www.com/",
+ "https://www.ooops-https-www.com/",
+ [["https://www.ooops-https-www.com/", "https://www.ooops-https-www.com"]],
+ ],
+
+ [
+ "http://www.ooops-http.",
+ "http://www.ooops-http.",
+ "http://www.ooops-http.",
+ [],
+ ],
+
+ ["http://ooops-https", "http://ooops-https", "http://ooops-https", []],
+ ];
+
+ function toMatch(entry, index) {
+ if (Array.isArray(entry)) {
+ return {
+ value: entry[0],
+ comment: entry[1],
+ style: entry[2] || ["autofill", "heuristic", "preloaded-top-site"],
+ };
+ }
+ return {
+ uri: NetUtil.newURI(entry),
+ title: titlesMap.get(entry),
+ style: ["preloaded-top-site"],
+ };
+ }
+
+ for (let test of tests) {
+ let matches = test[3] ? test[3].map(toMatch) : null;
+ info("User types: " + test[0]);
+ await check_autocomplete({
+ checkSorting: true,
+ search: test[0],
+ autofilled: test[1].toLowerCase(),
+ completed: test[2].toLowerCase(),
+ matches,
+ });
+ }
+
+ await cleanup();
+});
+
+add_task(async function test_data_file() {
+ let response = await fetch(
+ "chrome://global/content/unifiedcomplete-top-urls.json"
+ );
+
+ info("Source file is supplied and fetched OK");
+ Assert.ok(response.ok);
+
+ info("The JSON is parsed");
+ let sites = await response.json();
+
+ info("Storage is populated");
+ autocompleteObject.populatePreloadedSiteStorage(sites);
+
+ let lastSite = sites.pop();
+ let uri = NetUtil.newURI(lastSite[0]);
+
+ info("Storage is populated from JSON correctly");
+ await check_autocomplete({
+ search: uri.host,
+ autofilled: uri.host + "/",
+ completed: uri.spec,
+ });
+
+ await cleanup();
+});
+
+add_task(async function test_partial_scheme() {
+ // "tt" should not result in a match of "ttps://whatever.com/".
+ autocompleteObject.populatePreloadedSiteStorage([
+ ["http://www.ttt.com/", "Test"],
+ ]);
+ await check_autocomplete({
+ search: "tt",
+ autofilled: "ttt.com/",
+ completed: "http://www.ttt.com/",
+ matches: [
+ {
+ value: "ttt.com/",
+ comment: "www.ttt.com",
+ style: ["autofill", "heuristic", "preloaded-top-site"],
+ },
+ ],
+ });
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
new file mode 100644
index 0000000000..c157506538
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js
@@ -0,0 +1,408 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim:set ts=2 sw=2 sts=2 et:
+ */
+"use strict";
+
+const { Weave } = ChromeUtils.import("resource://services-sync/main.js");
+
+Services.prefs.setCharPref("services.sync.username", "someone@somewhere.com");
+Services.prefs.setCharPref("services.sync.registerEngines", "");
+
+// A mock "Tabs" engine which autocomplete will use instead of the real
+// engine. We pass a constructor that Sync creates.
+function MockTabsEngine() {
+ this.clients = null; // We'll set this dynamically
+}
+
+MockTabsEngine.prototype = {
+ name: "tabs",
+
+ startTracking() {},
+ getAllClients() {
+ return this.clients;
+ },
+};
+
+// A clients engine that doesn't need to be a constructor.
+let MockClientsEngine = {
+ getClientType(guid) {
+ Assert.ok(guid.endsWith("desktop") || guid.endsWith("mobile"));
+ return guid.endsWith("mobile") ? "phone" : "desktop";
+ },
+ remoteClientExists(id) {
+ return true;
+ },
+ getClientName(id) {
+ return id.endsWith("mobile") ? "My Phone" : "My Desktop";
+ },
+};
+
+// Tell Sync about the mocks.
+Weave.Service.engineManager.register(MockTabsEngine);
+
+// Tell the Sync XPCOM service it is initialized.
+let weaveXPCService = Cc["@mozilla.org/weave/service;1"].getService(
+ Ci.nsISupports
+).wrappedJSObject;
+weaveXPCService.ready = true;
+
+// Configure the singleton engine for a test.
+function configureEngine(clients) {
+ // Configure the instance Sync created.
+ let engine = Weave.Service.engineManager.get("tabs");
+ engine.clients = clients;
+ Weave.Service.clientsEngine = MockClientsEngine;
+ // Send an observer that pretends the engine just finished a sync.
+ Services.obs.notifyObservers(null, "weave:engine:sync:finish", "tabs");
+}
+
+// Make a match object suitable for passing to check_autocomplete.
+function makeRemoteTabMatch(url, deviceName, extra = {}) {
+ return {
+ uri: makeActionURI("remotetab", { url, deviceName }),
+ title: extra.title || url,
+ style: ["action", "remotetab"],
+ icon: extra.icon,
+ };
+}
+
+add_task(async function test_minimal() {
+ // The minimal client and tabs info we can get away with.
+ configureEngine({
+ guid_desktop: {
+ id: "desktop",
+ tabs: [
+ {
+ urlHistory: ["http://example.com/"],
+ },
+ ],
+ },
+ });
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [makeRemoteTabMatch("http://example.com/", "My Desktop")],
+ });
+});
+
+add_task(async function test_maximal() {
+ // Every field that could possibly exist on a remote record.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: ["http://example.com/"],
+ title: "An Example",
+ icon: "http://favicon",
+ },
+ ],
+ },
+ });
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [
+ makeRemoteTabMatch("http://example.com/", "My Phone", {
+ title: "An Example",
+ icon: "moz-anno:favicon:http://favicon/",
+ }),
+ ],
+ });
+});
+
+add_task(async function test_noShowIcons() {
+ Services.prefs.setBoolPref("services.sync.syncedTabs.showRemoteIcons", false);
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: ["http://example.com/"],
+ title: "An Example",
+ icon: "http://favicon",
+ },
+ ],
+ },
+ });
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [
+ makeRemoteTabMatch("http://example.com/", "My Phone", {
+ title: "An Example",
+ // expecting the default favicon due to that pref.
+ icon: "",
+ }),
+ ],
+ });
+ Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteIcons");
+});
+
+add_task(async function test_dontMatchSyncedTabs() {
+ Services.prefs.setBoolPref("services.sync.syncedTabs.showRemoteTabs", false);
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: ["http://example.com/"],
+ title: "An Example",
+ icon: "http://favicon",
+ },
+ ],
+ },
+ });
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [],
+ });
+ Services.prefs.clearUserPref("services.sync.syncedTabs.showRemoteTabs");
+});
+
+add_task(async function test_matches_title() {
+ // URL doesn't match search expression, should still match the title.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: ["http://foo.com/"],
+ title: "An Example",
+ },
+ ],
+ },
+ });
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [
+ makeRemoteTabMatch("http://foo.com/", "My Phone", {
+ title: "An Example",
+ }),
+ ],
+ });
+});
+
+add_task(async function test_localtab_matches_override() {
+ // We have an open tab to the same page on a remote device, only "switch to
+ // tab" should appear as duplicate detection removed the remote one.
+
+ // First setup Sync to have the page as a remote tab.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: ["http://foo.com/"],
+ title: "An Example",
+ },
+ ],
+ },
+ });
+
+ // Setup Places to think the tab is open locally.
+ let uri = NetUtil.newURI("http://foo.com/");
+ await PlacesTestUtils.addVisits([{ uri, title: "An Example" }]);
+ await addOpenPages(uri, 1);
+
+ await check_autocomplete({
+ search: "ex",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("http://foo.com/", { title: "An Example" })],
+ });
+ await removeOpenPages(uri, 1);
+});
+
+add_task(async function test_remotetab_matches_override() {
+ // If We have an history result to the same page, we should only get the
+ // remote tab match.
+ let url = "http://foo.remote.com/";
+ // First setup Sync to have the page as a remote tab.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: [
+ {
+ urlHistory: [url],
+ title: "An Example",
+ },
+ ],
+ },
+ });
+
+ // Setup Places to think the tab is open locally.
+ await PlacesTestUtils.addVisits(url);
+
+ await check_autocomplete({
+ search: "rem",
+ searchParam: "enable-actions",
+ matches: [
+ makeRemoteTabMatch("http://foo.remote.com/", "My Phone", {
+ title: "An Example",
+ }),
+ ],
+ });
+});
+
+add_task(async function test_many_remotetab_matches() {
+ await PlacesUtils.history.clear();
+
+ // In case we have many results, the most recent ones should be added on top,
+ // while others should be appended.
+ let url = "http://foo.remote.com/";
+ // First setup Sync to have the page as a remote tab.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: Array(5)
+ .fill(0)
+ .map((e, i) => ({
+ urlHistory: [`${url}${i}`],
+ title: "A title",
+ lastUsed: Date.now() / 1000 - i * 86400, // i days ago.
+ })),
+ },
+ });
+
+ // Also add a local history result.
+ let historyUrl = url + "history/";
+ await PlacesTestUtils.addVisits(historyUrl);
+
+ await check_autocomplete({
+ search: "rem",
+ searchParam: "enable-actions",
+ checkSorting: true,
+ matches: [
+ makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/1", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/2", "My Phone", {
+ title: "A title",
+ }),
+ {
+ uri: Services.io.newURI(historyUrl),
+ title: "test visit for " + historyUrl,
+ },
+ makeRemoteTabMatch("http://foo.remote.com/3", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/4", "My Phone", {
+ title: "A title",
+ }),
+ ],
+ });
+});
+
+add_task(async function test_maxResults() {
+ await PlacesUtils.history.clear();
+
+ let url = "http://foo.remote.com/";
+
+ // Add 10 mock remote tabs. Important: We set `lastUsed` so that these tabs
+ // are newer than RECENT_REMOTE_TAB_THRESHOLD_MS in UnifiedComplete. That way
+ // they are added immediately in _matchRemoteTabs rather than being pushed
+ // onto _extraRemoteTabRows and then added later in execute(). The former
+ // does not check maxResults, but the latter does, and in this test, we want
+ // to verify that PlacesRemoteTabsAutocompleteProvider.getMatches returns at
+ // most ceil(maxResults / 2) tabs.
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: Array(10)
+ .fill(0)
+ .map((e, i) => ({
+ urlHistory: [`${url}${i}`],
+ title: "A title",
+ lastUsed: Date.now() - i,
+ })),
+ },
+ });
+
+ // Set maxResults to 4 in our search.
+ await check_autocomplete({
+ search: "rem",
+ searchParam: "enable-actions max-results:4",
+ checkSorting: true,
+ matches: [
+ makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/1", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/2", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/3", "My Phone", {
+ title: "A title",
+ }),
+ ],
+ });
+});
+
+add_task(async function test_restrictionCharacter() {
+ await PlacesUtils.history.clear();
+
+ let url = "http://foo.remote.com/";
+
+ configureEngine({
+ guid_mobile: {
+ id: "mobile",
+ tabs: Array(10)
+ .fill(0)
+ .map((e, i) => ({
+ urlHistory: [`${url}${i}`],
+ title: "A title",
+ lastUsed: Date.now() - i,
+ })),
+ },
+ });
+
+ // Also add an open page.
+ let uri = Services.io.newURI(`${url}openpage/`);
+ await PlacesTestUtils.addVisits([{ uri, title: "An Example" }]);
+ await addOpenPages(uri, 1);
+
+ // Set maxResults to 7 in our search. 7 results should be returned:
+ // ceil(maxResults / 2) remote tabs, then the open tab, then 2 more remote tab
+ // results to get to 7 total.
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.OPENPAGE,
+ searchParam: "enable-actions max-results:7",
+ checkSorting: true,
+ matches: [
+ makeRemoteTabMatch("http://foo.remote.com/0", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/1", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/2", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/3", "My Phone", {
+ title: "A title",
+ }),
+ makeSwitchToTabMatch("http://foo.remote.com/openpage/", {
+ title: "An Example",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/4", "My Phone", {
+ title: "A title",
+ }),
+ makeRemoteTabMatch("http://foo.remote.com/5", "My Phone", {
+ title: "A title",
+ }),
+ ],
+ });
+ await removeOpenPages(uri, 1);
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_search_engine_alias.js b/toolkit/components/places/tests/unifiedcomplete/test_search_engine_alias.js
new file mode 100644
index 0000000000..772334bb6d
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_search_engine_alias.js
@@ -0,0 +1,108 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+const SUGGESTIONS_ENGINE_NAME = "engine-suggestions.xml";
+
+/**
+ * Tests search engine aliases. See
+ * browser/components/urlbar/tests/browser/browser_tokenAlias.js for tests of
+ * the token alias list (i.e. showing all aliased engines on a "@" query).
+ */
+// Basic test that uses two engines, a GET engine and a POST engine, neither
+// providing search suggestions.
+add_task(async function basicGetAndPost() {
+ // Note that head_autocomplete.js has already added a MozSearch engine.
+ // Here we add another engine with a search alias.
+ await Services.search.addEngineWithDetails("AliasedGETMozSearch", {
+ alias: "get",
+ method: "GET",
+ template: "http://s.example.com/search",
+ });
+ await Services.search.addEngineWithDetails("AliasedPOSTMozSearch", {
+ alias: "post",
+ method: "POST",
+ template: "http://s.example.com/search",
+ });
+
+ await PlacesTestUtils.addVisits("http://s.example.com/search?q=firefox");
+ let historyMatch = {
+ value: "http://s.example.com/search?q=firefox",
+ comment: "test visit for http://s.example.com/search?q=firefox",
+ };
+
+ for (let alias of ["get", "post"]) {
+ await check_autocomplete({
+ search: alias,
+ searchParam: "enable-actions",
+ matches: [],
+ });
+
+ await check_autocomplete({
+ search: `${alias} `,
+ searchParam: "enable-actions",
+ matches: [
+ makeSearchMatch(`${alias} `, {
+ engineName: `Aliased${alias.toUpperCase()}MozSearch`,
+ searchQuery: "",
+ alias,
+ heuristic: true,
+ }),
+ historyMatch,
+ ],
+ });
+
+ await check_autocomplete({
+ search: `${alias} fire`,
+ searchParam: "enable-actions",
+ matches: [
+ makeSearchMatch(`${alias} fire`, {
+ engineName: `Aliased${alias.toUpperCase()}MozSearch`,
+ searchQuery: "fire",
+ alias,
+ heuristic: true,
+ }),
+ historyMatch,
+ ],
+ });
+
+ await check_autocomplete({
+ search: `${alias} mozilla`,
+ searchParam: "enable-actions",
+ matches: [
+ makeSearchMatch(`${alias} mozilla`, {
+ engineName: `Aliased${alias.toUpperCase()}MozSearch`,
+ searchQuery: "mozilla",
+ alias,
+ heuristic: true,
+ }),
+ ],
+ });
+
+ await check_autocomplete({
+ search: `${alias} MoZiLlA`,
+ searchParam: "enable-actions",
+ matches: [
+ makeSearchMatch(`${alias} MoZiLlA`, {
+ engineName: `Aliased${alias.toUpperCase()}MozSearch`,
+ searchQuery: "MoZiLlA",
+ alias,
+ heuristic: true,
+ }),
+ ],
+ });
+
+ await check_autocomplete({
+ search: `${alias} mozzarella mozilla`,
+ searchParam: "enable-actions",
+ matches: [
+ makeSearchMatch(`${alias} mozzarella mozilla`, {
+ engineName: `Aliased${alias.toUpperCase()}MozSearch`,
+ searchQuery: "mozzarella mozilla",
+ alias,
+ heuristic: true,
+ }),
+ ],
+ });
+ }
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_search_engine_restyle.js b/toolkit/components/places/tests/unifiedcomplete/test_search_engine_restyle.js
new file mode 100644
index 0000000000..a9d4e8e95f
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_search_engine_restyle.js
@@ -0,0 +1,90 @@
+/* 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/. */
+
+const engineDomain = "s.example.com";
+add_task(async function setup() {
+ let engine = await Services.search.addEngineWithDetails("SearchEngine", {
+ method: "GET",
+ template: `http://${engineDomain}/search`,
+ searchGetParams: "q={searchTerms}",
+ });
+ Services.prefs.setBoolPref("browser.urlbar.restyleSearches", true);
+ registerCleanupFunction(async () => {
+ Services.prefs.clearUserPref("browser.urlbar.restyleSearches");
+ Services.search.removeEngine(engine);
+ });
+});
+add_task(async function test_searchEngine() {
+ let uri = Services.io.newURI(`http://${engineDomain}/search?q=Terms`);
+ await PlacesTestUtils.addVisits({
+ uri,
+ title: "Terms - SearchEngine Search",
+ });
+
+ info("Past search terms should be styled.");
+
+ await check_autocomplete({
+ search: "term",
+ matches: [
+ makeSearchMatch("Terms", {
+ engineName: "SearchEngine",
+ searchSuggestion: "Terms",
+ isSearchHistory: true,
+ style: ["favicon"],
+ }),
+ ],
+ });
+
+ info(
+ "Searching for a superset of the search string in history should not restyle."
+ );
+ await check_autocomplete({
+ search: "Terms Foo",
+ });
+
+ info("Bookmarked past searches should not be restyled");
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri,
+ title: "Terms - SearchEngine Search",
+ });
+
+ await check_autocomplete({
+ search: "term",
+ matches: [
+ {
+ uri,
+ title: "Terms - SearchEngine Search",
+ style: ["bookmark"],
+ },
+ ],
+ });
+
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ info("Past search terms should not be styled if restyling is disabled");
+ Services.prefs.setBoolPref("browser.urlbar.restyleSearches", false);
+ await check_autocomplete({
+ search: "term",
+ matches: [{ uri, title: "Terms - SearchEngine Search" }],
+ });
+ Services.prefs.setBoolPref("browser.urlbar.restyleSearches", true);
+
+ await cleanup();
+});
+
+add_task(async function test_extraneousParameters() {
+ info("SERPs in history with extraneous parameters should not be restyled.");
+ let uri = Services.io.newURI(
+ `http://${engineDomain}/search?q=Terms&p=2&type=img`
+ );
+ await PlacesTestUtils.addVisits({
+ uri,
+ title: "Terms - SearchEngine Search",
+ });
+
+ await check_autocomplete({
+ search: "term",
+ matches: [{ uri, title: "Terms - SearchEngine Search" }],
+ });
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_special_search.js b/toolkit/components/places/tests/unifiedcomplete/test_special_search.js
new file mode 100644
index 0000000000..cee143c79c
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_special_search.js
@@ -0,0 +1,539 @@
+/* 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/. */
+
+/**
+ * Test for bug 395161 that allows special searches that restrict results to
+ * history/bookmark/tagged items and title/url matches.
+ *
+ * Test 485122 by making sure results don't have tags when restricting result
+ * to just history either by default behavior or dynamic query restrict.
+ */
+
+function setSuggestPrefsToFalse() {
+ Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
+ Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", false);
+}
+
+add_task(async function test_special_searches() {
+ let uri1 = NetUtil.newURI("http://url/");
+ let uri2 = NetUtil.newURI("http://url/2");
+ let uri3 = NetUtil.newURI("http://foo.bar/");
+ let uri4 = NetUtil.newURI("http://foo.bar/2");
+ let uri5 = NetUtil.newURI("http://url/star");
+ let uri6 = NetUtil.newURI("http://url/star/2");
+ let uri7 = NetUtil.newURI("http://foo.bar/star");
+ let uri8 = NetUtil.newURI("http://foo.bar/star/2");
+ let uri9 = NetUtil.newURI("http://url/tag");
+ let uri10 = NetUtil.newURI("http://url/tag/2");
+ let uri11 = NetUtil.newURI("http://foo.bar/tag");
+ let uri12 = NetUtil.newURI("http://foo.bar/tag/2");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title", transition: TRANSITION_TYPED },
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar", transition: TRANSITION_TYPED },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", transition: TRANSITION_TYPED },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri5, title: "title" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri6, title: "foo.bar" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri7, title: "title" });
+ await PlacesTestUtils.addBookmarkWithDetails({ uri: uri8, title: "foo.bar" });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri9,
+ title: "title",
+ tags: ["foo.bar"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ });
+
+ // Test restricting searches.
+
+ info("History restrict");
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.HISTORY,
+ matches: [
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info("Star restrict");
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.BOOKMARK,
+ matches: [
+ { uri: uri5, title: "title", style: ["bookmark"] },
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("Tag restrict");
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.TAG,
+ matches: [
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("Special as first word");
+ await check_autocomplete({
+ search: `${UrlbarTokenizer.RESTRICT.HISTORY} foo bar`,
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info("Special as last word");
+ await check_autocomplete({
+ search: `foo bar ${UrlbarTokenizer.RESTRICT.HISTORY}`,
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ // Test restricting and matching searches with a term.
+
+ info(`foo ${UrlbarTokenizer.RESTRICT.HISTORY} -> history`);
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.HISTORY}`,
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info(`foo ${UrlbarTokenizer.RESTRICT.BOOKMARK} -> is star`);
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.BOOKMARK}`,
+ matches: [
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info(`foo ${UrlbarTokenizer.RESTRICT.TITLE} -> in title`);
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.TITLE}`,
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ { uri: uri10, title: "foo.bar", tags: ["foo.bar"], style: ["tag"] },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ { uri: uri12, title: "foo.bar", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info(`foo ${UrlbarTokenizer.RESTRICT.URL} -> in url`);
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.URL}`,
+ matches: [
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ { uri: uri12, title: "foo.bar", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info(`foo ${UrlbarTokenizer.RESTRICT.TAG} -> is tag`);
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.TAG}`,
+ matches: [
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ // Test various pairs of special searches
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.TITLE} -> history, in title`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.TITLE}`,
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.URL} -> history, in url`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.URL}`,
+ matches: [
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.TITLE} -> is star, in title`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.TITLE}`,
+ matches: [
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.URL} -> is star, in url`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.URL}`,
+ matches: [
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.TITLE} ${UrlbarTokenizer.RESTRICT.TAG} -> in title, is tag`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.TITLE} ${UrlbarTokenizer.RESTRICT.TAG}`,
+ matches: [
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info(
+ `foo ${UrlbarTokenizer.RESTRICT.URL} ${UrlbarTokenizer.RESTRICT.TAG} -> in url, is tag`
+ );
+ await check_autocomplete({
+ search: `foo ${UrlbarTokenizer.RESTRICT.URL} ${UrlbarTokenizer.RESTRICT.TAG}`,
+ matches: [
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ // Test conflicting restrictions.
+
+ info(
+ `conflict ${UrlbarTokenizer.RESTRICT.TITLE} ${UrlbarTokenizer.RESTRICT.URL} -> url wins`
+ );
+ await PlacesTestUtils.addVisits([
+ {
+ uri: `http://conflict.com/${UrlbarTokenizer.RESTRICT.TITLE}`,
+ title: "test",
+ },
+ {
+ uri: "http://conflict.com/",
+ title: `test${UrlbarTokenizer.RESTRICT.TITLE}`,
+ },
+ ]);
+ await check_autocomplete({
+ search: `conflict ${UrlbarTokenizer.RESTRICT.TITLE} ${UrlbarTokenizer.RESTRICT.URL}`,
+ matches: [
+ {
+ uri: `http://conflict.com/${UrlbarTokenizer.RESTRICT.TITLE}`,
+ title: "test",
+ },
+ ],
+ });
+
+ info(
+ `conflict ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.BOOKMARK} -> bookmark wins`
+ );
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: "http://bookmark.conflict.com/",
+ title: `conflict ${UrlbarTokenizer.RESTRICT.HISTORY}`,
+ });
+ await check_autocomplete({
+ search: `conflict ${UrlbarTokenizer.RESTRICT.HISTORY} ${UrlbarTokenizer.RESTRICT.BOOKMARK}`,
+ matches: [
+ {
+ uri: "http://bookmark.conflict.com/",
+ title: `conflict ${UrlbarTokenizer.RESTRICT.HISTORY}`,
+ style: ["bookmark"],
+ },
+ ],
+ });
+
+ info(
+ `conflict ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.TAG} -> tag wins`
+ );
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: "http://tag.conflict.com/",
+ title: `conflict ${UrlbarTokenizer.RESTRICT.BOOKMARK}`,
+ tags: ["one"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: "http://nontag.conflict.com/",
+ title: `conflict ${UrlbarTokenizer.RESTRICT.BOOKMARK}`,
+ });
+ await check_autocomplete({
+ search: `conflict ${UrlbarTokenizer.RESTRICT.BOOKMARK} ${UrlbarTokenizer.RESTRICT.TAG}`,
+ matches: [
+ {
+ uri: "http://tag.conflict.com/",
+ title: `conflict ${UrlbarTokenizer.RESTRICT.BOOKMARK}`,
+ tags: ["one"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ // Disable autoFill for the next tests, see test_autoFill_default_behavior.js
+ // for specific tests.
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ // Test default usage by setting certain browser.urlbar.suggest.* prefs
+ info("foo -> default history");
+ setSuggestPrefsToFalse();
+ Services.prefs.setBoolPref("browser.urlbar.suggest.history", true);
+ await check_autocomplete({
+ search: "foo",
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar" },
+ { uri: uri11, title: "title", tags: ["foo.bar"], style: ["tag"] },
+ ],
+ });
+
+ info("foo -> default history, is star");
+ setSuggestPrefsToFalse();
+ Services.prefs.setBoolPref("browser.urlbar.suggest.history", true);
+ Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
+ await check_autocomplete({
+ search: "foo",
+ matches: [
+ { uri: uri2, title: "foo.bar" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "foo.bar" },
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ info("foo -> is star");
+ setSuggestPrefsToFalse();
+ Services.prefs.setBoolPref("browser.urlbar.suggest.history", false);
+ Services.prefs.setBoolPref("browser.urlbar.suggest.bookmark", true);
+ await check_autocomplete({
+ search: "foo",
+ matches: [
+ { uri: uri6, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri7, title: "title", style: ["bookmark"] },
+ { uri: uri8, title: "foo.bar", style: ["bookmark"] },
+ { uri: uri9, title: "title", tags: ["foo.bar"], style: ["bookmark-tag"] },
+ {
+ uri: uri10,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri11,
+ title: "title",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: uri12,
+ title: "foo.bar",
+ tags: ["foo.bar"],
+ style: ["bookmark-tag"],
+ },
+ ],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js b/toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js
new file mode 100644
index 0000000000..92927d6f2b
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_swap_protocol.js
@@ -0,0 +1,163 @@
+/* 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/. */
+
+/**
+ * Test bug 424717 to make sure searching with an existing location like
+ * http://site/ also matches https://site/ or ftp://site/. Same thing for
+ * ftp://site/ and https://site/.
+ *
+ * Test bug 461483 to make sure a search for "w" doesn't match the "www." from
+ * site subdomains.
+ */
+
+add_task(async function test_swap_protocol() {
+ let uri1 = NetUtil.newURI("http://www.site/");
+ let uri2 = NetUtil.newURI("http://site/");
+ let uri3 = NetUtil.newURI("ftp://ftp.site/");
+ let uri4 = NetUtil.newURI("ftp://site/");
+ let uri5 = NetUtil.newURI("https://www.site/");
+ let uri6 = NetUtil.newURI("https://site/");
+ let uri7 = NetUtil.newURI("http://woohoo/");
+ let uri8 = NetUtil.newURI("http://wwwwwwacko/");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "title" },
+ { uri: uri2, title: "title" },
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "title" },
+ { uri: uri5, title: "title" },
+ { uri: uri6, title: "title" },
+ { uri: uri7, title: "title" },
+ { uri: uri8, title: "title" },
+ ]);
+
+ // uri1 and uri2 won't appear since they are lower-ranked duplicates of uri6.
+ let allMatches = [
+ { uri: uri3, title: "title" },
+ { uri: uri4, title: "title" },
+ { uri: uri5, title: "title" },
+ { uri: uri6, title: "title" },
+ ];
+
+ // Disable autoFill to avoid handling the first result.
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+ Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
+
+ info("http://www.site matches 'www.site' pages");
+ await check_autocomplete({
+ search: "http://www.site",
+ matches: [{ uri: uri5, title: "title" }],
+ });
+
+ info("http://site matches all site");
+ await check_autocomplete({
+ search: "http://site",
+ matches: allMatches,
+ });
+
+ info("ftp://ftp.site matches itself");
+ await check_autocomplete({
+ search: "ftp://ftp.site",
+ matches: [{ uri: uri3, title: "title" }],
+ });
+
+ info("ftp://site matches all site");
+ await check_autocomplete({
+ search: "ftp://site",
+ matches: allMatches,
+ });
+
+ info("https://www.site matches all site");
+ await check_autocomplete({
+ search: "https://www.site",
+ matches: [{ uri: uri5, title: "title" }],
+ });
+
+ info("https://site matches all site");
+ await check_autocomplete({
+ search: "https://site",
+ matches: allMatches,
+ });
+
+ info("www.site matches 'www.site' pages");
+ await check_autocomplete({
+ search: "www.site",
+ matches: [{ uri: uri5, title: "title" }],
+ });
+
+ info("w matches 'w' pages, including 'www'");
+ await check_autocomplete({
+ search: "w",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri7, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://w matches 'w' pages, including 'www'");
+ await check_autocomplete({
+ search: "http://w",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri7, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://www.w matches nothing");
+ await check_autocomplete({
+ search: "http://www.w",
+ matches: [],
+ });
+
+ info("ww matches no 'ww' pages, including 'www'");
+ await check_autocomplete({
+ search: "ww",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://ww matches no 'ww' pages, including 'www'");
+ await check_autocomplete({
+ search: "http://ww",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://www.ww matches nothing");
+ await check_autocomplete({
+ search: "http://www.ww",
+ matches: [],
+ });
+
+ info("www matches 'www' pages");
+ await check_autocomplete({
+ search: "www",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://www matches 'www' pages");
+ await check_autocomplete({
+ search: "http://www",
+ matches: [
+ { uri: uri5, title: "title" },
+ { uri: uri8, title: "title" },
+ ],
+ });
+
+ info("http://www.www matches nothing");
+ await check_autocomplete({
+ search: "http://www.www",
+ matches: [],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js b/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js
new file mode 100644
index 0000000000..5cb4d790b1
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js
@@ -0,0 +1,263 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
+ * vim:set ts=2 sw=2 sts=2 et:
+ * 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/. */
+
+add_task(async function test_tab_matches() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ let uri1 = NetUtil.newURI("http://abc.com/");
+ let uri2 = NetUtil.newURI("http://xyz.net/");
+ let uri3 = NetUtil.newURI("about:mozilla");
+ let uri4 = NetUtil.newURI("data:text/html,test");
+ let uri5 = NetUtil.newURI("http://foobar.org");
+ await PlacesTestUtils.addVisits([
+ { uri: uri1, title: "ABC rocks" },
+ { uri: uri2, title: "xyz.net - we're better than ABC" },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ },
+ ]);
+ await addOpenPages(uri1, 1);
+ // Pages that cannot be registered in history.
+ await addOpenPages(uri3, 1);
+ await addOpenPages(uri4, 1);
+
+ info("basic tab match");
+ await check_autocomplete({
+ search: "abc.com",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
+ });
+
+ info("three results, one tab match");
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions",
+ matches: [
+ makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("three results, both normal results are tab matches");
+ await addOpenPages(uri2, 1);
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions",
+ matches: [
+ makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
+ makeSwitchToTabMatch("http://xyz.net/", {
+ title: "xyz.net - we're better than ABC",
+ }),
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("a container tab is not visible in 'switch to tab'");
+ await addOpenPages(uri5, 1, /* userContextId: */ 3);
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions",
+ matches: [
+ makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
+ makeSwitchToTabMatch("http://xyz.net/", {
+ title: "xyz.net - we're better than ABC",
+ }),
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info(
+ "a container tab should not see 'switch to tab' for other container tabs"
+ );
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions user-context-id:3",
+ matches: [
+ makeSwitchToTabMatch("http://foobar.org/", {
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ }),
+ { uri: uri1, title: "ABC rocks", style: ["favicon"] },
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("a different container tab should not see any 'switch to tab'");
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions user-context-id:2",
+ matches: [
+ { uri: uri1, title: "ABC rocks", style: ["favicon"] },
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info(
+ "three results, both normal results are tab matches, one has multiple tabs"
+ );
+ await addOpenPages(uri2, 5);
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions",
+ matches: [
+ makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
+ makeSwitchToTabMatch("http://xyz.net/", {
+ title: "xyz.net - we're better than ABC",
+ }),
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("three results, no tab matches (disable-private-actions)");
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions disable-private-actions",
+ matches: [
+ { uri: uri1, title: "ABC rocks", style: ["favicon"] },
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("two results (actions disabled)");
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "",
+ matches: [
+ { uri: uri1, title: "ABC rocks", style: ["favicon"] },
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("three results, no tab matches");
+ await removeOpenPages(uri1, 1);
+ await removeOpenPages(uri2, 6);
+ await check_autocomplete({
+ search: "abc",
+ searchParam: "enable-actions",
+ matches: [
+ { uri: uri1, title: "ABC rocks", style: ["favicon"] },
+ {
+ uri: uri2,
+ title: "xyz.net - we're better than ABC",
+ style: ["favicon"],
+ },
+ {
+ uri: uri5,
+ title: "foobar.org - much better than ABC, definitely better than XYZ",
+ style: ["favicon"],
+ },
+ ],
+ });
+
+ info("tab match search with restriction character");
+ await addOpenPages(uri1, 1);
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
+ });
+
+ info("tab match with not-addable pages");
+ await check_autocomplete({
+ search: "mozilla",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("about:mozilla")],
+ });
+
+ info("tab match with not-addable pages, no boundary search");
+ await check_autocomplete({
+ search: "ut:mo",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("about:mozilla")],
+ });
+
+ info("tab match with not-addable pages and restriction character");
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("about:mozilla")],
+ });
+
+ info("tab match with not-addable pages and only restriction character");
+ await check_autocomplete({
+ search: UrlbarTokenizer.RESTRICT.OPENPAGE,
+ searchParam: "enable-actions",
+ matches: [
+ makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" }),
+ makeSwitchToTabMatch("about:mozilla"),
+ makeSwitchToTabMatch("data:text/html,test"),
+ ],
+ });
+
+ info("tab match should not return tags as part of the title");
+ // Bookmark one of the pages, and add tags to it, to check they don't appear
+ // in the title.
+ let bm = await PlacesUtils.bookmarks.insert({
+ url: uri1,
+ parentGuid: PlacesUtils.bookmarks.toolbarGuid,
+ });
+ PlacesUtils.tagging.tagURI(uri1, ["test-tag"]);
+ await check_autocomplete({
+ search: "abc.com",
+ searchParam: "enable-actions",
+ matches: [makeSwitchToTabMatch("http://abc.com/", { title: "ABC rocks" })],
+ });
+ await PlacesUtils.bookmarks.remove(bm);
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js b/toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js
new file mode 100644
index 0000000000..6d417e758d
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/test_word_boundary_search.js
@@ -0,0 +1,266 @@
+/* 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/. */
+
+/**
+ * Test to make sure matches against the url, title, tags are first made on word
+ * boundaries, instead of in the middle of words, and later are extended to the
+ * whole words. For this test it is critical to check sorting of the matches.
+ *
+ * Make sure we don't try matching one after a CamelCase because the upper-case
+ * isn't really a word boundary. (bug 429498)
+ */
+
+var katakana = ["\u30a8", "\u30c9"]; // E, Do
+var ideograph = ["\u4efb", "\u5929", "\u5802"]; // Nin Ten Do
+
+add_task(async function test_escape() {
+ Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", false);
+ Services.prefs.setBoolPref("browser.urlbar.autoFill", false);
+
+ await PlacesTestUtils.addVisits([
+ { uri: "http://matchme/", title: "title1" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://tag/1", title: "title1" },
+ { uri: "http://tag/2", title: "title1" },
+ { uri: "http://crazytitle/", title: "!@#$%^&*()_+{}|:<>?word" },
+ { uri: "http://katakana/", title: katakana.join("") },
+ { uri: "http://ideograph/", title: ideograph.join("") },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ ]);
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ });
+ await PlacesTestUtils.addBookmarkWithDetails({
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ });
+
+ info("Match 'match' at the beginning or after / or on a CamelCase");
+ await check_autocomplete({
+ search: "match",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://matchme/", title: "title1" },
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ ],
+ });
+
+ info("Match 'dont' at the beginning or after /");
+ await check_autocomplete({
+ search: "dont",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ ],
+ });
+
+ info("Match 'match' at the beginning or after / or on a CamelCase");
+ await check_autocomplete({
+ search: "2",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://title/1", title: "matchme2" },
+ ],
+ });
+
+ info("Match 't' at the beginning or after /");
+ await check_autocomplete({
+ search: "t",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ { uri: "http://matchme/", title: "title1" },
+ { uri: "http://katakana/", title: katakana.join("") },
+ { uri: "http://crazytitle/", title: "!@#$%^&*()_+{}|:<>?word" },
+ ],
+ });
+
+ info("Match 'word' after many consecutive word boundaries");
+ await check_autocomplete({
+ search: "word",
+ checkSorting: true,
+ matches: [{ uri: "http://crazytitle/", title: "!@#$%^&*()_+{}|:<>?word" }],
+ });
+
+ info("Match a word boundary '/' for everything");
+ await check_autocomplete({
+ search: "/",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ { uri: "http://ideograph/", title: ideograph.join("") },
+ { uri: "http://katakana/", title: katakana.join("") },
+ { uri: "http://crazytitle/", title: "!@#$%^&*()_+{}|:<>?word" },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ { uri: "http://matchme/", title: "title1" },
+ ],
+ });
+
+ info("Match word boundaries '()_' that are among word boundaries");
+ await check_autocomplete({
+ search: "()_",
+ checkSorting: true,
+ matches: [{ uri: "http://crazytitle/", title: "!@#$%^&*()_+{}|:<>?word" }],
+ });
+
+ info("Katakana characters form a string, so match the beginning");
+ await check_autocomplete({
+ search: katakana[0],
+ checkSorting: true,
+ matches: [{ uri: "http://katakana/", title: katakana.join("") }],
+ });
+
+ /*
+ info("Middle of a katakana word shouldn't be matched");
+ await check_autocomplete({
+ search: katakana[1],
+ matches: [ ],
+ });
+*/
+
+ info("Ideographs are treated as words so 'nin' is one word");
+ await check_autocomplete({
+ search: ideograph[0],
+ checkSorting: true,
+ matches: [{ uri: "http://ideograph/", title: ideograph.join("") }],
+ });
+
+ info("Ideographs are treated as words so 'ten' is another word");
+ await check_autocomplete({
+ search: ideograph[1],
+ checkSorting: true,
+ matches: [{ uri: "http://ideograph/", title: ideograph.join("") }],
+ });
+
+ info("Ideographs are treated as words so 'do' is yet another word");
+ await check_autocomplete({
+ search: ideograph[2],
+ checkSorting: true,
+ matches: [{ uri: "http://ideograph/", title: ideograph.join("") }],
+ });
+
+ info("Match in the middle. Should just be sorted by frecency.");
+ await check_autocomplete({
+ search: "ch",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ { uri: "http://matchme/", title: "title1" },
+ ],
+ });
+
+ // Also this test should just be sorted by frecency.
+ info(
+ "Don't match one character after a camel-case word boundary (bug 429498). Should just be sorted by frecency."
+ );
+ await check_autocomplete({
+ search: "atch",
+ checkSorting: true,
+ matches: [
+ {
+ uri: "http://tag/2",
+ title: "title1",
+ tags: ["dontmatchme3"],
+ style: ["bookmark-tag"],
+ },
+ {
+ uri: "http://tag/1",
+ title: "title1",
+ tags: ["matchme2"],
+ style: ["bookmark-tag"],
+ },
+ { uri: "http://camel/pleaseMatchMe/", title: "title1" },
+ { uri: "http://title/2", title: "dontmatchme3" },
+ { uri: "http://title/1", title: "matchme2" },
+ { uri: "http://dontmatchme/", title: "title1" },
+ { uri: "http://matchme/", title: "title1" },
+ ],
+ });
+
+ await cleanup();
+});
diff --git a/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
new file mode 100644
index 0000000000..cf80015682
--- /dev/null
+++ b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini
@@ -0,0 +1,33 @@
+[DEFAULT]
+head = head_autocomplete.js
+skip-if = toolkit == "android" || appname == "thunderbird"
+firefox-appdir = browser
+support-files =
+ data/engine-rel-searchform.xml
+ data/engine-suggestions.xml
+ !/toolkit/components/places/tests/favicons/favicon-normal16.png
+
+[test_416211.js]
+[test_416214.js]
+[test_417798.js]
+[test_418257.js]
+[test_422277.js]
+[test_autocomplete_stopSearch_no_throw.js]
+[test_do_not_trim.js]
+[test_download_embed_bookmarks.js]
+[test_empty_search.js]
+[test_escape_self.js]
+[test_history_autocomplete_tags.js]
+[test_ignore_protocol.js]
+[test_keyword_search.js]
+[test_keyword_search_actions.js]
+[test_multi_word_search.js]
+[test_preloaded_sites.js]
+[test_remote_tab_matches.js]
+skip-if = !sync
+[test_search_engine_alias.js]
+[test_search_engine_restyle.js]
+[test_special_search.js]
+[test_swap_protocol.js]
+[test_tab_matches.js]
+[test_word_boundary_search.js]