Skip to content

[aw][test audit] Untested branches in cli.py: auto-refresh, uppercase commands, events_path=None, group-level --path, _ensure_aw [Content truncated due to length] #59

@microsasa

Description

@microsasa

Root Cause Analysis

test_cli.py has good coverage of the happy paths, but several distinct code branches in cli.py remain unexercised. Each gap is small on its own, but together they leave real execution paths unverified — including the auto-refresh feature which is central to the interactive mode.


1. _interactive_loop auto-refresh branches (lines 169–185)

When change_event.is_set() is True, three distinct re-render paths run depending on the current view:

if change_event.is_set():
    change_event.clear()
    sessions = get_all_sessions(path)
    if view == "home":          # ← untested
        _draw_home(...)
    elif view == "cost":        # ← untested
        render_cost_view(...)
    elif view == "detail" and detail_idx is not None:  # ← untested
        _show_session_by_index(...)

None of these branches are exercised. The _FileChangeHandler and _start_observer are unit-tested in isolation, but the wiring inside _interactive_loop that consumes the event is never triggered.

Tests to add — call _interactive_loop (or the main group) with a monkeypatched _read_line_nonblocking that:

  • Pre-sets change_event to assert home-view auto-refresh
  • Navigates to cost view, then pre-sets change_event to assert cost-view auto-refresh
  • Navigates to detail view (e.g. input "1"), then pre-sets change_event to assert detail-view auto-refresh (including the detail_idx is not None guard)

2. Uppercase interactive commands 'Q', 'C', 'R' (lines 207–220)

The interactive loop handles both cases:

if line in ("q", "Q"):   break
if line in ("c", "C"):   ...cost view...
if line in ("r", "R"):   ...refresh...

Tests only ever send lowercase q, c, r. The uppercase variants are dead code from the test perspective.

Tests to add:

  • test_interactive_quit_uppercase — input "Q\n", assert exit code 0
  • test_interactive_cost_view_uppercase — input "C\nq\n", assert "Cost" in output
  • test_interactive_refresh_uppercase — input "R\nq\n", assert exit code 0

3. _show_session_by_index with events_path=None (lines 77–80)

if s.events_path is None:
    console.print("[red]No events path for this session.[/red]")
    return

test_show_session_by_index_missing_file covers the OSError/FileNotFoundError path (non-None path to a deleted file), but the events_path=None branch is never hit.

Test to add: Create a SessionSummary with events_path=None, call _show_session_by_index(console, [s], 1), and assert "No events path" appears in the captured output.


4. Group-level --path propagation to subcommands (cli.py ctx.obj)

Each subcommand falls back to the group-level path:

path = path or ctx.obj.get("path")

All existing tests pass --path directly to the subcommand (e.g. ["summary", "--path", str(tmp_path)]). No test passes --path at the group level and omits it from the subcommand (e.g. ["--path", str(tmp_path), "summary"]).

Tests to add (one per subcommand — summary, session, cost, live):

  • Invoke with ["--path", str(tmp_path), "(subcommand)"] (no --path on subcommand)
  • Assert exit_code == 0 and expected output matches the subcommand-level --path tests

5. _ensure_aware — no unit tests

def _ensure_aware(dt: datetime | None) -> datetime | None:
    if dt is not None and dt.tzinfo is None:
        return dt.replace(tzinfo=UTC)
    return dt

This is exercised by --since/--until CLI option parsing end-to-end, but never verified directly. Three distinct cases exist:

  • dt=None → returns None
  • dt already timezone-aware → returns unchanged
  • dt naive → attaches UTC

Tests to add: Three parametrized unit tests covering all three cases.


Acceptance Criteria

  • Auto-refresh: tests trigger change_event while in each view (home, cost, detail) and assert the correct render function is called / output appears
  • Uppercase Q/C/R produce the same observable outcomes as their lowercase equivalents
  • _show_session_by_index(console, [session_with_none_path], 1) outputs the "No events path" error
  • Group-level --path propagates correctly to all four subcommands without error
  • _ensure_aware(None)None, _ensure_aware(aware_dt) → same aware_dt, _ensure_aware(naive_dt) → UTC-attached datetime
  • All new tests pass with no regressions

Generated by Test Suite Analysis ·

Warning

⚠️ Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • pypi.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "pypi.org"

See Network Configuration for more information.

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