Skip to content

Commit ce36fa9

Browse files
Kasper JungeRalphify
authored andcommitted
refactor: extract _format_run_info from ConsoleEmitter for testability
Follows the same pattern as the _format_summary extraction (c79694c). The run info line building logic (timeout, command count, max iterations) is now a standalone function that can be unit tested without a Console instance, with 10 focused tests covering all combinations. Co-authored-by: Ralphify <noreply@ralphify.co>
1 parent d072ce2 commit ce36fa9

2 files changed

Lines changed: 65 additions & 14 deletions

File tree

src/ralphify/_console_emitter.py

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,25 @@ def _format_summary(
6464
return f"{_plural(total, 'iteration')} {_ICON_DASH} {detail}"
6565

6666

67+
def _format_run_info(
68+
timeout: float | None, command_count: int, max_iterations: int | None
69+
) -> str:
70+
"""Build a plain-text run info string from configuration values.
71+
72+
Returns an empty string when no information is available. Used by
73+
:meth:`ConsoleEmitter._on_run_started` to show the config summary
74+
beneath the "Running:" header.
75+
"""
76+
parts: list[str] = []
77+
if timeout is not None and timeout > 0:
78+
parts.append(f"timeout {format_duration(timeout)}")
79+
if command_count > 0:
80+
parts.append(_plural(command_count, "command"))
81+
if max_iterations is not None:
82+
parts.append(f"max {_plural(max_iterations, 'iteration')}")
83+
return " · ".join(parts)
84+
85+
6786
class _IterationSpinner:
6887
"""Rich renderable that shows a spinner with elapsed time."""
6988

@@ -113,19 +132,9 @@ def _on_run_started(self, data: RunStartedData) -> None:
113132
self._console.print(
114133
f"\n[bold {_brand.PURPLE}]▶ Running:[/] [bold]{escape_markup(ralph_name)}[/]"
115134
)
116-
117-
info_parts: list[str] = []
118-
timeout = data["timeout"]
119-
if timeout is not None and timeout > 0:
120-
info_parts.append(f"timeout {format_duration(timeout)}")
121-
command_count = data["commands"]
122-
if command_count > 0:
123-
info_parts.append(_plural(command_count, "command"))
124-
max_iter = data["max_iterations"]
125-
if max_iter is not None:
126-
info_parts.append(f"max {_plural(max_iter, 'iteration')}")
127-
if info_parts:
128-
self._console.print(f" [dim]{' · '.join(info_parts)}[/]")
135+
info = _format_run_info(data["timeout"], data["commands"], data["max_iterations"])
136+
if info:
137+
self._console.print(f" [dim]{info}[/]")
129138

130139
def _start_live(self) -> None:
131140
spinner = _IterationSpinner()

tests/test_console_emitter.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
import pytest
44
from rich.console import Console
55

6-
from ralphify._console_emitter import ConsoleEmitter, _IterationSpinner, _format_summary
6+
from ralphify._console_emitter import (
7+
ConsoleEmitter,
8+
_IterationSpinner,
9+
_format_run_info,
10+
_format_summary,
11+
)
712
from ralphify._events import Event, EventType
813

914

@@ -505,6 +510,43 @@ def test_all_failed(self):
505510
assert "3 failed" in result
506511

507512

513+
class TestFormatRunInfo:
514+
def test_empty_when_no_config(self):
515+
assert _format_run_info(timeout=0, command_count=0, max_iterations=None) == ""
516+
assert _format_run_info(timeout=None, command_count=0, max_iterations=None) == ""
517+
518+
def test_timeout_only(self):
519+
result = _format_run_info(timeout=120, command_count=0, max_iterations=None)
520+
assert result == "timeout 2m 0s"
521+
522+
def test_commands_only(self):
523+
assert _format_run_info(timeout=0, command_count=3, max_iterations=None) == "3 commands"
524+
525+
def test_singular_command(self):
526+
assert _format_run_info(timeout=0, command_count=1, max_iterations=None) == "1 command"
527+
528+
def test_max_iterations_only(self):
529+
assert _format_run_info(timeout=0, command_count=0, max_iterations=5) == "max 5 iterations"
530+
531+
def test_singular_iteration(self):
532+
assert _format_run_info(timeout=0, command_count=0, max_iterations=1) == "max 1 iteration"
533+
534+
def test_all_fields(self):
535+
result = _format_run_info(timeout=60, command_count=2, max_iterations=3)
536+
assert "timeout 1m 0s" in result
537+
assert "2 commands" in result
538+
assert "max 3 iterations" in result
539+
assert " · " in result
540+
541+
def test_zero_timeout_excluded(self):
542+
result = _format_run_info(timeout=0, command_count=2, max_iterations=None)
543+
assert "timeout" not in result
544+
545+
def test_negative_timeout_excluded(self):
546+
result = _format_run_info(timeout=-1, command_count=2, max_iterations=None)
547+
assert "timeout" not in result
548+
549+
508550
class TestIterationSpinner:
509551
def test_renders_elapsed_time(self):
510552
spinner = _IterationSpinner()

0 commit comments

Comments
 (0)