Skip to content

[aw][test audit] Untested behavioral branches: last_resume_time display, FileChangeHandler debounce, config non-string model #44

@microsasa

Description

@microsasa

Root Cause

Three related behavioral branches in the interactive/live-mode code have no direct test coverage, meaning regressions in user-visible output could go undetected:

1. last_resume_time ignored in running-time display (report.py)

Both render_live_sessions and _render_active_section compute the "Running" / "Running Time" column as:

running = _format_duration(s.last_resume_time or s.start_time) if s.start_time else "—"

No test supplies a SessionSummary with both start_time and last_resume_time set to different values and then asserts that the displayed duration is measured from last_resume_time. A regression that dropped the last_resume_time branch would silently show the wrong elapsed time for resumed sessions.

2. _FileChangeHandler.dispatch debounce logic (cli.py)

_FileChangeHandler rate-limits change events to one per 2 seconds. The class has no unit test:

  • The happy path (first dispatch call sets the event) is untested.
  • The debounce (rapid second call within 2 s is suppressed) is untested.
  • _stop_observer(None) (the no-op guard) is also never directly tested.

3. _read_config_model non-string model value (parser.py)

The code guards return model if isinstance(model, str) else None, but there is no test where config.json contains {"model": 42} or {"model": null}. The False branch of the isinstance check is dead from a test perspective.

Expected Behaviour

  • render_live_sessions: when last_resume_time is set and is more recent than start_time, the displayed running time is measured from last_resume_time.
  • _render_active_section (full summary): same guarantee.
  • _FileChangeHandler.dispatch: first call within a cold window sets change_event; second call within 2 s is suppressed (event already set, _last_trigger not reset past the debounce window); calling with a gap > 2 s fires again.
  • _stop_observer(None): returns silently without raising.
  • _read_config_model: returns None when model is present but is not a str (e.g. 42, [], null).

Spec

tests/copilot_usage/test_report.py — add to TestRenderLiveSessions and TestRenderFullSummary:

# test: render_live_sessions — session with last_resume_time more recent than start_time
#   displays duration from last_resume_time (not start_time)
# test: _render_active_section — same guarantee for the full-summary active section

tests/copilot_usage/test_cli.py — add:

# test: _FileChangeHandler.dispatch sets change_event on first call
# test: _FileChangeHandler.dispatch suppresses second call within 2 s (debounce)
# test: _FileChangeHandler.dispatch fires again after > 2 s gap
# test: _stop_observer(None) returns without raising

tests/copilot_usage/test_parser.py — add to TestConfigModelReading:

# test: config.json with {"model": 42} → model is None
# test: config.json with {"model": null} → model is None
# test: config.json with {"model": []} → model is None

Generated by Test Suite Analysis ·

Metadata

Metadata

Assignees

No one assigned

    Labels

    awCreated by agentic workflowtest-auditTest coverage gaps

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions