Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* Any copyright is dedicated to the Public Domain.
"use strict";
const { MatchURLFilters } = ChromeUtils.importESModule(
"resource://gre/modules/MatchURLFilters.sys.mjs"
);
const { Preferences } = ChromeUtils.importESModule(
"resource://gre/modules/Preferences.sys.mjs"
);
function createTestFilter({ url, filters }) {
let m = new MatchURLFilters(filters);
return m.matches(url);
}
function expectPass({ url, filters }) {
ok(
createTestFilter({ url, filters }),
`Expected match: ${JSON.stringify(filters)}, ${url}`
);
}
function expectFail({ url, filters }) {
ok(
!createTestFilter({ url, filters }),
`Expected no match: ${JSON.stringify(filters)}, ${url}`
);
}
function expectThrow({ url, filters, exceptionMessageContains }) {
let logData = { filters, url };
Assert.throws(
() => {
createTestFilter({ url, filters });
},
exceptionMessageContains,
`Check received exception for expected message: ${JSON.stringify(logData)}`
);
}
add_task(async function test_match_url_filters() {
const shouldPass = true;
const shouldFail = true;
const shouldThrow = true;
var testCases = [
// Empty, undefined and null filters.
{
shouldThrow,
exceptionMessageContains: /filters array should not be empty/,
filters: [],
},
{
shouldThrow,
exceptionMessageContains: /filters should be an array/,
filters: undefined,
},
{
shouldThrow,
exceptionMessageContains: /filters should be an array/,
filters: null,
},
// Wrong formats (in a real webextension this will be blocked by the schema validation).
{
shouldThrow,
exceptionMessageContains: /filters should be an array/,
filters: {},
},
{
shouldThrow,
exceptionMessageContains: /filters should be an array/,
filters: { nonExistentCriteria: true },
},
{
shouldPass,
filters: [{ nonExistentCriteria: true }],
},
// Schemes filter over various url schemes.
{
shouldPass,
filters: [{ schemes: ["https"] }],
},
{ shouldPass, filters: [{ schemes: ["about"] }], url: "about:blank" },
{ shouldPass, filters: [{ schemes: ["data"] }], url: "data:,testDataURL" },
// Multiple schemes: pass when at least one scheme matches.
{
shouldPass,
filters: [{ schemes: ["https", "about"] }],
},
{
shouldPass,
filters: [{ schemes: ["about", "https"] }],
},
{
shouldFail,
filters: [{ schemes: ["about", "http"] }],
},
// Port filter: standard (implicit) ports.
// Port matching unknown protocols will fail.
{
shouldFail,
filters: [{ ports: [21] }],
},
// Port filter: schemes without a default port.
{ shouldFail, filters: [{ ports: [-1] }], url: "about:blank" },
{ shouldFail, filters: [{ ports: [-1] }], url: "data:,testDataURL" },
{ shouldFail, filters: [{ ports: [[1, 65535]] }], url: "about:blank" },
{
shouldFail,
filters: [{ ports: [[1, 65535]] }],
url: "data:,testDataURL",
},
// Host filters (hostEquals, hostContains, hostPrefix, hostSuffix): schemes with an host.
{
shouldPass,
filters: [{ hostEquals: "mozilla.org" }],
},
{
shouldFail,
filters: [{ hostEquals: "mozilla.com" }],
},
// NOTE: trying at least once another valid protocol.
{
shouldPass,
filters: [{ hostEquals: "mozilla.org" }],
},
{
shouldFail,
filters: [{ hostEquals: "mozilla.com" }],
},
{
shouldPass,
filters: [{ hostEquals: "mozilla.org" }],
},
{
shouldPass,
filters: [{ hostContains: "moz" }],
},
// NOTE: an implicit '.' char is inserted into the host.
{
shouldPass,
filters: [{ hostContains: ".moz" }],
},
{
shouldFail,
filters: [{ hostContains: "com" }],
},
{
shouldPass,
filters: [{ hostContains: null }],
},
{
shouldPass,
filters: [{ hostPrefix: "moz" }],
},
{
shouldFail,
filters: [{ hostPrefix: "org" }],
},
{
shouldPass,
filters: [{ hostSuffix: ".org" }],
},
{
shouldFail,
filters: [{ hostSuffix: "moz" }],
},
{
shouldPass,
filters: [{ hostSuffix: "lla.org" }],
},
// hostEquals: urls without an host.
// TODO: should we explicitly cover hostContains, hostPrefix, hostSuffix for
// these sub-cases?
{ shouldFail, filters: [{ hostEquals: "blank" }], url: "about:blank" },
{
shouldFail,
filters: [{ hostEquals: "testDataURL" }],
url: "data:,testDataURL",
},
{ shouldPass, filters: [{ hostEquals: "" }], url: "about:blank" },
{ shouldPass, filters: [{ hostEquals: "" }], url: "data:,testDataURL" },
// Path filters (pathEquals, pathContains, pathPrefix, pathSuffix).
{
shouldFail,
filters: [{ pathEquals: "" }],
},
{
shouldPass,
filters: [{ pathEquals: null }],
},
{
shouldPass,
filters: [{ pathEquals: "/test/path" }],
},
{
shouldFail,
filters: [{ pathEquals: "/wrong/path" }],
},
{
shouldPass,
filters: [{ pathEquals: "/test/path" }],
},
// NOTE: trying at least once another valid protocol
{
shouldPass,
filters: [{ pathEquals: "/test/path" }],
},
{
shouldFail,
filters: [{ pathEquals: "/wrong/path" }],
},
{
shouldPass,
filters: [{ pathContains: "st/" }],
},
{
shouldPass,
filters: [{ pathContains: "/test" }],
},
{
shouldFail,
filters: [{ pathContains: "org" }],
},
{
shouldPass,
filters: [{ pathContains: "" }],
},
{
shouldPass,
filters: [{ pathContains: null }],
},
{
shouldFail,
filters: [{ pathContains: "param" }],
},
{
shouldFail,
filters: [{ pathContains: "ref" }],
},
{
shouldPass,
filters: [{ pathContains: "st/pa" }],
},
{
shouldPass,
filters: [{ pathPrefix: "/te" }],
},
{
shouldFail,
filters: [{ pathPrefix: "org/" }],
},
{
shouldPass,
filters: [{ pathPrefix: "" }],
},
{
shouldPass,
filters: [{ pathPrefix: null }],
},
{
shouldPass,
filters: [{ pathSuffix: "/path" }],
},
{
shouldFail,
filters: [{ pathSuffix: "th/" }],
},
{
shouldPass,
filters: [{ pathSuffix: "" }],
},
{
shouldPass,
filters: [{ pathSuffix: null }],
},
{
shouldFail,
filters: [{ pathSuffix: "p=1" }],
},
{
shouldFail,
filters: [{ pathSuffix: "ref" }],
},
// Query filters (queryEquals, queryContains, queryPrefix, querySuffix).
{
shouldFail,
filters: [{ queryEquals: "" }],
},
{
shouldPass,
filters: [{ queryEquals: null }],
},
{
shouldPass,
filters: [{ queryEquals: "param=val" }],
},
{
shouldFail,
filters: [{ queryEquals: "?param=val" }],
},
{
shouldFail,
filters: [{ queryEquals: "/path?param=val" }],
},
// NOTE: about scheme urls cannot be matched by query.
{
shouldFail,
filters: [{ queryEquals: "param=val" }],
url: "about:blank?param=val",
},
{
shouldFail,
filters: [{ queryEquals: "param" }],
},
{
shouldPass,
filters: [{ queryContains: "ram" }],
},
{
shouldPass,
filters: [{ queryContains: "=val" }],
},
{
shouldFail,
filters: [{ queryContains: "?param" }],
},
{
shouldFail,
filters: [{ queryContains: "path" }],
},
{
shouldPass,
filters: [{ queryContains: "" }],
},
{
shouldPass,
filters: [{ queryContains: null }],
},
{
shouldPass,
filters: [{ queryPrefix: "param" }],
},
{
shouldFail,
filters: [{ queryPrefix: "p=" }],
},
{
shouldFail,
filters: [{ queryPrefix: "path" }],
},
{
shouldPass,
filters: [{ queryPrefix: "" }],
},
{
shouldPass,
filters: [{ queryPrefix: null }],
},
{
shouldPass,
filters: [{ querySuffix: "=val" }],
},
{
shouldFail,
filters: [{ querySuffix: "=wrong" }],
},
{
shouldPass,
filters: [{ querySuffix: "" }],
},
{
shouldPass,
filters: [{ querySuffix: null }],
},
// URL filters (urlEquals, urlContains, urlPrefix, urlSuffix).
{
shouldFail,
filters: [{ urlEquals: "" }],
},
{
shouldPass,
filters: [{ urlEquals: null }],
},
{
shouldPass,
},
{
shouldFail,
},
{
shouldPass,
filters: [{ urlEquals: "about:blank?p=v#ref" }],
url: "about:blank?p=v#ref",
},
{
shouldPass,
},
{
shouldPass,
filters: [{ urlContains: "org/?p" }],
},
{
shouldPass,
filters: [{ urlContains: "=v#ref" }],
},
{
shouldFail,
filters: [{ urlContains: "ftp" }],
},
{
shouldPass,
filters: [{ urlContains: "" }],
},
{
shouldPass,
filters: [{ urlContains: null }],
},
{
shouldPass,
filters: [{ urlPrefix: "http" }],
},
{
shouldFail,
filters: [{ urlPrefix: "moz" }],
},
{
shouldPass,
filters: [{ urlPrefix: "" }],
},
{
shouldPass,
filters: [{ urlPrefix: null }],
},
{
shouldPass,
filters: [{ urlSuffix: "#ref" }],
},
{
shouldFail,
filters: [{ urlSuffix: "=wrong" }],
},
{
shouldPass,
filters: [{ urlSuffix: "" }],
},
{
shouldPass,
filters: [{ urlSuffix: null }],
},
// More url filters: urlMatches.
{
shouldPass,
filters: [{ urlMatches: ".*://mozilla" }],
},
{
shouldPass,
filters: [{ urlMatches: ".*://mozilla" }],
},
{
shouldPass,
filters: [{ urlMatches: ".*://.*/?p" }],
},
// NOTE: urlMatches should not match the url without the ref.
{
shouldFail,
filters: [{ urlMatches: "v#ref$" }],
},
{
shouldPass,
filters: [{ urlMatches: "^ftp" }],
},
// More url filters: originAndPathMatches.
{
shouldPass,
filters: [{ originAndPathMatches: ".*://mozilla" }],
},
{
shouldPass,
filters: [{ originAndPathMatches: ".*://mozilla" }],
},
// NOTE: urlMatches should not match the url without the query and the ref.
{
shouldFail,
filters: [{ originAndPathMatches: ".*://.*/?p" }],
},
{
shouldFail,
filters: [{ originAndPathMatches: "v#ref$" }],
},
{
shouldPass,
filters: [{ originAndPathMatches: "^ftp" }],
},
// Filter with all criteria: all matches, none matches, some matches.
// All matches.
{
shouldPass,
filters: [
{
schemes: ["https", "http"],
ports: [443, 80],
hostEquals: "www.mozilla.org",
hostContains: ".moz",
hostPrefix: "www",
hostSuffix: "org",
pathEquals: "/sub/path",
pathContains: "b/p",
pathPrefix: "/sub",
pathSuffix: "/path",
queryEquals: "p1=v",
queryContains: "1=",
queryPrefix: "p1",
querySuffix: "=v",
urlContains: "org/sub",
urlSuffix: "#ref",
urlMatches: "p1=v$",
originAndPathMatches: ".*://www.moz.*/",
},
],
},
// None matches.
{
shouldFail,
filters: [
{
schemes: ["http"],
ports: [80],
hostEquals: "mozilla.com",
hostContains: "www.moz",
hostPrefix: "www",
hostSuffix: "com",
pathEquals: "/wrong/path",
pathContains: "g/p",
pathPrefix: "/wrong",
pathSuffix: "/wrong",
queryEquals: "p2=v",
queryContains: "2=",
queryPrefix: "p2",
querySuffix: "=value",
urlContains: "com/sub",
urlSuffix: "#ref2",
urlMatches: "value#ref2$",
originAndPathMatches: ".*://moz.*com/",
},
],
},
// Some matches
{
shouldFail,
filters: [
{
schemes: ["https"],
ports: [80],
hostEquals: "mozilla.com",
hostContains: "www.moz",
hostPrefix: "www",
hostSuffix: "com",
pathEquals: "/wrong/path",
pathContains: "g/p",
pathPrefix: "/wrong",
pathSuffix: "/wrong",
queryEquals: "p2=v",
queryContains: "2=",
queryPrefix: "p2",
querySuffix: "=value",
urlContains: "com/sub",
urlSuffix: "#ref2",
urlMatches: "value#ref2$",
originAndPathMatches: ".*://moz.*com/",
},
],
},
// Filter with multiple filters: all matches, some matches, none matches.
// All matches.
{
shouldPass,
filters: [
{ schemes: ["https", "http"] },
{ ports: [443, 80] },
{ hostEquals: "www.mozilla.org" },
{ hostContains: ".moz" },
{ hostPrefix: "www" },
{ hostSuffix: "org" },
{ pathEquals: "/sub/path" },
{ pathContains: "b/p" },
{ pathPrefix: "/sub" },
{ pathSuffix: "/path" },
{ queryEquals: "p=v" },
{ queryContains: "1=" },
{ queryPrefix: "p1" },
{ querySuffix: "=v" },
{ urlContains: "org/sub" },
{ urlSuffix: "#ref" },
{ urlMatches: "v#ref$" },
{ originAndPathMatches: ".*://moz.*/" },
],
},
// None matches.
{
shouldFail,
filters: [
{ schemes: ["http"] },
{ ports: [80] },
{ hostEquals: "mozilla.com" },
{ hostContains: "www.moz" },
{ hostPrefix: "www" },
{ hostSuffix: "com" },
{ pathEquals: "/wrong/path" },
{ pathContains: "g/p" },
{ pathPrefix: "/wrong" },
{ pathSuffix: "/wrong" },
{ queryEquals: "p2=v" },
{ queryContains: "2=" },
{ queryPrefix: "p2" },
{ querySuffix: "=value" },
{ urlContains: "com/sub" },
{ urlSuffix: "#ref2" },
{ urlMatches: "value#ref2$" },
{ originAndPathMatches: ".*://moz.*com/" },
],
},
// Some matches.
{
shouldPass,
filters: [
{ schemes: ["https"] },
{ ports: [80] },
{ hostEquals: "mozilla.com" },
{ hostContains: "www.moz" },
{ hostPrefix: "www" },
{ hostSuffix: "com" },
{ pathEquals: "/wrong/path" },
{ pathContains: "g/p" },
{ pathPrefix: "/wrong" },
{ pathSuffix: "/wrong" },
{ queryEquals: "p2=v" },
{ queryContains: "2=" },
{ queryPrefix: "p2" },
{ querySuffix: "=value" },
{ urlContains: "com/sub" },
{ urlSuffix: "#ref2" },
{ urlMatches: "value#ref2$" },
{ originAndPathMatches: ".*://moz.*com/" },
],
},
];
// Run all the the testCases defined above.
for (let currentTest of testCases) {
let { exceptionMessageContains, url, filters, prefs } = currentTest;
if (prefs !== undefined) {
for (let [name, val] of prefs) {
Preferences.set(name, val);
}
}
if (currentTest.shouldThrow) {
expectThrow({ url, filters, exceptionMessageContains });
} else if (currentTest.shouldFail) {
expectFail({ url, filters });
} else {
expectPass({ url, filters });
}
if (prefs !== undefined) {
for (let [name] of prefs) {
Preferences.reset(name);
}
}
}
});