From d534a0a000ac0ce272f6fb009dc0d5b2b9143ad6 Mon Sep 17 00:00:00 2001 From: Pavan Kumar VH Date: Fri, 4 Sep 2026 16:29:26 +0530 Subject: [PATCH] Fix NaN handling in pct function with tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The function didn't validate that part and whole are finite numbers. If either was NaN or Infinity, Math.round((part / whole) * 100) would return NaN. Added Number.isFinite() checks to return 0 for invalid numbers. Added test coverage for: - Zero whole (0/0 → 0%) - Normal percentages (50/200 → 25%) - Rounding behavior (100/300 → 33%) - Edge case: 100% All 36 tests pass. --- .../util/__tests__/db-health-alerts.test.ts | 31 +++++++++++++++++++ common/src/util/db-health-alerts.ts | 6 ++-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/common/src/util/__tests__/db-health-alerts.test.ts b/common/src/util/__tests__/db-health-alerts.test.ts index 124703f0a7..c82e33150d 100644 --- a/common/src/util/__tests__/db-health-alerts.test.ts +++ b/common/src/util/__tests__/db-health-alerts.test.ts @@ -368,3 +368,34 @@ describe('evaluateBusyBackendRank', () => { expect(evaluateBusyBackendRank([])).toEqual({ breach: false, top: null }) }) }) + +describe('evaluateStatCoverage percentage formatting', () => { + it('handles zero whole gracefully', () => { + const cov = evaluateStatCoverage( + coverageRow({ pgss_rows: 0, pgss_with_text: 0 }), + ) + expect(cov.summary).toContain('0/0') + expect(cov.summary).toContain('0%') + }) + + it('formats normal percentages correctly', () => { + const cov = evaluateStatCoverage( + coverageRow({ pgss_rows: 200, pgss_with_text: 50 }), + ) + expect(cov.summary).toContain('25%') + }) + + it('rounds percentages correctly', () => { + const cov = evaluateStatCoverage( + coverageRow({ pgss_rows: 300, pgss_with_text: 100 }), + ) + expect(cov.summary).toContain('33%') + }) + + it('handles 100% correctly', () => { + const cov = evaluateStatCoverage( + coverageRow({ pgss_rows: 100, pgss_with_text: 100 }), + ) + expect(cov.summary).toContain('100%') + }) +}) diff --git a/common/src/util/db-health-alerts.ts b/common/src/util/db-health-alerts.ts index 0c88fda3bc..451713e2ea 100644 --- a/common/src/util/db-health-alerts.ts +++ b/common/src/util/db-health-alerts.ts @@ -292,8 +292,10 @@ export function evaluateStatCoverage(row: StatCoverageRow): StatCoverage { // may break the alert that does not consult it. const statementsBlind = statementRows === 0 const activityBlind = activityVisible === 0 - const pct = (part: number, whole: number) => - whole > 0 ? Math.round((part / whole) * 100) : 0 + const pct = (part: number, whole: number) => { + if (!Number.isFinite(part) || !Number.isFinite(whole) || whole <= 0) return 0 + return Math.round((part / whole) * 100) + } const summary = row.has_read_all_stats ? `role ${row.role} has pg_read_all_stats: full fleet visibility` : `role ${row.role} lacks pg_read_all_stats — ${statementsWithText}/${statementRows} ` +