Backed out 6 changesets (bug 1648468) for perma failures on browser_test_focus_urlbar.js. CLOSED TREE

Backed out changeset 60b6915e8037 (bug 1648468)
Backed out changeset fc7a6b8f84a2 (bug 1648468)
Backed out changeset 97c7475abf85 (bug 1648468)
Backed out changeset bb37a0821844 (bug 1648468)
Backed out changeset 10447a3e04ff (bug 1648468)
Backed out changeset 69a210ce0e9a (bug 1648468)
This commit is contained in:
Razvan Maries 2020-07-12 01:31:42 +03:00
Родитель 2ae63de7b8
Коммит 911baac099
46 изменённых файлов: 4173 добавлений и 6043 удалений

Просмотреть файл

@ -337,9 +337,6 @@ async function runTipTests() {
),
];
// Ensure the tip appears in the expected position.
matches[1].suggestedIndex = 2;
let provider = new TipTestProvider(matches);
UrlbarProvidersManager.registerProvider(provider);

Просмотреть файл

@ -48,8 +48,6 @@ const heuristicOrder = [
"UrlbarProviderSearchTips",
"Omnibox",
"UnifiedComplete",
"Autofill",
"TokenAliasEngines",
"HeuristicFallback",
];
/**
@ -76,6 +74,8 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
*
* @param {UrlbarQueryContext} context
* The query context.
* @returns {boolean} If results were successfully sorted. This return value
* is a stopgap and can be removed when bug 1648468 lands.
*/
sort(context) {
// This method is called multiple times per keystroke, so it should be as
@ -131,17 +131,21 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
let resultsWithSuggestedIndex = [];
let formHistoryResults = new Set();
let formHistorySuggestions = new Set();
// Used to deduped URLs based on their stripped prefix and title. Schema:
// {string} strippedUrl => {prefix, title, rank}
let strippedUrlToTopPrefixAndTitle = new Map();
let maxFormHistoryCount = Math.min(
UrlbarPrefs.get("maxHistoricalSearchSuggestions"),
context.maxResults
);
let hasUnifiedComplete = false;
// Do the first pass through the results. We only collect info for the
// second pass here.
for (let result of context.results) {
// Keep track of whether UnifiedComplete has returned results. We will
// quit early if it hasn't.
if (result.providerName == "UnifiedComplete") {
hasUnifiedComplete = true;
}
// The "Search in a Private Window" result should only be shown when there
// are other results and all of them are searches. It should not be shown
// if the user typed an alias because that's an explicit engine choice.
@ -180,28 +184,16 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
) {
canShowTailSuggestions = false;
}
}
if (result.type == UrlbarUtils.RESULT_TYPE.URL && result.payload.url) {
let [strippedUrl, prefix] = UrlbarUtils.stripPrefixAndTrim(
result.payload.url,
{
stripHttp: true,
stripHttps: true,
stripWww: true,
trimEmptyQuery: true,
}
);
let prefixRank = UrlbarUtils.getPrefixRank(prefix);
let topPrefixData = strippedUrlToTopPrefixAndTitle.get(strippedUrl);
let topPrefixRank = topPrefixData ? topPrefixData.rank : -1;
if (topPrefixRank < prefixRank) {
strippedUrlToTopPrefixAndTitle.set(strippedUrl, {
prefix,
title: result.payload.title,
rank: prefixRank,
});
}
}
// Quit early if we're still waiting on UnifiedComplete. If it turns out
// UnifiedComplete doesn't need to return any results, it will call sort()
// regardless to unblock showing results.
if (
!hasUnifiedComplete &&
context.pendingHeuristicProviders.has("UnifiedComplete")
) {
return false;
}
// Do the second pass through results to build the list of unsorted results.
@ -212,62 +204,6 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
continue;
}
// We expect UnifiedComplete sent us the highest-ranked www. and non-www
// origins, if any. Now, compare them to each other and to the heuristic
// result.
// 1. If the heuristic result is lower ranked than both, discard the www
// origin, unless it has a different page title than the non-www
// origin. This is a guard against deduping when www.site.com and
// site.com have different content.
// 2. If the heuristic result is higher than either the www origin or
// non-www origin:
// 2a. If the heuristic is a www origin, discard the non-www origin.
// 2b. If the heuristic is a non-www origin, discard the www origin.
if (
!result.heuristic &&
result.type == UrlbarUtils.RESULT_TYPE.URL &&
result.payload.url
) {
let [strippedUrl, prefix] = UrlbarUtils.stripPrefixAndTrim(
result.payload.url,
{
stripHttp: true,
stripHttps: true,
stripWww: true,
trimEmptyQuery: true,
}
);
let topPrefixData = strippedUrlToTopPrefixAndTitle.get(strippedUrl);
// We don't expect completely identical URLs in the results at this
// point, so if the prefixes are the same, then we're deduping a result
// against itself.
if (topPrefixData && prefix != topPrefixData.prefix) {
let prefixRank = UrlbarUtils.getPrefixRank(prefix);
if (
topPrefixData.rank > prefixRank &&
prefix.endsWith("www.") == topPrefixData.prefix.endsWith("www.")
) {
continue;
} else if (
topPrefixData.rank > prefixRank &&
result.payload?.title == topPrefixData.title
) {
continue;
}
}
}
// Exclude results that dupe autofill.
if (
context.heuristicResult &&
context.heuristicResult.providerName == "Autofill" &&
result.providerName != "Autofill" &&
context.heuristicResult.payload?.url == result.payload.url &&
context.heuristicResult.type == result.type
) {
continue;
}
// Exclude "Search in a Private Window" as determined in the first pass.
if (
result.type == UrlbarUtils.RESULT_TYPE.SEARCH &&
@ -389,6 +325,7 @@ class MuxerUnifiedComplete extends UrlbarMuxer {
}
context.results = sortedResults;
return true;
}
/**

Просмотреть файл

@ -1,755 +0,0 @@
/* 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/. */
"use strict";
/**
* This module exports a provider that provides an autofill result.
*/
var EXPORTED_SYMBOLS = ["UrlbarProviderAutofill"];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
AboutPagesUtils: "resource://gre/modules/AboutPagesUtils.jsm",
PlacesUtils: "resource://gre/modules/PlacesUtils.jsm",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
});
// Sqlite result row index constants.
const QUERYINDEX = {
QUERYTYPE: 0,
URL: 1,
TITLE: 2,
BOOKMARKED: 3,
BOOKMARKTITLE: 4,
TAGS: 5,
VISITCOUNT: 6,
TYPED: 7,
PLACEID: 8,
SWITCHTAB: 9,
FRECENCY: 10,
};
// Result row indexes for originQuery()
const QUERYINDEX_ORIGIN = {
AUTOFILLED_VALUE: 1,
URL: 2,
FRECENCY: 3,
};
// Result row indexes for urlQuery()
const QUERYINDEX_URL = {
URL: 1,
STRIPPED_URL: 2,
FRECENCY: 3,
};
// AutoComplete query type constants.
// Describes the various types of queries that we can process rows for.
const QUERYTYPE = {
FILTERED: 0,
AUTOFILL_ORIGIN: 1,
AUTOFILL_URL: 2,
ADAPTIVE: 3,
};
// `WITH` clause for the autofill queries. autofill_frecency_threshold.value is
// the mean of all moz_origins.frecency values + stddevMultiplier * one standard
// deviation. This is inlined directly in the SQL (as opposed to being a custom
// Sqlite function for example) in order to be as efficient as possible.
const SQL_AUTOFILL_WITH = `
WITH
frecency_stats(count, sum, squares) AS (
SELECT
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_count') AS REAL),
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_sum') AS REAL),
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_sum_of_squares') AS REAL)
),
autofill_frecency_threshold(value) AS (
SELECT
CASE count
WHEN 0 THEN 0.0
WHEN 1 THEN sum
ELSE (sum / count) + (:stddevMultiplier * sqrt((squares - ((sum * sum) / count)) / count))
END
FROM frecency_stats
)
`;
const SQL_AUTOFILL_FRECENCY_THRESHOLD = `host_frecency >= (
SELECT value FROM autofill_frecency_threshold
)`;
function originQuery({ select = "", where = "", having = "" }) {
return `${SQL_AUTOFILL_WITH}
SELECT :query_type,
fixed_up_host || '/',
IFNULL(:prefix, prefix) || moz_origins.host || '/',
frecency,
bookmarked,
id
FROM (
SELECT host,
host AS fixed_up_host,
TOTAL(frecency) AS host_frecency,
(
SELECT TOTAL(foreign_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS bookmarked
${select}
FROM moz_origins
WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
${where}
GROUP BY host
HAVING ${having}
UNION ALL
SELECT host,
fixup_url(host) AS fixed_up_host,
TOTAL(frecency) AS host_frecency,
(
SELECT TOTAL(foreign_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS bookmarked
${select}
FROM moz_origins
WHERE host BETWEEN 'www.' || :searchString AND 'www.' || :searchString || X'FFFF'
${where}
GROUP BY host
HAVING ${having}
) AS grouped_hosts
JOIN moz_origins ON moz_origins.host = grouped_hosts.host
ORDER BY frecency DESC, id DESC
LIMIT 1 `;
}
function urlQuery(where1, where2) {
// We limit the search to places that are either bookmarked or have a frecency
// over some small, arbitrary threshold (20) in order to avoid scanning as few
// rows as possible. Keep in mind that we run this query every time the user
// types a key when the urlbar value looks like a URL with a path.
return `/* do not warn (bug no): cannot use an index to sort */
SELECT :query_type,
url,
:strippedURL,
frecency,
foreign_count > 0 AS bookmarked,
visit_count > 0 AS visited,
id
FROM moz_places
WHERE rev_host = :revHost
${where1}
UNION ALL
SELECT :query_type,
url,
:strippedURL,
frecency,
foreign_count > 0 AS bookmarked,
visit_count > 0 AS visited,
id
FROM moz_places
WHERE rev_host = :revHost || 'www.'
${where2}
ORDER BY frecency DESC, id DESC
LIMIT 1 `;
}
// Queries
const QUERY_ORIGIN_HISTORY_BOOKMARK = originQuery({
having: `bookmarked OR ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_PREFIX_HISTORY_BOOKMARK = originQuery({
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `bookmarked OR ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_HISTORY = originQuery({
select: `, (
SELECT TOTAL(visit_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS visited`,
having: `visited AND ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_PREFIX_HISTORY = originQuery({
select: `, (
SELECT TOTAL(visit_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS visited`,
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `visited AND ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_BOOKMARK = originQuery({
having: `bookmarked`,
});
const QUERY_ORIGIN_PREFIX_BOOKMARK = originQuery({
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `bookmarked`,
});
const QUERY_URL_HISTORY_BOOKMARK = urlQuery(
`AND (bookmarked OR frecency > 20)
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND (bookmarked OR frecency > 20)
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_HISTORY_BOOKMARK = urlQuery(
`AND (bookmarked OR frecency > 20)
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND (bookmarked OR frecency > 20)
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_HISTORY = urlQuery(
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_HISTORY = urlQuery(
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_BOOKMARK = urlQuery(
`AND bookmarked
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND bookmarked
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_BOOKMARK = urlQuery(
`AND bookmarked
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND bookmarked
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
const kProtocolsWithIcons = [
"chrome:",
"moz-extension:",
"about:",
"http:",
"https:",
"ftp:",
];
function iconHelper(url) {
if (typeof url == "string") {
return kProtocolsWithIcons.some(p => url.startsWith(p))
? "page-icon:" + url
: UrlbarUtils.ICON.DEFAULT;
}
if (url && url instanceof URL && kProtocolsWithIcons.includes(url.protocol)) {
return "page-icon:" + url.href;
}
return UrlbarUtils.ICON.DEFAULT;
}
/**
* Class used to create the provider.
*/
class ProviderAutofill extends UrlbarProvider {
constructor() {
super();
// Maps the running queries by queryContext.
this.queries = new Map();
}
/**
* Returns the name of this provider.
* @returns {string} the name of this provider.
*/
get name() {
return "Autofill";
}
/**
* Returns the type of this provider.
* @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
*/
get type() {
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
}
/**
* Whether this provider should be invoked for the given context.
* If this method returns false, the providers manager won't start a query
* with this provider, to save on resources.
* @param {UrlbarQueryContext} queryContext The query context object
* @returns {boolean} Whether this provider should be invoked for the search.
*/
async isActive(queryContext) {
// First of all, check for the autoFill pref.
if (!UrlbarPrefs.get("autoFill")) {
return false;
}
if (!queryContext.allowAutofill) {
return false;
}
if (queryContext.tokens.length != 1) {
return false;
}
// autoFill can only cope with history, bookmarks, and about: entries.
if (
!queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.HISTORY) &&
!queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.BOOKMARKS)
) {
return false;
}
// Autofill doesn't search tags or titles
if (
queryContext.tokens.some(
t =>
t.type == UrlbarTokenizer.TYPE.RESTRICT_TAG ||
t.type == UrlbarTokenizer.TYPE.RESTRICT_TITLE
)
) {
return false;
}
[this._strippedPrefix, this._searchString] = UrlbarUtils.stripURLPrefix(
queryContext.searchString
);
this._strippedPrefix = this._strippedPrefix.toLowerCase();
if (!this._searchString || !this._searchString.length) {
return false;
}
// Don't try to autofill if the search term includes any whitespace.
// This may confuse completeDefaultIndex cause the AUTOCOMPLETE_MATCH
// tokenizer ends up trimming the search string and returning a value
// that doesn't match it, or is even shorter.
if (UrlbarTokenizer.REGEXP_SPACES.test(queryContext.searchString)) {
return false;
}
// Fetch autofill result now, rather than in startQuery. We do this so the
// muxer doesn't have to wait on autofill for every query, since startQuery
// will be guaranteed to return a result very quickly using this approach.
// Bug 1651101 is filed to improve this behaviour.
let autofilled = await this._getAutofillResult(queryContext);
if (!autofilled || !this._autofillResult) {
return false;
}
return true;
}
/**
* Gets the provider's priority.
* @param {UrlbarQueryContext} queryContext The query context object
* @returns {number} The provider's priority for the given query.
*/
getPriority(queryContext) {
// Priority search results are restricting.
if (
this._autofillResult &&
this._autofillResult.type == UrlbarUtils.RESULT_TYPE.SEARCH
) {
return 1;
}
return 0;
}
/**
* Starts querying.
* @param {object} queryContext The query context object
* @param {function} addCallback Callback invoked by the provider to add a new
* result.
* @returns {Promise} resolved when the query stops.
*/
async startQuery(queryContext, addCallback) {
// This serves as the equivalent of checking this.queries.has to see if the
// query has been cancelled, since this._autofillResult is deleted in
// cancelQuery.
if (!this._autofillResult) {
return;
}
this._autofillResult.heuristic = true;
addCallback(this, this._autofillResult);
delete this._autofillResult;
}
/**
* Cancels a running query.
* @param {object} queryContext The query context object
*/
cancelQuery(queryContext) {
delete this._autofillResult;
}
/**
* Obtains the query to search for autofill origin results.
*
* @param {UrlbarQueryContext} queryContext
* @returns {array} consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
_getOriginQuery(queryContext) {
// At this point, searchString is not a URL with a path; it does not
// contain a slash, except for possibly at the very end. If there is
// trailing slash, remove it when searching here to match the rest of the
// string because it may be an origin.
let searchStr = this._searchString.endsWith("/")
? this._searchString.slice(0, -1)
: this._searchString;
let opts = {
query_type: QUERYTYPE.AUTOFILL_ORIGIN,
searchString: searchStr.toLowerCase(),
stddevMultiplier: UrlbarPrefs.get("autoFill.stddevMultiplier"),
};
if (this._strippedPrefix) {
opts.prefix = this._strippedPrefix;
}
if (
queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.HISTORY) &&
queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.BOOKMARKS)
) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_HISTORY_BOOKMARK
: QUERY_ORIGIN_HISTORY_BOOKMARK,
opts,
];
}
if (queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.HISTORY)) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_HISTORY
: QUERY_ORIGIN_HISTORY,
opts,
];
}
if (queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.BOOKMARKS)) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_BOOKMARK
: QUERY_ORIGIN_BOOKMARK,
opts,
];
}
throw new Error("Either history or bookmark behavior expected");
}
/**
* Obtains the query to search for autoFill url results.
*
* @param {UrlbarQueryContext} queryContext
* @returns {array} consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
_getUrlQuery(queryContext) {
// Try to get the host from the search string. The host is the part of the
// URL up to either the path slash, port colon, or query "?". If the search
// string doesn't look like it begins with a host, then return; it doesn't
// make sense to do a URL query with it.
const urlQueryHostRegexp = /^[^/:?]+/;
let hostMatch = urlQueryHostRegexp.exec(this._searchString);
if (!hostMatch) {
return [null, null];
}
let host = hostMatch[0].toLowerCase();
let revHost =
host
.split("")
.reverse()
.join("") + ".";
// Build a string that's the URL stripped of its prefix, i.e., the host plus
// everything after the host. Use queryContext.searchString instead of
// this._searchString because this._searchString has had unEscapeURIForUI()
// called on it. It's therefore not necessarily the literal URL.
let strippedURL = queryContext.searchString.trim();
if (this._strippedPrefix) {
strippedURL = strippedURL.substr(this._strippedPrefix.length);
}
strippedURL = host + strippedURL.substr(host.length);
let opts = {
query_type: QUERYTYPE.AUTOFILL_URL,
revHost,
strippedURL,
};
if (this._strippedPrefix) {
opts.prefix = this._strippedPrefix;
}
if (
queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.HISTORY) &&
queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.BOOKMARKS)
) {
return [
this._strippedPrefix
? QUERY_URL_PREFIX_HISTORY_BOOKMARK
: QUERY_URL_HISTORY_BOOKMARK,
opts,
];
}
if (queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.HISTORY)) {
return [
this._strippedPrefix ? QUERY_URL_PREFIX_HISTORY : QUERY_URL_HISTORY,
opts,
];
}
if (queryContext.sources.includes(UrlbarUtils.RESULT_SOURCE.BOOKMARKS)) {
return [
this._strippedPrefix ? QUERY_URL_PREFIX_BOOKMARK : QUERY_URL_BOOKMARK,
opts,
];
}
throw new Error("Either history or bookmark behavior expected");
}
/**
* Processes a matched row in the Places database and sets
* this._autofillResult to any matches.
* @param {object} row
* The matched row.
* @param {function} cancel
* A callback to cancel the search.
* @param {UrlbarQueryContext} queryContext
*/
_onResultRow(row, cancel, queryContext) {
let queryType = row.getResultByIndex(QUERYINDEX.QUERYTYPE);
let autofilledValue, finalCompleteValue;
switch (queryType) {
case QUERYTYPE.AUTOFILL_ORIGIN:
autofilledValue = row.getResultByIndex(
QUERYINDEX_ORIGIN.AUTOFILLED_VALUE
);
finalCompleteValue = row.getResultByIndex(QUERYINDEX_ORIGIN.URL);
break;
case QUERYTYPE.AUTOFILL_URL:
let url = row.getResultByIndex(QUERYINDEX_URL.URL);
let strippedURL = row.getResultByIndex(QUERYINDEX_URL.STRIPPED_URL);
// We autofill urls to-the-next-slash.
// http://mozilla.org/foo/bar/baz will be autofilled to:
// - http://mozilla.org/f[oo/]
// - http://mozilla.org/foo/b[ar/]
// - http://mozilla.org/foo/bar/b[az]
let strippedURLIndex = url.indexOf(strippedURL);
let strippedPrefix = url.substr(0, strippedURLIndex);
let nextSlashIndex = url.indexOf(
"/",
strippedURLIndex + strippedURL.length - 1
);
if (nextSlashIndex == -1) {
autofilledValue = url.substr(strippedURLIndex);
} else {
autofilledValue = url.substring(strippedURLIndex, nextSlashIndex + 1);
}
finalCompleteValue = strippedPrefix + autofilledValue;
break;
}
// We cancel the query right away since we're just looking for a single
// autofill result.
cancel();
let [title] = UrlbarUtils.stripPrefixAndTrim(finalCompleteValue, {
stripHttp: true,
trimEmptyQuery: true,
trimSlash: !this._searchString.includes("/"),
});
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.HISTORY,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
title: [title, UrlbarUtils.HIGHLIGHT.TYPED],
url: [finalCompleteValue, UrlbarUtils.HIGHLIGHT.TYPED],
icon: iconHelper(finalCompleteValue),
})
);
autofilledValue =
queryContext.searchString +
autofilledValue.substring(this._searchString.length);
result.autofill = {
value: autofilledValue,
selectionStart: queryContext.searchString.length,
selectionEnd: autofilledValue.length,
};
this._autofillResult = result;
}
async _getAutofillResult(queryContext) {
// We may be autofilling an about: link.
this._matchAboutPageForAutofill(queryContext);
if (this._autofillResult) {
return true;
}
// It may also look like a URL we know from the database.
await this._matchKnownUrl(queryContext);
if (this._autofillResult) {
return true;
}
// Or it may look like a search engine domain.
await this._matchSearchEngineDomain(queryContext);
if (this._autofillResult) {
return true;
}
return false;
}
_matchAboutPageForAutofill(queryContext) {
// Check that the typed query is at least one character longer than the
// about: prefix.
if (this._strippedPrefix != "about:" || !this._searchString) {
return;
}
for (const aboutUrl of AboutPagesUtils.visibleAboutUrls) {
if (aboutUrl.startsWith(`about:${this._searchString.toLowerCase()}`)) {
let [trimmedUrl] = UrlbarUtils.stripPrefixAndTrim(aboutUrl, {
stripHttp: true,
trimEmptyQuery: true,
trimSlash: !this._searchString.includes("/"),
});
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.URL,
UrlbarUtils.RESULT_SOURCE.HISTORY,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
title: [trimmedUrl, UrlbarUtils.HIGHLIGHT.TYPED],
url: [aboutUrl, UrlbarUtils.HIGHLIGHT.TYPED],
icon: iconHelper(aboutUrl),
})
);
let autofilledValue =
queryContext.searchString +
aboutUrl.substring(queryContext.searchString.length);
result.autofill = {
value: autofilledValue,
selectionStart: queryContext.searchString.length,
selectionEnd: autofilledValue.length,
};
this._autofillResult = result;
return;
}
}
}
async _matchKnownUrl(queryContext) {
let conn = await PlacesUtils.promiseLargeCacheDBConnection();
if (!conn) {
return;
}
// If search string looks like an origin, try to autofill against origins.
// Otherwise treat it as a possible URL. When the string has only one slash
// at the end, we still treat it as an URL.
let query, params;
if (
UrlbarTokenizer.looksLikeOrigin(this._searchString, {
ignoreKnownDomains: true,
})
) {
[query, params] = this._getOriginQuery(queryContext);
} else {
[query, params] = this._getUrlQuery(queryContext);
}
// _getrlQuery doesn't always return a query.
if (query) {
await conn.executeCached(query, params, (row, cancel) => {
this._onResultRow(row, cancel, queryContext);
});
}
}
async _matchSearchEngineDomain(queryContext) {
if (!UrlbarPrefs.get("autoFill.searchEngines")) {
return;
}
// engineForDomainPrefix only matches against engine domains.
// Remove an eventual trailing slash from the search string (without the
// prefix) and check if the resulting string is worth matching.
// Later, we'll verify that the found result matches the original
// searchString and eventually discard it.
let searchStr = this._searchString;
if (searchStr.indexOf("/") == searchStr.length - 1) {
searchStr = searchStr.slice(0, -1);
}
// If the search string looks more like a url than a domain, bail out.
if (
!UrlbarTokenizer.looksLikeOrigin(searchStr, { ignoreKnownDomains: true })
) {
return;
}
let engine = await UrlbarSearchUtils.engineForDomainPrefix(searchStr);
if (!engine) {
return;
}
let url = engine.searchForm;
let domain = engine.getResultDomain();
// Verify that the match we got is acceptable. Autofilling "example/" to
// "example.com/" would not be good.
if (
(this._strippedPrefix && !url.startsWith(this._strippedPrefix)) ||
!(domain + "/").includes(this._searchString)
) {
return;
}
// The value that's autofilled in the input is the prefix the user typed, if
// any, plus the portion of the engine domain that the user typed. Append a
// trailing slash too, as is usual with autofill.
let value =
this._strippedPrefix + domain.substr(domain.indexOf(searchStr)) + "/";
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
})
);
let autofilledValue =
queryContext.searchString +
value.substring(queryContext.searchString.length);
result.autofill = {
value: autofilledValue,
selectionStart: queryContext.searchString.length,
selectionEnd: autofilledValue.length,
};
this._autofillResult = result;
}
}
var UrlbarProviderAutofill = new ProviderAutofill();

