@@ -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
384446describe ( "aggregateRepresentativenessResults" , ( ) => {
0 commit comments