forked from cleveragents/cleveragents-core
258 lines
7.8 KiB
Python
258 lines
7.8 KiB
Python
"""Step definitions for the CleverAgents CLI feature."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import contextlib
|
|
import io
|
|
import sys
|
|
from collections.abc import Sequence
|
|
from typing import Any
|
|
from unittest.mock import MagicMock, patch
|
|
|
|
import click
|
|
from behave import then, when
|
|
from click.testing import CliRunner
|
|
|
|
from cleveragents.__main__ import run
|
|
from cleveragents.cli import _convert_exit_code, cli, main
|
|
from cleveragents.platform import ensure_cli_importable
|
|
|
|
|
|
def _run_cli(context: Any, args: Sequence[str]) -> None:
|
|
buffer = io.StringIO()
|
|
with contextlib.redirect_stdout(buffer):
|
|
exit_code = main(list(args))
|
|
context.result = {
|
|
"exit_code": exit_code,
|
|
"output": buffer.getvalue(),
|
|
}
|
|
|
|
|
|
@when('I run the CleverAgents CLI with "--help"')
|
|
def step_run_help(context: Any) -> None:
|
|
_run_cli(context, ["--help"])
|
|
|
|
|
|
@then('the output should contain "CleverAgents"')
|
|
def step_output_help(context: Any) -> None:
|
|
assert context.result["exit_code"] == 0
|
|
assert "CleverAgents" in context.result["output"]
|
|
|
|
|
|
@when('I run the CleverAgents CLI with "--version"')
|
|
def step_run_version(context: Any) -> None:
|
|
_run_cli(context, ["--version"])
|
|
|
|
|
|
@then('the output should contain "1.0.0"')
|
|
def step_output_version(context: Any) -> None:
|
|
assert context.result["exit_code"] == 0
|
|
assert "1.0.0" in context.result["output"]
|
|
|
|
|
|
# New generic steps for other commands
|
|
@when('I run the CleverAgents CLI with "{args}"')
|
|
def step_run_cli_with_args(context, args):
|
|
"""Execute the CLI with specific arguments."""
|
|
runner = CliRunner()
|
|
result = runner.invoke(cli, args.split())
|
|
context.result = {
|
|
"exit_code": result.exit_code,
|
|
"output": result.output,
|
|
"runner_result": result,
|
|
}
|
|
|
|
|
|
@then('the output should contain "{text}"')
|
|
def step_output_should_contain(context, text):
|
|
"""Verify the CLI output contains expected text."""
|
|
assert text in context.result["output"], (
|
|
f"Expected '{text}' not found in output: {context.result['output']}"
|
|
)
|
|
|
|
|
|
@then("the command should fail")
|
|
def step_command_should_fail(context):
|
|
"""Verify the command failed."""
|
|
assert context.result["exit_code"] != 0
|
|
|
|
|
|
@then('the error should contain "{text}"')
|
|
def step_error_should_contain(context, text):
|
|
"""Verify error output contains text."""
|
|
output = context.result["output"].lower() if "output" in context.result else ""
|
|
assert text.lower() in output, f"Expected '{text}' not found in error output"
|
|
|
|
|
|
# Exit code conversion steps
|
|
@when("I convert exit code {code}")
|
|
def step_convert_exit_code(context, code):
|
|
"""Convert an exit code."""
|
|
if code == "None":
|
|
context.converted_code = _convert_exit_code(None)
|
|
else:
|
|
context.converted_code = _convert_exit_code(int(code))
|
|
|
|
|
|
@then("the result should be {expected}")
|
|
def step_result_should_be(context, expected):
|
|
"""Verify the conversion result."""
|
|
assert context.converted_code == int(expected)
|
|
|
|
|
|
@when("I convert a Click Exit exception with code {code}")
|
|
def step_convert_click_exit(context, code):
|
|
"""Convert a Click Exit exception."""
|
|
exit_exc = click.exceptions.Exit(int(code))
|
|
context.converted_code = _convert_exit_code(exit_exc)
|
|
|
|
|
|
# Main function steps
|
|
@when('I call main with arguments "{args}"')
|
|
def step_call_main_with_args(context, args):
|
|
"""Call main function with arguments."""
|
|
with patch("cleveragents.cli.cli.main") as mock_cli:
|
|
mock_cli.side_effect = SystemExit(0)
|
|
context.main_result = main(args.split())
|
|
|
|
|
|
@then("main should process the version flag")
|
|
def step_main_processes_version(context):
|
|
"""Verify main processed the version flag."""
|
|
assert context.main_result == 0
|
|
|
|
|
|
@when("I call main with no arguments")
|
|
def step_call_main_no_args(context):
|
|
"""Call main with no arguments."""
|
|
with patch("cleveragents.cli.cli.main") as mock_cli:
|
|
mock_cli.side_effect = SystemExit(0)
|
|
context.main_result = main()
|
|
|
|
|
|
@then("main should display help")
|
|
def step_main_displays_help(context):
|
|
"""Verify main displays help."""
|
|
assert context.main_result == 0
|
|
|
|
|
|
@when("I call main and CLI raises SystemExit {code}")
|
|
def step_main_system_exit(context, code):
|
|
"""Simulate CLI raising SystemExit."""
|
|
with patch("cleveragents.cli.cli.main") as mock_cli:
|
|
mock_cli.side_effect = SystemExit(int(code))
|
|
context.main_result = main(["bad-command"])
|
|
|
|
|
|
@then("main should return {code}")
|
|
def step_main_returns_code(context, code):
|
|
"""Verify main returns expected code."""
|
|
assert context.main_result == int(code)
|
|
|
|
|
|
# Module steps
|
|
@when("I execute the __main__ module")
|
|
def step_execute_main_module(context):
|
|
"""Execute the __main__ module."""
|
|
with patch("sys.argv", ["agents", "--help"]):
|
|
with patch("cleveragents.__main__.main") as mock_main:
|
|
mock_main.return_value = 0
|
|
with patch("sys.exit") as mock_exit:
|
|
run()
|
|
context.main_called = mock_main.called
|
|
mock_exit.assert_called_once_with(0)
|
|
|
|
|
|
@then("the CLI should start")
|
|
def step_cli_should_start(context):
|
|
"""Verify CLI started."""
|
|
assert context.main_called
|
|
|
|
|
|
@when("I import the __main__ module")
|
|
def step_import_main_module(context):
|
|
"""Import the __main__ module."""
|
|
from cleveragents import __main__
|
|
|
|
context.main_module = __main__
|
|
|
|
|
|
@then("it should have a run function")
|
|
def step_has_run_function(context):
|
|
"""Verify module has run function."""
|
|
assert hasattr(context.main_module, "run")
|
|
assert callable(context.main_module.run)
|
|
|
|
|
|
# Platform module steps
|
|
@when("I call ensure_cli_importable")
|
|
def step_call_ensure_cli_importable(context):
|
|
"""Call ensure_cli_importable."""
|
|
context.cli_module = ensure_cli_importable()
|
|
|
|
|
|
@then("it should return the CLI module")
|
|
def step_returns_cli_module(context):
|
|
"""Verify it returns CLI module."""
|
|
assert context.cli_module is not None
|
|
|
|
|
|
@then("the module should have a cli attribute")
|
|
def step_module_has_cli(context):
|
|
"""Verify module has cli attribute."""
|
|
assert hasattr(context.cli_module, "cli")
|
|
|
|
|
|
@then("the module should have a main attribute")
|
|
def step_module_has_main(context):
|
|
"""Verify module has main attribute."""
|
|
assert hasattr(context.cli_module, "main")
|
|
|
|
|
|
@when("the CLI module is already imported")
|
|
def step_cli_already_imported(context):
|
|
"""Setup already imported module."""
|
|
context.mock_module = MagicMock()
|
|
context.original_module = sys.modules.get("cleveragents.cli")
|
|
sys.modules["cleveragents.cli"] = context.mock_module
|
|
|
|
|
|
@then("it should return the cached module")
|
|
def step_returns_cached_module(context):
|
|
"""Verify cached module returned."""
|
|
result = ensure_cli_importable()
|
|
assert result is context.mock_module
|
|
# Restore original
|
|
if context.original_module:
|
|
sys.modules["cleveragents.cli"] = context.original_module
|
|
else:
|
|
sys.modules.pop("cleveragents.cli", None)
|
|
|
|
|
|
@when("the CLI module import fails")
|
|
def step_cli_import_fails(context):
|
|
"""Setup import failure."""
|
|
# Save original module
|
|
context.original_module = sys.modules.get("cleveragents.cli")
|
|
# Remove from sys.modules to force import
|
|
sys.modules.pop("cleveragents.cli", None)
|
|
context.import_error = ImportError("Test error")
|
|
|
|
|
|
@then("it should propagate the import error")
|
|
def step_propagates_import_error(context):
|
|
"""Verify import error propagated."""
|
|
# Ensure module is not in sys.modules
|
|
sys.modules.pop("cleveragents.cli", None)
|
|
|
|
with patch("cleveragents.platform.import_module") as mock_import:
|
|
mock_import.side_effect = ImportError("Test error")
|
|
try:
|
|
ensure_cli_importable()
|
|
assert False, "Should have raised ImportError"
|
|
except ImportError as e:
|
|
assert str(e) == "Test error"
|
|
# Restore original module
|
|
if context.original_module:
|
|
sys.modules["cleveragents.cli"] = context.original_module
|