From 05011a3d19faaf927de5028d934bf49a3ea40db9 Mon Sep 17 00:00:00 2001 From: Sasa Junuzovic <44276455+microsasa@users.noreply.github.com> Date: Thu, 9 Apr 2026 08:39:05 -0700 Subject: [PATCH] test(models): add dedicated TestParseTokenInt unit tests Add a TestParseTokenInt class in test_models.py that directly tests the public parse_token_int() function with all documented contract cases: - bool inputs (True/False) return None - str inputs ('42', 'abc', '') return None - non-whole floats (3.14, 0.5, -1.5, 1.999) return None - zero/negative ints (0, -1, -100000) return None - zero/negative floats (0.0, -1.0, -100.0) return None - unsupported types (None, dict, list, object) return None - positive int returned as-is - positive whole float coerced to int - large positive int returned unchanged - return type verified as int (not float) Closes #886 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/copilot_usage/test_models.py | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/tests/copilot_usage/test_models.py b/tests/copilot_usage/test_models.py index 3e48ebe..3cd680f 100644 --- a/tests/copilot_usage/test_models.py +++ b/tests/copilot_usage/test_models.py @@ -28,6 +28,7 @@ ensure_aware_opt, has_active_period_stats, merge_model_metrics, + parse_token_int, shutdown_output_tokens, total_output_tokens, ) @@ -371,6 +372,68 @@ def test_session_summary_full() -> None: assert s.model_metrics["claude-opus-4.6-1m"].usage.inputTokens == 1627935 +# --------------------------------------------------------------------------- +# parse_token_int +# --------------------------------------------------------------------------- + + +class TestParseTokenInt: + """Direct unit tests for the public parse_token_int() function.""" + + # --- invalid / non-contributing inputs --- + + @pytest.mark.parametrize("value", [True, False]) + def test_bool_returns_none(self, value: bool) -> None: + """Bool inputs (subclass of int) must be rejected.""" + assert parse_token_int(value) is None + + @pytest.mark.parametrize("value", ["42", "abc", ""]) + def test_str_returns_none(self, value: str) -> None: + """String inputs must be rejected even if numeric.""" + assert parse_token_int(value) is None + + @pytest.mark.parametrize("value", [3.14, 0.5, -1.5, 1.999]) + def test_non_whole_float_returns_none(self, value: float) -> None: + """Non-whole floats must be rejected.""" + assert parse_token_int(value) is None + + @pytest.mark.parametrize("value", [0, -1, -100_000]) + def test_zero_or_negative_int_returns_none(self, value: int) -> None: + """Zero and negative ints must be rejected.""" + assert parse_token_int(value) is None + + @pytest.mark.parametrize("value", [0.0, -1.0, -100.0]) + def test_zero_or_negative_float_returns_none(self, value: float) -> None: + """Zero and negative whole floats must be rejected.""" + assert parse_token_int(value) is None + + @pytest.mark.parametrize("value", [None, {}, [], object()]) + def test_other_types_return_none(self, value: object) -> None: + """Unsupported types must be rejected.""" + assert parse_token_int(value) is None + + # --- valid / contributing inputs --- + + def test_positive_int_returned_as_is(self) -> None: + """Positive int should be returned unchanged.""" + assert parse_token_int(42) == 42 + + def test_positive_whole_float_coerced_to_int(self) -> None: + """Positive whole float should be coerced to int.""" + result = parse_token_int(1234.0) + assert result == 1234 + assert isinstance(result, int) + + def test_large_positive_int(self) -> None: + """Large positive ints should be returned unchanged.""" + assert parse_token_int(1_000_000) == 1_000_000 + + def test_return_type_is_int_not_float(self) -> None: + """Whole-number float coercion must produce an int, not a float.""" + result = parse_token_int(99.0) + assert type(result) is int + + # --------------------------------------------------------------------------- # add_to_model_metrics # ---------------------------------------------------------------------------