Source code

Revision control

Copy as Markdown

Other Tools

Test Info:

/* Any copyright is dedicated to the Public Domain.
"use strict";
const { analyzeURL, SEARCH_CTA_ACTIONS, SEARCH_CTA_REASONS } =
ChromeUtils.importESModule(
"resource://gre/modules/URLKeywordAnalyzer.sys.mjs"
);
function checkAnalyze(url, expected, options) {
Assert.deepEqual(analyzeURL(url, options), expected, `analyzeURL(${url})`);
}
add_task(function test_blocked_hosts() {
const blocked = [
"http://192.168.1.1/status", // IPv4 literal
"http://10.0.0.5/admin/login", // IPv4 literal
"http://[::1]/dashboard", // IPv6 literal
"http://localhost/wiki", // single-label host
"http://intranet/home", // single-label host
"http://db.internal/status", // reserved TLD (worked example)
"http://foo.test/bar", // reserved TLD
"http://service.local/api", // reserved TLD
"https://example.invalid/x", // reserved TLD
];
for (const url of blocked) {
checkAnalyze(url, {
action: SEARCH_CTA_ACTIONS.NONE,
query: null,
reason: SEARCH_CTA_REASONS.HOST_UNUSABLE,
});
}
});
// Path tokens first, in path order, then the host's tokens: the kept subdomain
// and the registrable label, never the public suffix.
add_task(function test_descriptive_path_includes_host_tokens() {
action: SEARCH_CTA_ACTIONS.KEYWORDS,
query: "mountain hiking boots shop wildernessgear",
reason: SEARCH_CTA_REASONS.KEYWORDS_FOUND,
});
});
add_task(function test_www_is_stripped_from_host_tokens() {
action: SEARCH_CTA_ACTIONS.KEYWORDS,
query: "tents wildernessgear",
reason: SEARCH_CTA_REASONS.KEYWORDS_FOUND,
});
});
// Ten path tokens, capped at MAX_SEARCH_KEYWORDS (8), so the host's tokens are
// cut off entirely rather than displacing path tokens.
add_task(function test_keyword_query_is_capped() {
checkAnalyze(
{
action: SEARCH_CTA_ACTIONS.KEYWORDS,
query: "alpha bravo charlie delta echo foxtrot golf hotel",
reason: SEARCH_CTA_REASONS.KEYWORDS_FOUND,
}
);
});
add_task(function test_empty_path_falls_back_to_registrable_domain() {
for (const url of [
]) {
checkAnalyze(url, {
action: SEARCH_CTA_ACTIONS.HOST,
query: "wildernessgear.com",
reason: SEARCH_CTA_REASONS.NO_PATH,
});
}
});
add_task(function test_opaque_path_falls_back_to_registrable_domain() {
// A path with no letters yields no keywords (digits are stripped).
action: SEARCH_CTA_ACTIONS.HOST,
query: "wildernessgear.com",
reason: SEARCH_CTA_REASONS.NO_MEANINGFUL_KEYWORDS,
});
});
// CountVectorizer removes digits before splitting, so an alphanumeric token
// keeps its letters rather than being dropped whole: "mp3" -> "mp" and
// "covid19" -> "covid". This documents the current tokenizer behavior.
add_task(function test_alphanumeric_tokens_strip_digits_in_place() {
action: SEARCH_CTA_ACTIONS.KEYWORDS,
query: "mp covid reviews shop wildernessgear",
reason: SEARCH_CTA_REASONS.KEYWORDS_FOUND,
});
});
// The secret in the query string and the fragment are both absent from the
// exact expected query, so neither can reach the search engine.
add_task(function test_query_string_and_fragment_never_tokenized() {
checkAnalyze(
{
action: SEARCH_CTA_ACTIONS.KEYWORDS,
query: "tents shop wildernessgear",
reason: SEARCH_CTA_REASONS.KEYWORDS_FOUND,
}
);
});
add_task(function test_min_keywords_option() {
// One path keyword clears the default threshold of 1...
Assert.equal(
SEARCH_CTA_ACTIONS.KEYWORDS
);
// ...but not a threshold of 2, which falls back to the host.
checkAnalyze(
{
action: SEARCH_CTA_ACTIONS.HOST,
query: "wildernessgear.com",
reason: SEARCH_CTA_REASONS.NO_MEANINGFUL_KEYWORDS,
},
{ minKeywords: 2 }
);
});
add_task(function test_curated_stopwords_keep_content_words() {
// Content words the shared ENGLISH_STOP_WORDS drops but our forked list keeps
// (bug 2057648). Canary: if the fork ever re-stops these, this fails.
const { query } = analyzeURL(
);
const words = query.split(" ");
for (const w of ["system", "fire", "interest", "name", "part"]) {
Assert.ok(
words.includes(w),
`un-stopped content word survives: ${w} (${query})`
);
}
});
add_task(function test_common_stopwords_still_filtered() {
// Our list must still behave as a stopword filter, not pass everything.
const { query } = analyzeURL(
);
const words = query.split(" ");
for (const w of ["the", "and", "of"]) {
Assert.ok(!words.includes(w), `stopword dropped: ${w} (${query})`);
}
Assert.ok(
words.includes("hiking") && words.includes("boots"),
`content words kept: ${query}`
);
});
add_task(function test_invalid_input() {
for (const url of ["not a url", "", "://missing-scheme"]) {
checkAnalyze(url, {
action: SEARCH_CTA_ACTIONS.NONE,
query: null,
reason: SEARCH_CTA_REASONS.HOST_UNUSABLE,
});
}
});