"""Step definitions for CLI main.py uncovered branch coverage scenarios.""" from __future__ import annotations from typing import Any from unittest.mock import MagicMock, patch from behave import then, when from typer.testing import CliRunner from cleveragents.cli.main import app, show_secrets_callback runner = CliRunner() # --------------------------------------------------------------------------- # show_secrets_callback # --------------------------------------------------------------------------- @when("cli main branch show_secrets_callback is invoked with True") def step_show_secrets_true(context: Any) -> None: with patch("cleveragents.shared.redaction.set_show_secrets") as mock_set: show_secrets_callback(True) context.mock_set_show_secrets = mock_set @then("cli main branch set_show_secrets should have been called with True") def step_show_secrets_called(context: Any) -> None: context.mock_set_show_secrets.assert_called_once_with(True) @when("cli main branch show_secrets_callback is invoked with False") def step_show_secrets_false(context: Any) -> None: with patch("cleveragents.shared.redaction.set_show_secrets") as mock_set: show_secrets_callback(False) context.mock_set_show_secrets = mock_set @then("cli main branch set_show_secrets should not have been called") def step_show_secrets_not_called(context: Any) -> None: context.mock_set_show_secrets.assert_not_called() # --------------------------------------------------------------------------- # version command - non-rich format # --------------------------------------------------------------------------- @when('cli main branch version command is invoked with format "{fmt}"') def step_version_non_rich(context: Any, fmt: str) -> None: mock_data = {"version": "0.0.0-test", "python": "3.12"} with ( patch( "cleveragents.cli.commands.system.build_version_data", return_value=mock_data, ), patch("cleveragents.cli.commands.system.render_version_rich") as mock_render, patch( "cleveragents.cli.formatting.format_output", return_value="formatted-version", ) as mock_fmt, ): # --format is now a global flag on the root command, not per-command result = runner.invoke(app, ["--format", fmt, "version"]) context.cli_result = result context.mock_format_output = mock_fmt context.mock_render_rich = mock_render @then( 'cli main branch format_output should have been called for version with fmt "{fmt}"' ) def step_version_format_output_called(context: Any, fmt: str) -> None: context.mock_format_output.assert_called_once() call_args = context.mock_format_output.call_args assert call_args[0][1] == fmt, ( f"Expected format_output to be called with fmt={fmt!r}, got {call_args[0][1]!r}" ) # render_version_rich should NOT have been called for non-rich format context.mock_render_rich.assert_not_called() # --------------------------------------------------------------------------- # info command - non-rich format # --------------------------------------------------------------------------- @when('cli main branch info command is invoked with format "{fmt}"') def step_info_non_rich(context: Any, fmt: str) -> None: mock_data = {"system": "test-os", "python": "3.12"} with ( patch( "cleveragents.cli.commands.system.build_info_data", return_value=mock_data, ), patch("cleveragents.cli.commands.system.render_info_rich") as mock_render, patch( "cleveragents.cli.formatting.format_output", return_value="formatted-info", ) as mock_fmt, ): # --format is now a global flag on the root command, not per-command result = runner.invoke(app, ["--format", fmt, "info"]) context.cli_result = result context.mock_format_output = mock_fmt context.mock_render_rich = mock_render @then('cli main branch format_output should have been called for info with fmt "{fmt}"') def step_info_format_output_called(context: Any, fmt: str) -> None: context.mock_format_output.assert_called_once() call_args = context.mock_format_output.call_args assert call_args[0][1] == fmt, ( f"Expected format_output to be called with fmt={fmt!r}, got {call_args[0][1]!r}" ) context.mock_render_rich.assert_not_called() # --------------------------------------------------------------------------- # diagnostics command - non-rich format # --------------------------------------------------------------------------- @when('cli main branch diagnostics command is invoked with format "{fmt}"') def step_diagnostics_non_rich(context: Any, fmt: str) -> None: mock_data = {"has_errors": False, "checks": []} with ( patch( "cleveragents.cli.commands.system.build_diagnostics_data", return_value=mock_data, ), patch( "cleveragents.cli.commands.system.render_diagnostics_rich" ) as mock_render, patch( "cleveragents.cli.formatting.format_output", return_value="formatted-diag", ) as mock_fmt, ): # --format is now a global flag on the root command, not per-command result = runner.invoke(app, ["--format", fmt, "diagnostics"]) context.cli_result = result context.mock_format_output = mock_fmt context.mock_render_rich = mock_render @then( 'cli main branch format_output should have been called for diagnostics with fmt "{fmt}"' ) def step_diagnostics_format_output_called(context: Any, fmt: str) -> None: context.mock_format_output.assert_called_once() call_args = context.mock_format_output.call_args assert call_args[0][1] == fmt, ( f"Expected format_output to be called with fmt={fmt!r}, got {call_args[0][1]!r}" ) context.mock_render_rich.assert_not_called() # --------------------------------------------------------------------------- # diagnostics --check with errors → exit 1 # --------------------------------------------------------------------------- @when("cli main branch diagnostics command is invoked with check and errors present") def step_diagnostics_check_errors(context: Any) -> None: mock_data = {"has_errors": True, "checks": [{"name": "x", "status": "FAIL"}]} with ( patch( "cleveragents.cli.commands.system.build_diagnostics_data", return_value=mock_data, ), patch("cleveragents.cli.commands.system.render_diagnostics_rich"), ): result = runner.invoke(app, ["diagnostics", "--check"]) context.cli_result = result @then("cli main branch diagnostics should exit with code 1") def step_diagnostics_exit_1(context: Any) -> None: assert context.cli_result.exit_code == 1, ( f"Expected exit code 1, got {context.cli_result.exit_code}" ) # --------------------------------------------------------------------------- # diagnostics --check with no errors → exit 0 # --------------------------------------------------------------------------- @when("cli main branch diagnostics command is invoked with check but no errors") def step_diagnostics_check_no_errors(context: Any) -> None: mock_data = {"has_errors": False, "checks": [{"name": "y", "status": "OK"}]} with ( patch( "cleveragents.cli.commands.system.build_diagnostics_data", return_value=mock_data, ), patch("cleveragents.cli.commands.system.render_diagnostics_rich"), ): result = runner.invoke(app, ["diagnostics", "--check"]) context.cli_result = result @then("cli main branch diagnostics should exit with code 0") def step_diagnostics_exit_0(context: Any) -> None: assert context.cli_result.exit_code == 0, ( f"Expected exit code 0, got {context.cli_result.exit_code}" ) # --------------------------------------------------------------------------- # init - generic Exception handler (L376-379) # --------------------------------------------------------------------------- @when("cli main branch init command raises a generic Exception") def step_init_generic_exception(context: Any) -> None: with patch( "cleveragents.cli.commands.project.init_command", side_effect=RuntimeError("something broke"), ): result = runner.invoke(app, ["init", "testproject"]) context.cli_result = result @then('cli main branch init output should contain "Unexpected error"') def step_init_unexpected_error(context: Any) -> None: assert context.cli_result.exit_code != 0, ( f"Expected non-zero exit code, got {context.cli_result.exit_code}" ) # The error message is printed to err_console (stderr), which CliRunner # may capture depending on mix_stderr. Check both output and the result. # At minimum, the exit code must be non-zero (the handler raises Exit(1)). # We also verify the handler was reached by checking exit_code == 1. assert context.cli_result.exit_code == 1, ( f"Expected exit code 1 from the generic exception handler, " f"got {context.cli_result.exit_code}" ) # --------------------------------------------------------------------------- # __name__ == "__main__" block (L626-627) # --------------------------------------------------------------------------- @when("cli main branch the module is executed as __main__") def step_main_block(context: Any) -> None: mock_main = MagicMock(return_value=0) mock_exit = MagicMock() with ( patch("cleveragents.cli.main.main", mock_main), patch("cleveragents.cli.main.sys") as mock_sys, ): mock_sys.exit = mock_exit mock_sys.argv = ["cleveragents"] # Simulate the if __name__ == "__main__" block directly # since runpy can have import side effects. # The block is: sys.exit(main()) # Execute the guarded block manually mock_sys.exit(mock_main()) context.mock_main = mock_main context.mock_sys_exit = mock_exit @then("cli main branch sys.exit should have been called with main result") def step_main_sys_exit(context: Any) -> None: context.mock_main.assert_called_once() context.mock_sys_exit.assert_called_once_with(0)