From 8df2e2e06cf32d8f68404b01359b0878a0108f9c Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic <44276455+microsasa@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:44:55 -0700 Subject: [PATCH 1/3] test: exercise duration_by_model absent-key fallback (#869) Add two tests to TestRenderVscodeSummaryPerModelTable that verify the .get(model, 0) guard in render_vscode_summary when a model appears in requests_by_model but is missing from duration_by_model: - test_per_model_table_absent_duration_defaults_to_zero_avg - test_per_model_table_partial_duration_dict These catch regressions if the defensive fallback is accidentally removed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_vscode_report.py | 26 +++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/tests/copilot_usage/test_vscode_report.py b/tests/copilot_usage/test_vscode_report.py index 838f77b5..55162c40 100644 --- a/tests/copilot_usage/test_vscode_report.py +++ b/tests/copilot_usage/test_vscode_report.py @@ -182,6 +182,32 @@ def test_total_duration_formatted(self) -> None: # format_duration(389_114) -> "6m 29s" assert "6m 29s" in output + def test_per_model_table_absent_duration_defaults_to_zero_avg(self) -> None: + """Model in requests_by_model but absent from duration_by_model → 0ms avg.""" + summary = _make_summary( + total_requests=3, + requests_by_model={"claude-opus-4.6": 3}, + duration_by_model={}, + ) + output = _capture(summary) + assert "claude-opus-4.6" in output + assert "0ms" in output + + def test_per_model_table_partial_duration_dict(self) -> None: + """Only one of two models has a duration entry; the other defaults to 0ms.""" + summary = _make_summary( + total_requests=5, + requests_by_model={"gpt-4o-mini": 3, "claude-opus-4.6": 2}, + duration_by_model={"gpt-4o-mini": 1500}, + ) + output = _capture(summary) + assert "gpt-4o-mini" in output + assert "claude-opus-4.6" in output + # gpt-4o-mini avg = 1500 // 3 = 500ms + assert "500ms" in output + # claude-opus-4.6 has no duration entry → 0ms avg + assert "0ms" in output + def test_empty_requests_by_model_table_absent(self) -> None: summary = _make_summary(total_requests=5, requests_by_model={}) output = _capture(summary) From 14cf8ed2781e4d8b61f0f8b2135a3e2e547f143c Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic <44276455+microsasa@users.noreply.github.com> Date: Wed, 8 Apr 2026 13:53:35 -0700 Subject: [PATCH 2/3] fix: address review comments - Make test assertions target specific model rows instead of matching anywhere in the output, preventing false passes from incidental matches in the totals panel or other columns. - Set total_duration_ms to non-zero values to avoid ambiguous 0ms matches. - Apply same fix to pre-existing test_avg_ms_division_by_zero_guard which had the same class of issue (fix-forward). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_vscode_report.py | 29 ++++++++++++++++------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/tests/copilot_usage/test_vscode_report.py b/tests/copilot_usage/test_vscode_report.py index 55162c40..906196bd 100644 --- a/tests/copilot_usage/test_vscode_report.py +++ b/tests/copilot_usage/test_vscode_report.py @@ -166,11 +166,15 @@ def test_avg_ms_division_by_zero_guard(self) -> None: """A model with count=0 in duration_by_model produces avg_ms=0.""" summary = _make_summary( total_requests=0, + total_duration_ms=1_000, requests_by_model={"some-model": 0}, duration_by_model={"some-model": 100}, ) output = _capture(summary) - assert "0ms" in output + model_line = _strip_ansi( + next(line for line in output.splitlines() if "some-model" in line) + ) + assert "0ms" in model_line def test_total_duration_formatted(self) -> None: summary = _make_summary( @@ -186,27 +190,36 @@ def test_per_model_table_absent_duration_defaults_to_zero_avg(self) -> None: """Model in requests_by_model but absent from duration_by_model → 0ms avg.""" summary = _make_summary( total_requests=3, + total_duration_ms=1_000, requests_by_model={"claude-opus-4.6": 3}, duration_by_model={}, ) output = _capture(summary) - assert "claude-opus-4.6" in output - assert "0ms" in output + model_line = _strip_ansi( + next(line for line in output.splitlines() if "claude-opus-4.6" in line) + ) + assert "claude-opus-4.6" in model_line + assert model_line.count("0ms") == 2 def test_per_model_table_partial_duration_dict(self) -> None: """Only one of two models has a duration entry; the other defaults to 0ms.""" summary = _make_summary( total_requests=5, + total_duration_ms=1_500, requests_by_model={"gpt-4o-mini": 3, "claude-opus-4.6": 2}, duration_by_model={"gpt-4o-mini": 1500}, ) output = _capture(summary) - assert "gpt-4o-mini" in output - assert "claude-opus-4.6" in output + gpt_line = _strip_ansi( + next(line for line in output.splitlines() if "gpt-4o-mini" in line) + ) + opus_line = _strip_ansi( + next(line for line in output.splitlines() if "claude-opus-4.6" in line) + ) # gpt-4o-mini avg = 1500 // 3 = 500ms - assert "500ms" in output - # claude-opus-4.6 has no duration entry → 0ms avg - assert "0ms" in output + assert "500ms" in gpt_line + # claude-opus-4.6 has no duration entry → 0ms avg and 0ms total + assert opus_line.count("0ms") == 2 def test_empty_requests_by_model_table_absent(self) -> None: summary = _make_summary(total_requests=5, requests_by_model={}) From 19dbe6d30098b8c3dc7f647d4a07a8a966ff2dbf Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic <44276455+microsasa@users.noreply.github.com> Date: Wed, 8 Apr 2026 14:02:29 -0700 Subject: [PATCH 3/3] fix: address review comments - Use regex word-boundary assertion for standalone '0ms' check to avoid matching '0ms' inside '100ms' (line 177) - Assert '500ms' count==2 to verify avg and total columns independently rather than relying on ambiguous substring match (line 220) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_vscode_report.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/copilot_usage/test_vscode_report.py b/tests/copilot_usage/test_vscode_report.py index 906196bd..97c88b47 100644 --- a/tests/copilot_usage/test_vscode_report.py +++ b/tests/copilot_usage/test_vscode_report.py @@ -174,7 +174,7 @@ def test_avg_ms_division_by_zero_guard(self) -> None: model_line = _strip_ansi( next(line for line in output.splitlines() if "some-model" in line) ) - assert "0ms" in model_line + assert re.search(r"(? None: summary = _make_summary( @@ -216,8 +216,9 @@ def test_per_model_table_partial_duration_dict(self) -> None: opus_line = _strip_ansi( next(line for line in output.splitlines() if "claude-opus-4.6" in line) ) - # gpt-4o-mini avg = 1500 // 3 = 500ms - assert "500ms" in gpt_line + # gpt-4o-mini avg = 1500 // 3 = 500ms; total = "1s 500ms" + # "500ms" appears once for avg and once inside the total format. + assert gpt_line.count("500ms") == 2 # claude-opus-4.6 has no duration entry → 0ms avg and 0ms total assert opus_line.count("0ms") == 2