Просмотреть файл

@ -14,7 +14,6 @@ const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
XPCOMUtils.defineLazyModuleGetters(this, {
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
UrlbarProvider: "resource:///modules/UrlbarUtils.jsm",
UrlbarResult: "resource:///modules/UrlbarResult.jsm",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
@ -45,7 +44,7 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
* @returns {integer} one of the types from UrlbarUtils.PROVIDER_TYPE.*
*/
get type() {
return UrlbarUtils.PROVIDER_TYPE.HEURISTIC;
return UrlbarUtils.PROVIDER_TYPE.PROFILE;
}
get PRIORITY() {
@ -61,34 +60,12 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
* @returns {boolean} Whether this provider should be invoked for the search.
*/
async isActive(queryContext) {
// Once the user starts typing a search string after the token, we hand off
// suggestions to UrlbarProviderSearchSuggestions.
if (
!queryContext.searchString.startsWith("@") ||
queryContext.tokens.length != 1
) {
return false;
}
this._engines = await UrlbarSearchUtils.tokenAliasEngines();
if (!this._engines.length) {
return false;
}
this._engines = [];
if (queryContext.searchString.trim() == "@") {
return true;
this._engines = await UrlbarSearchUtils.tokenAliasEngines();
}
// If there's no engine associated with the searchString, then we don't want
// to block other kinds of results.
if (UrlbarPrefs.get("autoFill") && queryContext.allowAutofill) {
this._autofillResult = this._getAutofillResult(queryContext);
if (this._autofillResult) {
return true;
}
}
return false;
return this._engines.length;
}
/**
@ -112,25 +89,19 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
return;
}
if (queryContext.searchString.trim() == "@") {
for (let { engine, tokenAliases } of this._engines) {
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [tokenAliases[0], UrlbarUtils.HIGHLIGHT.TYPED],
query: ["", UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
keywordOffer: UrlbarUtils.KEYWORD_OFFER.SHOW,
})
);
addCallback(this, result);
}
} else if (this._autofillResult) {
addCallback(this, this._autofillResult);
this.queries.delete(queryContext);
return;
for (let { engine, tokenAliases } of this._engines) {
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [tokenAliases[0], UrlbarUtils.HIGHLIGHT.TYPED],
query: ["", UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : null,
keywordOffer: UrlbarUtils.KEYWORD_OFFER.SHOW,
})
);
addCallback(this, result);
}
this.queries.delete(queryContext);
@ -150,49 +121,8 @@ class ProviderTokenAliasEngines extends UrlbarProvider {
* @param {object} queryContext The query context object
*/
cancelQuery(queryContext) {
delete this._autofillResult;
this.queries.delete(queryContext);
}
_getAutofillResult(queryContext) {
let token = queryContext.tokens[0];
// The user is typing a specific engine. We should show a heuristic result.
for (let { engine, tokenAliases } of this._engines) {
for (let alias of tokenAliases) {
if (alias.startsWith(token.lowerCaseValue)) {
// We found a specific engine. We will add an autofill result.
let aliasPreservingUserCase =
token.value + alias.substr(token.value.length);
let value = aliasPreservingUserCase + " ";
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engine.name, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [aliasPreservingUserCase, UrlbarUtils.HIGHLIGHT.TYPED],
query: ["", UrlbarUtils.HIGHLIGHT.TYPED],
icon: engine.iconURI ? engine.iconURI.spec : "",
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
// For test interoperabilty with UrlbarProviderSearchSuggestions.
suggestion: undefined,
tailPrefix: undefined,
tail: undefined,
tailOffsetIndex: -1,
isSearchHistory: false,
})
);
result.heuristic = true;
result.autofill = {
value,
selectionStart: queryContext.searchString.length,
selectionEnd: value.length,
};
return result;
}
}
}
return null;
}
}
var UrlbarProviderTokenAliasEngines = new ProviderTokenAliasEngines();

Просмотреть файл

@ -84,8 +84,17 @@ class ProviderUnifiedComplete extends UrlbarProvider {
acResult,
urls
);
for (let result of results) {
addCallback(this, result);
// The Muxer gives UnifiedComplete special status and waits for it to
// return results before sorting them. We need to know that
// UnifiedComplete has finished even if it isn't returning results, so we
// call addCallback with an empty result here, which is something only
// UnifiedComplete is allowed to do.
if (!results.length) {
addCallback(this, null);
} else {
for (let result of results) {
addCallback(this, result);
}
}
});
this.queries.delete(queryContext);

Просмотреть файл

