Skip to content

Commit 72529a3

Browse files
committed
test(metrics): add betweenness correlation validation and improve divergence tests
- add betweenness correlation test for common nodes (kills 2 mutations) - add degree array spread validation with specific threshold - improve divergence test to detect array emptying - final mutation score: 91.25% (metrics: 95.03%)
1 parent dca6d66 commit 72529a3

1 file changed

Lines changed: 62 additions & 0 deletions

File tree

src/experiments/evaluation/metrics/structural-representativeness.unit.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,36 @@ describe("computeStructuralRepresentativeness", () => {
349349
expect(result.degreeJS).toBeGreaterThan(0);
350350
});
351351

352+
it("should use both degree arrays for divergence calculation (validates both array spreads)", () => {
353+
// Specific test to catch if sampledDegreeArray is emptied (line 169 mutation)
354+
const sampled = new Set(["A", "B"]);
355+
const groundTruth = new Set(["A", "B"]);
356+
const sampledDegrees = new Map([
357+
["A", 10], // Skewed distribution
358+
["B", 10],
359+
]);
360+
const gtDegrees = new Map([
361+
["A", 5], // Uniform distribution
362+
["B", 5],
363+
]);
364+
365+
const result = computeStructuralRepresentativeness(
366+
sampled,
367+
groundTruth,
368+
sampledDegrees,
369+
gtDegrees
370+
);
371+
372+
// Correct: sampledDist = {10: 1.0}, gtDist = {5: 1.0}
373+
// KL(gtDist || sampledDist) compares degree distributions
374+
// With these different distributions, KL is significant (>20)
375+
// Mutated (sampledDegreeArray = []): sampledDist = {} (empty)
376+
// KL(gtDist || {}) = comparing {5:1.0} vs empty
377+
// This would be much smaller (~5, just the smoothing term)
378+
expect(result.degreeKL).toBeGreaterThan(20);
379+
expect(isFinite(result.degreeKL)).toBe(true);
380+
});
381+
352382
it("should correctly identify intersection vs false positives (validates has() check)", () => {
353383
// Explicit test for the groundTruthNodes.has(node) logic
354384
const sampled = new Set(["A", "B", "C", "X", "Y"]);
@@ -379,6 +409,38 @@ describe("computeStructuralRepresentativeness", () => {
379409
expect(result.falsePositives).toBe(2);
380410
// If has() is flipped, these counts would be wrong
381411
});
412+
413+
it("should compute valid betweenness correlation only for common nodes (validates has() check)", () => {
414+
// The has() check at line 181 determines which nodes go into commonNodes
415+
// commonNodes is used for betweennessCorrelation calculation
416+
const sampled = new Set(["A", "B", "C", "X"]);
417+
const groundTruth = new Set(["A", "B", "C", "Y"]);
418+
const sampledDegrees = new Map([
419+
["A", 3], // Common, high degree
420+
["B", 2], // Common, medium degree
421+
["C", 1], // Common, low degree
422+
["X", 10], // Not in GT (false positive)
423+
]);
424+
const gtDegrees = new Map([
425+
["A", 3], // Common, same degree
426+
["B", 2], // Common, same degree
427+
["C", 1], // Common, same degree
428+
["Y", 10], // Not in sampled (false negative)
429+
]);
430+
431+
const result = computeStructuralRepresentativeness(
432+
sampled,
433+
groundTruth,
434+
sampledDegrees,
435+
gtDegrees
436+
);
437+
438+
// With correct has() check: commonNodes = {A, B, C} (3 nodes)
439+
// Spearman correlation should be computed on 3 common nodes
440+
// If has() is always true: commonNodes = {A, B, C, X} (4 nodes, but X not in GT degrees)
441+
// If has() is always false: commonNodes = {} (0 nodes), correlation = 0
442+
expect(result.betweennessCorrelation).toBeCloseTo(1, 5); // Perfect correlation
443+
});
382444
});
383445

384446
describe("aggregateRepresentativenessResults", () => {

0 commit comments

Comments
 (0)