"""Step definitions for A2A clients coverage boost scenarios. Covers: - Protocol default method bodies (the ``...`` expression on lines 28, 36, 52, 63, 74, 90, 101) - Stub validation branches for empty/non-string inputs (lines 149, 159, 186) """ from __future__ import annotations import contextlib from behave import given, then, when from behave.runner import Context with contextlib.suppress(ImportError): from cleveragents.a2a.clients import ( AuthClient, RemoteExecutionClient, ServerClient, StubAuthClient, StubRemoteExecutionClient, ) # --------------------------------------------------------------------------- # Concrete subclasses that inherit Protocol default method bodies # --------------------------------------------------------------------------- class _ConcreteServerClient(ServerClient): """Minimal concrete subclass — inherits the ``...`` default bodies.""" pass class _ConcreteRemoteExecutionClient(RemoteExecutionClient): """Minimal concrete subclass — inherits the ``...`` default bodies.""" pass class _ConcreteAuthClient(AuthClient): """Minimal concrete subclass — inherits the ``...`` default bodies.""" pass # --------------------------------------------------------------------------- # Given steps — Protocol concrete subclasses # --------------------------------------------------------------------------- @given("a concrete subclass of ServerClient protocol") def step_concrete_server_client(context: Context) -> None: context.concrete_server = _ConcreteServerClient() context.call_error = None @given("a concrete subclass of RemoteExecutionClient protocol") def step_concrete_exec_client(context: Context) -> None: context.concrete_exec = _ConcreteRemoteExecutionClient() context.call_error = None @given("a concrete subclass of AuthClient protocol") def step_concrete_auth_client(context: Context) -> None: context.concrete_auth = _ConcreteAuthClient() context.call_error = None # --------------------------------------------------------------------------- # When steps — call Protocol default method bodies # --------------------------------------------------------------------------- @when("I call health_check on the concrete server client") def step_call_concrete_health_check(context: Context) -> None: try: context.call_result = context.concrete_server.health_check() except Exception as exc: context.call_error = exc @when("I call get_version on the concrete server client") def step_call_concrete_get_version(context: Context) -> None: try: context.call_result = context.concrete_server.get_version() except Exception as exc: context.call_error = exc @when("I call execute_plan on the concrete execution client") def step_call_concrete_execute_plan(context: Context) -> None: try: context.call_result = context.concrete_exec.execute_plan("test-plan") except Exception as exc: context.call_error = exc @when("I call get_plan_status on the concrete execution client") def step_call_concrete_get_plan_status(context: Context) -> None: try: context.call_result = context.concrete_exec.get_plan_status("test-plan") except Exception as exc: context.call_error = exc @when("I call cancel_plan on the concrete execution client") def step_call_concrete_cancel_plan(context: Context) -> None: try: context.call_result = context.concrete_exec.cancel_plan("test-plan") except Exception as exc: context.call_error = exc @when("I call authenticate on the concrete auth client") def step_call_concrete_authenticate(context: Context) -> None: try: context.call_result = context.concrete_auth.authenticate("tok_test") except Exception as exc: context.call_error = exc @when("I call validate_token on the concrete auth client") def step_call_concrete_validate_token(context: Context) -> None: try: context.call_result = context.concrete_auth.validate_token("tok_test") except Exception as exc: context.call_error = exc # --------------------------------------------------------------------------- # Then step — Protocol calls complete without error # --------------------------------------------------------------------------- @then("the call should complete without error") def step_call_completes(context: Context) -> None: assert context.call_error is None, ( f"Expected no error but got: {context.call_error!r}" ) # --------------------------------------------------------------------------- # Given steps — Stub instances for validation branch coverage # --------------------------------------------------------------------------- @given("a fresh StubRemoteExecutionClient for coverage") def step_fresh_stub_exec(context: Context) -> None: context.cov_stub_exec = StubRemoteExecutionClient() context.cov_caught_error = None @given("a fresh StubAuthClient for coverage") def step_fresh_stub_auth(context: Context) -> None: context.cov_stub_auth = StubAuthClient() context.cov_caught_error = None # --------------------------------------------------------------------------- # When steps — empty string inputs to stubs # --------------------------------------------------------------------------- @when("I call get_plan_status with empty plan_id on the stub") def step_stub_get_plan_status_empty(context: Context) -> None: try: context.cov_stub_exec.get_plan_status("") except ValueError as exc: context.cov_caught_error = exc @when("I call cancel_plan with empty plan_id on the stub") def step_stub_cancel_plan_empty(context: Context) -> None: try: context.cov_stub_exec.cancel_plan("") except ValueError as exc: context.cov_caught_error = exc @when("I call validate_token with empty token on the stub") def step_stub_validate_token_empty(context: Context) -> None: try: context.cov_stub_auth.validate_token("") except ValueError as exc: context.cov_caught_error = exc # --------------------------------------------------------------------------- # When steps — non-string type inputs to stubs # --------------------------------------------------------------------------- @when("I call get_plan_status with a non-string plan_id on the stub") def step_stub_get_plan_status_non_string(context: Context) -> None: try: context.cov_stub_exec.get_plan_status(12345) # type: ignore[arg-type] except ValueError as exc: context.cov_caught_error = exc @when("I call cancel_plan with a non-string plan_id on the stub") def step_stub_cancel_plan_non_string(context: Context) -> None: try: context.cov_stub_exec.cancel_plan(12345) # type: ignore[arg-type] except ValueError as exc: context.cov_caught_error = exc @when("I call validate_token with a non-string token on the stub") def step_stub_validate_token_non_string(context: Context) -> None: try: context.cov_stub_auth.validate_token(12345) # type: ignore[arg-type] except ValueError as exc: context.cov_caught_error = exc # --------------------------------------------------------------------------- # Then steps — ValueError assertions # --------------------------------------------------------------------------- @then("a ValueError should be raised with plan_id validation message") def step_value_error_plan_id_msg(context: Context) -> None: assert context.cov_caught_error is not None, ( "Expected ValueError but none was raised" ) assert isinstance(context.cov_caught_error, ValueError), ( f"Expected ValueError, got {type(context.cov_caught_error).__name__}" ) assert "plan_id" in str(context.cov_caught_error), ( f"Expected 'plan_id' in error message, got: {context.cov_caught_error}" ) @then("a ValueError should be raised with token validation message") def step_value_error_token_msg(context: Context) -> None: assert context.cov_caught_error is not None, ( "Expected ValueError but none was raised" ) assert isinstance(context.cov_caught_error, ValueError), ( f"Expected ValueError, got {type(context.cov_caught_error).__name__}" ) assert "token" in str(context.cov_caught_error), ( f"Expected 'token' in error message, got: {context.cov_caught_error}" )