@ -34,7 +34,6 @@ XPCOMUtils.defineLazyGetter(this, "logger", () =>
var localProviderModules = {
UrlbarProviderUnifiedComplete:
"resource:///modules/UrlbarProviderUnifiedComplete.jsm",
UrlbarProviderAutofill: "resource:///modules/UrlbarProviderAutofill.jsm",
UrlbarProviderHeuristicFallback:
"resource:///modules/UrlbarProviderHeuristicFallback.jsm",
UrlbarProviderInterventions:
@ -454,9 +453,16 @@ class Query {
return;
}
let addResult = true;
if (!result) {
addResult = false;
}
// Check if the result source should be filtered out. Pay attention to the
// heuristic result though, that is supposed to be added regardless.
if (
addResult &&
!this.acceptableSources.includes(result.source) &&
!result.heuristic &&
// Treat form history as searches for the purpose of acceptableSources.
@ -464,21 +470,33 @@ class Query {
result.source != UrlbarUtils.RESULT_SOURCE.HISTORY ||
!this.acceptableSources.includes(UrlbarUtils.RESULT_SOURCE.SEARCH))
) {
return;
addResult = false;
}
// Filter out javascript results for safety. The provider is supposed to do
// it, but we don't want to risk leaking these out.
if (
addResult &&
result.type != UrlbarUtils.RESULT_TYPE.KEYWORD &&
result.payload.url &&
result.payload.url.startsWith("javascript:") &&
!this.context.searchString.startsWith("javascript:") &&
UrlbarPrefs.get("filter.javascript")
) {
return;
addResult = false;
}
// We wait on UnifiedComplete to return a heuristic result. If it has no
// heuristic result to return, we still need to sort and display results, so
// we follow the usual codepath to muxer.sort. We only offer this for
// UnifiedComplete, so we check the provider's name here. This is a stopgap
// measure until bug 1648468 lands.
if (!addResult) {
if (provider.name == "UnifiedComplete") {
this._notifyResultsFromProvider(provider);
}
return;
}
result.providerName = provider.name;
result.providerType = provider.type;
this.context.results.push(result);
@ -525,7 +543,7 @@ class Query {
}
_notifyResults() {
this.muxer.sort(this.context);
let sorted = this.muxer.sort(this.context);
if (this._heuristicProviderTimer) {
this._heuristicProviderTimer.cancel().catch(Cu.reportError);
@ -537,6 +555,10 @@ class Query {
this._chunkTimer = null;
}
if (!sorted) {
return;
}
// Before the muxer.sort call above, this.context.results should never be
// empty since this method is called when results are added. But the muxer
// may have excluded one or more results from the final sorted list. For

Просмотреть файл

@ -444,16 +444,6 @@ var UrlbarUtils = {
return [submission.uri.spec, submission.postData];
},
// Ranks a URL prefix from 3 - 0 with the following preferences:
// https:// > https://www. > http:// > http://www.
// Higher is better for the purposes of deduping URLs.
// Returns -1 if the prefix does not match any of the above.
getPrefixRank(prefix) {
return ["http://www.", "http://", "https://www.", "https://"].indexOf(
prefix
);
},
/**
* Get the number of rows a result should span in the autocomplete dropdown.
*
@ -521,58 +511,6 @@ var UrlbarUtils = {
}
},
/**
* Strips parts of a URL defined in `options`.
*
* @param {string} spec
* The text to modify.
* @param {object} options
* @param {boolean} options.stripHttp
* Whether to strip http.
* @param {boolean} options.stripHttps
* Whether to strip https.
* @param {boolean} options.stripWww
* Whether to strip `www.`.
* @param {boolean} options.trimSlash
* Whether to trim the trailing slash.
* @param {boolean} options.trimEmptyQuery
* Whether to trim a trailing `?`.
* @param {boolean} options.trimEmptyHash
* Whether to trim a trailing `#`.
* @returns {array} [modified, prefix, suffix]
* modified: {string} The modified spec.
* prefix: {string} The parts stripped from the prefix, if any.
* suffix: {string} The parts trimmed from the suffix, if any.
*/
stripPrefixAndTrim(spec, options = {}) {
let prefix = "";
let suffix = "";
if (options.stripHttp && spec.startsWith("http://")) {
spec = spec.slice(7);
prefix = "http://";
} else if (options.stripHttps && spec.startsWith("https://")) {
spec = spec.slice(8);
prefix = "https://";
}
if (options.stripWww && spec.startsWith("www.")) {
spec = spec.slice(4);
prefix += "www.";
}
if (options.trimEmptyHash && spec.endsWith("#")) {
spec = spec.slice(0, -1);
suffix = "#" + suffix;
}
if (options.trimEmptyQuery && spec.endsWith("?")) {
spec = spec.slice(0, -1);
suffix = "?" + suffix;
}
if (options.trimSlash && spec.endsWith("/")) {
spec = spec.slice(0, -1);
suffix = "/" + suffix;
}
return [spec, prefix, suffix];
},
/**
* Used to filter out the javascript protocol from URIs, since we don't
* support LOAD_FLAGS_DISALLOW_INHERIT_PRINCIPAL for those.

Просмотреть файл

@ -547,18 +547,6 @@ class UrlbarView {
});
}
// If we update the selected element, a new unique ID is generated for it.
// We need to ensure that aria-activedescendant reflects this new ID.
if (this.selectedElement && !this.oneOffSearchButtons.selectedButton) {
let aadID = this.input.inputField.getAttribute("aria-activedescendant");
if (!aadID) {
Cu.reportError("Selected element but no aria-activedescendant!");
this._setAccessibleFocus(this.selectedElement);
} else if (!this.document.getElementById(aadID)) {
this._setAccessibleFocus(this.selectedElement);
}
}
this._openPanel();
if (firstResult.heuristic) {

Просмотреть файл

@ -11,7 +11,6 @@ EXTRA_JS_MODULES += [
'UrlbarInput.jsm',
'UrlbarMuxerUnifiedComplete.jsm',
'UrlbarPrefs.jsm',
'UrlbarProviderAutofill.jsm',
'UrlbarProviderExtension.jsm',
'UrlbarProviderHeuristicFallback.jsm',
'UrlbarProviderInterventions.jsm',

Просмотреть файл

@ -43,40 +43,6 @@ add_task(async function initXPCShellDependencies() {
await UrlbarTestUtils.initXPCShellDependencies();
});
/**
* Gets the database connection. If the Places connection is invalid it will
* try to create a new connection.
*
* @param [optional] aForceNewConnection
* Forces creation of a new connection to the database. When a
* connection is asyncClosed it cannot anymore schedule async statements,
* though connectionReady will keep returning true (Bug 726990).
*
* @return The database connection or null if unable to get one.
*/
var gDBConn;
function DBConn(aForceNewConnection) {
if (!aForceNewConnection) {
let db = PlacesUtils.history.DBConnection;
if (db.connectionReady) {
return db;
}
}
// If the Places database connection has been closed, create a new connection.
if (!gDBConn || aForceNewConnection) {
let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
file.append("places.sqlite");
let dbConn = (gDBConn = Services.storage.openDatabase(file));
TestUtils.topicObserved("profile-before-change").then(() =>
dbConn.asyncClose()
);
}
return gDBConn.connectionReady ? gDBConn : null;
}
/**
* @param {string} searchString The search string to insert into the context.
* @param {object} properties Overrides for the default values.
@ -313,69 +279,6 @@ async function addTestTailSuggestionsEngine(suggestionsFn = null) {
return engine;
}
/**
* Helper for tests that generate search results but aren't interested in
* suggestions, such as autofill tests. Installs a test engine and disables
* suggestions.
*/
function testEngine_setup() {
add_task(async function setup() {
await cleanupPlaces();
let engine = await addTestSuggestionsEngine();
let oldDefaultEngine = await Services.search.getDefault();
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
Services.prefs.clearUserPref(
"browser.search.separatePrivateDefault.ui.enabled"
);
Services.search.setDefault(oldDefaultEngine);
});
Services.search.setDefault(engine);
Services.prefs.setBoolPref(
"browser.search.separatePrivateDefault.ui.enabled",
false
);
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
});
}
async function cleanupPlaces() {
Services.prefs.clearUserPref("browser.urlbar.autoFill");
Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines");
await PlacesUtils.bookmarks.eraseEverything();
await PlacesUtils.history.clear();
}
/**
* Returns the frecency of a url.
*
* @param {string} aURI The URI or spec to get frecency for.
* @returns {number} the frecency value.
*/
function frecencyForUrl(aURI) {
let url = aURI;
if (aURI instanceof Ci.nsIURI) {
url = aURI.spec;
} else if (aURI instanceof URL) {
url = aURI.href;
}
let stmt = DBConn().createStatement(
"SELECT frecency FROM moz_places WHERE url_hash = hash(?1) AND url = ?1"
);
stmt.bindByIndex(0, url);
try {
if (!stmt.executeStep()) {
throw new Error("No result for frecency.");
}
return stmt.getInt32(0);
} finally {
stmt.finalize();
}
}
/**
* Creates a UrlbarResult for a bookmark result.
* @param {UrlbarQueryContext} queryContext
@ -468,79 +371,6 @@ function makeOmniboxResult(
return result;
}
/**
* Creates a UrlbarResult for a keyword search result.
* @param {UrlbarQueryContext} queryContext
* The context that this result will be displayed in.
* @param {string} options.uri
* The page URI.
* @param {string} options.keyword
* The page's search keyword.
* @param {string} [options.title]
* The title for the bookmarked keyword page.
* @param {string} [options.iconUri]
* A URI for the engine's icon.
* @param {string} [options.postData]
* The search POST data.
* @param {boolean} [options.heuristic]
* True if this is a heuristic result. Defaults to false.
* @returns {UrlbarResult}
*/
function makeKeywordSearchResult(
queryContext,
{ uri, keyword, title, iconUri, postData, heuristic = false }
) {
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.KEYWORD,
UrlbarUtils.RESULT_SOURCE.BOOKMARKS,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
title: [title ? title : uri, UrlbarUtils.HIGHLIGHT.TYPED],
url: [uri, UrlbarUtils.HIGHLIGHT.TYPED],
keyword: [keyword, UrlbarUtils.HIGHLIGHT.TYPED],
input: [queryContext.searchString, UrlbarUtils.HIGHLIGHT.TYPED],
postData,
icon: typeof iconUri != "undefined" ? iconUri : `page-icon:${uri}`,
})
);
if (heuristic) {
result.heuristic = heuristic;
}
return result;
}
/**
* Creates a UrlbarResult for a priority search result.
* @param {UrlbarQueryContext} queryContext
* The context that this result will be displayed in.
* @param {string} [options.engineName]
* The name of the engine providing the suggestion. Leave blank if there
* is no suggestion.
* @param {string} [options.engineIconUri]
* A URI for the engine's icon.
* @param {boolean} [options.heuristic]
* True if this is a heuristic result. Defaults to false.
* @returns {UrlbarResult}
*/
function makePrioritySearchResult(
queryContext,
{ engineName, engineIconUri, heuristic }
) {
let result = new UrlbarResult(
UrlbarUtils.RESULT_TYPE.SEARCH,
UrlbarUtils.RESULT_SOURCE.SEARCH,
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, {
engine: [engineName, UrlbarUtils.HIGHLIGHT.TYPED],
icon: engineIconUri ? engineIconUri : "",
})
);
if (heuristic) {
result.heuristic = heuristic;
}
return result;
}
/**
* Creates a UrlbarResult for a search result.
* @param {UrlbarQueryContext} queryContext
@ -563,9 +393,6 @@ function makePrioritySearchResult(
* True if this is a heuristic result. Defaults to false.
* @param {number} [options.keywordOffer]
* A value from UrlbarUtils.KEYWORD_OFFER.
* @param {string} providerName
* The name of the provider offering this result. The test suite will not
* check which provider offered a result unless this option is specified.
* @returns {UrlbarResult}
*/
function makeSearchResult(
@ -581,7 +408,6 @@ function makeSearchResult(
engineIconUri,
heuristic = false,
keywordOffer,
providerName,
}
) {
if (!keywordOffer) {
@ -627,10 +453,6 @@ function makeSearchResult(
result.payload.lowerCaseSuggestion = result.payload.suggestion.toLocaleLowerCase();
}
if (providerName) {
result.providerName = providerName;
}
result.heuristic = heuristic;
return result;
}
@ -649,14 +471,11 @@ function makeSearchResult(
* A URI for the page's icon.
* @param {boolean} [options.heuristic]
* True if this is a heuristic result. Defaults to false.
* * @param {string} providerName
* The name of the provider offering this result. The test suite will not
* check which provider offered a result unless this option is specified.
* @returns {UrlbarResult}
*/
function makeVisitResult(
queryContext,
{ title, uri, iconUri, tags = null, heuristic = false, providerName }
{ title, uri, iconUri, tags = null, heuristic = false }
) {
let payload = {
url: [uri, UrlbarUtils.HIGHLIGHT.TYPED],
@ -675,10 +494,6 @@ function makeVisitResult(
...UrlbarResult.payloadAndSimpleHighlights(queryContext.tokens, payload)
);
if (providerName) {
result.providerName = providerName;
}
result.heuristic = heuristic;
return result;
}
@ -688,26 +503,12 @@ function makeVisitResult(
* the param `matches`.
* @param {UrlbarQueryContext} context
* The context for this query.
* @param {string} [incompleteSearch]
* A search will be fired for this string and then be immediately canceled by
* the query in `context`.
* @param {string} [autofilled]
* The autofilled value in the first result.
* @param {string} [completed]
* The value that would be filled if the autofill result was confirmed.
* Has no effect if `autofilled` is not specified.
* @param {array} matches
* An array of UrlbarResults.
* @param {boolean} [isPrivate]
* Set this to `true` to simulate a search in a private window.
*/
async function check_results({
context,
incompleteSearch,
autofilled,
completed,
matches = [],
} = {}) {
async function check_results({ context, matches = [] } = {}) {
if (!context) {
return;
}
@ -729,35 +530,8 @@ async function check_results({
autofillFirstResult() {},
},
});
if (incompleteSearch) {
let incompleteContext = createContext(incompleteSearch, {
isPrivate: context.isPrivate,
});
controller.startQuery(incompleteContext);
}
await controller.startQuery(context);
if (autofilled) {
Assert.ok(context.results[0], "There is a first result.");
Assert.ok(
context.results[0].autofill,
"The first result is an autofill result"
);
Assert.equal(
context.results[0].autofill.value,
autofilled,
"The correct value was autofilled."
);
if (completed) {
Assert.equal(
context.results[0].payload.url,
completed,
"The completed autofill value is correct."
);
}
}
Assert.equal(
context.results.length,
matches.length,
@ -775,14 +549,4 @@ async function check_results({
context.results.map(m => m.heuristic),
"Heuristic results are correctly flagged."
);
matches.forEach((match, i) => {
if (match.providerName) {
Assert.equal(
match.providerName,
context.results[i].providerName,
`The result at index ${i} is from the correct provider.`
);
}
});
}

Просмотреть файл

@ -1,100 +0,0 @@
/* 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/. */
"use strict";
const ENGINE_NAME = "engine-suggestions.xml";
testEngine_setup();
// "about:ab" should match "about:about"
add_task(async function aboutAb() {
let context = createContext("about:ab", { isPrivate: false });
await check_results({
context,
autofilled: "about:about",
completed: "about:about",
matches: [
makeVisitResult(context, {
uri: "about:about",
title: "about:about",
heuristic: true,
}),
],
});
});
// "about:Ab" should match "about:about"
add_task(async function aboutAb() {
let context = createContext("about:Ab", { isPrivate: false });
await check_results({
context,
autofilled: "about:About",
completed: "about:about",
matches: [
makeVisitResult(context, {
uri: "about:about",
title: "about:about",
heuristic: true,
}),
],
});
});
// "about:about" should match "about:about"
add_task(async function aboutAbout() {
let context = createContext("about:about", { isPrivate: false });
await check_results({
context,
autofilled: "about:about",
completed: "about:about",
matches: [
makeVisitResult(context, {
uri: "about:about",
title: "about:about",
heuristic: true,
}),
],
});
});
// "about:a" should complete to "about:about" and also match "about:addons"
add_task(async function aboutAboutAndAboutAddons() {
let context = createContext("about:a", { isPrivate: false });
await check_results({
context,
search: "about:a",
autofilled: "about:about",
completed: "about:about",
matches: [
makeVisitResult(context, {
uri: "about:about",
title: "about:about",
heuristic: true,
}),
makeVisitResult(context, {
uri: "about:addons",
title: "about:addons",
iconUri: "",
providerName: "UnifiedComplete",
}),
],
});
});
// "about:" should *not* match anything
add_task(async function aboutColonHasNoMatch() {
let context = createContext("about:", { isPrivate: false });
await check_results({
context,
search: "about:",
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
providerName: "HeuristicFallback",
heuristic: true,
}),
],
});
});

Просмотреть файл

@ -1,112 +0,0 @@
/* 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/. */
// Functional tests for inline autocomplete
add_task(async function setup() {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
});
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
});
add_task(async function test_urls_order() {
info("Add urls, check for correct order");
let places = [
{ uri: Services.io.newURI("http://visit1.mozilla.org") },
{ uri: Services.io.newURI("http://visit2.mozilla.org") },
];
await PlacesTestUtils.addVisits(places);
let context = createContext("vis", { isPrivate: false });
await check_results({
context,
autofilled: "visit2.mozilla.org/",
completed: "http://visit2.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://visit2.mozilla.org/",
title: "visit2.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://visit1.mozilla.org/",
title: "test visit for http://visit1.mozilla.org/",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_bookmark_first() {
info("With a bookmark and history, the query result should be the bookmark");
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://bookmark1.mozilla.org/"),
});
await PlacesTestUtils.addVisits(
Services.io.newURI("http://bookmark1.mozilla.org/foo")
);
let context = createContext("bookmark", { isPrivate: false });
await check_results({
context,
autofilled: "bookmark1.mozilla.org/",
completed: "http://bookmark1.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://bookmark1.mozilla.org/",
title: "bookmark1.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://bookmark1.mozilla.org/foo",
title: "test visit for http://bookmark1.mozilla.org/foo",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_complete_querystring() {
info("Check to make sure we autocomplete after ?");
await PlacesTestUtils.addVisits(
Services.io.newURI("http://smokey.mozilla.org/foo?bacon=delicious")
);
let context = createContext("smokey.mozilla.org/foo?", { isPrivate: false });
await check_results({
context,
autofilled: "smokey.mozilla.org/foo?bacon=delicious",
completed: "http://smokey.mozilla.org/foo?bacon=delicious",
matches: [
makeVisitResult(context, {
uri: "http://smokey.mozilla.org/foo?bacon=delicious",
title: "smokey.mozilla.org/foo?bacon=delicious",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_complete_fragment() {
info("Check to make sure we autocomplete after #");
await PlacesTestUtils.addVisits(
Services.io.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar")
);
let context = createContext("smokey.mozilla.org/foo?bacon=delicious#bar", {
isPrivate: false,
});
await check_results({
context,
autofilled: "smokey.mozilla.org/foo?bacon=delicious#bar",
completed: "http://smokey.mozilla.org/foo?bacon=delicious#bar",
matches: [
makeVisitResult(context, {
uri: "http://smokey.mozilla.org/foo?bacon=delicious#bar",
title: "smokey.mozilla.org/foo?bacon=delicious#bar",
heuristic: true,
}),
],
});
await cleanupPlaces();
});

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -1,232 +0,0 @@
/* 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/. */
// The autoFill.searchEngines pref autofills the domains of engines registered
// with the search service. That's what this test checks. It's a different
// path in UnifiedComplete.js from normal moz_places autofill, which is tested
// in test_autofill_origins.js and test_autofill_urls.js.
"use strict";
const ENGINE_NAME = "TestEngine";
add_task(async function searchEngines() {
Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
Services.prefs.setBoolPref(
"browser.search.separatePrivateDefault.ui.enabled",
false
);
registerCleanupFunction(() => {
Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines");
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
Services.prefs.clearUserPref(
"browser.search.separatePrivateDefault.ui.enabled"
);
});
let schemes = ["http", "https"];
for (let i = 0; i < schemes.length; i++) {
let scheme = schemes[i];
let engine = await Services.search.addEngineWithDetails(ENGINE_NAME, {
method: "GET",
template: scheme + "://www.example.com/",
searchGetParams: "q={searchTerms}",
});
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext("example.com", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext("example.com/", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext("www.ex", { isPrivate: false });
await check_results({
context,
autofilled: "www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext("www.example.com", { isPrivate: false });
await check_results({
context,
autofilled: "www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext("www.example.com/", { isPrivate: false });
await check_results({
context,
autofilled: "www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://ex", { isPrivate: false });
await check_results({
context,
autofilled: scheme + "://example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://example.com", { isPrivate: false });
await check_results({
context,
autofilled: scheme + "://example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://example.com/", { isPrivate: false });
await check_results({
context,
autofilled: scheme + "://example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://www.ex", { isPrivate: false });
await check_results({
context,
autofilled: scheme + "://www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://www.example.com", {
isPrivate: false,
});
await check_results({
context,
autofilled: scheme + "://www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
context = createContext(scheme + "://www.example.com/", {
isPrivate: false,
});
await check_results({
context,
search: scheme + "://www.example.com/",
autofilled: scheme + "://www.example.com/",
matches: [
makePrioritySearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
});
// We should just get a normal heuristic result from HeuristicFallback for
// these queries.
let otherScheme = schemes[(i + 1) % schemes.length];
context = createContext(otherScheme + "://ex", { isPrivate: false });
await check_results({
context,
search: otherScheme + "://ex",
matches: [
makeVisitResult(context, {
uri: otherScheme + "://ex/",
title: otherScheme + "://ex/",
iconUri: "",
heuristic: true,
}),
],
});
context = createContext(otherScheme + "://www.ex", { isPrivate: false });
await check_results({
context,
search: otherScheme + "://www.ex",
matches: [
makeVisitResult(context, {
uri: otherScheme + "://www.ex/",
title: otherScheme + "://www.ex/",
iconUri: "",
heuristic: true,
}),
],
});
context = createContext("example/", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://example/",
title: "http://example/",
heuristic: true,
}),
],
});
await Services.search.removeEngine(engine);
}
});

Просмотреть файл

@ -1,133 +0,0 @@
/* 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/. */
"use strict";
const HEURISTIC_FALLBACK_PROVIDERNAME = "HeuristicFallback";
const UNIFIEDCOMPLETE_PROVIDERNAME = "UnifiedComplete";
// "example.com/foo/" should match http://example.com/foo/.
testEngine_setup();
add_task(async function multipleSlashes() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com/foo/",
},
]);
let context = createContext("example.com/foo/", { isPrivate: false });
await check_results({
context,
autofilled: "example.com/foo/",
completed: "http://example.com/foo/",
matches: [
makeVisitResult(context, {
uri: "http://example.com/foo/",
title: "example.com/foo/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
// "example.com:8888/f" should match http://example.com:8888/foo.
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo",
},
]);
let context = createContext("example.com:8888/f", { isPrivate: false });
await check_results({
context,
autofilled: "example.com:8888/foo",
completed: "http://example.com:8888/foo",
matches: [
makeVisitResult(context, {
uri: "http://example.com:8888/foo",
title: "example.com:8888/foo",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
// "example.com:8999/f" should *not* autofill http://example.com:8888/foo.
add_task(async function portNoMatch() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo",
},
]);
let context = createContext("example.com:8999/f", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://example.com:8999/f",
title: "http://example.com:8999/f",
iconUri: "page-icon:http://example.com:8999/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
// autofill to the next slash
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo/bar/baz",
},
]);
let context = createContext("example.com:8888/foo/b", { isPrivate: false });
await check_results({
context,
autofilled: "example.com:8888/foo/bar/",
completed: "http://example.com:8888/foo/bar/",
matches: [
makeVisitResult(context, {
uri: "http://example.com:8888/foo/bar/",
title: "example.com:8888/foo/bar/",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://example.com:8888/foo/bar/baz",
title: "test visit for http://example.com:8888/foo/bar/baz",
tags: [],
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
// autofill to the next slash, end of url
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo/bar/baz",
},
]);
let context = createContext("example.com:8888/foo/bar/b", {
isPrivate: false,
});
await check_results({
context,
autofilled: "example.com:8888/foo/bar/baz",
completed: "http://example.com:8888/foo/bar/baz",
matches: [
makeVisitResult(context, {
uri: "http://example.com:8888/foo/bar/baz",
title: "example.com:8888/foo/bar/baz",
heuristic: true,
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,120 +0,0 @@
/* 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 ENGINE_NAME = "engine-suggestions.xml";
testEngine_setup();
add_task(async function test_protocol_trimming() {
for (let prot of ["http", "https", "ftp"]) {
let visit = {
// Include the protocol in the query string to ensure we get matches (see bug 1059395)
uri: Services.io.newURI(
prot +
"://www.mozilla.org/test/?q=" +
prot +
encodeURIComponent("://") +
"www.foo"
),
title: "Test title",
};
await PlacesTestUtils.addVisits(visit);
let input = prot + "://www.";
info("Searching for: " + input);
let context = createContext(input, { isPrivate: false });
await check_results({
context,
autofilled: prot + "://www.mozilla.org/",
completed: prot + "://www.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: prot + "://www.mozilla.org/",
title:
prot == "http" ? "www.mozilla.org" : prot + "://www.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: visit.uri.spec,
title: visit.title,
}),
],
});
input = "www.";
info("Searching for: " + input);
context = createContext(input, { isPrivate: false });
await check_results({
context,
autofilled: "www.mozilla.org/",
completed: prot + "://www.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: prot + "://www.mozilla.org/",
title:
prot == "http" ? "www.mozilla.org" : prot + "://www.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: visit.uri.spec,
title: visit.title,
}),
],
});
input = prot + "://www. ";
info("Searching for: " + input);
context = createContext(input, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `${input.trim()}/`,
title: `${input.trim()}/`,
iconUri: "",
heuristic: true,
providerName: "HeuristicFallback",
}),
makeVisitResult(context, {
uri: visit.uri.spec,
title: visit.title,
providerName: "UnifiedComplete",
}),
],
});
let inputs = [
prot + "://",
prot + ":// ",
prot + ":// mo",
prot + "://mo te",
prot + "://www. mo",
prot + "://www.mo te",
"www. ",
"www. mo",
"www.mo te",
];
for (input of inputs) {
info("Searching for: " + input);
context = createContext(input, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
query: input,
heuristic: true,
}),
makeVisitResult(context, {
uri: visit.uri.spec,
title: visit.title,
providerName: "UnifiedComplete",
}),
],
});
}
await cleanupPlaces();
}
});

Просмотреть файл

@ -1,363 +0,0 @@
/* 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 ENGINE_NAME = "engine-suggestions.xml";
const HEURISTIC_FALLBACK_PROVIDERNAME = "HeuristicFallback";
const UNIFIEDCOMPLETE_PROVIDERNAME = "UnifiedComplete";
testEngine_setup();
add_task(async function test_casing_1() {
info("Searching for cased entry 1");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
let context = createContext("MOZ", { isPrivate: false });
await check_results({
context,
autofilled: "MOZilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/test/",
title: "test visit for http://mozilla.org/test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_casing_2() {
info("Searching for cased entry 2");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
let context = createContext("mozilla.org/T", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/T",
title: "http://mozilla.org/T",
iconUri: "page-icon:http://mozilla.org/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/test/",
title: "test visit for http://mozilla.org/test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_casing_3() {
info("Searching for cased entry 3");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("mozilla.org/T", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/Test/",
completed: "http://mozilla.org/Test/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "mozilla.org/Test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_casing_4() {
info("Searching for cased entry 4");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("mOzilla.org/t", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/t",
title: "http://mozilla.org/t",
iconUri: "page-icon:http://mozilla.org/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "test visit for http://mozilla.org/Test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_casing_5() {
info("Searching for cased entry 5");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("mOzilla.org/T", { isPrivate: false });
await check_results({
context,
autofilled: "mOzilla.org/Test/",
completed: "http://mozilla.org/Test/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "mozilla.org/Test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_casing() {
info("Searching for untrimmed cased entry");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("http://mOz", { isPrivate: false });
await check_results({
context,
autofilled: "http://mOzilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "test visit for http://mozilla.org/Test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_www_casing() {
info("Searching for untrimmed cased entry with www");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://www.mozilla.org/Test/"),
});
let context = createContext("http://www.mOz", { isPrivate: false });
await check_results({
context,
autofilled: "http://www.mOzilla.org/",
completed: "http://www.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://www.mozilla.org/",
title: "www.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://www.mozilla.org/Test/",
title: "test visit for http://www.mozilla.org/Test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_path_casing() {
info("Searching for untrimmed cased entry with path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("http://mOzilla.org/t", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/t",
title: "http://mozilla.org/t",
iconUri: "page-icon:http://mozilla.org/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "test visit for http://mozilla.org/Test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_path_casing_2() {
info("Searching for untrimmed cased entry with path 2");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/Test/"),
});
let context = createContext("http://mOzilla.org/T", { isPrivate: false });
await check_results({
context,
autofilled: "http://mOzilla.org/Test/",
completed: "http://mozilla.org/Test/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/Test/",
title: "mozilla.org/Test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_path_www_casing() {
info("Searching for untrimmed cased entry with www and path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://www.mozilla.org/Test/"),
});
let context = createContext("http://www.mOzilla.org/t", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://www.mozilla.org/t",
title: "http://www.mozilla.org/t",
iconUri: "page-icon:http://www.mozilla.org/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
makeVisitResult(context, {
uri: "http://www.mozilla.org/Test/",
title: "test visit for http://www.mozilla.org/Test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_path_www_casing_2() {
info("Searching for untrimmed cased entry with www and path 2");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://www.mozilla.org/Test/"),
});
let context = createContext("http://www.mOzilla.org/T", { isPrivate: false });
await check_results({
context,
autofilled: "http://www.mOzilla.org/Test/",
completed: "http://www.mozilla.org/Test/",
matches: [
makeVisitResult(context, {
uri: "http://www.mozilla.org/Test/",
title: "www.mozilla.org/Test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_searching() {
let uri1 = Services.io.newURI("http://dummy/1/");
let uri2 = Services.io.newURI("http://dummy/2/");
let uri3 = Services.io.newURI("http://dummy/3/");
let uri4 = Services.io.newURI("http://dummy/4/");
let uri5 = Services.io.newURI("http://dummy/5/");
await PlacesTestUtils.addVisits([
{ uri: uri1, title: "uppercase lambda \u039B" },
{ uri: uri2, title: "lowercase lambda \u03BB" },
{ uri: uri3, title: "symbol \u212A" }, // kelvin
{ uri: uri4, title: "uppercase K" },
{ uri: uri5, title: "lowercase k" },
]);
info("Search for lowercase lambda");
let context = createContext("\u03BB", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
makeVisitResult(context, {
uri: uri2.spec,
title: "lowercase lambda \u03BB",
}),
makeVisitResult(context, {
uri: uri1.spec,
title: "uppercase lambda \u039B",
}),
],
});
info("Search for uppercase lambda");
context = createContext("\u039B", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
makeVisitResult(context, {
uri: uri2.spec,
title: "lowercase lambda \u03BB",
}),
makeVisitResult(context, {
uri: uri1.spec,
title: "uppercase lambda \u039B",
}),
],
});
info("Search for kelvin sign");
context = createContext("\u212A", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
makeVisitResult(context, { uri: uri5.spec, title: "lowercase k" }),
makeVisitResult(context, { uri: uri4.spec, title: "uppercase K" }),
makeVisitResult(context, { uri: uri3.spec, title: "symbol \u212A" }),
],
});
info("Search for lowercase k");
context = createContext("k", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
makeVisitResult(context, { uri: uri5.spec, title: "lowercase k" }),
makeVisitResult(context, { uri: uri4.spec, title: "uppercase K" }),
makeVisitResult(context, { uri: uri3.spec, title: "symbol \u212A" }),
],
});
info("Search for uppercase k");
context = createContext("K", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, { engineName: ENGINE_NAME, heuristic: true }),
makeVisitResult(context, { uri: uri5.spec, title: "lowercase k" }),
makeVisitResult(context, { uri: uri4.spec, title: "uppercase K" }),
makeVisitResult(context, { uri: uri3.spec, title: "symbol \u212A" }),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,63 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Ensure inline autocomplete doesn't return zero frecency pages.
add_task(async function setup() {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
});
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
});
add_task(async function test_dupe_urls() {
info("Searching for urls with dupes should only show one");
await PlacesTestUtils.addVisits(
{
uri: Services.io.newURI("http://mozilla.org/"),
},
{
uri: Services.io.newURI("http://mozilla.org/?"),
}
);
let context = createContext("moz", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_dupe_secure_urls() {
await PlacesTestUtils.addVisits(
{
uri: Services.io.newURI("https://example.org/"),
},
{
uri: Services.io.newURI("https://example.org/?"),
}
);
let context = createContext("exam", { isPrivate: false });
await check_results({
context,
autofilled: "example.org/",
completed: "https://example.org/",
matches: [
makeVisitResult(context, {
uri: "https://example.org/",
title: "https://example.org",
heuristic: true,
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,97 +0,0 @@
add_task(async function test_encoded() {
info("Searching for over encoded url should not break it");
let url = "https://www.mozilla.com/search/top/?q=%25%32%35";
await PlacesTestUtils.addVisits({
uri: Services.io.newURI(url),
title: url,
});
let context = createContext(url, { isPrivate: false });
await check_results({
context,
autofilled: url,
completed: url,
matches: [
makeVisitResult(context, {
uri: url,
title: url,
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_encoded_trimmed() {
info("Searching for over encoded url should not break it");
let url = "https://www.mozilla.com/search/top/?q=%25%32%35";
await PlacesTestUtils.addVisits({
uri: Services.io.newURI(url),
title: url,
});
let context = createContext("mozilla.com/search/top/?q=%25%32%35", {
isPrivate: false,
});
await check_results({
context,
autofilled: "mozilla.com/search/top/?q=%25%32%35",
completed: url,
matches: [
makeVisitResult(context, {
uri: url,
title: url,
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_encoded_partial() {
info("Searching for over encoded url should not break it");
let url = "https://www.mozilla.com/search/top/?q=%25%32%35";
await PlacesTestUtils.addVisits({
uri: Services.io.newURI(url),
title: url,
});
let context = createContext("https://www.mozilla.com/search/top/?q=%25", {
isPrivate: false,
});
await check_results({
context,
autofilled: url,
completed: url,
matches: [
makeVisitResult(context, {
uri: url,
title: url,
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_encoded_path() {
info("Searching for over encoded url should not break it");
let url = "https://www.mozilla.com/%25%32%35/top/";
await PlacesTestUtils.addVisits({
uri: Services.io.newURI(url),
title: url,
});
let context = createContext("https://www.mozilla.com/%25%32%35/t", {
isPrivate: false,
});
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: url,
title: url,
heuristic: true,
}),
],
autofilled: url,
completed: url,
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,207 +0,0 @@
/* 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 ENGINE_NAME = "engine-suggestions.xml";
testEngine_setup();
add_task(async function test_non_keyword() {
info("Searching for non-keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
let context = createContext("moz", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeBookmarkResult(context, {
uri: "http://mozilla.org/test/",
title: "A bookmark",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_keyword() {
info("Searching for keyworded entry should not autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
let context = createContext("moz", { isPrivate: false });
await check_results({
context,
matches: [
makeKeywordSearchResult(context, {
uri: "http://mozilla.org/test/",
keyword: "moz",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_more_than_keyword() {
info("Searching for more than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
let context = createContext("mozi", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeBookmarkResult(context, {
uri: "http://mozilla.org/test/",
title: "A bookmark",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_less_than_keyword() {
info("Searching for less than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
search: "mo",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeBookmarkResult(context, {
uri: "http://mozilla.org/test/",
title: "A bookmark",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_keyword_casing() {
info("Searching for keyworded entry is case-insensitive");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
let context = createContext("MoZ", { isPrivate: false });
await check_results({
context,
matches: [
makeKeywordSearchResult(context, {
uri: "http://mozilla.org/test/",
keyword: "MoZ",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_less_then_equal_than_keyword_bug_1124238() {
info("Searching for less than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addVisits("http://mozilla.com/");
PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.com/"),
keyword: "moz",
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
search: "mo",
autofilled: "mozilla.com/",
completed: "http://mozilla.com/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.com/",
title: "mozilla.com",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/test/",
title: "test visit for http://mozilla.org/test/",
}),
],
});
// Search with an additional character. As the input matches a keyword, the
// completion should equal the keyword and not the URI as before.
context = createContext("moz", { isPrivate: false });
await check_results({
context,
matches: [
makeKeywordSearchResult(context, {
uri: "http://mozilla.com/",
keyword: "moz",
heuristic: true,
}),
],
});
// Search with an additional character. The input doesn't match a keyword
// anymore, it should be autofilled.
context = createContext("mozi", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.com/",
completed: "http://mozilla.com/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.com/",
title: "mozilla.com",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/test/",
title: "test visit for http://mozilla.org/test/",
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,123 +0,0 @@
/* 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 ENGINE_NAME = "engine-suggestions.xml";
const HEURISTIC_FALLBACK_PROVIDERNAME = "HeuristicFallback";
const UNIFIEDCOMPLETE_PROVIDERNAME = "UnifiedComplete";
testEngine_setup();
add_task(async function test_no_slash() {
info("Searching for host match without slash should match host");
await PlacesTestUtils.addVisits([
{ uri: "http://file.org/test/" },
{ uri: "file:///c:/test.html" },
]);
let context = createContext("file", { isPrivate: false });
await check_results({
context,
autofilled: "file.org/",
completed: "http://file.org/",
matches: [
makeVisitResult(context, {
uri: "http://file.org/",
title: "file.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "file:///c:/test.html",
title: "test visit for file:///c:/test.html",
iconUri: UrlbarUtils.ICON.DEFAULT,
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
makeVisitResult(context, {
uri: "http://file.org/test/",
title: "test visit for http://file.org/test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_w_slash() {
info("Searching match with slash at the end should match url");
await PlacesTestUtils.addVisits(
{
uri: Services.io.newURI("http://file.org/test/"),
},
{
uri: Services.io.newURI("file:///c:/test.html"),
}
);
let context = createContext("file.org/", { isPrivate: false });
await check_results({
context,
autofilled: "file.org/",
completed: "http://file.org/",
matches: [
makeVisitResult(context, {
uri: "http://file.org/",
title: "file.org/",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://file.org/test/",
title: "test visit for http://file.org/test/",
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_middle() {
info("Searching match with slash in the middle should match url");
await PlacesTestUtils.addVisits(
{
uri: Services.io.newURI("http://file.org/test/"),
},
{
uri: Services.io.newURI("file:///c:/test.html"),
}
);
let context = createContext("file.org/t", { isPrivate: false });
await check_results({
context,
autofilled: "file.org/test/",
completed: "http://file.org/test/",
matches: [
makeVisitResult(context, {
uri: "http://file.org/test/",
title: "file.org/test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_nonhost() {
info("Searching for non-host match without slash should not match url");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("file:///c:/test.html"),
});
let context = createContext("file", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
makeVisitResult(context, {
uri: "file:///c:/test.html",
title: "test visit for file:///c:/test.html",
iconUri: UrlbarUtils.ICON.DEFAULT,
providerName: UNIFIEDCOMPLETE_PROVIDERNAME,
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1,80 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_searchEngine_autoFill() {
Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
await Services.search.addEngineWithDetails("MySearchEngine", {
method: "GET",
template: "http://my.search.com/",
});
let engine = Services.search.getEngineByName("MySearchEngine");
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.autoFill.searchEngines");
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
Services.search.removeEngine(engine);
});
// Add an uri that matches the search string with high frecency.
let uri = Services.io.newURI("http://www.example.com/my/");
let visits = [];
for (let i = 0; i < 100; ++i) {
visits.push({ uri, title: "Terms - SearchEngine Search" });
}
await PlacesTestUtils.addVisits(visits);
await PlacesTestUtils.addBookmarkWithDetails({
uri,
title: "Example bookmark",
});
await PlacesTestUtils.promiseAsyncUpdates();
ok(
frecencyForUrl(uri) > 10000,
"Added URI should have expected high frecency"
);
info(
"Check search domain is autoFilled even if there's an higher frecency match"
);
let context = createContext("my", { isPrivate: false });
await check_results({
search: "my",
autofilled: "my.search.com/",
matches: [
makePrioritySearchResult(context, {
engineName: "MySearchEngine",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_searchEngine_noautoFill() {
await PlacesTestUtils.addVisits(
Services.io.newURI("http://my.search.com/samplepage/")
);
info("Check search domain is not autoFilled if it matches a visited domain");
let context = createContext("my", { isPrivate: false });
await check_results({
context,
autofilled: "my.search.com/",
completed: "http://my.search.com/",
matches: [
// Note this result is a normal Autofill result and not a priority engine.
makeVisitResult(context, {
uri: "http://my.search.com/",
title: "my.search.com",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://my.search.com/samplepage/",
title: "test visit for http://my.search.com/samplepage/",
providerName: "UnifiedComplete",
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -1514,6 +1514,7 @@ add_task(async function formHistory() {
uri: "http://foo.example.com/",
title: "foo.example.com",
heuristic: true,
tags: [],
}),
makeFormHistoryResult(context, {
suggestion: "foo",

Просмотреть файл

@ -1,221 +0,0 @@
/* 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 setup() {
registerCleanupFunction(async () => {
Services.prefs.clearUserPref("browser.urlbar.suggest.searches");
});
Services.prefs.setBoolPref("browser.urlbar.suggest.searches", false);
});
add_task(async function test_untrimmed_secure_www() {
info("Searching for untrimmed https://www entry");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("https://www.mozilla.org/test/"),
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "https://www.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "https://www.mozilla.org/",
title: "https://www.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "https://www.mozilla.org/test/",
title: "test visit for https://www.mozilla.org/test/",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_secure_www_path() {
info("Searching for untrimmed https://www entry with path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("https://www.mozilla.org/test/"),
});
let context = createContext("mozilla.org/t", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/test/",
completed: "https://www.mozilla.org/test/",
matches: [
makeVisitResult(context, {
uri: "https://www.mozilla.org/test/",
title: "https://www.mozilla.org/test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_secure() {
info("Searching for untrimmed https:// entry");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("https://mozilla.org/test/"),
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "https://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "https://mozilla.org/",
title: "https://mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "https://mozilla.org/test/",
title: "test visit for https://mozilla.org/test/",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_secure_path() {
info("Searching for untrimmed https:// entry with path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("https://mozilla.org/test/"),
});
let context = createContext("mozilla.org/t", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/test/",
completed: "https://mozilla.org/test/",
matches: [
makeVisitResult(context, {
uri: "https://mozilla.org/test/",
title: "https://mozilla.org/test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_www() {
info("Searching for untrimmed http://www entry");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://www.mozilla.org/test/"),
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "http://www.mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://www.mozilla.org/",
title: "www.mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://www.mozilla.org/test/",
title: "test visit for http://www.mozilla.org/test/",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_www_path() {
info("Searching for untrimmed http://www entry with path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://www.mozilla.org/test/"),
});
let context = createContext("mozilla.org/t", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/test/",
completed: "http://www.mozilla.org/test/",
matches: [
makeVisitResult(context, {
uri: "http://www.mozilla.org/test/",
title: "www.mozilla.org/test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_ftp() {
info("Searching for untrimmed ftp:// entry");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("ftp://mozilla.org/test/"),
});
let context = createContext("mo", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/",
completed: "ftp://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "ftp://mozilla.org/",
title: "ftp://mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "ftp://mozilla.org/test/",
title: "test visit for ftp://mozilla.org/test/",
}),
],
});
await cleanupPlaces();
});
add_task(async function test_untrimmed_ftp_path() {
info("Searching for untrimmed ftp:// entry with path");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("ftp://mozilla.org/test/"),
});
let context = createContext("mozilla.org/t", { isPrivate: false });
await check_results({
context,
autofilled: "mozilla.org/test/",
completed: "ftp://mozilla.org/test/",
matches: [
makeVisitResult(context, {
uri: "ftp://mozilla.org/test/",
title: "ftp://mozilla.org/test/",
heuristic: true,
}),
],
});
await cleanupPlaces();
});
add_task(async function test_escaped_chars() {
info("Searching for URL with characters that are normally escaped");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("https://www.mozilla.org/啊-test"),
});
let context = createContext("https://www.mozilla.org/啊-test", {
isPrivate: false,
});
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "https://www.mozilla.org/%E5%95%8A-test",
title: "https://www.mozilla.org/啊-test",
iconUri: "page-icon:https://www.mozilla.org/",
heuristic: true,
}),
// UnifiedComplete escapes this character.
makeVisitResult(context, {
uri: "https://www.mozilla.org/%E5%95%8A-test",
title: "test visit for https://www.mozilla.org/%E5%95%8A-test",
}),
],
});
await cleanupPlaces();
});

Просмотреть файл

@ -5,20 +5,6 @@ support-files =
data/engine-suggestions.xml
data/engine-tail-suggestions.xml
[test_autofill_about_urls.js]
[test_autofill_functional.js]
[test_autofill_origins.js]
[test_autofill_originsAndQueries.js]
[test_autofill_search_engines.js]
[test_autofill_search_engine_aliases.js]
[test_autofill_urls.js]
[test_avoid_middle_complete.js]
[test_avoid_stripping_to_empty_tokens.js]
[test_casing.js]
[test_dedupe_prefix.js]
[test_dupe_urls.js]
[test_encoded_urls.js]
[test_keywords.js]
[test_muxer.js]
[test_providerHeuristicFallback.js]
[test_providerOmnibox.js]
@ -28,14 +14,11 @@ support-files =
[test_providersManager_maxResults.js]
[test_providerUnifiedComplete.js]
[test_providerUnifiedComplete_duplicate_entries.js]
[test_query_url.js]
[test_queryScorer.js]
[test_search_engine_host.js]
[test_search_suggestions.js]
[test_search_suggestions_aliases.js]
[test_search_suggestions_tail.js]
[test_tokenizer.js]
[test_trimming.js]
[test_UrlbarController_integration.js]
[test_UrlbarController_telemetry.js]
[test_UrlbarController_unit.js]

Просмотреть файл

@ -14,6 +14,8 @@ const MS_PER_DAY = 86400000; // 24 * 60 * 60 * 1000
// AutoComplete query type constants.
// Describes the various types of queries that we can process rows for.
const QUERYTYPE_FILTERED = 0;
const QUERYTYPE_AUTOFILL_ORIGIN = 1;
const QUERYTYPE_AUTOFILL_URL = 2;
const QUERYTYPE_ADAPTIVE = 3;
// The default frecency value used when inserting matches with unknown frecency.
@ -131,6 +133,201 @@ const SQL_ADAPTIVE_QUERY = `/* do not warn (bug 487789) */
ORDER BY rank DESC, h.frecency DESC
LIMIT :maxResults`;
// Result row indexes for originQuery()
const QUERYINDEX_ORIGIN_AUTOFILLED_VALUE = 1;
const QUERYINDEX_ORIGIN_URL = 2;
const QUERYINDEX_ORIGIN_FRECENCY = 3;
// `WITH` clause for the autofill queries. autofill_frecency_threshold.value is
// the mean of all moz_origins.frecency values + stddevMultiplier * one standard
// deviation. This is inlined directly in the SQL (as opposed to being a custom
// Sqlite function for example) in order to be as efficient as possible.
const SQL_AUTOFILL_WITH = `
WITH
frecency_stats(count, sum, squares) AS (
SELECT
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_count') AS REAL),
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_sum') AS REAL),
CAST((SELECT IFNULL(value, 0.0) FROM moz_meta WHERE key = 'origin_frecency_sum_of_squares') AS REAL)
),
autofill_frecency_threshold(value) AS (
SELECT
CASE count
WHEN 0 THEN 0.0
WHEN 1 THEN sum
ELSE (sum / count) + (:stddevMultiplier * sqrt((squares - ((sum * sum) / count)) / count))
END
FROM frecency_stats
)
`;
const SQL_AUTOFILL_FRECENCY_THRESHOLD = `host_frecency >= (
SELECT value FROM autofill_frecency_threshold
)`;
function originQuery({ select = "", where = "", having = "" }) {
return `${SQL_AUTOFILL_WITH}
SELECT :query_type,
fixed_up_host || '/',
IFNULL(:prefix, prefix) || moz_origins.host || '/',
frecency,
bookmarked,
id
FROM (
SELECT host,
host AS fixed_up_host,
TOTAL(frecency) AS host_frecency,
(
SELECT TOTAL(foreign_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS bookmarked
${select}
FROM moz_origins
WHERE host BETWEEN :searchString AND :searchString || X'FFFF'
${where}
GROUP BY host
HAVING ${having}
UNION ALL
SELECT host,
fixup_url(host) AS fixed_up_host,
TOTAL(frecency) AS host_frecency,
(
SELECT TOTAL(foreign_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS bookmarked
${select}
FROM moz_origins
WHERE host BETWEEN 'www.' || :searchString AND 'www.' || :searchString || X'FFFF'
${where}
GROUP BY host
HAVING ${having}
) AS grouped_hosts
JOIN moz_origins ON moz_origins.host = grouped_hosts.host
ORDER BY frecency DESC, id DESC
LIMIT 1 `;
}
const QUERY_ORIGIN_HISTORY_BOOKMARK = originQuery({
having: `bookmarked OR ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_PREFIX_HISTORY_BOOKMARK = originQuery({
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `bookmarked OR ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_HISTORY = originQuery({
select: `, (
SELECT TOTAL(visit_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS visited`,
having: `visited AND ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_PREFIX_HISTORY = originQuery({
select: `, (
SELECT TOTAL(visit_count) > 0
FROM moz_places
WHERE moz_places.origin_id = moz_origins.id
) AS visited`,
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `visited AND ${SQL_AUTOFILL_FRECENCY_THRESHOLD}`,
});
const QUERY_ORIGIN_BOOKMARK = originQuery({
having: `bookmarked`,
});
const QUERY_ORIGIN_PREFIX_BOOKMARK = originQuery({
where: `AND prefix BETWEEN :prefix AND :prefix || X'FFFF'`,
having: `bookmarked`,
});
// Result row indexes for urlQuery()
const QUERYINDEX_URL_URL = 1;
const QUERYINDEX_URL_STRIPPED_URL = 2;
const QUERYINDEX_URL_FRECENCY = 3;
function urlQuery(where1, where2) {
// We limit the search to places that are either bookmarked or have a frecency
// over some small, arbitrary threshold (20) in order to avoid scanning as few
// rows as possible. Keep in mind that we run this query every time the user
// types a key when the urlbar value looks like a URL with a path.
return `/* do not warn (bug no): cannot use an index to sort */
SELECT :query_type,
url,
:strippedURL,
frecency,
foreign_count > 0 AS bookmarked,
visit_count > 0 AS visited,
id
FROM moz_places
WHERE rev_host = :revHost
${where1}
UNION ALL
SELECT :query_type,
url,
:strippedURL,
frecency,
foreign_count > 0 AS bookmarked,
visit_count > 0 AS visited,
id
FROM moz_places
WHERE rev_host = :revHost || 'www.'
${where2}
ORDER BY frecency DESC, id DESC
LIMIT 1 `;
}
const QUERY_URL_HISTORY_BOOKMARK = urlQuery(
`AND (bookmarked OR frecency > 20)
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND (bookmarked OR frecency > 20)
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_HISTORY_BOOKMARK = urlQuery(
`AND (bookmarked OR frecency > 20)
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND (bookmarked OR frecency > 20)
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_HISTORY = urlQuery(
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_HISTORY = urlQuery(
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND (visited OR NOT bookmarked)
AND frecency > 20
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_BOOKMARK = urlQuery(
`AND bookmarked
AND strip_prefix_and_userinfo(url) BETWEEN :strippedURL AND :strippedURL || X'FFFF'`,
`AND bookmarked
AND strip_prefix_and_userinfo(url) BETWEEN 'www.' || :strippedURL AND 'www.' || :strippedURL || X'FFFF'`
);
const QUERY_URL_PREFIX_BOOKMARK = urlQuery(
`AND bookmarked
AND url BETWEEN :prefix || :strippedURL AND :prefix || :strippedURL || X'FFFF'`,
`AND bookmarked
AND url BETWEEN :prefix || 'www.' || :strippedURL AND :prefix || 'www.' || :strippedURL || X'FFFF'`
);
// Getters
const { XPCOMUtils } = ChromeUtils.import(
@ -762,18 +959,20 @@ Search.prototype = {
// For any given search, we run many queries/heuristics:
// 1) by alias (as defined in SearchService)
// 2) inline completion from search engine resultDomains
// 3) submission for the current search engine
// 4) Places keywords
// 5) adaptive learning (this._adaptiveQuery)
// 6) open pages not supported by history (this._switchToTabQuery)
// 7) query based on match behavior
// 3) inline completion for origins (this._originQuery) or urls (this._urlQuery)
// 4) directly typed in url (ie, can be navigated to as-is)
// 5) submission for the current search engine
// 6) Places keywords
// 7) adaptive learning (this._adaptiveQuery)
// 8) open pages not supported by history (this._switchToTabQuery)
// 9) query based on match behavior
//
// (4) only gets run if we get any filtered tokens, since if there are no
// (6) only gets run if we get any filtered tokens, since if there are no
// tokens, there is nothing to match.
//
// (1) and (5) only get run if actions are enabled. When actions are
// (1), (4), (5) only get run if actions are enabled. When actions are
// enabled, the first result is always a special result (resulting from one
// of the queries between (1) and (4) inclusive). As such, the UI is
// of the queries between (1) and (6) inclusive). As such, the UI is
// expected to auto-select the first result when actions are enabled. If the
// first result is an inline completion result, that will also be the
// default result and therefore be autofilled (this also happens if actions
@ -814,14 +1013,16 @@ Search.prototype = {
// If the heuristic result is an engine from a token alias, the search
// restriction char, or we're in search-restriction mode, then we're done.
// UrlbarProviderSearchSuggestions will handle suggestions, if any.
let tokenAliasQuery =
this._searchEngineAliasMatch &&
this._searchEngineAliasMatch.isTokenAlias;
let emptySearchRestriction =
this._trimmedOriginalSearchString.length <= 3 &&
this._leadingRestrictionToken == UrlbarTokenizer.RESTRICT.SEARCH &&
/\s*\S?$/.test(this._trimmedOriginalSearchString);
if (
emptySearchRestriction ||
(tokenAliasEngines &&
this._trimmedOriginalSearchString.startsWith("@")) ||
tokenAliasQuery ||
(this.hasBehavior("search") && this.hasBehavior("restrict"))
) {
this._autocompleteSearch.finishSearch(true);
@ -926,6 +1127,20 @@ Search.prototype = {
}
},
_matchAboutPageForAutofill() {
if (!this._shouldMatchAboutPages()) {
return false;
}
for (const url of AboutPagesUtils.visibleAboutUrls) {
if (url.startsWith(`about:${this._searchString.toLowerCase()}`)) {
this._result.setDefaultIndex(0);
this._addAutofillMatch(url.substr(6), url);
return true;
}
}
return false;
},
async _checkPreloadedSitesExpiry() {
if (!UrlbarPrefs.get("usepreloadedtopurls.enabled")) {
return;
@ -998,6 +1213,60 @@ Search.prototype = {
return true;
},
async _matchSearchEngineTokenAliasForAutofill() {
// We need an "@engine" heuristic token.
let token = this._heuristicToken;
if (!token || token.length == 1 || !token.startsWith("@")) {
return false;
}
// See if any engine has a token alias that starts with the heuristic token.
let engines = await UrlbarSearchUtils.tokenAliasEngines();
for (let { engine, tokenAliases } of engines) {
for (let alias of tokenAliases) {
if (alias.startsWith(token.toLocaleLowerCase())) {
// We found one. The match we add here is a little special compared
// to others. It needs to be an autofill match and its `value` must
// be the string that will be autofilled so that the controller will
// autofill it. But it also must be a searchengine action so that the
// front end will style it as a search engine result. The front end
// uses `finalCompleteValue` as the URL for autofill results, so set
// that to the moz-action URL.
let aliasPreservingUserCase = token + alias.substr(token.length);
let value = aliasPreservingUserCase + " ";
this._result.setDefaultIndex(0);
this._addMatch({
value,
finalCompleteValue: makeActionUrl("searchengine", {
engineName: engine.name,
alias: aliasPreservingUserCase,
input: value,
searchQuery: "",
}),
comment: engine.name,
frecency: FRECENCY_DEFAULT,
style: "autofill action searchengine",
icon: engine.iconURI ? engine.iconURI.spec : null,
});
// Set _searchEngineAliasMatch with an empty query so that we don't
// attempt to add any more matches. When a token alias is autofilled,
// the only match should be the one we just added.
this._searchEngineAliasMatch = {
engine,
alias: aliasPreservingUserCase,
query: "",
isTokenAlias: true,
};
return true;
}
}
}
return false;
},
async _matchFirstHeuristicResult(conn) {
// We always try to make the first result a special "heuristic" result. The
// heuristics below determine what type of result it will be, if any.
@ -1020,6 +1289,30 @@ Search.prototype = {
let shouldAutofill = this._shouldAutofill;
if (this.pending && shouldAutofill) {
// It may also look like an about: link.
let matched = await this._matchAboutPageForAutofill();
if (matched) {
return true;
}
}
if (this.pending && shouldAutofill) {
// It may also look like a URL we know from the database.
let matched = await this._matchKnownUrl(conn);
if (matched) {
return true;
}
}
if (this.pending && shouldAutofill) {
// Or it may look like a search engine domain.
let matched = await this._matchSearchEngineDomain();
if (matched) {
return true;
}
}
if (this.pending && shouldAutofill) {
let matched = this._matchPreloadedSiteForAutofill();
if (matched) {
@ -1027,10 +1320,44 @@ Search.prototype = {
}
}
if (this.pending && shouldAutofill) {
let matched = await this._matchSearchEngineTokenAliasForAutofill();
if (matched) {
return true;
}
}
// Fall back to UrlbarProviderHeuristicFallback.
return false;
},
async _matchKnownUrl(conn) {
let gotResult = false;
// If search string looks like an origin, try to autofill against origins.
// Otherwise treat it as a possible URL. When the string has only one slash
// at the end, we still treat it as an URL.
let query, params;
if (
UrlbarTokenizer.looksLikeOrigin(this._searchString, {
ignoreKnownDomains: true,
})
) {
[query, params] = this._originQuery;
} else {
[query, params] = this._urlQuery;
}
// _urlQuery doesn't always return a query.
if (query) {
await conn.executeCached(query, params, (row, cancel) => {
gotResult = true;
this._onResultRow(row, cancel);
});
}
return gotResult;
},
async _matchPlacesKeyword(keyword) {
let entry = await PlacesUtils.keywords.fetch(keyword);
if (!entry) {
@ -1087,6 +1414,71 @@ Search.prototype = {
return true;
},
async _matchSearchEngineDomain() {
if (!UrlbarPrefs.get("autoFill.searchEngines")) {
return false;
}
if (!this._searchString) {
return false;
}
// engineForDomainPrefix only matches against engine domains.
// Remove an eventual trailing slash from the search string (without the
// prefix) and check if the resulting string is worth matching.
// Later, we'll verify that the found result matches the original
// searchString and eventually discard it.
let searchStr = this._searchString;
if (searchStr.indexOf("/") == searchStr.length - 1) {
searchStr = searchStr.slice(0, -1);
}
// If the search string looks more like a url than a domain, bail out.
if (
!UrlbarTokenizer.looksLikeOrigin(searchStr, { ignoreKnownDomains: true })
) {
return false;
}
let engine = await UrlbarSearchUtils.engineForDomainPrefix(searchStr);
if (!engine) {
return false;
}
let url = engine.searchForm;
let domain = engine.getResultDomain();
// Verify that the match we got is acceptable. Autofilling "example/" to
// "example.com/" would not be good.
if (
(this._strippedPrefix && !url.startsWith(this._strippedPrefix)) ||
!(domain + "/").includes(this._searchString)
) {
return false;
}
// The value that's autofilled in the input is the prefix the user typed, if
// any, plus the portion of the engine domain that the user typed. Append a
// trailing slash too, as is usual with autofill.
let value =
this._strippedPrefix + domain.substr(domain.indexOf(searchStr)) + "/";
let finalCompleteValue = url;
try {
let fixupInfo = Services.uriFixup.getFixupURIInfo(url, 0);
if (fixupInfo.fixedURI) {
finalCompleteValue = fixupInfo.fixedURI.spec;
}
} catch (ex) {}
this._result.setDefaultIndex(0);
this._addMatch({
value,
finalCompleteValue,
comment: engine.name,
icon: engine.iconURI ? engine.iconURI.spec : null,
style: "priority-search",
frecency: Infinity,
});
return true;
},
async _matchSearchEngineAlias(alias) {
let engine = await UrlbarSearchUtils.engineForAlias(alias);
if (!engine) {
@ -1208,6 +1600,14 @@ Search.prototype = {
_onResultRow(row, cancel) {
let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);
switch (queryType) {
case QUERYTYPE_AUTOFILL_ORIGIN:
this._result.setDefaultIndex(0);
this._addOriginAutofillMatch(row);
break;
case QUERYTYPE_AUTOFILL_URL:
this._result.setDefaultIndex(0);
this._addURLAutofillMatch(row);
break;
case QUERYTYPE_ADAPTIVE:
this._addAdaptiveQueryMatch(row);
break;
@ -1336,6 +1736,16 @@ Search.prototype = {
this.notifyResult(true, match.type == UrlbarUtils.RESULT_GROUP.HEURISTIC);
},
// Ranks a URL prefix from 3 - 0 with the following preferences:
// https:// > https://www. > http:// > http://www.
// Higher is better.
// Returns -1 if the prefix does not match any of the above.
_getPrefixRank(prefix) {
return ["http://www.", "http://", "https://www.", "https://"].indexOf(
prefix
);
},
/**
* Check for duplicates and either discard the duplicate or replace the
* original match, in case the new one is more specific. For example,
@ -1401,9 +1811,12 @@ Search.prototype = {
// 1. If the two URLs are the same, dedupe whichever is not the
// heuristic result.
// 2. If they both contain www. or both do not contain it, prefer https.
// 3. If they differ by www., send both results to the Muxer and allow
// it to decide based on results from other providers.
let prefixRank = UrlbarUtils.getPrefixRank(prefix);
// 3. If they differ by www.:
// 3a. If the page titles are different, keep both. This is a guard
// against deduping when www.site.com and site.com have different
// content.
// 3b. Otherwise, dedupe based on the priorities in _getPrefixRank.
let prefixRank = this._getPrefixRank(prefix);
for (let i = 0; i < this._usedURLs.length; ++i) {
if (!this._usedURLs[i]) {
// This is true when the result at [i] is a searchengine result.
@ -1414,9 +1827,10 @@ Search.prototype = {
key: existingKey,
prefix: existingPrefix,
type: existingType,
comment: existingComment,
} = this._usedURLs[i];
let existingPrefixRank = UrlbarUtils.getPrefixRank(existingPrefix);
let existingPrefixRank = this._getPrefixRank(existingPrefix);
if (ObjectUtils.deepEqual(existingKey, urlMapKey)) {
isDupe = true;
@ -1461,12 +1875,25 @@ Search.prototype = {
continue;
}
} else {
// We have two identical URLs that differ only by www. We need to
// be sure what the heuristic result is before deciding how we
// should dedupe. We mark these as non-duplicates and let the
// muxer handle it.
isDupe = false;
continue;
// If either result is the heuristic, this will be true and we
// will keep both results.
if (match.comment != existingComment) {
isDupe = false;
continue;
}
if (prefixRank <= existingPrefixRank) {
break; // Replace match.
} else {
this._usedURLs[i] = {
key: urlMapKey,
action,
type: match.type,
prefix,
comment: match.comment,
};
return { index: i, replace: true };
}
}
}
}
@ -1540,6 +1967,42 @@ Search.prototype = {
return { index, replace };
},
_addOriginAutofillMatch(row) {
this._addAutofillMatch(
row.getResultByIndex(QUERYINDEX_ORIGIN_AUTOFILLED_VALUE),
row.getResultByIndex(QUERYINDEX_ORIGIN_URL),
row.getResultByIndex(QUERYINDEX_ORIGIN_FRECENCY)
);
},
_addURLAutofillMatch(row) {
let url = row.getResultByIndex(QUERYINDEX_URL_URL);
let strippedURL = row.getResultByIndex(QUERYINDEX_URL_STRIPPED_URL);
// We autofill urls to-the-next-slash.
// http://mozilla.org/foo/bar/baz will be autofilled to:
// - http://mozilla.org/f[oo/]
// - http://mozilla.org/foo/b[ar/]
// - http://mozilla.org/foo/bar/b[az]
let value;
let strippedURLIndex = url.indexOf(strippedURL);
let strippedPrefix = url.substr(0, strippedURLIndex);
let nextSlashIndex = url.indexOf(
"/",
strippedURLIndex + strippedURL.length - 1
);
if (nextSlashIndex == -1) {
value = url.substr(strippedURLIndex);
} else {
value = url.substring(strippedURLIndex, nextSlashIndex + 1);
}
this._addAutofillMatch(
value,
strippedPrefix + value,
row.getResultByIndex(QUERYINDEX_URL_FRECENCY)
);
},
_addAutofillMatch(
autofilledValue,
finalCompleteValue,
@ -1810,6 +2273,125 @@ Search.prototype = {
return true;
},
/**
* Obtains the query to search for autofill origin results.
*
* @return an array consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
get _originQuery() {
// At this point, _searchString is not a URL with a path; it does not
// contain a slash, except for possibly at the very end. If there is
// trailing slash, remove it when searching here to match the rest of the
// string because it may be an origin.
let searchStr = this._searchString.endsWith("/")
? this._searchString.slice(0, -1)
: this._searchString;
let opts = {
query_type: QUERYTYPE_AUTOFILL_ORIGIN,
searchString: searchStr.toLowerCase(),
stddevMultiplier: UrlbarPrefs.get("autoFill.stddevMultiplier"),
};
if (this._strippedPrefix) {
opts.prefix = this._strippedPrefix;
}
if (this.hasBehavior("history") && this.hasBehavior("bookmark")) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_HISTORY_BOOKMARK
: QUERY_ORIGIN_HISTORY_BOOKMARK,
opts,
];
}
if (this.hasBehavior("history")) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_HISTORY
: QUERY_ORIGIN_HISTORY,
opts,
];
}
if (this.hasBehavior("bookmark")) {
return [
this._strippedPrefix
? QUERY_ORIGIN_PREFIX_BOOKMARK
: QUERY_ORIGIN_BOOKMARK,
opts,
];
}
throw new Error("Either history or bookmark behavior expected");
},
/**
* Obtains the query to search for autoFill url results.
*
* @return an array consisting of the correctly optimized query to search the
* database with and an object containing the params to bound.
*/
get _urlQuery() {
// Try to get the host from the search string. The host is the part of the
// URL up to either the path slash, port colon, or query "?". If the search
// string doesn't look like it begins with a host, then return; it doesn't
// make sense to do a URL query with it.
if (!this._urlQueryHostRegexp) {
this._urlQueryHostRegexp = /^[^/:?]+/;
}
let hostMatch = this._urlQueryHostRegexp.exec(this._searchString);
if (!hostMatch) {
return [null, null];
}
let host = hostMatch[0].toLowerCase();
let revHost =
host
.split("")
.reverse()
.join("") + ".";
// Build a string that's the URL stripped of its prefix, i.e., the host plus
// everything after the host. Use _trimmedOriginalSearchString instead of
// this._searchString because this._searchString has had unEscapeURIForUI()
// called on it. It's therefore not necessarily the literal URL.
let strippedURL = this._trimmedOriginalSearchString;
if (this._strippedPrefix) {
strippedURL = strippedURL.substr(this._strippedPrefix.length);
}
strippedURL = host + strippedURL.substr(host.length);
let opts = {
query_type: QUERYTYPE_AUTOFILL_URL,
revHost,
strippedURL,
};
if (this._strippedPrefix) {
opts.prefix = this._strippedPrefix;
}
if (this.hasBehavior("history") && this.hasBehavior("bookmark")) {
return [
this._strippedPrefix
? QUERY_URL_PREFIX_HISTORY_BOOKMARK
: QUERY_URL_HISTORY_BOOKMARK,
opts,
];
}
if (this.hasBehavior("history")) {
return [
this._strippedPrefix ? QUERY_URL_PREFIX_HISTORY : QUERY_URL_HISTORY,
opts,
];
}
if (this.hasBehavior("bookmark")) {
return [
this._strippedPrefix ? QUERY_URL_PREFIX_BOOKMARK : QUERY_URL_BOOKMARK,
opts,
];
}
throw new Error("Either history or bookmark behavior expected");
},
// The result is notified to the search listener on a timer, to chunk multiple
// match updates together and avoid rebuilding the popup at every new match.
_notifyTimer: null,

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -44,6 +44,14 @@ var {
Services.scriptloader.loadSubScript(uri.spec, this);
}
// Add a lazy getter for common autofill test tasks used by some tests.
{
/* import-globals-from ./autofill_tasks.js */
let file = do_get_file("autofill_tasks.js", false);
let uri = Services.io.newFileURI(file);
XPCOMUtils.defineLazyScriptGetter(this, "addAutofillTasks", uri.spec);
}
// Put any other stuff relative to this test folder below.
XPCOMUtils.defineLazyModuleGetters(this, {
@ -267,6 +275,10 @@ async function check_autocomplete(test) {
};
});
let expectedSearches = 1;
if (test.incompleteSearch) {
controller.startSearch(test.incompleteSearch);
expectedSearches++;
}
info("Searching for: '" + test.search + "'");
controller.startSearch(test.search);

Просмотреть файл

@ -0,0 +1,62 @@
/* 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/. */
// Functional tests for inline autocomplete
add_task(async function test_urls_order() {
info("Add urls, check for correct order");
let places = [
{ uri: NetUtil.newURI("http://visit1.mozilla.org") },
{ uri: NetUtil.newURI("http://visit2.mozilla.org") },
];
await PlacesTestUtils.addVisits(places);
await check_autocomplete({
search: "vis",
autofilled: "visit2.mozilla.org/",
completed: "http://visit2.mozilla.org/",
});
await cleanup();
});
add_task(async function test_bookmark_first() {
info("With a bookmark and history, the query result should be the bookmark");
await PlacesTestUtils.addBookmarkWithDetails({
uri: NetUtil.newURI("http://bookmark1.mozilla.org/"),
});
await PlacesTestUtils.addVisits(
NetUtil.newURI("http://bookmark1.mozilla.org/foo")
);
await check_autocomplete({
search: "bookmark",
autofilled: "bookmark1.mozilla.org/",
completed: "http://bookmark1.mozilla.org/",
});
await cleanup();
});
add_task(async function test_complete_querystring() {
info("Check to make sure we autocomplete after ?");
await PlacesTestUtils.addVisits(
NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious")
);
await check_autocomplete({
search: "smokey.mozilla.org/foo?",
autofilled: "smokey.mozilla.org/foo?bacon=delicious",
completed: "http://smokey.mozilla.org/foo?bacon=delicious",
});
await cleanup();
});
add_task(async function test_complete_fragment() {
info("Check to make sure we autocomplete after #");
await PlacesTestUtils.addVisits(
NetUtil.newURI("http://smokey.mozilla.org/foo?bacon=delicious#bar")
);
await check_autocomplete({
search: "smokey.mozilla.org/foo?bacon=delicious#bar",
autofilled: "smokey.mozilla.org/foo?bacon=delicious#bar",
completed: "http://smokey.mozilla.org/foo?bacon=delicious#bar",
});
await cleanup();
});

Просмотреть файл

@ -0,0 +1,83 @@
/* 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/. */
"use strict";
// "about:ab" should match "about:about"
add_task(async function aboutAb() {
await check_autocomplete({
search: "about:ab",
autofilled: "about:about",
completed: "about:about",
matches: [
{
value: "about:about",
comment: "about:about",
style: ["autofill", "heuristic"],
},
],
});
});
// "about:Ab" should match "about:about"
add_task(async function aboutAb() {
await check_autocomplete({
search: "about:Ab",
autofilled: "about:About",
completed: "about:about",
matches: [
{
value: "about:about",
comment: "about:about",
style: ["autofill", "heuristic"],
},
],
});
});
// "about:about" should match "about:about"
add_task(async function aboutAbout() {
await check_autocomplete({
search: "about:about",
autofilled: "about:about",
completed: "about:about",
matches: [
{
value: "about:about",
comment: "about:about",
style: ["autofill", "heuristic"],
},
],
});
});
// "about:a" should complete to "about:about" and also match "about:addons"
add_task(async function aboutAboutAndAboutAddons() {
await check_autocomplete({
search: "about:a",
autofilled: "about:about",
completed: "about:about",
matches: [
{
value: "about:about",
comment: "about:about",
style: ["autofill", "heuristic"],
},
{
value: "about:addons",
comment: "about:addons",
},
],
});
});
// "about:" should *not* match anything
add_task(async function aboutColonHasNoMatch() {
await check_autocomplete({
search: "about:",
autofilled: "about:",
completed: "about:",
matches: [],
});
});

Просмотреть файл

@ -4,20 +4,7 @@
"use strict";
const ENGINE_NAME = "engine-suggestions.xml";
const HEURISTIC_FALLBACK_PROVIDERNAME = "HeuristicFallback";
const origin = "example.com";
async function cleanup() {
let suggestPrefs = ["history", "bookmark", "openpage"];
for (let type of suggestPrefs) {
Services.prefs.clearUserPref("browser.urlbar.suggest." + type);
}
await cleanupPlaces();
}
testEngine_setup();
addAutofillTasks(true);
// "example.com/" should match http://example.com/. i.e., the search string
// should be treated as if it didn't have the trailing slash.
@ -27,18 +14,16 @@ add_task(async function trailingSlash() {
uri: "http://example.com/",
},
]);
let context = createContext(`${origin}/`, { isPrivate: false });
await check_results({
context,
autofilled: `${origin}/`,
completed: `http://${origin}/`,
await check_autocomplete({
search: "example.com/",
autofilled: "example.com/",
completed: "http://example.com/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}/`,
title: `${origin}/`,
heuristic: true,
}),
{
value: "example.com/",
comment: "example.com/",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -52,17 +37,16 @@ add_task(async function trailingSlashWWW() {
uri: "http://www.example.com/",
},
]);
let context = createContext(`${origin}/`, { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "example.com/",
autofilled: "example.com/",
completed: "http://www.example.com/",
matches: [
makeVisitResult(context, {
uri: `http://www.${origin}/`,
title: `www.${origin}/`,
heuristic: true,
}),
{
value: "example.com/",
comment: "www.example.com/",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -75,17 +59,16 @@ add_task(async function port() {
uri: "http://example.com:8888/",
},
]);
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "ex",
autofilled: "example.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `${origin}:8888`,
heuristic: true,
}),
{
value: "example.com:8888/",
comment: "example.com:8888",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -99,17 +82,16 @@ add_task(async function portPartial() {
uri: "http://example.com:8888/",
},
]);
let context = createContext(`${origin}:8`, { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "example.com:8",
autofilled: "example.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `${origin}:8888`,
heuristic: true,
}),
{
value: "example.com:8888/",
comment: "example.com:8888",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -123,17 +105,16 @@ add_task(async function preserveCase() {
uri: "http://example.com/",
},
]);
let context = createContext("EXaM", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "EXaM",
autofilled: "EXaMple.com/",
completed: "http://example.com/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}/`,
title: `${origin}`,
heuristic: true,
}),
{
value: "example.com/",
comment: "example.com",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -148,17 +129,16 @@ add_task(async function preserveCasePort() {
uri: "http://example.com:8888/",
},
]);
let context = createContext("EXaM", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "EXaM",
autofilled: "EXaMple.com:8888/",
completed: "http://example.com:8888/",
matches: [
makeVisitResult(context, {
uri: `http://${origin}:8888/`,
title: `${origin}:8888`,
heuristic: true,
}),
{
value: "example.com:8888/",
comment: "example.com:8888",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -171,18 +151,9 @@ add_task(async function portNoMatch1() {
uri: "http://example.com:8888/",
},
]);
let context = createContext(`${origin}:89`, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `http://${origin}:89/`,
title: `http://${origin}:89/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search: "example.com:89",
matches: [],
});
await cleanup();
});
@ -194,18 +165,9 @@ add_task(async function portNoMatch2() {
uri: "http://example.com:8888/",
},
]);
let context = createContext(`${origin}:9`, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `http://${origin}:9/`,
title: `http://${origin}:9/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search: "example.com:9",
matches: [],
});
await cleanup();
});
@ -217,17 +179,9 @@ add_task(async function trailingSlash() {
uri: "http://example.com/",
},
]);
let context = createContext("example/", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://example/",
title: "http://example/",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search: "example/",
matches: [],
});
await cleanup();
});
@ -239,31 +193,21 @@ add_task(async function multidotted() {
uri: "http://www.example.co.jp:8888/",
},
]);
let context = createContext("www.example.co.", { isPrivate: false });
await check_results({
context,
autofilled: "www.example.co.jp:8888/",
await check_autocomplete({
search: "www.example.co.",
completed: "http://www.example.co.jp:8888/",
matches: [
makeVisitResult(context, {
uri: "http://www.example.co.jp:8888/",
title: "www.example.co.jp:8888",
heuristic: true,
}),
makeSearchResult(context, {
engineName: ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
{
value: "www.example.co.jp:8888/",
comment: "www.example.co.jp:8888",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
});
add_task(async function test_ip() {
// IP addresses have complicated rules around whether they show
// HeuristicFallback's backup search result. Flip this pref to disable that
// backup search and simplify ths subtest.
Services.prefs.setBoolPref("keyword.enabled", false);
for (let str of [
"192.168.1.1/",
"255.255.255.255:8080/",
@ -274,23 +218,20 @@ add_task(async function test_ip() {
info("testing " + str);
await PlacesTestUtils.addVisits("http://" + str);
for (let i = 1; i < str.length; ++i) {
let context = createContext(str.substring(0, i), { isPrivate: false });
await check_results({
context,
autofilled: str,
await check_autocomplete({
search: str.substring(0, i),
completed: "http://" + str,
matches: [
makeVisitResult(context, {
uri: "http://" + str,
title: str.replace(/\/$/, ""), // strip trailing slash
heuristic: true,
}),
{
value: str,
comment: str.replace(/\/$/, ""), // strip trailing slash
style: ["autofill", "heuristic"],
},
],
});
}
await cleanup();
}
Services.prefs.clearUserPref("keyword.enabled");
});
// host starting with large number.
@ -300,17 +241,15 @@ add_task(async function large_number_host() {
uri: "http://12345example.it:8888/",
},
]);
let context = createContext("1234", { isPrivate: false });
await check_results({
context,
autofilled: "12345example.it:8888/",
await check_autocomplete({
search: "1234",
completed: "http://12345example.it:8888/",
matches: [
makeVisitResult(context, {
uri: "http://12345example.it:8888/",
title: "12345example.it:8888",
heuristic: true,
}),
{
value: "12345example.it:8888/",
comment: "12345example.it:8888",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
@ -357,17 +296,16 @@ add_task(async function groupByHost() {
);
// The https origin should be autofilled.
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "ex",
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
uri: "https://example.com/",
title: "https://example.com",
heuristic: true,
}),
{
value: "example.com/",
comment: "https://example.com",
style: ["autofill", "heuristic"],
},
],
});
@ -422,17 +360,16 @@ add_task(async function groupByHostNonDefaultStddevMultiplier() {
);
// The https origin should be autofilled.
let context = createContext("ex", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "ex",
autofilled: "example.com/",
completed: "https://example.com/",
matches: [
makeVisitResult(context, {
uri: "https://example.com/",
title: "https://example.com",
heuristic: true,
}),
{
value: "example.com/",
comment: "https://example.com",
style: ["autofill", "heuristic"],
},
],
});
@ -441,8 +378,8 @@ add_task(async function groupByHostNonDefaultStddevMultiplier() {
await cleanup();
});
// This is similar to suggestHistoryFalse_bookmark_0 in test_autofill_tasks.js,
// but it adds unbookmarked visits for multiple URLs with the same origin.
// This is similar to suggestHistoryFalse_bookmark_0 in autofill_tasks.js, but
// it adds unbookmarked visits for multiple URLs with the same origin.
add_task(async function suggestHistoryFalse_bookmark_multiple() {
// Force only bookmarked pages to be suggested and therefore only bookmarked
// pages to be completed.
@ -463,16 +400,9 @@ add_task(async function suggestHistoryFalse_bookmark_multiple() {
uri: baseURL + "other1",
},
]);
let context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
await check_autocomplete({
search,
matches: [],
});
await PlacesTestUtils.addVisits([
@ -480,16 +410,9 @@ add_task(async function suggestHistoryFalse_bookmark_multiple() {
uri: bookmarkedURL,
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
await check_autocomplete({
search,
matches: [],
});
await PlacesTestUtils.addVisits([
@ -497,37 +420,30 @@ add_task(async function suggestHistoryFalse_bookmark_multiple() {
uri: baseURL + "other2",
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
heuristic: true,
}),
],
await check_autocomplete({
search,
matches: [],
});
// Now bookmark the second URL. It should be suggested and completed.
await PlacesTestUtils.addBookmarkWithDetails({
uri: bookmarkedURL,
});
context = createContext(search, { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search,
autofilled: "example.com/",
completed: baseURL,
matches: [
makeVisitResult(context, {
uri: baseURL,
title: "example.com",
heuristic: true,
}),
makeBookmarkResult(context, {
uri: bookmarkedURL,
title: "A bookmark",
}),
{
value: "example.com/",
comment: "example.com",
style: ["autofill", "heuristic"],
},
{
value: bookmarkedURL,
comment: "A bookmark",
style: ["bookmark"],
},
],
});
@ -557,18 +473,9 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
uri: baseURL + "other1",
},
]);
let context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `${search}/`,
title: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search,
matches: [],
});
await PlacesTestUtils.addVisits([
@ -576,18 +483,9 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
uri: bookmarkedURL,
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `${search}/`,
title: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search,
matches: [],
});
await PlacesTestUtils.addVisits([
@ -595,82 +493,32 @@ add_task(async function suggestHistoryFalse_bookmark_prefix_multiple() {
uri: baseURL + "other2",
},
]);
context = createContext(search, { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: `${search}/`,
title: `${search}/`,
iconUri: "",
heuristic: true,
providerName: HEURISTIC_FALLBACK_PROVIDERNAME,
}),
],
await check_autocomplete({
search,
matches: [],
});
// Now bookmark the second URL. It should be suggested and completed.
await PlacesTestUtils.addBookmarkWithDetails({
uri: bookmarkedURL,
});
context = createContext(search, { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search,
autofilled: "http://example.com/",
completed: baseURL,
matches: [
makeVisitResult(context, {
uri: baseURL,
title: "example.com",
heuristic: true,
}),
makeBookmarkResult(context, {
uri: bookmarkedURL,
title: "A bookmark",
}),
{
value: "http://example.com/",
comment: "example.com",
style: ["autofill", "heuristic"],
},
{
value: bookmarkedURL,
comment: "A bookmark",
style: ["bookmark"],
},
],
});
await cleanup();
});
/**
* Returns the origin frecency stats.
*
* @returns {object}
* An object { count, sum, squares }.
*/
async function getOriginFrecencyStats() {
let db = await PlacesUtils.promiseDBConnection();
let rows = await db.execute(`
SELECT
IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_count'), 0),
IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_sum'), 0),
IFNULL((SELECT value FROM moz_meta WHERE key = 'origin_frecency_sum_of_squares'), 0)
`);
let count = rows[0].getResultByIndex(0);
let sum = rows[0].getResultByIndex(1);
let squares = rows[0].getResultByIndex(2);
return { count, sum, squares };
}
/**
* Returns the origin autofill frecency threshold.
*
* @returns {number}
* The threshold.
*/
async function getOriginAutofillThreshold() {
let { count, sum, squares } = await getOriginFrecencyStats();
if (!count) {
return 0;
}
if (count == 1) {
return sum;
}
let stddevMultiplier = UrlbarPrefs.get("autoFill.stddevMultiplier");
return (
sum / count +
stddevMultiplier * Math.sqrt((squares - (sum * sum) / count) / count)
);
}

Просмотреть файл

@ -32,26 +32,30 @@ add_task(async function basic() {
title: TEST_ENGINE_ALIAS,
});
let search = TEST_ENGINE_ALIAS.substr(
0,
Math.round(TEST_ENGINE_ALIAS.length / 2)
);
let autofilledValue = TEST_ENGINE_ALIAS + " ";
let context = createContext(search, { isPrivate: false });
await check_results({
context,
let completedURL = makeActionURI("searchengine", {
engineName: TEST_ENGINE_NAME,
alias: TEST_ENGINE_ALIAS,
input: autofilledValue,
searchQuery: "",
}).spec;
await check_autocomplete({
search: TEST_ENGINE_ALIAS.substr(
0,
Math.round(TEST_ENGINE_ALIAS.length / 2)
),
autofilled: autofilledValue,
completed: completedURL,
matches: [
makeSearchResult(context, {
engineName: TEST_ENGINE_NAME,
alias: TEST_ENGINE_ALIAS,
query: "",
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
heuristic: true,
}),
{
value: autofilledValue,
comment: TEST_ENGINE_NAME,
uri: completedURL,
style: ["autofill", "action", "searchengine", "heuristic"],
},
],
});
await cleanupPlaces();
await cleanup();
});
// Searching for @AUTOFI should autofill to @AUTOFIlltest, preserving the case
@ -70,21 +74,25 @@ add_task(async function preserveCase() {
Math.round(TEST_ENGINE_ALIAS.length / 2)
);
let alias = search + TEST_ENGINE_ALIAS.substr(search.length);
let autofilledValue = alias + " ";
let context = createContext(search, { isPrivate: false });
await check_results({
context,
let completedURL = makeActionURI("searchengine", {
engineName: TEST_ENGINE_NAME,
alias,
input: autofilledValue,
searchQuery: "",
}).spec;
await check_autocomplete({
search,
autofilled: autofilledValue,
completed: completedURL,
matches: [
makeSearchResult(context, {
engineName: TEST_ENGINE_NAME,
alias,
query: "",
keywordOffer: UrlbarUtils.KEYWORD_OFFER.HIDE,
heuristic: true,
}),
{
value: autofilledValue,
comment: TEST_ENGINE_NAME,
uri: completedURL,
style: ["autofill", "action", "searchengine", "heuristic"],
},
],
});
await cleanupPlaces();
await cleanup();
});

Просмотреть файл

@ -0,0 +1,201 @@
/* 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/. */
// The autoFill.searchEngines pref autofills the domains of engines registered
// with the search service. That's what this test checks. It's a different
// path in UnifiedComplete.js from normal moz_places autofill, which is tested
// in test_autofill_origins.js and test_autofill_urls.js.
"use strict";
add_task(async function searchEngines() {
Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
let schemes = ["http", "https"];
for (let i = 0; i < schemes.length; i++) {
let scheme = schemes[i];
let engine = await Services.search.addEngineWithDetails("TestEngine", {
method: "GET",
template: scheme + "://www.example.com/",
searchGetParams: "q={searchTerms}",
});
await check_autocomplete({
search: "ex",
autofilled: "example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: "example.com",
autofilled: "example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: "example.com/",
autofilled: "example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: "www.ex",
autofilled: "www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: "www.example.com",
autofilled: "www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: "www.example.com/",
autofilled: "www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: "www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://ex",
autofilled: scheme + "://example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://example.com",
autofilled: scheme + "://example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://example.com/",
autofilled: scheme + "://example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://www.ex",
autofilled: scheme + "://www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://www.example.com",
autofilled: scheme + "://www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
await check_autocomplete({
search: scheme + "://www.example.com/",
autofilled: scheme + "://www.example.com/",
completed: scheme + "://www.example.com/",
matches: [
{
value: scheme + "://www.example.com/",
comment: "TestEngine",
style: ["heuristic", "priority-search"],
},
],
});
let otherScheme = schemes[(i + 1) % schemes.length];
await check_autocomplete({
search: otherScheme + "://ex",
matches: [],
});
await check_autocomplete({
search: otherScheme + "://www.ex",
matches: [],
});
await check_autocomplete({
search: "example/",
autofilled: "example/",
completed: "example/",
matches: [],
});
await Services.search.removeEngine(engine);
}
await cleanup();
});

Просмотреть файл

@ -0,0 +1,114 @@
/* 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/. */
"use strict";
addAutofillTasks(false);
// "example.com/foo/" should match http://example.com/foo/.
add_task(async function multipleSlashes() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com/foo/",
},
]);
await check_autocomplete({
search: "example.com/foo/",
autofilled: "example.com/foo/",
completed: "http://example.com/foo/",
matches: [
{
value: "example.com/foo/",
comment: "example.com/foo/",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
});
// "example.com:8888/f" should match http://example.com:8888/foo.
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo",
},
]);
await check_autocomplete({
search: "example.com:8888/f",
autofilled: "example.com:8888/foo",
completed: "http://example.com:8888/foo",
matches: [
{
value: "example.com:8888/foo",
comment: "example.com:8888/foo",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
});
// "example.com:8999/f" should *not* match http://example.com:8888/foo.
add_task(async function portNoMatch() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo",
},
]);
await check_autocomplete({
search: "example.com:8999/f",
matches: [],
});
await cleanup();
});
// autofill to the next slash
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo/bar/baz",
},
]);
await check_autocomplete({
search: "example.com:8888/foo/b",
autofilled: "example.com:8888/foo/bar/",
completed: "http://example.com:8888/foo/bar/",
matches: [
{
value: "example.com:8888/foo/bar/",
comment: "example.com:8888/foo/bar/",
style: ["autofill", "heuristic"],
},
{
value: "http://example.com:8888/foo/bar/baz",
comment: "test visit for http://example.com:8888/foo/bar/baz",
style: ["favicon"],
},
],
});
await cleanup();
});
// autofill to the next slash, end of url
add_task(async function port() {
await PlacesTestUtils.addVisits([
{
uri: "http://example.com:8888/foo/bar/baz",
},
]);
await check_autocomplete({
search: "example.com:8888/foo/bar/b",
autofilled: "example.com:8888/foo/bar/baz",
completed: "http://example.com:8888/foo/bar/baz",
matches: [
{
value: "example.com:8888/foo/bar/baz",
comment: "example.com:8888/foo/bar/baz",
style: ["autofill", "heuristic"],
},
],
});
await cleanup();
});

Просмотреть файл

@ -2,58 +2,36 @@
* 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 ENGINE_NAME = "engine-suggestions.xml";
testEngine_setup();
add_task(async function test_prefix_space_noautofill() {
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://moz.org/test/"),
uri: NetUtil.newURI("http://moz.org/test/"),
transition: TRANSITION_TYPED,
});
info("Should not try to autoFill if search string contains a space");
let context = createContext(" mo", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
query: " mo",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://moz.org/test/",
title: "test visit for http://moz.org/test/",
}),
],
await check_autocomplete({
search: " mo",
autofilled: " mo",
completed: " mo",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_trailing_space_noautofill() {
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://moz.org/test/"),
uri: NetUtil.newURI("http://moz.org/test/"),
transition: TRANSITION_TYPED,
});
info("Should not try to autoFill if search string contains a space");
let context = createContext("mo ", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
query: "mo ",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://moz.org/test/",
title: "test visit for http://moz.org/test/",
}),
],
await check_autocomplete({
search: "mo ",
autofilled: "mo ",
completed: "mo ",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_autofill() {
@ -68,18 +46,13 @@ add_task(async function test_searchEngine_autofill() {
info(
"Should autoFill search engine if search string does not contains a space"
);
let context = createContext("ca", { isPrivate: false });
await check_results({
context,
matches: [
makePrioritySearchResult(context, {
engineName: "CakeSearch",
heuristic: true,
}),
],
await check_autocomplete({
search: "ca",
autofilled: "cake.search/",
completed: "http://cake.search/",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_prefix_space_noautofill() {
@ -94,19 +67,13 @@ add_task(async function test_searchEngine_prefix_space_noautofill() {
info(
"Should not try to autoFill search engine if search string contains a space"
);
let context = createContext(" cu", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
query: " cu",
heuristic: true,
}),
],
await check_autocomplete({
search: " cu",
autofilled: " cu",
completed: " cu",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_trailing_space_noautofill() {
@ -121,19 +88,13 @@ add_task(async function test_searchEngine_trailing_space_noautofill() {
info(
"Should not try to autoFill search engine if search string contains a space"
);
let context = createContext("ba ", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
query: "ba ",
heuristic: true,
}),
],
await check_autocomplete({
search: "ba ",
autofilled: "ba ",
completed: "ba ",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_www_noautofill() {
@ -148,18 +109,13 @@ add_task(async function test_searchEngine_www_noautofill() {
info(
"Should not autoFill search engine if search string contains www. but engine doesn't"
);
let context = createContext("www.ham", { isPrivate: false });
await check_results({
context,
matches: [
makeSearchResult(context, {
engineName: ENGINE_NAME,
heuristic: true,
}),
],
await check_autocomplete({
search: "www.ham",
autofilled: "www.ham",
completed: "www.ham",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_different_scheme_noautofill() {
@ -174,20 +130,13 @@ add_task(async function test_searchEngine_different_scheme_noautofill() {
info(
"Should not autoFill search engine if search string has a different scheme."
);
let context = createContext("http://pie", { isPrivate: false });
await check_results({
context,
matches: [
makeVisitResult(context, {
uri: "http://pie/",
title: "http://pie/",
iconUri: "",
heuristic: true,
}),
],
await check_autocomplete({
search: "http://pie",
autofilled: "http://pie",
completed: "http://pie",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_searchEngine_matching_prefix_autofill() {
@ -200,77 +149,46 @@ add_task(async function test_searchEngine_matching_prefix_autofill() {
registerCleanupFunction(async () => Services.search.removeEngine(engine));
info("Should autoFill search engine if search string has matching prefix.");
let context = createContext("http://www.be", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "http://www.be",
autofilled: "http://www.bean.search/",
matches: [
makePrioritySearchResult(context, {
engineName: "BeanSearch",
heuristic: true,
}),
],
completed: "http://www.bean.search/",
});
info("Should autoFill search engine if search string has www prefix.");
context = createContext("www.be", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "www.be",
autofilled: "www.bean.search/",
matches: [
makePrioritySearchResult(context, {
engineName: "BeanSearch",
heuristic: true,
}),
],
completed: "http://www.bean.search/",
});
info("Should autoFill search engine if search string has matching scheme.");
context = createContext("http://be", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "http://be",
autofilled: "http://bean.search/",
matches: [
makePrioritySearchResult(context, {
engineName: "BeanSearch",
heuristic: true,
}),
],
completed: "http://www.bean.search/",
});
await cleanupPlaces();
await cleanup();
});
add_task(async function test_prefix_autofill() {
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
uri: NetUtil.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://moz.org/test/"),
uri: NetUtil.newURI("http://moz.org/test/"),
});
info(
"Should not try to autoFill in-the-middle if a search is canceled immediately"
);
let context = createContext("mozi", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
incompleteSearch: "moz",
search: "mozi",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
makeVisitResult(context, {
uri: "http://mozilla.org/",
title: "mozilla.org",
heuristic: true,
}),
makeVisitResult(context, {
uri: "http://mozilla.org/test/",
title: "test visit for http://mozilla.org/test/",
providerName: "UnifiedComplete",
}),
],
});
await cleanupPlaces();
await cleanup();
});

Просмотреть файл

@ -0,0 +1,81 @@
/* 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_protocol_trimming() {
for (let prot of ["http", "https", "ftp"]) {
let visit = {
// Include the protocol in the query string to ensure we get matches (see bug 1059395)
uri: NetUtil.newURI(
prot +
"://www.mozilla.org/test/?q=" +
prot +
encodeURIComponent("://") +
"www.foo"
),
title: "Test title",
transition: TRANSITION_TYPED,
};
await PlacesTestUtils.addVisits(visit);
let input = prot + "://www.";
info("Searching for: " + input);
await check_autocomplete({
search: input,
matches: [
{
value: prot + "://www.mozilla.org/",
comment:
prot == "http" ? "www.mozilla.org" : prot + "://www.mozilla.org",
style: ["autofill", "heuristic"],
},
{
value: visit.uri.spec,
comment: visit.title,
style: ["favicon"],
},
],
});
input = "www.";
info("Searching for: " + input);
await check_autocomplete({
search: input,
matches: [
{
value: "www.mozilla.org/",
comment:
prot == "http" ? "www.mozilla.org" : prot + "://www.mozilla.org",
style: ["autofill", "heuristic"],
},
{
value: visit.uri.spec,
comment: visit.title,
style: ["favicon"],
},
],
});
let inputs = [
prot + "://",
prot + ":// ",
prot + ":// mo",
prot + "://mo te",
prot + "://www. ",
prot + "://www. mo",
prot + "://www.mo te",
"www. ",
"www. mo",
"www.mo te",
];
for (input of inputs) {
info("Searching for: " + input);
await check_autocomplete({
search: input,
matches: [{ uri: visit.uri, title: visit.title }],
});
}
await cleanup();
}
});

Просмотреть файл

@ -0,0 +1,212 @@
/* 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_casing_1() {
info("Searching for cased entry 1");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/test/"),
});
await check_autocomplete({
search: "MOZ",
autofilled: "MOZilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});
add_task(async function test_casing_2() {
info("Searching for cased entry 2");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/test/"),
});
await check_autocomplete({
search: "mozilla.org/T",
autofilled: "mozilla.org/T",
completed: "mozilla.org/T",
});
await cleanup();
});
add_task(async function test_casing_3() {
info("Searching for cased entry 3");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "mozilla.org/T",
autofilled: "mozilla.org/Test/",
completed: "http://mozilla.org/Test/",
});
await cleanup();
});
add_task(async function test_casing_4() {
info("Searching for cased entry 4");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "mOzilla.org/t",
autofilled: "mOzilla.org/t",
completed: "mOzilla.org/t",
});
await cleanup();
});
add_task(async function test_casing_5() {
info("Searching for cased entry 5");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "mOzilla.org/T",
autofilled: "mOzilla.org/Test/",
completed: "http://mozilla.org/Test/",
});
await cleanup();
});
add_task(async function test_untrimmed_casing() {
info("Searching for untrimmed cased entry");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://mOz",
autofilled: "http://mOzilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_www_casing() {
info("Searching for untrimmed cased entry with www");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://www.mOz",
autofilled: "http://www.mOzilla.org/",
completed: "http://www.mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_path_casing() {
info("Searching for untrimmed cased entry with path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://mOzilla.org/t",
autofilled: "http://mOzilla.org/t",
completed: "http://mOzilla.org/t",
});
await cleanup();
});
add_task(async function test_untrimmed_path_casing_2() {
info("Searching for untrimmed cased entry with path 2");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://mOzilla.org/T",
autofilled: "http://mOzilla.org/Test/",
completed: "http://mozilla.org/Test/",
});
await cleanup();
});
add_task(async function test_untrimmed_path_www_casing() {
info("Searching for untrimmed cased entry with www and path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://www.mOzilla.org/t",
autofilled: "http://www.mOzilla.org/t",
completed: "http://www.mOzilla.org/t",
});
await cleanup();
});
add_task(async function test_untrimmed_path_www_casing_2() {
info("Searching for untrimmed cased entry with www and path 2");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://www.mozilla.org/Test/"),
});
await check_autocomplete({
search: "http://www.mOzilla.org/T",
autofilled: "http://www.mOzilla.org/Test/",
completed: "http://www.mozilla.org/Test/",
});
await cleanup();
});
add_task(async function test_searching() {
let uri1 = NetUtil.newURI("http://dummy/1/");
let uri2 = NetUtil.newURI("http://dummy/2/");
let uri3 = NetUtil.newURI("http://dummy/3/");
let uri4 = NetUtil.newURI("http://dummy/4/");
let uri5 = NetUtil.newURI("http://dummy/5/");
await PlacesTestUtils.addVisits([
{ uri: uri1, title: "uppercase lambda \u039B" },
{ uri: uri2, title: "lowercase lambda \u03BB" },
{ uri: uri3, title: "symbol \u212A" }, // kelvin
{ uri: uri4, title: "uppercase K" },
{ uri: uri5, title: "lowercase k" },
]);
info("Search for lowercase lambda");
await check_autocomplete({
search: "\u03BB",
matches: [
{ uri: uri1, title: "uppercase lambda \u039B" },
{ uri: uri2, title: "lowercase lambda \u03BB" },
],
});
info("Search for uppercase lambda");
await check_autocomplete({
search: "\u039B",
matches: [
{ uri: uri1, title: "uppercase lambda \u039B" },
{ uri: uri2, title: "lowercase lambda \u03BB" },
],
});
info("Search for kelvin sign");
await check_autocomplete({
search: "\u212A",
matches: [
{ uri: uri3, title: "symbol \u212A" },
{ uri: uri4, title: "uppercase K" },
{ uri: uri5, title: "lowercase k" },
],
});
info("Search for lowercase k");
await check_autocomplete({
search: "k",
matches: [
{ uri: uri3, title: "symbol \u212A" },
{ uri: uri4, title: "uppercase K" },
{ uri: uri5, title: "lowercase k" },
],
});
info("Search for uppercase k");
await check_autocomplete({
search: "K",
matches: [
{ uri: uri3, title: "symbol \u212A" },
{ uri: uri4, title: "uppercase K" },
{ uri: uri5, title: "lowercase k" },
],
});
await cleanup();
});

Просмотреть файл

@ -31,23 +31,22 @@ add_task(async function dedupe_prefix() {
},
]);
// We should get https://www. as the heuristic result but https:// in the
// We should get https://www. as the heuristic result and https:// in the
// results since the latter's prefix is a higher priority.
let context = createContext("example.com/foo/", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "example.com/foo/",
autofilled: "example.com/foo/",
completed: "https://www.example.com/foo/",
matches: [
makeVisitResult(context, {
uri: "https://www.example.com/foo/",
title: "https://www.example.com/foo/",
heuristic: true,
}),
makeVisitResult(context, {
uri: "https://example.com/foo/",
title: "Example Page",
}),
{
value: "example.com/foo/",
comment: "https://www.example.com/foo/",
style: ["autofill", "heuristic"],
},
{
value: "https://example.com/foo/",
comment: "Example Page",
},
],
});
@ -63,21 +62,20 @@ add_task(async function dedupe_prefix() {
]);
}
context = createContext("example.com/foo/", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "example.com/foo/",
autofilled: "example.com/foo/",
completed: "http://www.example.com/foo/",
matches: [
makeVisitResult(context, {
uri: "http://www.example.com/foo/",
title: "www.example.com/foo/",
heuristic: true,
}),
makeVisitResult(context, {
uri: "https://example.com/foo/",
title: "Example Page",
}),
{
value: "example.com/foo/",
comment: "www.example.com/foo/",
style: ["autofill", "heuristic"],
},
{
value: "https://example.com/foo/",
comment: "Example Page",
},
],
});
@ -94,23 +92,22 @@ add_task(async function dedupe_prefix() {
]);
}
context = createContext("example.com/foo/", { isPrivate: false });
await check_results({
context,
await check_autocomplete({
search: "example.com/foo/",
autofilled: "example.com/foo/",
completed: "https://example.com/foo/",
matches: [
makeVisitResult(context, {
uri: "https://example.com/foo/",
title: "https://example.com/foo/",
heuristic: true,
}),
makeVisitResult(context, {
uri: "https://www.example.com/foo/",
title: "Example Page",
}),
{
value: "example.com/foo/",
comment: "https://example.com/foo/",
style: ["autofill", "heuristic"],
},
{
value: "https://www.example.com/foo/",
comment: "Example Page",
},
],
});
await cleanupPlaces();
await cleanup();
});

Просмотреть файл

@ -0,0 +1,51 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Ensure inline autocomplete doesn't return zero frecency pages.
add_task(async function test_dupe_urls() {
info("Searching for urls with dupes should only show one");
await PlacesTestUtils.addVisits(
{
uri: NetUtil.newURI("http://mozilla.org/"),
},
{
uri: NetUtil.newURI("http://mozilla.org/?"),
}
);
await check_autocomplete({
search: "moz",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
matches: [
{
value: "mozilla.org/",
comment: "mozilla.org",
style: ["autofill", "heuristic"],
},
],
});
});
add_task(async function test_dupe_secure_urls() {
await PlacesTestUtils.addVisits(
{
uri: NetUtil.newURI("https://example.org/"),
},
{
uri: NetUtil.newURI("https://example.org/?"),
}
);
await check_autocomplete({
search: "exam",
autofilled: "example.org/",
completed: "https://example.org/",
matches: [
{
value: "example.org/",
comment: "https://example.org",
style: ["autofill", "heuristic"],
},
],
});
});

Просмотреть файл

@ -0,0 +1,87 @@
add_task(async function test_encoded() {
info("Searching for over encoded url should not break it");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.com/search/top/?q=%25%32%35"),
title: "https://www.mozilla.com/search/top/?q=%25%32%35",
transition: TRANSITION_TYPED,
});
await check_autocomplete({
search: "https://www.mozilla.com/search/top/?q=%25%32%35",
matches: [
{
uri: NetUtil.newURI("https://www.mozilla.com/search/top/?q=%25%32%35"),
title: "https://www.mozilla.com/search/top/?q=%25%32%35",
style: ["autofill", "heuristic"],
},
],
autofilled: "https://www.mozilla.com/search/top/?q=%25%32%35",
completed: "https://www.mozilla.com/search/top/?q=%25%32%35",
});
await cleanup();
});
add_task(async function test_encoded_trimmed() {
info("Searching for over encoded url should not break it");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.com/search/top/?q=%25%32%35"),
title: "https://www.mozilla.com/search/top/?q=%25%32%35",
transition: TRANSITION_TYPED,
});
await check_autocomplete({
search: "mozilla.com/search/top/?q=%25%32%35",
matches: [
{
value: "mozilla.com/search/top/?q=%25%32%35",
comment: "https://www.mozilla.com/search/top/?q=%25%32%35",
style: ["autofill", "heuristic"],
},
],
autofilled: "mozilla.com/search/top/?q=%25%32%35",
completed: "https://www.mozilla.com/search/top/?q=%25%32%35",
});
await cleanup();
});
add_task(async function test_encoded_partial() {
info("Searching for over encoded url should not break it");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.com/search/top/?q=%25%32%35"),
title: "https://www.mozilla.com/search/top/?q=%25%32%35",
transition: TRANSITION_TYPED,
});
await check_autocomplete({
search: "https://www.mozilla.com/search/top/?q=%25",
matches: [
{
uri: NetUtil.newURI("https://www.mozilla.com/search/top/?q=%25%32%35"),
title: "https://www.mozilla.com/search/top/?q=%25%32%35",
style: ["autofill", "heuristic"],
},
],
autofilled: "https://www.mozilla.com/search/top/?q=%25%32%35",
completed: "https://www.mozilla.com/search/top/?q=%25%32%35",
});
await cleanup();
});
add_task(async function test_encoded_path() {
info("Searching for over encoded url should not break it");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.com/%25%32%35/top/"),
title: "https://www.mozilla.com/%25%32%35/top/",
transition: TRANSITION_TYPED,
});
await check_autocomplete({
search: "https://www.mozilla.com/%25%32%35/t",
matches: [
{
uri: NetUtil.newURI("https://www.mozilla.com/%25%32%35/top/"),
title: "https://www.mozilla.com/%25%32%35/top/",
style: ["autofill", "heuristic"],
},
],
autofilled: "https://www.mozilla.com/%25%32%35/top/",
completed: "https://www.mozilla.com/%25%32%35/top/",
});
await cleanup();
});

Просмотреть файл

@ -0,0 +1,130 @@
/* 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_non_keyword() {
info("Searching for non-keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await check_autocomplete({
search: "moz",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});
add_task(async function test_keyword() {
info("Searching for keyworded entry should not autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
await check_autocomplete({
search: "moz",
autofilled: "moz",
completed: "moz",
});
await cleanup();
});
add_task(async function test_more_than_keyword() {
info("Searching for more than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
await check_autocomplete({
search: "mozi",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});
add_task(async function test_less_than_keyword() {
info("Searching for less than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});
add_task(async function test_keyword_casing() {
info("Searching for keyworded entry is case-insensitive");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
});
await PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.org/test/"),
keyword: "moz",
});
await check_autocomplete({
search: "MoZ",
autofilled: "MoZ",
completed: "MoZ",
});
await cleanup();
});
add_task(async function test_less_then_equal_than_keyword_bug_1124238() {
info("Searching for less than keyworded entry should autoFill it");
await PlacesTestUtils.addVisits({
uri: Services.io.newURI("http://mozilla.org/test/"),
transition: TRANSITION_TYPED,
});
await PlacesTestUtils.addVisits("http://mozilla.com/");
PlacesTestUtils.addBookmarkWithDetails({
uri: Services.io.newURI("http://mozilla.com/"),
keyword: "moz",
});
let input = await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
});
info(input.textValue);
// Emulate the input of an additional character. As the input matches a
// keyword, the completion should equal the keyword and not the URI as before.
input.textValue = "moz";
await check_autocomplete({
input,
search: "moz",
autofilled: "moz",
completed: "moz",
});
// Emulate the input of an additional character. The input doesn't match a
// keyword anymore, it should be autofilled.
input.textValue = "moz";
await check_autocomplete({
input,
search: "mozi",
autofilled: "mozilla.org/",
completed: "http://mozilla.org/",
});
await cleanup();
});

Просмотреть файл

@ -0,0 +1,66 @@
/* 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_no_slash() {
info("Searching for host match without slash should match host");
await PlacesTestUtils.addVisits([
{ uri: "http://file.org/test/" },
{ uri: "file:///c:/test.html" },
]);
await check_autocomplete({
search: "file",
autofilled: "file.org/",
completed: "http://file.org/",
});
await cleanup();
});
add_task(async function test_w_slash() {
info("Searching match with slash at the end should match url");
await PlacesTestUtils.addVisits(
{
uri: NetUtil.newURI("http://file.org/test/"),
},
{
uri: NetUtil.newURI("file:///c:/test.html"),
}
);
await check_autocomplete({
search: "file.org/",
autofilled: "file.org/",
completed: "http://file.org/",
});
await cleanup();
});
add_task(async function test_middle() {
info("Searching match with slash in the middle should match url");
await PlacesTestUtils.addVisits(
{
uri: NetUtil.newURI("http://file.org/test/"),
},
{
uri: NetUtil.newURI("file:///c:/test.html"),
}
);
await check_autocomplete({
search: "file.org/t",
autofilled: "file.org/test/",
completed: "http://file.org/test/",
});
await cleanup();
});
add_task(async function test_nonhost() {
info("Searching for non-host match without slash should not match url");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("file:///c:/test.html"),
});
await check_autocomplete({
search: "file",
autofilled: "file",
completed: "file",
});
await cleanup();
});

Просмотреть файл

@ -0,0 +1,57 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
add_task(async function test_searchEngine_autoFill() {
Services.prefs.setBoolPref("browser.urlbar.autoFill.searchEngines", true);
await Services.search.addEngineWithDetails("MySearchEngine", {
method: "GET",
template: "http://my.search.com/",
});
let engine = Services.search.getEngineByName("MySearchEngine");
registerCleanupFunction(async () => Services.search.removeEngine(engine));
// Add an uri that matches the search string with high frecency.
let uri = NetUtil.newURI("http://www.example.com/my/");
let visits = [];
for (let i = 0; i < 100; ++i) {
visits.push({ uri, title: "Terms - SearchEngine Search" });
}
await PlacesTestUtils.addVisits(visits);
await PlacesTestUtils.addBookmarkWithDetails({
uri,
title: "Example bookmark",
});
await PlacesTestUtils.promiseAsyncUpdates();
ok(
frecencyForUrl(uri) > 10000,
"Added URI should have expected high frecency"
);
info(
"Check search domain is autoFilled even if there's an higher frecency match"
);
await check_autocomplete({
search: "my",
autofilled: "my.search.com/",
completed: "http://my.search.com/",
});
await cleanup();
});
add_task(async function test_searchEngine_noautoFill() {
let engineName = "engine-rel-searchform.xml";
let engine = await addTestEngine(engineName);
equal(engine.searchForm, "http://example.com/?search");
await PlacesTestUtils.addVisits(NetUtil.newURI("http://example.com/my/"));
info("Check search domain is not autoFilled if it matches a visited domain");
await check_autocomplete({
search: "example",
autofilled: "example.com/",
completed: "http://example.com/",
});
await cleanup();
});

Просмотреть файл

@ -31,11 +31,11 @@ add_task(async function test_swap_protocol() {
{ uri: uri8, title: "title" },
]);
// uri1 and uri2 won't appear since they are lower-ranked duplicates of uri6.
// uri1, uri2, and uri5 won't appear since they are duplicates of uri6, except
// for their prefixes.
let allMatches = [
{ uri: uri3, title: "title" },
{ uri: uri4, title: "title" },
{ uri: uri5, title: "title" },
{ uri: uri6, title: "title" },
];

Просмотреть файл

@ -0,0 +1,120 @@
/* 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_untrimmed_secure_www() {
info("Searching for untrimmed https://www entry");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.org/test/"),
});
await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "https://www.mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_secure_www_path() {
info("Searching for untrimmed https://www entry with path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.org/test/"),
});
await check_autocomplete({
search: "mozilla.org/t",
autofilled: "mozilla.org/test/",
completed: "https://www.mozilla.org/test/",
});
await cleanup();
});
add_task(async function test_untrimmed_secure() {
info("Searching for untrimmed https:// entry");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://mozilla.org/test/"),
});
await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "https://mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_secure_path() {
info("Searching for untrimmed https:// entry with path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://mozilla.org/test/"),
});
await check_autocomplete({
search: "mozilla.org/t",
autofilled: "mozilla.org/test/",
completed: "https://mozilla.org/test/",
});
await cleanup();
});
add_task(async function test_untrimmed_www() {
info("Searching for untrimmed http://www entry");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://www.mozilla.org/test/"),
});
await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "http://www.mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_www_path() {
info("Searching for untrimmed http://www entry with path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("http://www.mozilla.org/test/"),
});
await check_autocomplete({
search: "mozilla.org/t",
autofilled: "mozilla.org/test/",
completed: "http://www.mozilla.org/test/",
});
await cleanup();
});
add_task(async function test_untrimmed_ftp() {
info("Searching for untrimmed ftp:// entry");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("ftp://mozilla.org/test/"),
});
await check_autocomplete({
search: "mo",
autofilled: "mozilla.org/",
completed: "ftp://mozilla.org/",
});
await cleanup();
});
add_task(async function test_untrimmed_ftp_path() {
info("Searching for untrimmed ftp:// entry with path");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("ftp://mozilla.org/test/"),
});
await check_autocomplete({
search: "mozilla.org/t",
autofilled: "mozilla.org/test/",
completed: "ftp://mozilla.org/test/",
});
await cleanup();
});
add_task(async function test_escaped_chars() {
info("Searching for URL with characters that are normally escaped");
await PlacesTestUtils.addVisits({
uri: NetUtil.newURI("https://www.mozilla.org/啊-test"),
});
await check_autocomplete({
search: "https://www.mozilla.org/啊-test",
autofilled: "https://www.mozilla.org/啊-test",
completed: "https://www.mozilla.org/啊-test",
});
await cleanup();
});

Просмотреть файл

@ -6,28 +6,45 @@ support-files =
data/engine-rel-searchform.xml
data/engine-suggestions.xml
!/toolkit/components/places/tests/favicons/favicon-normal16.png
autofill_tasks.js
[test_416211.js]
[test_416214.js]
[test_417798.js]
[test_418257.js]
[test_422277.js]
[test_autocomplete_functional.js]
[test_autocomplete_stopSearch_no_throw.js]
[test_autofill_about_urls.js]
[test_autofill_origins.js]
[test_autofill_search_engine_aliases.js]
[test_autofill_search_engines.js]
[test_autofill_urls.js]
[test_avoid_middle_complete.js]
[test_avoid_stripping_to_empty_tokens.js]
[test_casing.js]
[test_dedupe_prefix.js]
[test_do_not_trim.js]
[test_download_embed_bookmarks.js]
[test_dupe_urls.js]
[test_empty_search.js]
[test_encoded_urls.js]
[test_escape_self.js]
[test_history_autocomplete_tags.js]
[test_ignore_protocol.js]
[test_keyword_search.js]
[test_keyword_search_actions.js]
[test_keywords.js]
[test_multi_word_search.js]
[test_preloaded_sites.js]
[test_query_url.js]
[test_remote_tab_matches.js]
skip-if = !sync
[test_search_engine_alias.js]
[test_search_engine_host.js]
[test_search_engine_restyle.js]
[test_special_search.js]
[test_swap_protocol.js]
[test_tab_matches.js]
[test_trimming.js]
[test_word_boundary_search.js]