Source code

Revision control

Copy as Markdown

Other Tools

Test Info: Warnings

/* Any copyright is dedicated to the Public Domain.
const { SmartTabGroupingManager } = ChromeUtils.importESModule(
"moz-src:///browser/components/tabbrowser/SmartTabGrouping.sys.mjs"
);
add_task(function test_logistic_regression_get_base_domain() {
// Basic HTTPS URL with www
Assert.equal(
SmartTabGroupingManager.getBaseDomain("https://www.example.com/path"),
"example.com",
"www.example.com should normalize to example.com"
);
// Multiple subdomains
Assert.equal(
SmartTabGroupingManager.getBaseDomain("https://docs.example.com"),
"docs.example.com",
"Should keep last subdomain + baseDomain"
);
// Hosted services like blogs
Assert.equal(
SmartTabGroupingManager.getBaseDomain("https://myblog.example.com/"),
"myblog.example.com",
"Should bucket per hosted subdomain (blog, docs, etc.)"
);
// Host without dots
Assert.equal(
SmartTabGroupingManager.getBaseDomain("http://localhost"),
"localhost",
"Should return hostname as-is when there is no dot"
);
// Invalid / empty URL should be handled gracefully
Assert.equal(
SmartTabGroupingManager.getBaseDomain(""),
"",
"Invalid URL should return empty string"
);
});
add_task(function test_logistic_regression_domain_match_fractions() {
const mgr = new SmartTabGroupingManager();
const anchors = [
{ url: "https://a.com/foo" },
{ url: "https://www.a.com/bar" },
{ url: "https://b.com/baz" },
];
const candidates = [
{ url: "https://a.com/other" }, // matches 2 of 3 anchors
{ url: "https://b.com/other" }, // matches 1 of 3 anchors
{ url: "https://c.com/other" }, // matches 0 of 3 anchors
{ url: "" }, // invalid / empty URL
];
const fractions = mgr.getDomainMatchFractions(anchors, candidates);
Assert.equal(
fractions.length,
candidates.length,
"Should return one value per candidate"
);
Assert.less(
Math.abs(fractions[0] - 2 / 3),
1e-6,
"Candidate with domain matching two of three anchors should have fraction 2/3"
);
Assert.less(
Math.abs(fractions[1] - 1 / 3),
1e-6,
"Candidate with domain matching one of three anchors should have fraction 1/3"
);
Assert.equal(
fractions[2],
0,
"Candidate with domain not matching any anchor should have fraction 0"
);
Assert.equal(
fractions[3],
0,
"Candidate with invalid URL should have fraction 0"
);
});
add_task(function test_logistic_regression_get_max_similarity() {
const mgr = new SmartTabGroupingManager();
const anchors = [
[1, 0],
[0, 1],
];
const candidates = [
[1, 0], // identical to first anchor -> cos ~ 1
[0.5, 0.5], // at 45 degrees -> cos ~ 0.707 with either anchor
];
const maxSims = mgr.getMaxSimilarity(anchors, candidates);
Assert.equal(
maxSims.length,
candidates.length,
"Should return one max similarity per candidate"
);
Assert.less(
Math.abs(maxSims[0] - 1),
1e-6,
"First candidate identical to first anchor should have cosine similarity ~1"
);
Assert.ok(
maxSims[1] > 0.7 && maxSims[1] < 0.8,
"Second candidate should have cosine similarity ~sqrt(1/2) ≈ 0.707 with at least one anchor"
);
});
add_task(function test_logistic_regression_sigmoid_and_calculate_probability() {
const mgr = new SmartTabGroupingManager();
// Basic sigmoid sanity checks
Assert.less(Math.abs(mgr.sigmoid(0) - 0.5), 1e-6, "sigmoid(0) should be 0.5");
Assert.greater(
mgr.sigmoid(10),
0.99,
"sigmoid of large positive number should be close to 1"
);
Assert.less(
mgr.sigmoid(-10),
0.01,
"sigmoid of large negative number should be close to 0"
);
// Check that calculateProbability matches explicit linear combination + sigmoid
const params = {
GROUP_SIMILARITY_WEIGHT: 1,
TITLE_SIMILARITY_WEIGHT: 2,
DOMAIN_SIMILARITY_WEIGHT: 3,
INTERCEPT: 0,
};
const s_gc = 0.5;
const s_tt = 0.5;
const s_dd = 0.5;
const prob = mgr.calculateProbability(s_gc, s_tt, s_dd, params);
const expectedZ = s_gc * 1 + s_tt * 2 + s_dd * 3; // 3
const expectedProb = mgr.sigmoid(expectedZ);
Assert.less(
Math.abs(prob - expectedProb),
1e-6,
"calculateProbability should equal sigmoid(linear combination of features and weights)"
);
});
add_task(
function test_logistic_regression_calculate_all_probabilities_with_group() {
const mgr = new SmartTabGroupingManager();
// cos = 0 for both candidates -> s_gc = s_tt_max = 0.5 for both
const groupSimilaritiesCos = [0, 0];
const titleSimilaritiesCos = [0, 0];
// Candidate 0 has full domain match, candidate 1 has none.
const domainSimilarities = [1, 0];
const probs = mgr.calculateAllProbabilities(
groupSimilaritiesCos,
titleSimilaritiesCos,
domainSimilarities
);
Assert.equal(
probs.length,
2,
"Should return one probability per candidate"
);
Assert.greater(
probs[0],
probs[1],
"With group present, candidate with higher domain match fraction should have higher probability"
);
}
);
add_task(
function test_logistic_regression_calculate_all_probabilities_without_group() {
const mgr = new SmartTabGroupingManager();
// cos = 0 for both candidates -> s_tt_max = 0.5 for both
const titleSimilaritiesCos = [0, 0];
// Candidate 0 has full domain match, candidate 1 has none.
const domainSimilarities = [1, 0];
const probs = mgr.calculateAllProbabilities(
null, // no group similarities -> TITLE_ONLY params
titleSimilaritiesCos,
domainSimilarities
);
Assert.equal(
probs.length,
2,
"Should return one probability per candidate"
);
Assert.greater(
probs[0],
probs[1],
"Without group, candidate with higher domain match fraction should have higher probability"
);
}
);