From 2fbc75fa69e0b7f7e50c74fbad9d3075f1aa9a03 Mon Sep 17 00:00:00 2001 From: Marco Bonardo Date: Wed, 11 Dec 2019 16:52:09 +0000 Subject: [PATCH] Bug 1599840 - part 2 - Set restricting behavior based on QueryContext sources. r=adw Differential Revision: https://phabricator.services.mozilla.com/D56354 --- .../urlbar/UrlbarProviderOpenTabs.jsm | 8 +- .../urlbar/UrlbarProvidersManager.jsm | 4 + browser/components/urlbar/UrlbarUtils.jsm | 20 ++--- browser/components/urlbar/tests/unit/head.js | 18 ++-- .../test_UrlbarQueryContext_restrictSource.js | 90 +++++++++++++++++++ .../components/urlbar/tests/unit/xpcshell.ini | 1 + toolkit/components/places/UnifiedComplete.jsm | 46 ++++++++-- .../unifiedcomplete/head_autocomplete.js | 8 +- .../unifiedcomplete/test_empty_search.js | 2 +- .../test_remote_tab_matches.js | 2 +- .../tests/unifiedcomplete/test_tab_matches.js | 24 +++-- .../places/tests/unifiedcomplete/xpcshell.ini | 1 - 12 files changed, 180 insertions(+), 44 deletions(-) create mode 100644 browser/components/urlbar/tests/unit/test_UrlbarQueryContext_restrictSource.js diff --git a/browser/components/urlbar/UrlbarProviderOpenTabs.jsm b/browser/components/urlbar/UrlbarProviderOpenTabs.jsm index f25d068cc088..b77c5348c0d3 100644 --- a/browser/components/urlbar/UrlbarProviderOpenTabs.jsm +++ b/browser/components/urlbar/UrlbarProviderOpenTabs.jsm @@ -126,13 +126,13 @@ class ProviderOpenTabs extends UrlbarProvider { * @param {string} url Address of the tab * @param {integer} userContextId Containers user context id */ - registerOpenTab(url, userContextId = 0) { + async registerOpenTab(url, userContextId = 0) { if (!this.openTabs.has(userContextId)) { this.openTabs.set(userContextId, []); } this.openTabs.get(userContextId).push(url); if (this._db) { - addToMemoryTable(this._db, url, userContextId); + await addToMemoryTable(this._db, url, userContextId); } } @@ -141,14 +141,14 @@ class ProviderOpenTabs extends UrlbarProvider { * @param {string} url Address of the tab * @param {integer} userContextId Containers user context id */ - unregisterOpenTab(url, userContextId = 0) { + async unregisterOpenTab(url, userContextId = 0) { let openTabs = this.openTabs.get(userContextId); if (openTabs) { let index = openTabs.indexOf(url); if (index != -1) { openTabs.splice(index, 1); if (this._db) { - removeFromMemoryTable(this._db, url, userContextId); + await removeFromMemoryTable(this._db, url, userContextId); } } } diff --git a/browser/components/urlbar/UrlbarProvidersManager.jsm b/browser/components/urlbar/UrlbarProvidersManager.jsm index 081c47a7fbb1..75a7a9b05b2a 100644 --- a/browser/components/urlbar/UrlbarProvidersManager.jsm +++ b/browser/components/urlbar/UrlbarProvidersManager.jsm @@ -168,6 +168,10 @@ class ProvidersManager { // Apply tokenization. UrlbarTokenizer.tokenize(queryContext); + // If there's a single source, we are in restriction mode. + if (queryContext.sources && queryContext.sources.length == 1) { + queryContext.restrictSource = queryContext.sources[0]; + } // Providers can use queryContext.sources to decide whether they want to be // invoked or not. updateSourcesIfEmpty(queryContext); diff --git a/browser/components/urlbar/UrlbarUtils.jsm b/browser/components/urlbar/UrlbarUtils.jsm index 12aa374effdb..f983b5b3a4f2 100644 --- a/browser/components/urlbar/UrlbarUtils.jsm +++ b/browser/components/urlbar/UrlbarUtils.jsm @@ -559,18 +559,18 @@ class UrlbarQueryContext { ); } - if ( - options.providers && - (!Array.isArray(options.providers) || !options.providers.length) - ) { - throw new Error(`Invalid providers list`); + if (options.providers) { + if (!Array.isArray(options.providers) || !options.providers.length) { + throw new Error(`Invalid providers list`); + } + this.providers = options.providers; } - if ( - options.sources && - (!Array.isArray(options.sources) || !options.sources.length) - ) { - throw new Error(`Invalid sources list`); + if (options.sources) { + if (!Array.isArray(options.sources) || !options.sources.length) { + throw new Error(`Invalid sources list`); + } + this.sources = options.sources; } this.lastResultCount = 0; diff --git a/browser/components/urlbar/tests/unit/head.js b/browser/components/urlbar/tests/unit/head.js index ca4e4ea6d141..da9fa47877b4 100644 --- a/browser/components/urlbar/tests/unit/head.js +++ b/browser/components/urlbar/tests/unit/head.js @@ -43,13 +43,17 @@ const { sinon } = ChromeUtils.import("resource://testing-common/Sinon.jsm"); * required options. */ function createContext(searchString = "foo", properties = {}) { - let context = new UrlbarQueryContext({ - allowAutofill: UrlbarPrefs.get("autoFill"), - isPrivate: true, - maxResults: UrlbarPrefs.get("maxRichResults"), - searchString, - }); - return Object.assign(context, properties); + return new UrlbarQueryContext( + Object.assign( + { + allowAutofill: UrlbarPrefs.get("autoFill"), + isPrivate: true, + maxResults: UrlbarPrefs.get("maxRichResults"), + searchString, + }, + properties + ) + ); } /** diff --git a/browser/components/urlbar/tests/unit/test_UrlbarQueryContext_restrictSource.js b/browser/components/urlbar/tests/unit/test_UrlbarQueryContext_restrictSource.js new file mode 100644 index 000000000000..b851fb771668 --- /dev/null +++ b/browser/components/urlbar/tests/unit/test_UrlbarQueryContext_restrictSource.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/. */ + +/** + * Test for restrictions set through UrlbarQueryContext.sources. + */ + +add_task(async function setup() { + Services.prefs.setBoolPref("browser.urlbar.geoSpecificDefaults", false); + let engine = await addTestSuggestionsEngine(); + let oldDefaultEngine = await Services.search.getDefault(); + Services.search.setDefault(engine); + registerCleanupFunction(async () => + Services.search.setDefault(oldDefaultEngine) + ); +}); + +XPCOMUtils.defineLazyServiceGetter( + this, + "unifiedComplete", + "@mozilla.org/autocomplete/search;1?name=unifiedcomplete", + "nsIAutoCompleteSearch" +); + +add_task(async function test_restrictions() { + await PlacesTestUtils.addVisits([ + { uri: "http://history.com/", title: "match" }, + ]); + await PlacesUtils.bookmarks.insert({ + url: "http://bookmark.com/", + parentGuid: PlacesUtils.bookmarks.unfiledGuid, + title: "match", + }); + await UrlbarProviderOpenTabs.registerOpenTab("http://openpagematch.com/"); + + info("Bookmark restrict"); + let results = await get_results({ + sources: [UrlbarUtils.RESULT_SOURCE.BOOKMARKS], + searchString: "match", + }); + // Skip the heuristic result. + Assert.deepEqual(results.filter(r => !r.heuristic).map(r => r.payload.url), [ + "http://bookmark.com/", + ]); + + info("History restrict"); + results = await get_results({ + sources: [UrlbarUtils.RESULT_SOURCE.HISTORY], + searchString: "match", + }); + // Skip the heuristic result. + Assert.deepEqual(results.filter(r => !r.heuristic).map(r => r.payload.url), [ + "http://history.com/", + ]); + + info("tabs restrict"); + results = await get_results({ + sources: [UrlbarUtils.RESULT_SOURCE.TABS], + searchString: "match", + }); + // Skip the heuristic result. + Assert.deepEqual(results.filter(r => !r.heuristic).map(r => r.payload.url), [ + "http://openpagematch.com/", + ]); + + info("search restrict"); + results = await get_results({ + sources: [UrlbarUtils.RESULT_SOURCE.SEARCH], + searchString: "match", + }); + // Heuristic, private window, 2 suggestions. + Assert.deepEqual( + results.map(r => r.payload.engine), + new Array(4).fill("engine-suggestions.xml") + ); +}); + +async function get_results(test) { + let controller = UrlbarTestUtils.newMockController(); + let queryContext = createContext(test.searchString, { + allowAutofill: false, + isPrivate: false, + maxResults: 10, + sources: test.sources, + }); + await controller.startQuery(queryContext); + info(JSON.stringify(queryContext.results)); + return queryContext.results; +} diff --git a/browser/components/urlbar/tests/unit/xpcshell.ini b/browser/components/urlbar/tests/unit/xpcshell.ini index e9f78f974d1f..089184b8755a 100644 --- a/browser/components/urlbar/tests/unit/xpcshell.ini +++ b/browser/components/urlbar/tests/unit/xpcshell.ini @@ -15,6 +15,7 @@ support-files = [test_UrlbarController_telemetry.js] [test_UrlbarController_integration.js] [test_UrlbarQueryContext.js] +[test_UrlbarQueryContext_restrictSource.js] [test_UrlbarUtils_addToUrlbarHistory.js] [test_UrlbarUtils_getShortcutOrURIAndPostData.js] [test_UrlbarUtils_getTokenMatches.js] diff --git a/toolkit/components/places/UnifiedComplete.jsm b/toolkit/components/places/UnifiedComplete.jsm index 4b8e11c4fbd1..9f6dbc538507 100644 --- a/toolkit/components/places/UnifiedComplete.jsm +++ b/toolkit/components/places/UnifiedComplete.jsm @@ -454,6 +454,15 @@ XPCOMUtils.defineLazyGetter(this, "typeToBehaviorMap", () => { ]); }); +XPCOMUtils.defineLazyGetter(this, "sourceToBehaviorMap", () => { + return new Map([ + [UrlbarUtils.RESULT_SOURCE.HISTORY, "history"], + [UrlbarUtils.RESULT_SOURCE.BOOKMARKS, "bookmark"], + [UrlbarUtils.RESULT_SOURCE.TABS, "openpage"], + [UrlbarUtils.RESULT_SOURCE.SEARCH, "search"], + ]); +}); + // Helper functions /** @@ -721,7 +730,28 @@ function Search( } } - this._searchTokens = this.filterTokens(tokens); + // The behavior can be set through: + // 1. a specific restrictSource in the QueryContext + // 2. typed restriction tokens + if ( + queryContext && + queryContext.restrictSource && + sourceToBehaviorMap.has(queryContext.restrictSource) + ) { + this._searchTokens = tokens; + this._behavior = 0; + this.setBehavior("restrict"); + this.setBehavior(sourceToBehaviorMap.get(queryContext.restrictSource)); + } else { + this._searchTokens = this.filterTokens(tokens); + } + + // Set the right JavaScript behavior based on our preference. Note that the + // preference is whether or not we should filter JavaScript, and the + // behavior is if we should search it or not. + if (!UrlbarPrefs.get("filter.javascript")) { + this.setBehavior("javascript"); + } // The heuristic token is the first filtered search token, but only when it's // actually the first thing in the search string. If a prefix or restriction @@ -895,12 +925,6 @@ Search.prototype = { } } } - // Set the right JavaScript behavior based on our preference. Note that the - // preference is whether or not we should filter JavaScript, and the - // behavior is if we should search it or not. - if (!UrlbarPrefs.get("filter.javascript")) { - this.setBehavior("javascript"); - } return filtered; }, @@ -1157,7 +1181,7 @@ Search.prototype = { } queries.push(this._searchQuery); - // Finally run all the other queries. + // Finally run all the remaining queries. for (let [query, params] of queries) { await conn.executeCached(query, params, this._onResultRow.bind(this)); if (!this.pending) { @@ -1194,7 +1218,11 @@ Search.prototype = { this._counts[UrlbarUtils.RESULT_GROUP.HEURISTIC]; if (count < this._maxResults) { this._matchBehavior = Ci.mozIPlacesAutoComplete.MATCH_ANYWHERE; - for (let [query, params] of [this._adaptiveQuery, this._searchQuery]) { + let queries = [this._adaptiveQuery, this._searchQuery]; + if (this.hasBehavior("openpage")) { + queries.unshift(this._switchToTabQuery); + } + for (let [query, params] of queries) { await conn.executeCached(query, params, this._onResultRow.bind(this)); if (!this.pending) { return; diff --git a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js index 3b4f422837cb..0278a5c135da 100644 --- a/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js +++ b/toolkit/components/places/tests/unifiedcomplete/head_autocomplete.js @@ -408,15 +408,15 @@ var addBookmark = async function(aBookmarkObj) { } }; -function addOpenPages(aUri, aCount = 1, aUserContextId = 0) { +async function addOpenPages(aUri, aCount = 1, aUserContextId = 0) { for (let i = 0; i < aCount; i++) { - UrlbarProviderOpenTabs.registerOpenTab(aUri.spec, aUserContextId); + await UrlbarProviderOpenTabs.registerOpenTab(aUri.spec, aUserContextId); } } -function removeOpenPages(aUri, aCount = 1, aUserContextId = 0) { +async function removeOpenPages(aUri, aCount = 1, aUserContextId = 0) { for (let i = 0; i < aCount; i++) { - UrlbarProviderOpenTabs.unregisterOpenTab(aUri.spec, aUserContextId); + await UrlbarProviderOpenTabs.unregisterOpenTab(aUri.spec, aUserContextId); } } diff --git a/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js b/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js index 029dafb47d59..91d282dd24ec 100644 --- a/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js +++ b/toolkit/components/places/tests/unifiedcomplete/test_empty_search.js @@ -30,7 +30,7 @@ add_task(async function test_javascript_match() { await addBookmark({ uri: uri5, title: "title" }); await addBookmark({ uri: uri6, title: "title" }); - addOpenPages(uri7, 1); + await addOpenPages(uri7, 1); // Now remove page 6 from history, so it is an unvisited bookmark. await PlacesUtils.history.remove(uri6); diff --git a/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js index 4eb24fb7a5b8..74dabcf1eeed 100644 --- a/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js +++ b/toolkit/components/places/tests/unifiedcomplete/test_remote_tab_matches.js @@ -238,7 +238,7 @@ add_task(async function test_localtab_matches_override() { // Setup Places to think the tab is open locally. let uri = NetUtil.newURI("http://foo.com/"); await PlacesTestUtils.addVisits([{ uri, title: "An Example" }]); - addOpenPages(uri, 1); + await addOpenPages(uri, 1); await check_autocomplete({ search: "ex", diff --git a/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js b/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js index 6cc4f8e2137c..42c3b566a866 100644 --- a/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js +++ b/toolkit/components/places/tests/unifiedcomplete/test_tab_matches.js @@ -20,10 +20,10 @@ add_task(async function test_tab_matches() { title: "foobar.org - much better than ABC, definitely better than XYZ", }, ]); - addOpenPages(uri1, 1); + await addOpenPages(uri1, 1); // Pages that cannot be registered in history. - addOpenPages(uri3, 1); - addOpenPages(uri4, 1); + await addOpenPages(uri3, 1); + await addOpenPages(uri4, 1); info("two results, normal result is a tab match"); await check_autocomplete({ @@ -57,7 +57,7 @@ add_task(async function test_tab_matches() { }); info("three results, both normal results are tab matches"); - addOpenPages(uri2, 1); + await addOpenPages(uri2, 1); await check_autocomplete({ search: "abc", searchParam: "enable-actions", @@ -76,7 +76,7 @@ add_task(async function test_tab_matches() { }); info("a container tab is not visible in 'switch to tab'"); - addOpenPages(uri5, 1, /* userContextId: */ 3); + await addOpenPages(uri5, 1, /* userContextId: */ 3); await check_autocomplete({ search: "abc", searchParam: "enable-actions", @@ -137,7 +137,7 @@ add_task(async function test_tab_matches() { info( "three results, both normal results are tab matches, one has multiple tabs" ); - addOpenPages(uri2, 5); + await addOpenPages(uri2, 5); await check_autocomplete({ search: "abc", searchParam: "enable-actions", @@ -217,7 +217,7 @@ add_task(async function test_tab_matches() { }); info("tab match search with restriction character"); - addOpenPages(uri1, 1); + await addOpenPages(uri1, 1); await check_autocomplete({ search: UrlbarTokenizer.RESTRICT.OPENPAGE + " abc", searchParam: "enable-actions", @@ -240,6 +240,16 @@ add_task(async function test_tab_matches() { ], }); + info("tab match with not-addable pages, no boundary search"); + await check_autocomplete({ + search: "ut:mo", + searchParam: "enable-actions", + matches: [ + makeSearchMatch("ut:mo", { heuristic: true }), + makeSwitchToTabMatch("about:mozilla"), + ], + }); + info("tab match with not-addable pages and restriction character"); await check_autocomplete({ search: UrlbarTokenizer.RESTRICT.OPENPAGE + " mozilla", diff --git a/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini index 661d06688ad0..91935216bf88 100644 --- a/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini +++ b/toolkit/components/places/tests/unifiedcomplete/xpcshell.ini @@ -38,7 +38,6 @@ support-files = [test_keywords.js] [test_multi_word_search.js] [test_PlacesSearchAutocompleteProvider.js] -skip-if = appname == "thunderbird" [test_preloaded_sites.js] [test_query_url.js] [test_remote_tab_matches.js]