From 6bf0a5cb5034a7e684dcc3500e841785237ce2dd Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:32:43 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- .../urlbar/tests/unit/test_UrlbarSearchUtils.js | 462 +++++++++++++++++++++ 1 file changed, 462 insertions(+) create mode 100644 browser/components/urlbar/tests/unit/test_UrlbarSearchUtils.js (limited to 'browser/components/urlbar/tests/unit/test_UrlbarSearchUtils.js') diff --git a/browser/components/urlbar/tests/unit/test_UrlbarSearchUtils.js b/browser/components/urlbar/tests/unit/test_UrlbarSearchUtils.js new file mode 100644 index 0000000000..a39815937e --- /dev/null +++ b/browser/components/urlbar/tests/unit/test_UrlbarSearchUtils.js @@ -0,0 +1,462 @@ +/* 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 { UrlbarSearchUtils } = ChromeUtils.importESModule( + "resource:///modules/UrlbarSearchUtils.sys.mjs" +); + +let baconEngineExtension; + +add_task(async function () { + await UrlbarSearchUtils.init(); + // Tell the search service we are running in the US. This also has the + // desired side-effect of preventing our geoip lookup. + Services.prefs.setCharPref("browser.search.region", "US"); + + Services.search.restoreDefaultEngines(); + Services.search.resetToAppDefaultEngine(); +}); + +add_task(async function search_engine_match() { + let engine = await Services.search.getDefault(); + let domain = engine.searchUrlDomain; + let token = domain.substr(0, 1); + let matchedEngine = ( + await UrlbarSearchUtils.enginesForDomainPrefix(token) + )[0]; + Assert.equal(matchedEngine, engine); +}); + +add_task(async function no_match() { + Assert.equal( + 0, + (await UrlbarSearchUtils.enginesForDomainPrefix("test")).length + ); +}); + +add_task(async function hide_search_engine_nomatch() { + let engine = await Services.search.getDefault(); + let domain = engine.searchUrlDomain; + let token = domain.substr(0, 1); + let promiseTopic = promiseSearchTopic("engine-changed"); + await Promise.all([Services.search.removeEngine(engine), promiseTopic]); + Assert.ok(engine.hidden); + let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token); + Assert.ok( + !matchedEngines.length || matchedEngines[0].searchUrlDomain != domain + ); + engine.hidden = false; + await TestUtils.waitForCondition( + async () => (await UrlbarSearchUtils.enginesForDomainPrefix(token)).length + ); + let matchedEngine2 = ( + await UrlbarSearchUtils.enginesForDomainPrefix(token) + )[0]; + Assert.ok(matchedEngine2); + await Services.search.setDefault( + engine, + Ci.nsISearchService.CHANGE_REASON_UNKNOWN + ); +}); + +add_task(async function onlyEnabled_option_nomatch() { + let engine = await Services.search.getDefault(); + let domain = engine.searchUrlDomain; + let token = domain.substr(0, 1); + Services.prefs.setCharPref("browser.search.hiddenOneOffs", engine.name); + let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token, { + onlyEnabled: true, + }); + Assert.notEqual(matchedEngines[0].searchUrlDomain, domain); + Services.prefs.clearUserPref("browser.search.hiddenOneOffs"); + matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix(token, { + onlyEnabled: true, + }); + Assert.equal(matchedEngines[0].searchUrlDomain, domain); +}); + +add_task(async function add_search_engine_match() { + Assert.equal( + 0, + (await UrlbarSearchUtils.enginesForDomainPrefix("bacon")).length + ); + baconEngineExtension = await SearchTestUtils.installSearchExtension( + { + name: "bacon", + keyword: "pork", + search_url: "https://www.bacon.moz/", + }, + { skipUnload: true } + ); + let matchedEngine = ( + await UrlbarSearchUtils.enginesForDomainPrefix("bacon") + )[0]; + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.searchForm, "https://www.bacon.moz"); + Assert.equal(matchedEngine.name, "bacon"); + Assert.equal(matchedEngine.iconURI, null); + info("also type part of the public suffix"); + matchedEngine = ( + await UrlbarSearchUtils.enginesForDomainPrefix("bacon.m") + )[0]; + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.searchForm, "https://www.bacon.moz"); + Assert.equal(matchedEngine.name, "bacon"); + Assert.equal(matchedEngine.iconURI, null); +}); + +add_task(async function match_multiple_search_engines() { + Assert.equal( + 0, + (await UrlbarSearchUtils.enginesForDomainPrefix("baseball")).length + ); + await SearchTestUtils.installSearchExtension({ + name: "baseball", + search_url: "https://www.baseball.moz/", + }); + let matchedEngines = await UrlbarSearchUtils.enginesForDomainPrefix("ba"); + Assert.equal( + matchedEngines.length, + 2, + "enginesForDomainPrefix returned two engines." + ); + Assert.equal(matchedEngines[0].searchForm, "https://www.bacon.moz"); + Assert.equal(matchedEngines[0].name, "bacon"); + Assert.equal(matchedEngines[1].searchForm, "https://www.baseball.moz"); + Assert.equal(matchedEngines[1].name, "baseball"); +}); + +add_task(async function test_aliased_search_engine_match() { + Assert.equal(null, await UrlbarSearchUtils.engineForAlias("sober")); + // Lower case + let matchedEngine = await UrlbarSearchUtils.engineForAlias("pork"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "bacon"); + Assert.ok(matchedEngine.aliases.includes("pork")); + Assert.equal(matchedEngine.iconURI, null); + // Upper case + matchedEngine = await UrlbarSearchUtils.engineForAlias("PORK"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "bacon"); + Assert.ok(matchedEngine.aliases.includes("pork")); + Assert.equal(matchedEngine.iconURI, null); + // Cap case + matchedEngine = await UrlbarSearchUtils.engineForAlias("Pork"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "bacon"); + Assert.ok(matchedEngine.aliases.includes("pork")); + Assert.equal(matchedEngine.iconURI, null); +}); + +add_task(async function test_aliased_search_engine_match_upper_case_alias() { + Assert.equal( + 0, + (await UrlbarSearchUtils.enginesForDomainPrefix("patch")).length + ); + await SearchTestUtils.installSearchExtension({ + name: "patch", + keyword: "PR", + search_url: "https://www.patch.moz/", + }); + // lower case + let matchedEngine = await UrlbarSearchUtils.engineForAlias("pr"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "patch"); + Assert.ok(matchedEngine.aliases.includes("PR")); + Assert.equal(matchedEngine.iconURI, null); + // Upper case + matchedEngine = await UrlbarSearchUtils.engineForAlias("PR"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "patch"); + Assert.ok(matchedEngine.aliases.includes("PR")); + Assert.equal(matchedEngine.iconURI, null); + // Cap case + matchedEngine = await UrlbarSearchUtils.engineForAlias("Pr"); + Assert.ok(matchedEngine); + Assert.equal(matchedEngine.name, "patch"); + Assert.ok(matchedEngine.aliases.includes("PR")); + Assert.equal(matchedEngine.iconURI, null); +}); + +add_task(async function remove_search_engine_nomatch() { + let promiseTopic = promiseSearchTopic("engine-removed"); + await Promise.all([baconEngineExtension.unload(), promiseTopic]); + Assert.equal( + 0, + (await UrlbarSearchUtils.enginesForDomainPrefix("bacon")).length + ); +}); + +add_task(async function test_builtin_aliased_search_engine_match() { + let engine = await UrlbarSearchUtils.engineForAlias("@google"); + Assert.ok(engine); + Assert.equal(engine.name, "Google"); + let promiseTopic = promiseSearchTopic("engine-changed"); + await Promise.all([Services.search.removeEngine(engine), promiseTopic]); + let matchedEngine = await UrlbarSearchUtils.engineForAlias("@google"); + Assert.ok(!matchedEngine); + engine.hidden = false; + await TestUtils.waitForCondition(() => + UrlbarSearchUtils.engineForAlias("@google") + ); + engine = await UrlbarSearchUtils.engineForAlias("@google"); + Assert.ok(engine); +}); + +add_task(async function test_serps_are_equivalent() { + info("Subset URL has extraneous parameters."); + let url1 = "https://example.com/search?q=test&type=images"; + let url2 = "https://example.com/search?q=test"; + Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2)); + info("Superset URL has extraneous parameters."); + Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url2, url1)); + + info("Same keys, different values."); + url1 = "https://example.com/search?q=test&type=images"; + url2 = "https://example.com/search?q=test123&type=maps"; + Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2)); + Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url2, url1)); + + info("Subset matching isn't strict (URL is subset of itself)."); + Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url1)); + + info("Origin and pathname are ignored."); + url1 = "https://example.com/search?q=test"; + url2 = "https://example-1.com/maps?q=test"; + Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url2)); + Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url2, url1)); + + info("Params can be optionally ignored"); + url1 = "https://example.com/search?q=test&abc=123&foo=bar"; + url2 = "https://example.com/search?q=test"; + Assert.ok(!UrlbarSearchUtils.serpsAreEquivalent(url1, url2)); + Assert.ok(UrlbarSearchUtils.serpsAreEquivalent(url1, url2, ["abc", "foo"])); +}); + +add_task(async function test_get_root_domain_from_engine() { + let extension = await SearchTestUtils.installSearchExtension( + { + name: "TestEngine2", + search_url: "https://example.com/", + }, + { skipUnload: true } + ); + let engine = Services.search.getEngineByName("TestEngine2"); + Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "example"); + await extension.unload(); + + extension = await SearchTestUtils.installSearchExtension( + { + name: "TestEngine", + search_url: "https://www.subdomain.othersubdomain.example.com", + }, + { skipUnload: true } + ); + engine = Services.search.getEngineByName("TestEngine"); + Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "example"); + await extension.unload(); + + // We let engines with URL ending in .test through even though its not a valid + // TLD. + extension = await SearchTestUtils.installSearchExtension( + { + name: "TestMalformed", + search_url: "https://mochi.test/", + search_url_get_params: "search={searchTerms}", + }, + { skipUnload: true } + ); + engine = Services.search.getEngineByName("TestMalformed"); + Assert.equal(UrlbarSearchUtils.getRootDomainFromEngine(engine), "mochi"); + await extension.unload(); + + // We return the domain for engines with a malformed URL. + extension = await SearchTestUtils.installSearchExtension( + { + name: "TestMalformed", + search_url: "https://subdomain.foobar/", + search_url_get_params: "search={searchTerms}", + }, + { skipUnload: true } + ); + engine = Services.search.getEngineByName("TestMalformed"); + Assert.equal( + UrlbarSearchUtils.getRootDomainFromEngine(engine), + "subdomain.foobar" + ); + await extension.unload(); +}); + +// Tests getSearchTermIfDefaultSerpUri() by using a variety of +// input strings and nsIURI's. +// Should not throw an error if the consumer passes an input +// that when accessed, could cause an error. +add_task(async function get_search_term_if_default_serp_uri() { + let testCases = [ + { + url: null, + skipUriTest: true, + }, + { + url: "", + skipUriTest: true, + }, + { + url: "about:blank", + }, + { + url: "about:home", + }, + { + url: "about:newtab", + }, + { + url: "not://a/supported/protocol", + }, + { + url: "view-source:http://www.example.com/", + }, + { + // Not a default engine. + url: "http://mochi.test:8888/?q=chocolate&pc=sample_code", + }, + { + // Not the correct protocol. + url: "http://example.com/?q=chocolate&pc=sample_code", + }, + { + // Not the same query param values. + url: "https://example.com/?q=chocolate&pc=sample_code2", + }, + { + // Not the same query param values. + url: "https://example.com/?q=chocolate&pc=sample_code&pc2=sample_code_2", + }, + { + url: "https://example.com/?q=chocolate&pc=sample_code", + expectedString: "chocolate", + }, + { + url: "https://example.com/?q=chocolate+cakes&pc=sample_code", + expectedString: "chocolate cakes", + }, + ]; + + // Create a specific engine so that the tests are matched + // exactly against the query params used. + let extension = await SearchTestUtils.installSearchExtension( + { + name: "TestEngine", + search_url: "https://example.com/", + search_url_get_params: "?q={searchTerms}&pc=sample_code", + }, + { skipUnload: true } + ); + let engine = Services.search.getEngineByName("TestEngine"); + let originalDefaultEngine = Services.search.defaultEngine; + Services.search.defaultEngine = engine; + + for (let testCase of testCases) { + let expectedString = testCase.expectedString ?? ""; + Assert.equal( + UrlbarSearchUtils.getSearchTermIfDefaultSerpUri(testCase.url), + expectedString, + `Should return ${ + expectedString == "" ? "an empty string" : "a matching search string" + }` + ); + // Convert the string into a nsIURI and then + // try the test case with it. + if (!testCase.skipUriTest) { + Assert.equal( + UrlbarSearchUtils.getSearchTermIfDefaultSerpUri( + Services.io.newURI(testCase.url) + ), + expectedString, + `Should return ${ + expectedString == "" ? "an empty string" : "a matching search string" + }` + ); + } + } + + Services.search.defaultEngine = originalDefaultEngine; + await extension.unload(); +}); + +add_task(async function matchAllDomainLevels() { + let baseHostname = "matchalldomainlevels"; + Assert.equal( + (await UrlbarSearchUtils.enginesForDomainPrefix(baseHostname)).length, + 0, + `Sanity check: No engines initially match ${baseHostname}` + ); + + // Install engines with the following domains. When we match engines below, + // perfectly matching domains should come before partially matching domains. + let baseDomain = `${baseHostname}.com`; + let perfectDomains = [baseDomain, `www.${baseDomain}`]; + let partialDomains = [`foo.${baseDomain}`, `foo.bar.${baseDomain}`]; + + // Install engines with partially matching domains first so that the test + // isn't incidentally passing because engines are installed in the order it + // ultimately expects them in. Wait for each engine to finish installing + // before starting the next one to avoid intermittent out-of-order failures. + let extensions = []; + for (let list of [partialDomains, perfectDomains]) { + for (let domain of list) { + let ext = await SearchTestUtils.installSearchExtension( + { + name: domain, + search_url: `https://${domain}/`, + }, + { skipUnload: true } + ); + extensions.push(ext); + } + } + + // Perfect matches come before partial matches. + let expectedDomains = [...perfectDomains, ...partialDomains]; + + // Do searches for the following strings. Each should match all the engines + // installed above. + let searchStrings = [baseHostname, baseHostname + "."]; + for (let searchString of searchStrings) { + info(`Searching for "${searchString}"`); + let engines = await UrlbarSearchUtils.enginesForDomainPrefix(searchString, { + matchAllDomainLevels: true, + }); + let engineData = engines.map(e => ({ + name: e.name, + searchForm: e.searchForm, + })); + info("Matching engines: " + JSON.stringify(engineData)); + + Assert.equal( + engines.length, + expectedDomains.length, + "Expected number of matching engines" + ); + Assert.deepEqual( + engineData.map(d => d.name), + expectedDomains, + "Expected matching engine names/domains in the expected order" + ); + } + + await Promise.all(extensions.map(e => e.unload())); +}); + +function promiseSearchTopic(expectedVerb) { + return new Promise(resolve => { + Services.obs.addObserver(function observe(subject, topic, verb) { + info("browser-search-engine-modified: " + verb); + if (verb == expectedVerb) { + Services.obs.removeObserver(observe, "browser-search-engine-modified"); + resolve(); + } + }, "browser-search-engine-modified"); + }); +} -- cgit v1.2.3